github.com/dougneal/terraform@v0.6.15-0.20170330092735-b6a3840768a4/builtin/providers/aws/resource_aws_ssm_document.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/aws/aws-sdk-go/aws"
    10  	"github.com/aws/aws-sdk-go/aws/awserr"
    11  	"github.com/aws/aws-sdk-go/service/ssm"
    12  	"github.com/hashicorp/errwrap"
    13  	"github.com/hashicorp/terraform/helper/resource"
    14  	"github.com/hashicorp/terraform/helper/schema"
    15  )
    16  
    17  func resourceAwsSsmDocument() *schema.Resource {
    18  	return &schema.Resource{
    19  		Create: resourceAwsSsmDocumentCreate,
    20  		Read:   resourceAwsSsmDocumentRead,
    21  		Update: resourceAwsSsmDocumentUpdate,
    22  		Delete: resourceAwsSsmDocumentDelete,
    23  
    24  		Schema: map[string]*schema.Schema{
    25  			"name": {
    26  				Type:     schema.TypeString,
    27  				Required: true,
    28  			},
    29  			"content": {
    30  				Type:     schema.TypeString,
    31  				Required: true,
    32  			},
    33  			"document_type": {
    34  				Type:         schema.TypeString,
    35  				Required:     true,
    36  				ValidateFunc: validateAwsSSMDocumentType,
    37  			},
    38  			"created_date": {
    39  				Type:     schema.TypeString,
    40  				Computed: true,
    41  			},
    42  			"default_version": {
    43  				Type:     schema.TypeString,
    44  				Computed: true,
    45  			},
    46  			"description": {
    47  				Type:     schema.TypeString,
    48  				Computed: true,
    49  			},
    50  			"hash": {
    51  				Type:     schema.TypeString,
    52  				Computed: true,
    53  			},
    54  			"hash_type": {
    55  				Type:     schema.TypeString,
    56  				Computed: true,
    57  			},
    58  			"latest_version": {
    59  				Type:     schema.TypeString,
    60  				Computed: true,
    61  			},
    62  			"owner": {
    63  				Type:     schema.TypeString,
    64  				Computed: true,
    65  			},
    66  			"status": {
    67  				Type:     schema.TypeString,
    68  				Computed: true,
    69  			},
    70  			"platform_types": {
    71  				Type:     schema.TypeList,
    72  				Computed: true,
    73  				Elem:     &schema.Schema{Type: schema.TypeString},
    74  			},
    75  			"parameter": {
    76  				Type:     schema.TypeList,
    77  				Computed: true,
    78  				Elem: &schema.Resource{
    79  					Schema: map[string]*schema.Schema{
    80  						"name": {
    81  							Type:     schema.TypeString,
    82  							Optional: true,
    83  						},
    84  						"default_value": {
    85  							Type:     schema.TypeString,
    86  							Optional: true,
    87  						},
    88  						"description": {
    89  							Type:     schema.TypeString,
    90  							Optional: true,
    91  						},
    92  						"type": {
    93  							Type:     schema.TypeString,
    94  							Optional: true,
    95  						},
    96  					},
    97  				},
    98  			},
    99  			"permissions": {
   100  				Type:     schema.TypeMap,
   101  				Optional: true,
   102  				Elem: &schema.Resource{
   103  					Schema: map[string]*schema.Schema{
   104  						"type": {
   105  							Type:     schema.TypeString,
   106  							Required: true,
   107  						},
   108  						"account_ids": {
   109  							Type:     schema.TypeString,
   110  							Required: true,
   111  						},
   112  					},
   113  				},
   114  			},
   115  		},
   116  	}
   117  }
   118  
   119  func resourceAwsSsmDocumentCreate(d *schema.ResourceData, meta interface{}) error {
   120  	ssmconn := meta.(*AWSClient).ssmconn
   121  
   122  	log.Printf("[INFO] Creating SSM Document: %s", d.Get("name").(string))
   123  
   124  	docInput := &ssm.CreateDocumentInput{
   125  		Name:         aws.String(d.Get("name").(string)),
   126  		Content:      aws.String(d.Get("content").(string)),
   127  		DocumentType: aws.String(d.Get("document_type").(string)),
   128  	}
   129  
   130  	log.Printf("[DEBUG] Waiting for SSM Document %q to be created", d.Get("name").(string))
   131  	err := resource.Retry(5*time.Minute, func() *resource.RetryError {
   132  		resp, err := ssmconn.CreateDocument(docInput)
   133  
   134  		if err != nil {
   135  			return resource.NonRetryableError(err)
   136  		}
   137  
   138  		d.SetId(*resp.DocumentDescription.Name)
   139  		return nil
   140  	})
   141  
   142  	if err != nil {
   143  		return errwrap.Wrapf("[ERROR] Error creating SSM document: {{err}}", err)
   144  	}
   145  
   146  	if v, ok := d.GetOk("permissions"); ok && v != nil {
   147  		if err := setDocumentPermissions(d, meta); err != nil {
   148  			return err
   149  		}
   150  	} else {
   151  		log.Printf("[DEBUG] Not setting permissions for %q", d.Id())
   152  	}
   153  
   154  	return resourceAwsSsmDocumentRead(d, meta)
   155  }
   156  
   157  func resourceAwsSsmDocumentRead(d *schema.ResourceData, meta interface{}) error {
   158  	ssmconn := meta.(*AWSClient).ssmconn
   159  
   160  	log.Printf("[DEBUG] Reading SSM Document: %s", d.Id())
   161  
   162  	docInput := &ssm.DescribeDocumentInput{
   163  		Name: aws.String(d.Get("name").(string)),
   164  	}
   165  
   166  	resp, err := ssmconn.DescribeDocument(docInput)
   167  
   168  	if err != nil {
   169  		return errwrap.Wrapf("[ERROR] Error describing SSM document: {{err}}", err)
   170  	}
   171  
   172  	doc := resp.Document
   173  	d.Set("created_date", doc.CreatedDate)
   174  	d.Set("default_version", doc.DefaultVersion)
   175  	d.Set("description", doc.Description)
   176  
   177  	if _, ok := d.GetOk("document_type"); ok {
   178  		d.Set("document_type", doc.DocumentType)
   179  	}
   180  
   181  	d.Set("document_version", doc.DocumentVersion)
   182  	d.Set("hash", doc.Hash)
   183  	d.Set("hash_type", doc.HashType)
   184  	d.Set("latest_version", doc.LatestVersion)
   185  	d.Set("name", doc.Name)
   186  	d.Set("owner", doc.Owner)
   187  	d.Set("platform_types", flattenStringList(doc.PlatformTypes))
   188  
   189  	d.Set("status", doc.Status)
   190  
   191  	gp, err := getDocumentPermissions(d, meta)
   192  
   193  	if err != nil {
   194  		return errwrap.Wrapf("[ERROR] Error reading SSM document permissions: {{err}}", err)
   195  	}
   196  
   197  	d.Set("permissions", gp)
   198  
   199  	params := make([]map[string]interface{}, 0)
   200  	for i := 0; i < len(doc.Parameters); i++ {
   201  
   202  		dp := doc.Parameters[i]
   203  		param := make(map[string]interface{})
   204  
   205  		if dp.DefaultValue != nil {
   206  			param["default_value"] = *dp.DefaultValue
   207  		}
   208  		if dp.Description != nil {
   209  			param["description"] = *dp.Description
   210  		}
   211  		if dp.Name != nil {
   212  			param["name"] = *dp.Name
   213  		}
   214  		if dp.Type != nil {
   215  			param["type"] = *dp.Type
   216  		}
   217  		params = append(params, param)
   218  	}
   219  
   220  	if len(params) == 0 {
   221  		params = make([]map[string]interface{}, 1)
   222  	}
   223  
   224  	if err := d.Set("parameter", params); err != nil {
   225  		return err
   226  	}
   227  
   228  	return nil
   229  }
   230  
   231  func resourceAwsSsmDocumentUpdate(d *schema.ResourceData, meta interface{}) error {
   232  
   233  	if _, ok := d.GetOk("permissions"); ok {
   234  		if err := setDocumentPermissions(d, meta); err != nil {
   235  			return err
   236  		}
   237  	} else {
   238  		log.Printf("[DEBUG] Not setting document permissions on %q", d.Id())
   239  	}
   240  
   241  	return resourceAwsSsmDocumentRead(d, meta)
   242  }
   243  
   244  func resourceAwsSsmDocumentDelete(d *schema.ResourceData, meta interface{}) error {
   245  	ssmconn := meta.(*AWSClient).ssmconn
   246  
   247  	if err := deleteDocumentPermissions(d, meta); err != nil {
   248  		return err
   249  	}
   250  
   251  	log.Printf("[INFO] Deleting SSM Document: %s", d.Id())
   252  
   253  	params := &ssm.DeleteDocumentInput{
   254  		Name: aws.String(d.Get("name").(string)),
   255  	}
   256  
   257  	_, err := ssmconn.DeleteDocument(params)
   258  	if err != nil {
   259  		return err
   260  	}
   261  
   262  	log.Printf("[DEBUG] Waiting for SSM Document %q to be deleted", d.Get("name").(string))
   263  	err = resource.Retry(10*time.Minute, func() *resource.RetryError {
   264  		_, err := ssmconn.DescribeDocument(&ssm.DescribeDocumentInput{
   265  			Name: aws.String(d.Get("name").(string)),
   266  		})
   267  
   268  		if err != nil {
   269  			awsErr, ok := err.(awserr.Error)
   270  			if !ok {
   271  				return resource.NonRetryableError(err)
   272  			}
   273  
   274  			if awsErr.Code() == "InvalidDocument" {
   275  				return nil
   276  			}
   277  
   278  			return resource.NonRetryableError(err)
   279  		}
   280  
   281  		return resource.RetryableError(
   282  			fmt.Errorf("%q: Timeout while waiting for the document to be deleted", d.Id()))
   283  	})
   284  	if err != nil {
   285  		return err
   286  	}
   287  
   288  	d.SetId("")
   289  
   290  	return nil
   291  }
   292  
   293  func setDocumentPermissions(d *schema.ResourceData, meta interface{}) error {
   294  	ssmconn := meta.(*AWSClient).ssmconn
   295  
   296  	log.Printf("[INFO] Setting permissions for document: %s", d.Id())
   297  	permission := d.Get("permissions").(map[string]interface{})
   298  
   299  	ids := aws.StringSlice([]string{permission["account_ids"].(string)})
   300  
   301  	if strings.Contains(permission["account_ids"].(string), ",") {
   302  		ids = aws.StringSlice(strings.Split(permission["account_ids"].(string), ","))
   303  	}
   304  
   305  	permInput := &ssm.ModifyDocumentPermissionInput{
   306  		Name:            aws.String(d.Get("name").(string)),
   307  		PermissionType:  aws.String(permission["type"].(string)),
   308  		AccountIdsToAdd: ids,
   309  	}
   310  
   311  	_, err := ssmconn.ModifyDocumentPermission(permInput)
   312  
   313  	if err != nil {
   314  		return errwrap.Wrapf("[ERROR] Error setting permissions for SSM document: {{err}}", err)
   315  	}
   316  
   317  	return nil
   318  }
   319  
   320  func getDocumentPermissions(d *schema.ResourceData, meta interface{}) (map[string]interface{}, error) {
   321  	ssmconn := meta.(*AWSClient).ssmconn
   322  
   323  	log.Printf("[INFO] Getting permissions for document: %s", d.Id())
   324  
   325  	//How to get from nested scheme resource?
   326  	permissionType := "Share"
   327  
   328  	permInput := &ssm.DescribeDocumentPermissionInput{
   329  		Name:           aws.String(d.Get("name").(string)),
   330  		PermissionType: aws.String(permissionType),
   331  	}
   332  
   333  	resp, err := ssmconn.DescribeDocumentPermission(permInput)
   334  
   335  	if err != nil {
   336  		return nil, errwrap.Wrapf("[ERROR] Error setting permissions for SSM document: {{err}}", err)
   337  	}
   338  
   339  	var account_ids = make([]string, len(resp.AccountIds))
   340  	for i := 0; i < len(resp.AccountIds); i++ {
   341  		account_ids[i] = *resp.AccountIds[i]
   342  	}
   343  
   344  	var ids = ""
   345  	if len(account_ids) == 1 {
   346  		ids = account_ids[0]
   347  	} else if len(account_ids) > 1 {
   348  		ids = strings.Join(account_ids, ",")
   349  	} else {
   350  		ids = ""
   351  	}
   352  
   353  	if ids == "" {
   354  		return nil, nil
   355  	}
   356  
   357  	perms := make(map[string]interface{})
   358  	perms["type"] = permissionType
   359  	perms["account_ids"] = ids
   360  
   361  	return perms, nil
   362  }
   363  
   364  func deleteDocumentPermissions(d *schema.ResourceData, meta interface{}) error {
   365  	ssmconn := meta.(*AWSClient).ssmconn
   366  
   367  	log.Printf("[INFO] Removing permissions from document: %s", d.Id())
   368  
   369  	permInput := &ssm.ModifyDocumentPermissionInput{
   370  		Name:               aws.String(d.Get("name").(string)),
   371  		PermissionType:     aws.String("Share"),
   372  		AccountIdsToRemove: aws.StringSlice(strings.Split("all", ",")),
   373  	}
   374  
   375  	_, err := ssmconn.ModifyDocumentPermission(permInput)
   376  
   377  	if err != nil {
   378  		return errwrap.Wrapf("[ERROR] Error removing permissions for SSM document: {{err}}", err)
   379  	}
   380  
   381  	return nil
   382  }
   383  
   384  func validateAwsSSMDocumentType(v interface{}, k string) (ws []string, errors []error) {
   385  	value := v.(string)
   386  	types := map[string]bool{
   387  		"Command":    true,
   388  		"Policy":     true,
   389  		"Automation": true,
   390  	}
   391  
   392  	if !types[value] {
   393  		errors = append(errors, fmt.Errorf("Document type %s is invalid. Valid types are Command, Policy or Automation", value))
   394  	}
   395  	return
   396  }