github.com/ottenhoff/terraform@v0.7.0-rc1.0.20160607213102-ac2d195cc560/builtin/providers/aws/resource_aws_iam_role.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"regexp"
     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/iam"
    10  
    11  	"github.com/hashicorp/terraform/helper/resource"
    12  	"github.com/hashicorp/terraform/helper/schema"
    13  )
    14  
    15  func resourceAwsIamRole() *schema.Resource {
    16  	return &schema.Resource{
    17  		Create: resourceAwsIamRoleCreate,
    18  		Read:   resourceAwsIamRoleRead,
    19  		Update: resourceAwsIamRoleUpdate,
    20  		Delete: resourceAwsIamRoleDelete,
    21  
    22  		Schema: map[string]*schema.Schema{
    23  			"arn": &schema.Schema{
    24  				Type:     schema.TypeString,
    25  				Computed: true,
    26  			},
    27  
    28  			"unique_id": &schema.Schema{
    29  				Type:     schema.TypeString,
    30  				Computed: true,
    31  			},
    32  
    33  			"name": &schema.Schema{
    34  				Type:          schema.TypeString,
    35  				Optional:      true,
    36  				Computed:      true,
    37  				ForceNew:      true,
    38  				ConflictsWith: []string{"name_prefix"},
    39  				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
    40  					// https://github.com/boto/botocore/blob/2485f5c/botocore/data/iam/2010-05-08/service-2.json#L8329-L8334
    41  					value := v.(string)
    42  					if len(value) > 64 {
    43  						errors = append(errors, fmt.Errorf(
    44  							"%q cannot be longer than 64 characters", k))
    45  					}
    46  					if !regexp.MustCompile("^[\\w+=,.@-]*$").MatchString(value) {
    47  						errors = append(errors, fmt.Errorf(
    48  							"%q must match [\\w+=,.@-]", k))
    49  					}
    50  					return
    51  				},
    52  			},
    53  
    54  			"name_prefix": &schema.Schema{
    55  				Type:     schema.TypeString,
    56  				Optional: true,
    57  				ForceNew: true,
    58  				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
    59  					// https://github.com/boto/botocore/blob/2485f5c/botocore/data/iam/2010-05-08/service-2.json#L8329-L8334
    60  					value := v.(string)
    61  					if len(value) > 32 {
    62  						errors = append(errors, fmt.Errorf(
    63  							"%q cannot be longer than 32 characters, name is limited to 64", k))
    64  					}
    65  					if !regexp.MustCompile("^[\\w+=,.@-]*$").MatchString(value) {
    66  						errors = append(errors, fmt.Errorf(
    67  							"%q must match [\\w+=,.@-]", k))
    68  					}
    69  					return
    70  				},
    71  			},
    72  
    73  			"path": &schema.Schema{
    74  				Type:     schema.TypeString,
    75  				Optional: true,
    76  				Default:  "/",
    77  				ForceNew: true,
    78  			},
    79  
    80  			"assume_role_policy": &schema.Schema{
    81  				Type:     schema.TypeString,
    82  				Required: true,
    83  			},
    84  		},
    85  	}
    86  }
    87  
    88  func resourceAwsIamRoleCreate(d *schema.ResourceData, meta interface{}) error {
    89  	iamconn := meta.(*AWSClient).iamconn
    90  
    91  	var name string
    92  	if v, ok := d.GetOk("name"); ok {
    93  		name = v.(string)
    94  	} else if v, ok := d.GetOk("name_prefix"); ok {
    95  		name = resource.PrefixedUniqueId(v.(string))
    96  	} else {
    97  		name = resource.UniqueId()
    98  	}
    99  
   100  	request := &iam.CreateRoleInput{
   101  		Path:                     aws.String(d.Get("path").(string)),
   102  		RoleName:                 aws.String(name),
   103  		AssumeRolePolicyDocument: aws.String(d.Get("assume_role_policy").(string)),
   104  	}
   105  
   106  	createResp, err := iamconn.CreateRole(request)
   107  	if err != nil {
   108  		return fmt.Errorf("Error creating IAM Role %s: %s", name, err)
   109  	}
   110  	return resourceAwsIamRoleReadResult(d, createResp.Role)
   111  }
   112  
   113  func resourceAwsIamRoleRead(d *schema.ResourceData, meta interface{}) error {
   114  	iamconn := meta.(*AWSClient).iamconn
   115  
   116  	request := &iam.GetRoleInput{
   117  		RoleName: aws.String(d.Id()),
   118  	}
   119  
   120  	getResp, err := iamconn.GetRole(request)
   121  	if err != nil {
   122  		if iamerr, ok := err.(awserr.Error); ok && iamerr.Code() == "NoSuchEntity" { // XXX test me
   123  			d.SetId("")
   124  			return nil
   125  		}
   126  		return fmt.Errorf("Error reading IAM Role %s: %s", d.Id(), err)
   127  	}
   128  	return resourceAwsIamRoleReadResult(d, getResp.Role)
   129  }
   130  
   131  func resourceAwsIamRoleUpdate(d *schema.ResourceData, meta interface{}) error {
   132  	iamconn := meta.(*AWSClient).iamconn
   133  
   134  	if d.HasChange("assume_role_policy") {
   135  		assumeRolePolicyInput := &iam.UpdateAssumeRolePolicyInput{
   136  			RoleName:       aws.String(d.Id()),
   137  			PolicyDocument: aws.String(d.Get("assume_role_policy").(string)),
   138  		}
   139  		_, err := iamconn.UpdateAssumeRolePolicy(assumeRolePolicyInput)
   140  		if err != nil {
   141  			if iamerr, ok := err.(awserr.Error); ok && iamerr.Code() == "NoSuchEntity" {
   142  				d.SetId("")
   143  				return nil
   144  			}
   145  			return fmt.Errorf("Error Updating IAM Role (%s) Assume Role Policy: %s", d.Id(), err)
   146  		}
   147  	}
   148  
   149  	return nil
   150  }
   151  
   152  func resourceAwsIamRoleReadResult(d *schema.ResourceData, role *iam.Role) error {
   153  	d.SetId(*role.RoleName)
   154  	if err := d.Set("name", role.RoleName); err != nil {
   155  		return err
   156  	}
   157  	if err := d.Set("arn", role.Arn); err != nil {
   158  		return err
   159  	}
   160  	if err := d.Set("path", role.Path); err != nil {
   161  		return err
   162  	}
   163  	if err := d.Set("unique_id", role.RoleId); err != nil {
   164  		return err
   165  	}
   166  	return nil
   167  }
   168  
   169  func resourceAwsIamRoleDelete(d *schema.ResourceData, meta interface{}) error {
   170  	iamconn := meta.(*AWSClient).iamconn
   171  
   172  	// Roles cannot be destroyed when attached to an existing Instance Profile
   173  	resp, err := iamconn.ListInstanceProfilesForRole(&iam.ListInstanceProfilesForRoleInput{
   174  		RoleName: aws.String(d.Id()),
   175  	})
   176  	if err != nil {
   177  		return fmt.Errorf("Error listing Profiles for IAM Role (%s) when trying to delete: %s", d.Id(), err)
   178  	}
   179  
   180  	// Loop and remove this Role from any Profiles
   181  	if len(resp.InstanceProfiles) > 0 {
   182  		for _, i := range resp.InstanceProfiles {
   183  			_, err := iamconn.RemoveRoleFromInstanceProfile(&iam.RemoveRoleFromInstanceProfileInput{
   184  				InstanceProfileName: i.InstanceProfileName,
   185  				RoleName:            aws.String(d.Id()),
   186  			})
   187  			if err != nil {
   188  				return fmt.Errorf("Error deleting IAM Role %s: %s", d.Id(), err)
   189  			}
   190  		}
   191  	}
   192  
   193  	request := &iam.DeleteRoleInput{
   194  		RoleName: aws.String(d.Id()),
   195  	}
   196  
   197  	if _, err := iamconn.DeleteRole(request); err != nil {
   198  		return fmt.Errorf("Error deleting IAM Role %s: %s", d.Id(), err)
   199  	}
   200  	return nil
   201  }