github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_ssm_document_test.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/aws/aws-sdk-go/aws" 8 "github.com/aws/aws-sdk-go/aws/awserr" 9 "github.com/aws/aws-sdk-go/service/ssm" 10 "github.com/hashicorp/terraform/helper/acctest" 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/terraform" 13 ) 14 15 func TestAccAWSSSMDocument_basic(t *testing.T) { 16 name := acctest.RandString(10) 17 resource.Test(t, resource.TestCase{ 18 PreCheck: func() { testAccPreCheck(t) }, 19 Providers: testAccProviders, 20 CheckDestroy: testAccCheckAWSSSMDocumentDestroy, 21 Steps: []resource.TestStep{ 22 resource.TestStep{ 23 Config: testAccAWSSSMDocumentBasicConfig(name), 24 Check: resource.ComposeTestCheckFunc( 25 testAccCheckAWSSSMDocumentExists("aws_ssm_document.foo"), 26 ), 27 }, 28 }, 29 }) 30 } 31 32 func TestAccAWSSSMDocument_update(t *testing.T) { 33 name := acctest.RandString(10) 34 resource.Test(t, resource.TestCase{ 35 PreCheck: func() { testAccPreCheck(t) }, 36 Providers: testAccProviders, 37 CheckDestroy: testAccCheckAWSSSMDocumentDestroy, 38 Steps: []resource.TestStep{ 39 resource.TestStep{ 40 Config: testAccAWSSSMDocument20Config(name), 41 Check: resource.ComposeTestCheckFunc( 42 testAccCheckAWSSSMDocumentExists("aws_ssm_document.foo"), 43 resource.TestCheckResourceAttr( 44 "aws_ssm_document.foo", "schema_version", "2.0"), 45 resource.TestCheckResourceAttr( 46 "aws_ssm_document.foo", "latest_version", "1"), 47 resource.TestCheckResourceAttr( 48 "aws_ssm_document.foo", "default_version", "1"), 49 ), 50 }, 51 resource.TestStep{ 52 Config: testAccAWSSSMDocument20UpdatedConfig(name), 53 Check: resource.ComposeTestCheckFunc( 54 testAccCheckAWSSSMDocumentExists("aws_ssm_document.foo"), 55 resource.TestCheckResourceAttr( 56 "aws_ssm_document.foo", "latest_version", "2"), 57 resource.TestCheckResourceAttr( 58 "aws_ssm_document.foo", "default_version", "2"), 59 ), 60 }, 61 }, 62 }) 63 } 64 65 func TestAccAWSSSMDocument_permission(t *testing.T) { 66 name := acctest.RandString(10) 67 resource.Test(t, resource.TestCase{ 68 PreCheck: func() { testAccPreCheck(t) }, 69 Providers: testAccProviders, 70 CheckDestroy: testAccCheckAWSSSMDocumentDestroy, 71 Steps: []resource.TestStep{ 72 resource.TestStep{ 73 Config: testAccAWSSSMDocumentPermissionConfig(name), 74 Check: resource.ComposeTestCheckFunc( 75 testAccCheckAWSSSMDocumentExists("aws_ssm_document.foo"), 76 resource.TestCheckResourceAttr( 77 "aws_ssm_document.foo", "permissions.type", "Share"), 78 resource.TestCheckResourceAttr( 79 "aws_ssm_document.foo", "permissions.account_ids", "all"), 80 ), 81 }, 82 }, 83 }) 84 } 85 86 func TestAccAWSSSMDocument_params(t *testing.T) { 87 name := acctest.RandString(10) 88 resource.Test(t, resource.TestCase{ 89 PreCheck: func() { testAccPreCheck(t) }, 90 Providers: testAccProviders, 91 CheckDestroy: testAccCheckAWSSSMDocumentDestroy, 92 Steps: []resource.TestStep{ 93 resource.TestStep{ 94 Config: testAccAWSSSMDocumentParamConfig(name), 95 Check: resource.ComposeTestCheckFunc( 96 testAccCheckAWSSSMDocumentExists("aws_ssm_document.foo"), 97 resource.TestCheckResourceAttr( 98 "aws_ssm_document.foo", "parameter.0.name", "commands"), 99 resource.TestCheckResourceAttr( 100 "aws_ssm_document.foo", "parameter.0.type", "StringList"), 101 resource.TestCheckResourceAttr( 102 "aws_ssm_document.foo", "parameter.1.name", "workingDirectory"), 103 resource.TestCheckResourceAttr( 104 "aws_ssm_document.foo", "parameter.1.type", "String"), 105 resource.TestCheckResourceAttr( 106 "aws_ssm_document.foo", "parameter.2.name", "executionTimeout"), 107 resource.TestCheckResourceAttr( 108 "aws_ssm_document.foo", "parameter.2.type", "String"), 109 ), 110 }, 111 }, 112 }) 113 } 114 115 func TestAccAWSSSMDocument_automation(t *testing.T) { 116 name := acctest.RandString(10) 117 resource.Test(t, resource.TestCase{ 118 PreCheck: func() { testAccPreCheck(t) }, 119 Providers: testAccProviders, 120 CheckDestroy: testAccCheckAWSSSMDocumentDestroy, 121 Steps: []resource.TestStep{ 122 resource.TestStep{ 123 Config: testAccAWSSSMDocumentTypeAutomationConfig(name), 124 Check: resource.ComposeTestCheckFunc( 125 testAccCheckAWSSSMDocumentExists("aws_ssm_document.foo"), 126 resource.TestCheckResourceAttr( 127 "aws_ssm_document.foo", "document_type", "Automation"), 128 ), 129 }, 130 }, 131 }) 132 } 133 134 func testAccCheckAWSSSMDocumentExists(n string) resource.TestCheckFunc { 135 return func(s *terraform.State) error { 136 rs, ok := s.RootModule().Resources[n] 137 if !ok { 138 return fmt.Errorf("Not found: %s", n) 139 } 140 141 if rs.Primary.ID == "" { 142 return fmt.Errorf("No SSM Document ID is set") 143 } 144 145 conn := testAccProvider.Meta().(*AWSClient).ssmconn 146 147 _, err := conn.DescribeDocument(&ssm.DescribeDocumentInput{ 148 Name: aws.String(rs.Primary.ID), 149 }) 150 if err != nil { 151 return err 152 } 153 154 return nil 155 } 156 } 157 158 func testAccCheckAWSSSMDocumentDestroy(s *terraform.State) error { 159 conn := testAccProvider.Meta().(*AWSClient).ssmconn 160 161 for _, rs := range s.RootModule().Resources { 162 if rs.Type != "aws_ssm_document" { 163 continue 164 } 165 166 out, err := conn.DescribeDocument(&ssm.DescribeDocumentInput{ 167 Name: aws.String(rs.Primary.Attributes["name"]), 168 }) 169 170 if err != nil { 171 // InvalidDocument means it's gone, this is good 172 if wserr, ok := err.(awserr.Error); ok && wserr.Code() == "InvalidDocument" { 173 return nil 174 } 175 return err 176 } 177 178 if out != nil { 179 return fmt.Errorf("Expected AWS SSM Document to be gone, but was still found") 180 } 181 182 return nil 183 } 184 185 return fmt.Errorf("Default error in SSM Document Test") 186 } 187 188 /* 189 Based on examples from here: https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/create-ssm-doc.html 190 */ 191 192 func testAccAWSSSMDocumentBasicConfig(rName string) string { 193 return fmt.Sprintf(` 194 resource "aws_ssm_document" "foo" { 195 name = "test_document-%s" 196 document_type = "Command" 197 198 content = <<DOC 199 { 200 "schemaVersion": "1.2", 201 "description": "Check ip configuration of a Linux instance.", 202 "parameters": { 203 204 }, 205 "runtimeConfig": { 206 "aws:runShellScript": { 207 "properties": [ 208 { 209 "id": "0.aws:runShellScript", 210 "runCommand": ["ifconfig"] 211 } 212 ] 213 } 214 } 215 } 216 DOC 217 } 218 219 `, rName) 220 } 221 222 func testAccAWSSSMDocument20Config(rName string) string { 223 return fmt.Sprintf(` 224 resource "aws_ssm_document" "foo" { 225 name = "test_document-%s" 226 document_type = "Command" 227 228 content = <<DOC 229 { 230 "schemaVersion": "2.0", 231 "description": "Sample version 2.0 document v2", 232 "parameters": { 233 234 }, 235 "mainSteps": [ 236 { 237 "action": "aws:runPowerShellScript", 238 "name": "runPowerShellScript", 239 "inputs": { 240 "runCommand": [ 241 "Get-Process" 242 ] 243 } 244 } 245 ] 246 } 247 DOC 248 } 249 `, rName) 250 } 251 252 func testAccAWSSSMDocument20UpdatedConfig(rName string) string { 253 return fmt.Sprintf(` 254 resource "aws_ssm_document" "foo" { 255 name = "test_document-%s" 256 document_type = "Command" 257 258 content = <<DOC 259 { 260 "schemaVersion": "2.0", 261 "description": "Sample version 2.0 document v2", 262 "parameters": { 263 264 }, 265 "mainSteps": [ 266 { 267 "action": "aws:runPowerShellScript", 268 "name": "runPowerShellScript", 269 "inputs": { 270 "runCommand": [ 271 "Get-Process -Verbose" 272 ] 273 } 274 } 275 ] 276 } 277 DOC 278 } 279 `, rName) 280 } 281 282 func testAccAWSSSMDocumentPermissionConfig(rName string) string { 283 return fmt.Sprintf(` 284 resource "aws_ssm_document" "foo" { 285 name = "test_document-%s" 286 document_type = "Command" 287 288 permissions = { 289 type = "Share" 290 account_ids = "all" 291 } 292 293 content = <<DOC 294 { 295 "schemaVersion": "1.2", 296 "description": "Check ip configuration of a Linux instance.", 297 "parameters": { 298 299 }, 300 "runtimeConfig": { 301 "aws:runShellScript": { 302 "properties": [ 303 { 304 "id": "0.aws:runShellScript", 305 "runCommand": ["ifconfig"] 306 } 307 ] 308 } 309 } 310 } 311 DOC 312 } 313 `, rName) 314 } 315 316 func testAccAWSSSMDocumentParamConfig(rName string) string { 317 return fmt.Sprintf(` 318 resource "aws_ssm_document" "foo" { 319 name = "test_document-%s" 320 document_type = "Command" 321 322 content = <<DOC 323 { 324 "schemaVersion":"1.2", 325 "description":"Run a PowerShell script or specify the paths to scripts to run.", 326 "parameters":{ 327 "commands":{ 328 "type":"StringList", 329 "description":"(Required) Specify the commands to run or the paths to existing scripts on the instance.", 330 "minItems":1, 331 "displayType":"textarea" 332 }, 333 "workingDirectory":{ 334 "type":"String", 335 "default":"", 336 "description":"(Optional) The path to the working directory on your instance.", 337 "maxChars":4096 338 }, 339 "executionTimeout":{ 340 "type":"String", 341 "default":"3600", 342 "description":"(Optional) The time in seconds for a command to be completed before it is considered to have failed. Default is 3600 (1 hour). Maximum is 28800 (8 hours).", 343 "allowedPattern":"([1-9][0-9]{0,3})|(1[0-9]{1,4})|(2[0-7][0-9]{1,3})|(28[0-7][0-9]{1,2})|(28800)" 344 } 345 }, 346 "runtimeConfig":{ 347 "aws:runPowerShellScript":{ 348 "properties":[ 349 { 350 "id":"0.aws:runPowerShellScript", 351 "runCommand":"{{ commands }}", 352 "workingDirectory":"{{ workingDirectory }}", 353 "timeoutSeconds":"{{ executionTimeout }}" 354 } 355 ] 356 } 357 } 358 } 359 DOC 360 } 361 362 `, rName) 363 } 364 365 func testAccAWSSSMDocumentTypeAutomationConfig(rName string) string { 366 return fmt.Sprintf(` 367 data "aws_ami" "ssm_ami" { 368 most_recent = true 369 filter { 370 name = "name" 371 values = ["*hvm-ssd/ubuntu-trusty-14.04*"] 372 } 373 } 374 375 resource "aws_iam_instance_profile" "ssm_profile" { 376 name = "ssm_profile-%s" 377 roles = ["${aws_iam_role.ssm_role.name}"] 378 } 379 380 resource "aws_iam_role" "ssm_role" { 381 name = "ssm_role-%s" 382 path = "/" 383 assume_role_policy = <<EOF 384 { 385 "Version": "2012-10-17", 386 "Statement": [ 387 { 388 "Action": "sts:AssumeRole", 389 "Principal": { 390 "Service": "ec2.amazonaws.com" 391 }, 392 "Effect": "Allow", 393 "Sid": "" 394 } 395 ] 396 } 397 EOF 398 } 399 400 resource "aws_ssm_document" "foo" { 401 name = "test_document-%s" 402 document_type = "Automation" 403 content = <<DOC 404 { 405 "description": "Systems Manager Automation Demo", 406 "schemaVersion": "0.3", 407 "assumeRole": "${aws_iam_role.ssm_role.arn}", 408 "mainSteps": [ 409 { 410 "name": "startInstances", 411 "action": "aws:runInstances", 412 "timeoutSeconds": 1200, 413 "maxAttempts": 1, 414 "onFailure": "Abort", 415 "inputs": { 416 "ImageId": "${data.aws_ami.ssm_ami.id}", 417 "InstanceType": "t2.small", 418 "MinInstanceCount": 1, 419 "MaxInstanceCount": 1, 420 "IamInstanceProfileName": "${aws_iam_instance_profile.ssm_profile.name}" 421 } 422 }, 423 { 424 "name": "stopInstance", 425 "action": "aws:changeInstanceState", 426 "maxAttempts": 1, 427 "onFailure": "Continue", 428 "inputs": { 429 "InstanceIds": [ 430 "{{ startInstances.InstanceIds }}" 431 ], 432 "DesiredState": "stopped" 433 } 434 }, 435 { 436 "name": "terminateInstance", 437 "action": "aws:changeInstanceState", 438 "maxAttempts": 1, 439 "onFailure": "Continue", 440 "inputs": { 441 "InstanceIds": [ 442 "{{ startInstances.InstanceIds }}" 443 ], 444 "DesiredState": "terminated" 445 } 446 } 447 ] 448 } 449 DOC 450 } 451 452 `, rName, rName, rName) 453 } 454 455 func TestAccAWSSSMDocument_documentTypeValidation(t *testing.T) { 456 cases := []struct { 457 Value string 458 ErrCount int 459 }{ 460 {Value: "Command", ErrCount: 0}, 461 {Value: "Policy", ErrCount: 0}, 462 {Value: "Automation", ErrCount: 0}, 463 {Value: "XYZ", ErrCount: 1}, 464 } 465 466 for _, tc := range cases { 467 _, errors := validateAwsSSMDocumentType(tc.Value, "aws_ssm_document") 468 469 if len(errors) != tc.ErrCount { 470 t.Fatalf("Expected the AWS SSM Document document_type to trigger a validation error") 471 } 472 } 473 }