Skip to content

Commit

Permalink
resource/aws_ssm_maint_windows_task: Add CloudWatch configuration and…
Browse files Browse the repository at this point in the history
… plan time validations (#11774)

Output from acceptance testing in AWS Commercial:

```
--- PASS: TestAccAWSSSMMaintenanceWindowTask_disappears (19.58s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_emptyNotificationConfig (19.85s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_TaskInvocationStepFunctionParameters (22.39s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_updateForcesNewResource (34.36s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_basic (35.48s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_TaskInvocationAutomationParameters (42.68s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_TaskInvocationRunCommandParametersCloudWatch (44.70s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_TaskInvocationRunCommandParameters (45.14s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_TaskInvocationLambdaParameters (46.92s)
```

Output from acceptance testing in AWS GovCloud (US):

```
--- PASS: TestAccAWSSSMMaintenanceWindowTask_disappears (24.63s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_emptyNotificationConfig (24.80s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_TaskInvocationStepFunctionParameters (27.60s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_TaskInvocationLambdaParameters (39.96s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_basic (41.36s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_updateForcesNewResource (41.58s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_TaskInvocationAutomationParameters (48.45s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_TaskInvocationRunCommandParameters (49.11s)
--- PASS: TestAccAWSSSMMaintenanceWindowTask_TaskInvocationRunCommandParametersCloudWatch (54.92s)
```
  • Loading branch information
DrFaust92 committed Feb 12, 2021
1 parent e04e609 commit 596aa3d
Show file tree
Hide file tree
Showing 5 changed files with 282 additions and 89 deletions.
7 changes: 7 additions & 0 deletions .changelog/11774.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
resource/aws_ssm_maintenance_window_task: Add `task_invocation_parameters` `run_command_parameters` block `cloudwatch_config` and `document_version` arguments
```

```release-note:enhancement
resource/aws_ssm_maintenance_window_task: Add plan time validation to `max_concurrency`, `max_errors`, `priority`, `service_role_arn`, `targets`, `targets.notification_arn`, `targets.service_role_arn`, `task_type`, `task_invocation_parameters.run_command_parameters.comment`, `task_invocation_parameters.run_command_parameters.document_hash`, `task_invocation_parameters.run_command_parameters.timeout_seconds`, and `task_invocation_parameters.run_command_parameters.notification_config.notification_events` arguments
```
172 changes: 126 additions & 46 deletions aws/resource_aws_ssm_maintenance_window_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,22 @@ func resourceAwsSsmMaintenanceWindowTask() *schema.Resource {
},

"max_concurrency": {
Type: schema.TypeString,
Required: true,
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringMatch(regexp.MustCompile(`^([1-9][0-9]*|[1-9][0-9]%|[1-9]%|100%)$`), "must be a number without leading zeros or a percentage between 1% and 100% without leading zeros and ending with the percentage symbol"),
},

"max_errors": {
Type: schema.TypeString,
Required: true,
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringMatch(regexp.MustCompile(`^([1-9][0-9]*|[0]|[1-9][0-9]%|[0-9]%|100%)$`), "must be zero, a number without leading zeros, or a percentage between 1% and 100% without leading zeros and ending with the percentage symbol"),
},

"task_type": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice(ssm.MaintenanceWindowTaskType_Values(), false),
},

"task_arn": {
Expand All @@ -52,13 +55,15 @@ func resourceAwsSsmMaintenanceWindowTask() *schema.Resource {
},

"service_role_arn": {
Type: schema.TypeString,
Required: true,
Type: schema.TypeString,
Required: true,
ValidateFunc: validateArn,
},

"targets": {
Type: schema.TypeList,
Required: true,
Optional: true,
MaxItems: 5,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"key": {
Expand All @@ -68,16 +73,18 @@ func resourceAwsSsmMaintenanceWindowTask() *schema.Resource {
"values": {
Type: schema.TypeList,
Required: true,
MaxItems: 50,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
},

"name": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validateAwsSSMMaintenanceWindowTaskName,
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9_\-.]{3,128}$`),
"Only alphanumeric characters, hyphens, dots & underscores allowed."),
},

"description": {
Expand All @@ -87,8 +94,9 @@ func resourceAwsSsmMaintenanceWindowTask() *schema.Resource {
},

"priority": {
Type: schema.TypeInt,
Optional: true,
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntAtLeast(0),
},

"task_invocation_parameters": {
Expand Down Expand Up @@ -165,22 +173,26 @@ func resourceAwsSsmMaintenanceWindowTask() *schema.Resource {
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"comment": {
Type: schema.TypeString,
Optional: true,
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringLenBetween(0, 100),
},

"document_hash": {
Type: schema.TypeString,
Optional: true,
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringLenBetween(0, 256),
},

"document_hash_type": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
ssm.DocumentHashTypeSha256,
ssm.DocumentHashTypeSha1,
}, false),
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice(ssm.DocumentHashType_Values(), false),
},
"document_version": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringMatch(regexp.MustCompile(`([$]LATEST|[$]DEFAULT|^[1-9][0-9]*$)`), "must be $DEFAULT, $LATEST, or a version number"),
},

"notification_config": {
Expand All @@ -190,23 +202,24 @@ func resourceAwsSsmMaintenanceWindowTask() *schema.Resource {
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"notification_arn": {
Type: schema.TypeString,
Optional: true,
Type: schema.TypeString,
Optional: true,
ValidateFunc: validateArn,
},

"notification_events": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice(ssm.NotificationEvent_Values(), false),
},
},

"notification_type": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
ssm.NotificationTypeCommand,
ssm.NotificationTypeInvocation,
}, false),
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice(ssm.NotificationType_Values(), false),
},
},
},
Expand Down Expand Up @@ -242,13 +255,33 @@ func resourceAwsSsmMaintenanceWindowTask() *schema.Resource {
},

"service_role_arn": {
Type: schema.TypeString,
Optional: true,
Type: schema.TypeString,
Optional: true,
ValidateFunc: validateArn,
},

"timeout_seconds": {
Type: schema.TypeInt,
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntBetween(30, 2592000),
},
"cloudwatch_config": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cloudwatch_log_group_name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"cloudwatch_output_enabled": {
Type: schema.TypeBool,
Optional: true,
},
},
},
},
},
},
Expand Down Expand Up @@ -407,6 +440,9 @@ func expandAwsSsmTaskInvocationRunCommandParameters(config []interface{}) *ssm.M
if attr, ok := configParam["document_hash_type"]; ok && len(attr.(string)) != 0 {
params.DocumentHashType = aws.String(attr.(string))
}
if attr, ok := configParam["document_version"]; ok && len(attr.(string)) != 0 {
params.DocumentVersion = aws.String(attr.(string))
}
if attr, ok := configParam["notification_config"]; ok && len(attr.([]interface{})) > 0 {
params.NotificationConfig = expandAwsSsmTaskInvocationRunCommandParametersNotificationConfig(attr.([]interface{}))
}
Expand All @@ -425,6 +461,10 @@ func expandAwsSsmTaskInvocationRunCommandParameters(config []interface{}) *ssm.M
if attr, ok := configParam["timeout_seconds"]; ok && attr.(int) != 0 {
params.TimeoutSeconds = aws.Int64(int64(attr.(int)))
}

if attr, ok := configParam["cloudwatch_config"]; ok && len(attr.([]interface{})) > 0 {
params.CloudWatchOutputConfig = expandAwsSsmTaskInvocationRunCommandParametersCloudWatchConfig(attr.([]interface{}))
}
return params
}

Expand All @@ -440,6 +480,9 @@ func flattenAwsSsmTaskInvocationRunCommandParameters(parameters *ssm.Maintenance
if parameters.DocumentHashType != nil {
result["document_hash_type"] = aws.StringValue(parameters.DocumentHashType)
}
if parameters.DocumentVersion != nil {
result["document_version"] = aws.StringValue(parameters.DocumentVersion)
}
if parameters.NotificationConfig != nil {
result["notification_config"] = flattenAwsSsmTaskInvocationRunCommandParametersNotificationConfig(parameters.NotificationConfig)
}
Expand All @@ -458,6 +501,9 @@ func flattenAwsSsmTaskInvocationRunCommandParameters(parameters *ssm.Maintenance
if parameters.TimeoutSeconds != nil {
result["timeout_seconds"] = aws.Int64Value(parameters.TimeoutSeconds)
}
if parameters.CloudWatchOutputConfig != nil {
result["cloudwatch_config"] = flattenAwsSsmTaskInvocationRunCommandParametersCloudWatchConfig(parameters.CloudWatchOutputConfig)
}

return []interface{}{result}
}
Expand Down Expand Up @@ -529,6 +575,37 @@ func flattenAwsSsmTaskInvocationRunCommandParametersNotificationConfig(config *s
return []interface{}{result}
}

func expandAwsSsmTaskInvocationRunCommandParametersCloudWatchConfig(config []interface{}) *ssm.CloudWatchOutputConfig {
if len(config) == 0 || config[0] == nil {
return nil
}

params := &ssm.CloudWatchOutputConfig{}
configParam := config[0].(map[string]interface{})

if attr, ok := configParam["cloudwatch_log_group_name"]; ok && len(attr.(string)) != 0 {
params.CloudWatchLogGroupName = aws.String(attr.(string))
}
if attr, ok := configParam["cloudwatch_output_enabled"]; ok {
params.CloudWatchOutputEnabled = aws.Bool(attr.(bool))
}

return params
}

func flattenAwsSsmTaskInvocationRunCommandParametersCloudWatchConfig(config *ssm.CloudWatchOutputConfig) []interface{} {
result := make(map[string]interface{})

if config.CloudWatchLogGroupName != nil {
result["cloudwatch_log_group_name"] = aws.StringValue(config.CloudWatchLogGroupName)
}
if config.CloudWatchOutputEnabled != nil {
result["cloudwatch_output_enabled"] = aws.BoolValue(config.CloudWatchOutputEnabled)
}

return []interface{}{result}
}

func expandAwsSsmTaskInvocationCommonParameters(config []interface{}) map[string][]*string {
if len(config) == 0 || config[0] == nil {
return nil
Expand Down Expand Up @@ -569,7 +646,7 @@ func flattenAwsSsmTaskInvocationCommonParameters(parameters map[string][]*string
}

func resourceAwsSsmMaintenanceWindowTaskCreate(d *schema.ResourceData, meta interface{}) error {
ssmconn := meta.(*AWSClient).ssmconn
conn := meta.(*AWSClient).ssmconn

log.Printf("[INFO] Registering SSM Maintenance Window Task")

Expand All @@ -580,7 +657,10 @@ func resourceAwsSsmMaintenanceWindowTaskCreate(d *schema.ResourceData, meta inte
TaskType: aws.String(d.Get("task_type").(string)),
ServiceRoleArn: aws.String(d.Get("service_role_arn").(string)),
TaskArn: aws.String(d.Get("task_arn").(string)),
Targets: expandAwsSsmTargets(d.Get("targets").([]interface{})),
}

if v, ok := d.GetOk("targets"); ok {
params.Targets = expandAwsSsmTargets(v.([]interface{}))
}

if v, ok := d.GetOk("name"); ok {
Expand All @@ -599,7 +679,7 @@ func resourceAwsSsmMaintenanceWindowTaskCreate(d *schema.ResourceData, meta inte
params.TaskInvocationParameters = expandAwsSsmTaskInvocationParameters(v.([]interface{}))
}

resp, err := ssmconn.RegisterTaskWithMaintenanceWindow(params)
resp, err := conn.RegisterTaskWithMaintenanceWindow(params)
if err != nil {
return err
}
Expand All @@ -610,14 +690,14 @@ func resourceAwsSsmMaintenanceWindowTaskCreate(d *schema.ResourceData, meta inte
}

func resourceAwsSsmMaintenanceWindowTaskRead(d *schema.ResourceData, meta interface{}) error {
ssmconn := meta.(*AWSClient).ssmconn
conn := meta.(*AWSClient).ssmconn
windowID := d.Get("window_id").(string)

params := &ssm.GetMaintenanceWindowTaskInput{
WindowId: aws.String(windowID),
WindowTaskId: aws.String(d.Id()),
}
resp, err := ssmconn.GetMaintenanceWindowTask(params)
resp, err := conn.GetMaintenanceWindowTask(params)
if isAWSErr(err, ssm.ErrCodeDoesNotExistException, "") {
log.Printf("[WARN] Maintenance Window (%s) Task (%s) not found, removing from state", windowID, d.Id())
d.SetId("")
Expand Down Expand Up @@ -651,7 +731,7 @@ func resourceAwsSsmMaintenanceWindowTaskRead(d *schema.ResourceData, meta interf
}

func resourceAwsSsmMaintenanceWindowTaskUpdate(d *schema.ResourceData, meta interface{}) error {
ssmconn := meta.(*AWSClient).ssmconn
conn := meta.(*AWSClient).ssmconn
windowID := d.Get("window_id").(string)

params := &ssm.UpdateMaintenanceWindowTaskInput{
Expand Down Expand Up @@ -681,7 +761,7 @@ func resourceAwsSsmMaintenanceWindowTaskUpdate(d *schema.ResourceData, meta inte
params.TaskInvocationParameters = expandAwsSsmTaskInvocationParameters(v.([]interface{}))
}

_, err := ssmconn.UpdateMaintenanceWindowTask(params)
_, err := conn.UpdateMaintenanceWindowTask(params)
if isAWSErr(err, ssm.ErrCodeDoesNotExistException, "") {
log.Printf("[WARN] Maintenance Window (%s) Task (%s) not found, removing from state", windowID, d.Id())
d.SetId("")
Expand All @@ -696,7 +776,7 @@ func resourceAwsSsmMaintenanceWindowTaskUpdate(d *schema.ResourceData, meta inte
}

func resourceAwsSsmMaintenanceWindowTaskDelete(d *schema.ResourceData, meta interface{}) error {
ssmconn := meta.(*AWSClient).ssmconn
conn := meta.(*AWSClient).ssmconn

log.Printf("[INFO] Deregistering SSM Maintenance Window Task: %s", d.Id())

Expand All @@ -705,7 +785,7 @@ func resourceAwsSsmMaintenanceWindowTaskDelete(d *schema.ResourceData, meta inte
WindowTaskId: aws.String(d.Id()),
}

_, err := ssmconn.DeregisterTaskFromMaintenanceWindow(params)
_, err := conn.DeregisterTaskFromMaintenanceWindow(params)
if isAWSErr(err, ssm.ErrCodeDoesNotExistException, "") {
return nil
}
Expand Down
Loading

0 comments on commit 596aa3d

Please sign in to comment.