Lokasi ngalangkungan proxy:   [ UP ]  
[Ngawartoskeun bug]   [Panyetelan cookie]                
Skip to content

Commit a546a12

Browse files
committed
aws: Add support for aws_codedeploy_deployment_group resources
1 parent fa3dfd1 commit a546a12

2 files changed

Lines changed: 376 additions & 0 deletions

File tree

builtin/providers/aws/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ func Provider() terraform.ResourceProvider {
167167
"aws_autoscaling_lifecycle_hook": resourceAwsAutoscalingLifecycleHook(),
168168
"aws_cloudwatch_metric_alarm": resourceAwsCloudWatchMetricAlarm(),
169169
"aws_codedeploy_app": resourceAwsCodeDeployApp(),
170+
"aws_codedeploy_deployment_group": resourceAwsCodeDeployDeploymentGroup(),
170171
"aws_customer_gateway": resourceAwsCustomerGateway(),
171172
"aws_db_instance": resourceAwsDbInstance(),
172173
"aws_db_parameter_group": resourceAwsDbParameterGroup(),
Lines changed: 375 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,375 @@
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/codedeploy"
16+
)
17+
18+
func resourceAwsCodeDeployDeploymentGroup() *schema.Resource {
19+
return &schema.Resource{
20+
Create: resourceAwsCodeDeployDeploymentGroupCreate,
21+
Read: resourceAwsCodeDeployDeploymentGroupRead,
22+
Update: resourceAwsCodeDeployDeploymentGroupUpdate,
23+
Delete: resourceAwsCodeDeployDeploymentGroupDelete,
24+
25+
Schema: map[string]*schema.Schema{
26+
"application_name": &schema.Schema{
27+
Type: schema.TypeString,
28+
Required: true,
29+
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
30+
value := v.(string)
31+
if len(value) > 100 {
32+
errors = append(errors, fmt.Errorf(
33+
"%q cannot exceed 100 characters", k))
34+
}
35+
return
36+
},
37+
},
38+
39+
"deployment_group_name": &schema.Schema{
40+
Type: schema.TypeString,
41+
Required: true,
42+
ForceNew: true,
43+
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
44+
value := v.(string)
45+
if len(value) > 100 {
46+
errors = append(errors, fmt.Errorf(
47+
"%q cannot exceed 100 characters", k))
48+
}
49+
return
50+
},
51+
},
52+
53+
"service_role_arn": &schema.Schema{
54+
Type: schema.TypeString,
55+
Required: true,
56+
},
57+
58+
"autoscaling_groups": &schema.Schema{
59+
Type: schema.TypeSet,
60+
Optional: true,
61+
Elem: &schema.Schema{Type: schema.TypeString},
62+
Set: schema.HashString,
63+
},
64+
65+
"deployment_config_name": &schema.Schema{
66+
Type: schema.TypeString,
67+
Optional: true,
68+
Default: "CodeDeployDefault.OneAtATime",
69+
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
70+
value := v.(string)
71+
if len(value) > 100 {
72+
errors = append(errors, fmt.Errorf(
73+
"%q cannot exceed 100 characters", k))
74+
}
75+
return
76+
},
77+
},
78+
79+
"ec2_tag_filter": &schema.Schema{
80+
Type: schema.TypeSet,
81+
Optional: true,
82+
Elem: &schema.Resource{
83+
Schema: map[string]*schema.Schema{
84+
"key": &schema.Schema{
85+
Type: schema.TypeString,
86+
Optional: true,
87+
},
88+
89+
"type": &schema.Schema{
90+
Type: schema.TypeString,
91+
Optional: true,
92+
ValidateFunc: validateTagFilters,
93+
},
94+
95+
"value": &schema.Schema{
96+
Type: schema.TypeString,
97+
Optional: true,
98+
},
99+
},
100+
},
101+
Set: resourceAwsCodeDeployTagFilterHash,
102+
},
103+
104+
"on_premises_instance_tag_filter": &schema.Schema{
105+
Type: schema.TypeSet,
106+
Optional: true,
107+
Elem: &schema.Resource{
108+
Schema: map[string]*schema.Schema{
109+
"key": &schema.Schema{
110+
Type: schema.TypeString,
111+
Optional: true,
112+
},
113+
114+
"type": &schema.Schema{
115+
Type: schema.TypeString,
116+
Optional: true,
117+
ValidateFunc: validateTagFilters,
118+
},
119+
120+
"value": &schema.Schema{
121+
Type: schema.TypeString,
122+
Optional: true,
123+
},
124+
},
125+
},
126+
Set: resourceAwsCodeDeployTagFilterHash,
127+
},
128+
},
129+
}
130+
}
131+
132+
func resourceAwsCodeDeployDeploymentGroupCreate(d *schema.ResourceData, meta interface{}) error {
133+
conn := meta.(*AWSClient).codedeployconn
134+
135+
application := d.Get("application_name").(string)
136+
deploymentGroup := d.Get("deployment_group_name").(string)
137+
138+
input := codedeploy.CreateDeploymentGroupInput{
139+
ApplicationName: aws.String(application),
140+
DeploymentGroupName: aws.String(deploymentGroup),
141+
ServiceRoleArn: aws.String(d.Get("service_role_arn").(string)),
142+
}
143+
if attr, ok := d.GetOk("deployment_config_name"); ok {
144+
input.DeploymentConfigName = aws.String(attr.(string))
145+
}
146+
if attr, ok := d.GetOk("autoscaling_groups"); ok {
147+
input.AutoScalingGroups = expandStringList(attr.(*schema.Set).List())
148+
}
149+
if attr, ok := d.GetOk("on_premises_instance_tag_filters"); ok {
150+
onPremFilters := buildOnPremTagFilters(attr.(*schema.Set).List())
151+
input.OnPremisesInstanceTagFilters = onPremFilters
152+
}
153+
if attr, ok := d.GetOk("ec2_tag_filter"); ok {
154+
ec2TagFilters := buildEC2TagFilters(attr.(*schema.Set).List())
155+
input.Ec2TagFilters = ec2TagFilters
156+
}
157+
158+
// Retry to handle IAM role eventual consistency.
159+
var resp *codedeploy.CreateDeploymentGroupOutput
160+
var err error
161+
err = resource.Retry(2*time.Minute, func() error {
162+
resp, err = conn.CreateDeploymentGroup(&input)
163+
if err != nil {
164+
codedeployErr, ok := err.(awserr.Error)
165+
if !ok {
166+
return &resource.RetryError{Err: err}
167+
}
168+
if codedeployErr.Code() == "InvalidRoleException" {
169+
log.Printf("[DEBUG] Trying to create deployment group again: %q",
170+
codedeployErr.Message())
171+
return err
172+
}
173+
174+
return &resource.RetryError{Err: err}
175+
}
176+
return nil
177+
})
178+
if err != nil {
179+
return err
180+
}
181+
182+
d.SetId(*resp.DeploymentGroupId)
183+
184+
return resourceAwsCodeDeployDeploymentGroupRead(d, meta)
185+
}
186+
187+
func resourceAwsCodeDeployDeploymentGroupRead(d *schema.ResourceData, meta interface{}) error {
188+
conn := meta.(*AWSClient).codedeployconn
189+
190+
log.Printf("[DEBUG] Reading CodeDeploy DeploymentGroup %s", d.Id())
191+
resp, err := conn.GetDeploymentGroup(&codedeploy.GetDeploymentGroupInput{
192+
ApplicationName: aws.String(d.Get("application_name").(string)),
193+
DeploymentGroupName: aws.String(d.Get("deployment_group_name").(string)),
194+
})
195+
if err != nil {
196+
return err
197+
}
198+
199+
d.Set("application_name", *resp.DeploymentGroupInfo.ApplicationName)
200+
d.Set("autoscaling_groups", resp.DeploymentGroupInfo.AutoScalingGroups)
201+
d.Set("deployment_config_name", *resp.DeploymentGroupInfo.DeploymentConfigName)
202+
d.Set("deployment_group_name", *resp.DeploymentGroupInfo.DeploymentGroupName)
203+
d.Set("service_role_arn", *resp.DeploymentGroupInfo.ServiceRoleArn)
204+
if err := d.Set("ec2_tag_filter", ec2TagFiltersToMap(resp.DeploymentGroupInfo.Ec2TagFilters)); err != nil {
205+
return err
206+
}
207+
if err := d.Set("on_premises_instance_tag_filter", onPremisesTagFiltersToMap(resp.DeploymentGroupInfo.OnPremisesInstanceTagFilters)); err != nil {
208+
return err
209+
}
210+
211+
return nil
212+
}
213+
214+
func resourceAwsCodeDeployDeploymentGroupUpdate(d *schema.ResourceData, meta interface{}) error {
215+
conn := meta.(*AWSClient).codedeployconn
216+
217+
input := codedeploy.UpdateDeploymentGroupInput{
218+
ApplicationName: aws.String(d.Get("application_name").(string)),
219+
CurrentDeploymentGroupName: aws.String(d.Get("deployment_group_name").(string)),
220+
}
221+
222+
if d.HasChange("autoscaling_groups") {
223+
_, n := d.GetChange("autoscaling_groups")
224+
input.AutoScalingGroups = expandStringList(n.(*schema.Set).List())
225+
}
226+
if d.HasChange("deployment_config_name") {
227+
_, n := d.GetChange("deployment_config_name")
228+
input.DeploymentConfigName = aws.String(n.(string))
229+
}
230+
if d.HasChange("deployment_group_name") {
231+
_, n := d.GetChange("deployment_group_name")
232+
input.NewDeploymentGroupName = aws.String(n.(string))
233+
}
234+
235+
// TagFilters aren't like tags. They don't append. They simply replace.
236+
if d.HasChange("on_premises_instance_tag_filter") {
237+
_, n := d.GetChange("on_premises_instance_tag_filter")
238+
onPremFilters := buildOnPremTagFilters(n.(*schema.Set).List())
239+
input.OnPremisesInstanceTagFilters = onPremFilters
240+
}
241+
if d.HasChange("ec2_tag_filter") {
242+
_, n := d.GetChange("ec2_tag_filter")
243+
ec2Filters := buildEC2TagFilters(n.(*schema.Set).List())
244+
input.Ec2TagFilters = ec2Filters
245+
}
246+
247+
log.Printf("[DEBUG] Updating CodeDeploy DeploymentGroup %s", d.Id())
248+
_, err := conn.UpdateDeploymentGroup(&input)
249+
if err != nil {
250+
return err
251+
}
252+
253+
return resourceAwsCodeDeployDeploymentGroupRead(d, meta)
254+
}
255+
256+
func resourceAwsCodeDeployDeploymentGroupDelete(d *schema.ResourceData, meta interface{}) error {
257+
conn := meta.(*AWSClient).codedeployconn
258+
259+
log.Printf("[DEBUG] Deleting CodeDeploy DeploymentGroup %s", d.Id())
260+
_, err := conn.DeleteDeploymentGroup(&codedeploy.DeleteDeploymentGroupInput{
261+
ApplicationName: aws.String(d.Get("application_name").(string)),
262+
DeploymentGroupName: aws.String(d.Get("deployment_group_name").(string)),
263+
})
264+
if err != nil {
265+
return err
266+
}
267+
268+
d.SetId("")
269+
270+
return nil
271+
}
272+
273+
// buildOnPremTagFilters converts raw schema lists into a list of
274+
// codedeploy.TagFilters.
275+
func buildOnPremTagFilters(configured []interface{}) []*codedeploy.TagFilter {
276+
filters := make([]*codedeploy.TagFilter, 0)
277+
for _, raw := range configured {
278+
var filter codedeploy.TagFilter
279+
m := raw.(map[string]interface{})
280+
281+
filter.Key = aws.String(m["key"].(string))
282+
filter.Type = aws.String(m["type"].(string))
283+
filter.Value = aws.String(m["value"].(string))
284+
285+
filters = append(filters, &filter)
286+
}
287+
288+
return filters
289+
}
290+
291+
// buildEC2TagFilters converts raw schema lists into a list of
292+
// codedeploy.EC2TagFilters.
293+
func buildEC2TagFilters(configured []interface{}) []*codedeploy.EC2TagFilter {
294+
filters := make([]*codedeploy.EC2TagFilter, 0)
295+
for _, raw := range configured {
296+
var filter codedeploy.EC2TagFilter
297+
m := raw.(map[string]interface{})
298+
299+
filter.Key = aws.String(m["key"].(string))
300+
filter.Type = aws.String(m["type"].(string))
301+
filter.Value = aws.String(m["value"].(string))
302+
303+
filters = append(filters, &filter)
304+
}
305+
306+
return filters
307+
}
308+
309+
// ec2TagFiltersToMap converts lists of tag filters into a []map[string]string.
310+
func ec2TagFiltersToMap(list []*codedeploy.EC2TagFilter) []map[string]string {
311+
result := make([]map[string]string, 0, len(list))
312+
for _, tf := range list {
313+
l := make(map[string]string)
314+
if *tf.Key != "" {
315+
l["key"] = *tf.Key
316+
}
317+
if *tf.Value != "" {
318+
l["value"] = *tf.Value
319+
}
320+
if *tf.Type != "" {
321+
l["type"] = *tf.Type
322+
}
323+
result = append(result, l)
324+
}
325+
return result
326+
}
327+
328+
// onPremisesTagFiltersToMap converts lists of on-prem tag filters into a []map[string]string.
329+
func onPremisesTagFiltersToMap(list []*codedeploy.TagFilter) []map[string]string {
330+
result := make([]map[string]string, 0, len(list))
331+
for _, tf := range list {
332+
l := make(map[string]string)
333+
if *tf.Key != "" {
334+
l["key"] = *tf.Key
335+
}
336+
if *tf.Value != "" {
337+
l["value"] = *tf.Value
338+
}
339+
if *tf.Type != "" {
340+
l["type"] = *tf.Type
341+
}
342+
result = append(result, l)
343+
}
344+
return result
345+
}
346+
347+
// validateTagFilters confirms the "value" component of a tag filter is one of
348+
// AWS's three allowed types.
349+
func validateTagFilters(v interface{}, k string) (ws []string, errors []error) {
350+
value := v.(string)
351+
if value != "KEY_ONLY" && value != "VALUE_ONLY" && value != "KEY_AND_VALUE" {
352+
errors = append(errors, fmt.Errorf(
353+
"%q must be one of \"KEY_ONLY\", \"VALUE_ONLY\", or \"KEY_AND_VALUE\"", k))
354+
}
355+
return
356+
}
357+
358+
func resourceAwsCodeDeployTagFilterHash(v interface{}) int {
359+
var buf bytes.Buffer
360+
m := v.(map[string]interface{})
361+
362+
// Nothing's actually required in tag filters, so we must check the
363+
// presence of all values before attempting a hash.
364+
if v, ok := m["key"]; ok {
365+
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
366+
}
367+
if v, ok := m["type"]; ok {
368+
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
369+
}
370+
if v, ok := m["value"]; ok {
371+
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
372+
}
373+
374+
return hashcode.String(buf.String())
375+
}

0 commit comments

Comments
 (0)