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  }