provider/aws: Add support for aws_ssm_maintenance_window (#14087)

* provider/aws: Add support for aws_ssm_maintenance_window

Fixes: #14027

```
% make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSSSMMaintenanceWindow_basic'
==> Checking that code complies with gofmt requirements...
go generate $(go list ./... | grep -v /terraform/vendor/)
2017/04/29 13:38:19 Generated command/internal_plugin_list.go
TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSSSMMaintenanceWindow_basic -timeout 120m
=== RUN   TestAccAWSSSMMaintenanceWindow_basic
--- PASS: TestAccAWSSSMMaintenanceWindow_basic (51.69s)
PASS
ok  	github.com/hashicorp/terraform/builtin/providers/aws	51.711s
```

* provider/aws: Add documentation for aws_ssm_maintenance_window

* provider/aws: Add support for aws_ssm_maintenance_window_target

```
% make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSSSMMaintenanceWindowTarget'
==> Checking that code complies with gofmt requirements...
go generate $(go list ./... | grep -v /terraform/vendor/)
2017/04/29 16:38:22 Generated command/internal_plugin_list.go
TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSSSMMaintenanceWindowTarget -timeout 120m
=== RUN   TestAccAWSSSMMaintenanceWindowTarget_basic
--- PASS: TestAccAWSSSMMaintenanceWindowTarget_basic (34.68s)
PASS
ok  	github.com/hashicorp/terraform/builtin/providers/aws	34.701s
```

* provider/aws: Adding the documentation for aws_ssm_maintenance_window_target

* provider/aws: Add support for aws_ssm_maintenance_window_task

* provider/aws: Documentation for aws_ssm_maintenance_window_task
This commit is contained in:
Paul Stack 2017-05-04 20:36:28 +03:00 committed by GitHub
parent 3fe6b536ff
commit e18f8df845
11 changed files with 1165 additions and 0 deletions

View File

@ -422,6 +422,9 @@ func Provider() terraform.ResourceProvider {
"aws_ssm_activation": resourceAwsSsmActivation(), "aws_ssm_activation": resourceAwsSsmActivation(),
"aws_ssm_association": resourceAwsSsmAssociation(), "aws_ssm_association": resourceAwsSsmAssociation(),
"aws_ssm_document": resourceAwsSsmDocument(), "aws_ssm_document": resourceAwsSsmDocument(),
"aws_ssm_maintenance_window": resourceAwsSsmMaintenanceWindow(),
"aws_ssm_maintenance_window_target": resourceAwsSsmMaintenanceWindowTarget(),
"aws_ssm_maintenance_window_task": resourceAwsSsmMaintenanceWindowTask(),
"aws_spot_datafeed_subscription": resourceAwsSpotDataFeedSubscription(), "aws_spot_datafeed_subscription": resourceAwsSpotDataFeedSubscription(),
"aws_spot_instance_request": resourceAwsSpotInstanceRequest(), "aws_spot_instance_request": resourceAwsSpotInstanceRequest(),
"aws_spot_fleet_request": resourceAwsSpotFleetRequest(), "aws_spot_fleet_request": resourceAwsSpotFleetRequest(),

View File

@ -0,0 +1,168 @@
package aws
import (
"log"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/hashicorp/terraform/helper/schema"
)
func resourceAwsSsmMaintenanceWindow() *schema.Resource {
return &schema.Resource{
Create: resourceAwsSsmMaintenanceWindowCreate,
Read: resourceAwsSsmMaintenanceWindowRead,
Update: resourceAwsSsmMaintenanceWindowUpdate,
Delete: resourceAwsSsmMaintenanceWindowDelete,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"schedule": {
Type: schema.TypeString,
Required: true,
},
"duration": {
Type: schema.TypeInt,
Required: true,
},
"cutoff": {
Type: schema.TypeInt,
Required: true,
},
"allow_unassociated_targets": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"enabled": {
Type: schema.TypeBool,
Optional: true,
Default: true,
},
},
}
}
func resourceAwsSsmMaintenanceWindowCreate(d *schema.ResourceData, meta interface{}) error {
ssmconn := meta.(*AWSClient).ssmconn
params := &ssm.CreateMaintenanceWindowInput{
Name: aws.String(d.Get("name").(string)),
Schedule: aws.String(d.Get("schedule").(string)),
Duration: aws.Int64(int64(d.Get("duration").(int))),
Cutoff: aws.Int64(int64(d.Get("cutoff").(int))),
AllowUnassociatedTargets: aws.Bool(d.Get("allow_unassociated_targets").(bool)),
}
resp, err := ssmconn.CreateMaintenanceWindow(params)
if err != nil {
return err
}
d.SetId(*resp.WindowId)
return resourceAwsSsmMaintenanceWindowRead(d, meta)
}
func resourceAwsSsmMaintenanceWindowUpdate(d *schema.ResourceData, meta interface{}) error {
ssmconn := meta.(*AWSClient).ssmconn
params := &ssm.UpdateMaintenanceWindowInput{
WindowId: aws.String(d.Id()),
}
if d.HasChange("name") {
params.Name = aws.String(d.Get("name").(string))
}
if d.HasChange("schedule") {
params.Schedule = aws.String(d.Get("schedule").(string))
}
if d.HasChange("duration") {
params.Duration = aws.Int64(int64(d.Get("duration").(int)))
}
if d.HasChange("cutoff") {
params.Cutoff = aws.Int64(int64(d.Get("cutoff").(int)))
}
if d.HasChange("allow_unassociated_targets") {
params.AllowUnassociatedTargets = aws.Bool(d.Get("allow_unassociated_targets").(bool))
}
if d.HasChange("enabled") {
params.Enabled = aws.Bool(d.Get("enabled").(bool))
}
_, err := ssmconn.UpdateMaintenanceWindow(params)
if err != nil {
return err
}
return resourceAwsSsmMaintenanceWindowRead(d, meta)
}
func resourceAwsSsmMaintenanceWindowRead(d *schema.ResourceData, meta interface{}) error {
ssmconn := meta.(*AWSClient).ssmconn
params := &ssm.DescribeMaintenanceWindowsInput{
Filters: []*ssm.MaintenanceWindowFilter{
{
Key: aws.String("Name"),
Values: []*string{aws.String(d.Get("name").(string))},
},
},
}
resp, err := ssmconn.DescribeMaintenanceWindows(params)
if err != nil {
return err
}
found := false
for _, window := range resp.WindowIdentities {
if *window.WindowId == d.Id() {
found = true
d.Set("name", window.Name)
d.Set("cutoff", window.Cutoff)
d.Set("duration", window.Duration)
d.Set("enabled", window.Enabled)
}
}
if !found {
log.Printf("[INFO] Cannot find the SSM Maintenance Window %q. Removing from state", d.Get("name").(string))
d.SetId("")
return nil
}
return nil
}
func resourceAwsSsmMaintenanceWindowDelete(d *schema.ResourceData, meta interface{}) error {
ssmconn := meta.(*AWSClient).ssmconn
log.Printf("[INFO] Deleting SSM Maintenance Window: %s", d.Id())
params := &ssm.DeleteMaintenanceWindowInput{
WindowId: aws.String(d.Id()),
}
_, err := ssmconn.DeleteMaintenanceWindow(params)
if err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,179 @@
package aws
import (
"fmt"
"log"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/hashicorp/terraform/helper/schema"
)
func resourceAwsSsmMaintenanceWindowTarget() *schema.Resource {
return &schema.Resource{
Create: resourceAwsSsmMaintenanceWindowTargetCreate,
Read: resourceAwsSsmMaintenanceWindowTargetRead,
Delete: resourceAwsSsmMaintenanceWindowTargetDelete,
Schema: map[string]*schema.Schema{
"window_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"resource_type": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"targets": {
Type: schema.TypeList,
Required: true,
ForceNew: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"key": {
Type: schema.TypeString,
Required: true,
},
"values": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
},
"owner_information": {
Type: schema.TypeString,
ForceNew: true,
Optional: true,
},
},
}
}
func expandAwsSsmMaintenanceWindowTargets(d *schema.ResourceData) []*ssm.Target {
var targets []*ssm.Target
targetConfig := d.Get("targets").([]interface{})
for _, tConfig := range targetConfig {
config := tConfig.(map[string]interface{})
target := &ssm.Target{
Key: aws.String(config["key"].(string)),
Values: expandStringList(config["values"].([]interface{})),
}
targets = append(targets, target)
}
return targets
}
func flattenAwsSsmMaintenanceWindowTargets(targets []*ssm.Target) []map[string]interface{} {
if len(targets) == 0 {
return nil
}
result := make([]map[string]interface{}, 0, len(targets))
target := targets[0]
t := make(map[string]interface{})
t["key"] = *target.Key
t["values"] = flattenStringList(target.Values)
result = append(result, t)
return result
}
func resourceAwsSsmMaintenanceWindowTargetCreate(d *schema.ResourceData, meta interface{}) error {
ssmconn := meta.(*AWSClient).ssmconn
log.Printf("[INFO] Registering SSM Maintenance Window Target")
params := &ssm.RegisterTargetWithMaintenanceWindowInput{
WindowId: aws.String(d.Get("window_id").(string)),
ResourceType: aws.String(d.Get("resource_type").(string)),
Targets: expandAwsSsmMaintenanceWindowTargets(d),
}
if v, ok := d.GetOk("owner_information"); ok {
params.OwnerInformation = aws.String(v.(string))
}
resp, err := ssmconn.RegisterTargetWithMaintenanceWindow(params)
if err != nil {
return err
}
d.SetId(*resp.WindowTargetId)
return resourceAwsSsmMaintenanceWindowTargetRead(d, meta)
}
func resourceAwsSsmMaintenanceWindowTargetRead(d *schema.ResourceData, meta interface{}) error {
ssmconn := meta.(*AWSClient).ssmconn
params := &ssm.DescribeMaintenanceWindowTargetsInput{
WindowId: aws.String(d.Get("window_id").(string)),
Filters: []*ssm.MaintenanceWindowFilter{
{
Key: aws.String("WindowTargetId"),
Values: []*string{aws.String(d.Id())},
},
},
}
resp, err := ssmconn.DescribeMaintenanceWindowTargets(params)
if err != nil {
return err
}
found := false
for _, t := range resp.Targets {
if *t.WindowTargetId == d.Id() {
found = true
d.Set("owner_information", t.OwnerInformation)
d.Set("window_id", t.WindowId)
d.Set("resource_type", t.ResourceType)
if err := d.Set("targets", flattenAwsSsmMaintenanceWindowTargets(t.Targets)); err != nil {
return fmt.Errorf("[DEBUG] Error setting targets error: %#v", err)
}
}
}
if !found {
log.Printf("[INFO] Maintenance Window Target not found. Removing from state")
d.SetId("")
return nil
}
return nil
}
func resourceAwsSsmMaintenanceWindowTargetDelete(d *schema.ResourceData, meta interface{}) error {
ssmconn := meta.(*AWSClient).ssmconn
log.Printf("[INFO] Deregistering SSM Maintenance Window Target: %s", d.Id())
params := &ssm.DeregisterTargetFromMaintenanceWindowInput{
WindowId: aws.String(d.Get("window_id").(string)),
WindowTargetId: aws.String(d.Id()),
}
_, err := ssmconn.DeregisterTargetFromMaintenanceWindow(params)
if err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,122 @@
package aws
import (
"fmt"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccAWSSSMMaintenanceWindowTarget_basic(t *testing.T) {
name := acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSSSMMaintenanceWindowTargetDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSSSMMaintenanceWindowTargetBasicConfig(name),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSSSMMaintenanceWindowTargetExists("aws_ssm_maintenance_window_target.target"),
),
},
},
})
}
func testAccCheckAWSSSMMaintenanceWindowTargetExists(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No SSM Maintenance Window Target Window ID is set")
}
conn := testAccProvider.Meta().(*AWSClient).ssmconn
resp, err := conn.DescribeMaintenanceWindowTargets(&ssm.DescribeMaintenanceWindowTargetsInput{
WindowId: aws.String(rs.Primary.Attributes["window_id"]),
Filters: []*ssm.MaintenanceWindowFilter{
{
Key: aws.String("WindowTargetId"),
Values: []*string{aws.String(rs.Primary.ID)},
},
},
})
if err != nil {
return err
}
for _, i := range resp.Targets {
if *i.WindowTargetId == rs.Primary.ID {
return nil
}
}
return fmt.Errorf("No AWS SSM Maintenance window target found")
}
}
func testAccCheckAWSSSMMaintenanceWindowTargetDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).ssmconn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_ssm_maintenance_window_target" {
continue
}
out, err := conn.DescribeMaintenanceWindowTargets(&ssm.DescribeMaintenanceWindowTargetsInput{
WindowId: aws.String(rs.Primary.Attributes["window_id"]),
Filters: []*ssm.MaintenanceWindowFilter{
{
Key: aws.String("WindowTargetId"),
Values: []*string{aws.String(rs.Primary.ID)},
},
},
})
if err != nil {
// Verify the error is what we want
if ae, ok := err.(awserr.Error); ok && ae.Code() == "DoesNotExistException" {
continue
}
return err
}
if len(out.Targets) > 0 {
return fmt.Errorf("Expected AWS SSM Maintenance Target to be gone, but was still found")
}
return nil
}
return nil
}
func testAccAWSSSMMaintenanceWindowTargetBasicConfig(rName string) string {
return fmt.Sprintf(`
resource "aws_ssm_maintenance_window" "foo" {
name = "maintenance-window-%s"
schedule = "cron(0 16 ? * TUE *)"
duration = 3
cutoff = 1
}
resource "aws_ssm_maintenance_window_target" "target" {
window_id = "${aws_ssm_maintenance_window.foo.id}"
resource_type = "INSTANCE"
targets {
key = "tag:Name"
values = ["acceptance_test"]
}
}
`, rName)
}

View File

@ -0,0 +1,230 @@
package aws
import (
"fmt"
"log"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/hashicorp/terraform/helper/schema"
)
func resourceAwsSsmMaintenanceWindowTask() *schema.Resource {
return &schema.Resource{
Create: resourceAwsSsmMaintenanceWindowTaskCreate,
Read: resourceAwsSsmMaintenanceWindowTaskRead,
Delete: resourceAwsSsmMaintenanceWindowTaskDelete,
Schema: map[string]*schema.Schema{
"window_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"max_concurrency": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"max_errors": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"task_type": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"task_arn": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"service_role_arn": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"targets": {
Type: schema.TypeList,
Required: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"key": {
Type: schema.TypeString,
Required: true,
},
"values": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
},
"priority": {
Type: schema.TypeInt,
Optional: true,
ForceNew: true,
},
"logging_info": {
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"s3_bucket_name": {
Type: schema.TypeString,
Required: true,
},
"s3_region": {
Type: schema.TypeString,
Required: true,
},
"s3_bucket_prefix": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
},
}
}
func expandAwsSsmMaintenanceWindowLoggingInfo(config []interface{}) *ssm.LoggingInfo {
loggingConfig := config[0].(map[string]interface{})
loggingInfo := &ssm.LoggingInfo{
S3BucketName: aws.String(loggingConfig["s3_bucket_name"].(string)),
S3Region: aws.String(loggingConfig["s3_region"].(string)),
}
if s := loggingConfig["s3_bucket_prefix"].(string); s != "" {
loggingInfo.S3KeyPrefix = aws.String(s)
}
return loggingInfo
}
func flattenAwsSsmMaintenanceWindowLoggingInfo(loggingInfo *ssm.LoggingInfo) []interface{} {
result := make(map[string]interface{})
result["s3_bucket_name"] = *loggingInfo.S3BucketName
result["s3_region"] = *loggingInfo.S3Region
if loggingInfo.S3KeyPrefix != nil {
result["s3_bucket_prefix"] = *loggingInfo.S3KeyPrefix
}
return []interface{}{result}
}
func resourceAwsSsmMaintenanceWindowTaskCreate(d *schema.ResourceData, meta interface{}) error {
ssmconn := meta.(*AWSClient).ssmconn
log.Printf("[INFO] Registering SSM Maintenance Window Task")
params := &ssm.RegisterTaskWithMaintenanceWindowInput{
WindowId: aws.String(d.Get("window_id").(string)),
MaxConcurrency: aws.String(d.Get("max_concurrency").(string)),
MaxErrors: aws.String(d.Get("max_errors").(string)),
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: expandAwsSsmMaintenanceWindowTargets(d),
}
if v, ok := d.GetOk("priority"); ok {
params.Priority = aws.Int64(int64(v.(int)))
}
if v, ok := d.GetOk("logging_info"); ok {
params.LoggingInfo = expandAwsSsmMaintenanceWindowLoggingInfo(v.([]interface{}))
}
resp, err := ssmconn.RegisterTaskWithMaintenanceWindow(params)
if err != nil {
return err
}
d.SetId(*resp.WindowTaskId)
return resourceAwsSsmMaintenanceWindowTaskRead(d, meta)
}
func resourceAwsSsmMaintenanceWindowTaskRead(d *schema.ResourceData, meta interface{}) error {
ssmconn := meta.(*AWSClient).ssmconn
params := &ssm.DescribeMaintenanceWindowTasksInput{
WindowId: aws.String(d.Get("window_id").(string)),
}
resp, err := ssmconn.DescribeMaintenanceWindowTasks(params)
if err != nil {
return err
}
found := false
for _, t := range resp.Tasks {
if *t.WindowTaskId == d.Id() {
found = true
d.Set("window_id", t.WindowId)
d.Set("max_concurrency", t.MaxConcurrency)
d.Set("max_errors", t.MaxErrors)
d.Set("task_type", t.Type)
d.Set("service_role_arn", t.ServiceRoleArn)
d.Set("task_arn", t.TaskArn)
d.Set("priority", t.Priority)
if t.LoggingInfo != nil {
if err := d.Set("logging_info", flattenAwsSsmMaintenanceWindowLoggingInfo(t.LoggingInfo)); err != nil {
return fmt.Errorf("[DEBUG] Error setting logging_info error: %#v", err)
}
}
if err := d.Set("targets", flattenAwsSsmMaintenanceWindowTargets(t.Targets)); err != nil {
return fmt.Errorf("[DEBUG] Error setting targets error: %#v", err)
}
}
}
if !found {
log.Printf("[INFO] Maintenance Window Target not found. Removing from state")
d.SetId("")
return nil
}
return nil
}
func resourceAwsSsmMaintenanceWindowTaskDelete(d *schema.ResourceData, meta interface{}) error {
ssmconn := meta.(*AWSClient).ssmconn
log.Printf("[INFO] Deregistering SSM Maintenance Window Task: %s", d.Id())
params := &ssm.DeregisterTaskFromMaintenanceWindowInput{
WindowId: aws.String(d.Get("window_id").(string)),
WindowTaskId: aws.String(d.Id()),
}
_, err := ssmconn.DeregisterTaskFromMaintenanceWindow(params)
if err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,158 @@
package aws
import (
"fmt"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccAWSSSMMaintenanceWindowTask_basic(t *testing.T) {
name := acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSSSMMaintenanceWindowTaskDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSSSMMaintenanceWindowTaskBasicConfig(name),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSSSMMaintenanceWindowTaskExists("aws_ssm_maintenance_window_task.target"),
),
},
},
})
}
func testAccCheckAWSSSMMaintenanceWindowTaskExists(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No SSM Maintenance Window Task Window ID is set")
}
conn := testAccProvider.Meta().(*AWSClient).ssmconn
resp, err := conn.DescribeMaintenanceWindowTasks(&ssm.DescribeMaintenanceWindowTasksInput{
WindowId: aws.String(rs.Primary.Attributes["window_id"]),
})
if err != nil {
return err
}
for _, i := range resp.Tasks {
if *i.WindowTaskId == rs.Primary.ID {
return nil
}
}
return fmt.Errorf("No AWS SSM Maintenance window task found")
}
}
func testAccCheckAWSSSMMaintenanceWindowTaskDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).ssmconn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_ssm_maintenance_window_target" {
continue
}
out, err := conn.DescribeMaintenanceWindowTasks(&ssm.DescribeMaintenanceWindowTasksInput{
WindowId: aws.String(rs.Primary.Attributes["window_id"]),
})
if err != nil {
// Verify the error is what we want
if ae, ok := err.(awserr.Error); ok && ae.Code() == "DoesNotExistException" {
continue
}
return err
}
if len(out.Tasks) > 0 {
return fmt.Errorf("Expected AWS SSM Maintenance Task to be gone, but was still found")
}
return nil
}
return nil
}
func testAccAWSSSMMaintenanceWindowTaskBasicConfig(rName string) string {
return fmt.Sprintf(`
resource "aws_ssm_maintenance_window" "foo" {
name = "maintenance-window-%s"
schedule = "cron(0 16 ? * TUE *)"
duration = 3
cutoff = 1
}
resource "aws_ssm_maintenance_window_task" "target" {
window_id = "${aws_ssm_maintenance_window.foo.id}"
task_type = "RUN_COMMAND"
task_arn = "AWS-RunShellScript"
priority = 1
service_role_arn = "${aws_iam_role.ssm_role.arn}"
max_concurrency = "2"
max_errors = "1"
targets {
key = "InstanceIds"
values = ["${aws_instance.foo.id}"]
}
}
resource "aws_instance" "foo" {
ami = "ami-4fccb37f"
instance_type = "m1.small"
}
resource "aws_iam_role" "ssm_role" {
name = "ssm-role-%s"
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "events.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
POLICY
}
resource "aws_iam_role_policy" "bar" {
name = "ssm_role_policy_%s"
role = "${aws_iam_role.ssm_role.name}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "ssm:*",
"Resource": "*"
}
}
EOF
}
`, rName, rName, rName)
}

View File

@ -0,0 +1,141 @@
package aws
import (
"fmt"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccAWSSSMMaintenanceWindow_basic(t *testing.T) {
name := acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSSSMMaintenanceWindowDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSSSMMaintenanceWindowBasicConfig(name),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSSSMMaintenanceWindowExists("aws_ssm_maintenance_window.foo"),
resource.TestCheckResourceAttr(
"aws_ssm_maintenance_window.foo", "schedule", "cron(0 16 ? * TUE *)"),
resource.TestCheckResourceAttr(
"aws_ssm_maintenance_window.foo", "duration", "3"),
resource.TestCheckResourceAttr(
"aws_ssm_maintenance_window.foo", "cutoff", "1"),
resource.TestCheckResourceAttr(
"aws_ssm_maintenance_window.foo", "name", fmt.Sprintf("maintenance-window-%s", name)),
),
},
{
Config: testAccAWSSSMMaintenanceWindowBasicConfigUpdated(name),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSSSMMaintenanceWindowExists("aws_ssm_maintenance_window.foo"),
resource.TestCheckResourceAttr(
"aws_ssm_maintenance_window.foo", "schedule", "cron(0 16 ? * WED *)"),
resource.TestCheckResourceAttr(
"aws_ssm_maintenance_window.foo", "duration", "10"),
resource.TestCheckResourceAttr(
"aws_ssm_maintenance_window.foo", "cutoff", "8"),
resource.TestCheckResourceAttr(
"aws_ssm_maintenance_window.foo", "name", fmt.Sprintf("updated-maintenance-window-%s", name)),
),
},
},
})
}
func testAccCheckAWSSSMMaintenanceWindowExists(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No SSM Maintenance Window ID is set")
}
conn := testAccProvider.Meta().(*AWSClient).ssmconn
resp, err := conn.DescribeMaintenanceWindows(&ssm.DescribeMaintenanceWindowsInput{
Filters: []*ssm.MaintenanceWindowFilter{
{
Key: aws.String("Name"),
Values: []*string{aws.String(rs.Primary.Attributes["name"])},
},
},
})
for _, i := range resp.WindowIdentities {
if *i.WindowId == rs.Primary.ID {
return nil
}
}
if err != nil {
return err
}
return fmt.Errorf("No AWS SSM Maintenance window found")
}
}
func testAccCheckAWSSSMMaintenanceWindowDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).ssmconn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_ssm_maintenance_window" {
continue
}
out, err := conn.DescribeMaintenanceWindows(&ssm.DescribeMaintenanceWindowsInput{
Filters: []*ssm.MaintenanceWindowFilter{
{
Key: aws.String("Name"),
Values: []*string{aws.String(rs.Primary.Attributes["name"])},
},
},
})
if err != nil {
return err
}
if len(out.WindowIdentities) > 0 {
return fmt.Errorf("Expected AWS SSM Maintenance Document to be gone, but was still found")
}
return nil
}
return nil
}
func testAccAWSSSMMaintenanceWindowBasicConfig(rName string) string {
return fmt.Sprintf(`
resource "aws_ssm_maintenance_window" "foo" {
name = "maintenance-window-%s"
schedule = "cron(0 16 ? * TUE *)"
duration = 3
cutoff = 1
}
`, rName)
}
func testAccAWSSSMMaintenanceWindowBasicConfigUpdated(rName string) string {
return fmt.Sprintf(`
resource "aws_ssm_maintenance_window" "foo" {
name = "updated-maintenance-window-%s"
schedule = "cron(0 16 ? * WED *)"
duration = 10
cutoff = 8
}
`, rName)
}

View File

@ -0,0 +1,38 @@
---
layout: "aws"
page_title: "AWS: aws_ssm_maintenance_window"
sidebar_current: "docs-aws-resource-ssm-maintenance-window"
description: |-
Provides an SSM Maintenance Window resource
---
# aws_ssm_maintenance_window
Provides an SSM Maintenance Window resource
## Example Usage
```hcl
resource "aws_ssm_maintenance_window" "production" {
name = "maintenance-window-application"
schedule = "cron(0 16 ? * TUE *)"
duration = 3
cutoff = 1
}
```
## Argument Reference
The following arguments are supported:
* `name` - (Required) The name of the maintenance window.
* `schedule` - (Required) The schedule of the Maintenance Window in the form of a [cron](https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-maintenance-cron.html) or rate expression.
* `cutoff` - (Required) The number of hours before the end of the Maintenance Window that Systems Manager stops scheduling new tasks for execution.
* `duration` - (Required) The duration of the Maintenance Window in hours.
* `allow_unregistered_targets` - (Optional) Whether targets must be registered with the Maintenance Window before tasks can be defined for those targets.
## Attributes Reference
The following attributes are exported:
* `id` - The ID of the maintenance window.

View File

@ -0,0 +1,46 @@
---
layout: "aws"
page_title: "AWS: aws_ssm_maintenance_window_target"
sidebar_current: "docs-aws-resource-ssm-maintenance-window-target"
description: |-
Provides an SSM Maintenance Window Target resource
---
# aws_ssm_maintenance_window_target
Provides an SSM Maintenance Window Target resource
## Example Usage
```hcl
resource "aws_ssm_maintenance_window" "window" {
name = "maintenance-window-webapp"
schedule = "cron(0 16 ? * TUE *)"
duration = 3
cutoff = 1
}
resource "aws_ssm_maintenance_window_target" "target1" {
window_id = "${aws_ssm_maintenance_window.window.id}"
resource_type = "INSTANCE"
targets {
key = "tag:Name"
values = ["acceptance_test"]
}
}
```
## Argument Reference
The following arguments are supported:
* `window_id` - (Required) The Id of the maintenance window to register the target with.
* `resource_type` - (Required) The type of target being registered with the Maintenance Window. Possible values `INSTANCE`.
* `targets` - (Required) The targets (either instances or tags). Instances are specified using Key=instanceids,Values=instanceid1,instanceid2. Tags are specified using Key=tag name,Values=tag value.
* `owner_information` - (Optional) User-provided value that will be included in any CloudWatch events raised while running tasks for these targets in this Maintenance Window.
## Attributes Reference
The following attributes are exported:
* `id` - The ID of the maintenance window target.

View File

@ -0,0 +1,68 @@
---
layout: "aws"
page_title: "AWS: aws_ssm_maintenance_window_task"
sidebar_current: "docs-aws-resource-ssm-maintenance-window-task"
description: |-
Provides an SSM Maintenance Window Task resource
---
# aws_ssm_maintenance_window_task
Provides an SSM Maintenance Window Task resource
## Example Usage
```hcl
resource "aws_ssm_maintenance_window" "window" {
name = "maintenance-window-%s"
schedule = "cron(0 16 ? * TUE *)"
duration = 3
cutoff = 1
}
resource "aws_ssm_maintenance_window_task" "target" {
window_id = "${aws_ssm_maintenance_window.window.id}"
task_type = "RUN_COMMAND"
task_arn = "AWS-RunShellScript"
priority = 1
service_role_arn = "arn:aws:iam::187416307283:role/service-role/AWS_Events_Invoke_Run_Command_112316643"
max_concurrency = "2"
max_errors = "1"
targets {
key = "InstanceIds"
values = ["${aws_instance.instance.id}"]
}
}
resource "aws_instance" "instance" {
ami = "ami-4fccb37f"
instance_type = "m1.small"
}
```
## Argument Reference
The following arguments are supported:
* `window_id` - (Required) The Id of the maintenance window to register the task with.
* `max_concurrency` - (Required) The maximum number of targets this task can be run for in parallel.
* `max_errors` - (Required) The maximum number of errors allowed before this task stops being scheduled.
* `task_type` - (Required) The type of task being registered. The only allowed value is `RUN_COMMAND`.
* `task_arn` - (Required) The ARN of the task to execute.
* `service_role_arn` - (Required) The role that should be assumed when executing the task.
* `targets` - (Required) The targets (either instances or tags). Instances are specified using Key=instanceids,Values=instanceid1,instanceid2. Tags are specified using Key=tag name,Values=tag value.
* `priority` - (Optional) The priority of the task in the Maintenance Window, the lower the number the higher the priority. Tasks in a Maintenance Window are scheduled in priority order with tasks that have the same priority scheduled in parallel.
* `logging_info` - (Optional) A structure containing information about an Amazon S3 bucket to write instance-level logs to. Documented below.
`logging_info` supports the following:
* `s3_bucket_name` - (Required)
* `s3_region` - (Required)
* `s3_bucket_prefix` - (Optional)
## Attributes Reference
The following attributes are exported:
* `id` - The ID of the maintenance window task.

View File

@ -1249,6 +1249,18 @@
<a href="/docs/providers/aws/r/ssm_document.html">aws_ssm_document</a> <a href="/docs/providers/aws/r/ssm_document.html">aws_ssm_document</a>
</li> </li>
<li<%= sidebar_current("docs-aws-resource-ssm-maintenance-window") %>>
<a href="/docs/providers/aws/r/ssm_maintenance_window.html">aws_ssm_maintenance_window</a>
</li>
<li<%= sidebar_current("docs-aws-resource-ssm-maintenance-window-target") %>>
<a href="/docs/providers/aws/r/ssm_maintenance_window_target.html">aws_ssm_maintenance_window_target</a>
</li>
<li<%= sidebar_current("docs-aws-resource-ssm-maintenance-window-task") %>>
<a href="/docs/providers/aws/r/ssm_maintenance_window_task.html">aws_ssm_maintenance_window_task</a>
</li>
</ul> </ul>
</li> </li>