github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/builtin/providers/aws/resource_aws_iam_instance_profile.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 resourceAwsIamInstanceProfile() *schema.Resource {
    16  	return &schema.Resource{
    17  		Create: resourceAwsIamInstanceProfileCreate,
    18  		Read:   resourceAwsIamInstanceProfileRead,
    19  		Update: resourceAwsIamInstanceProfileUpdate,
    20  		Delete: resourceAwsIamInstanceProfileDelete,
    21  
    22  		Schema: map[string]*schema.Schema{
    23  			"arn": &schema.Schema{
    24  				Type:     schema.TypeString,
    25  				Computed: true,
    26  			},
    27  
    28  			"create_date": &schema.Schema{
    29  				Type:     schema.TypeString,
    30  				Computed: true,
    31  			},
    32  
    33  			"unique_id": &schema.Schema{
    34  				Type:     schema.TypeString,
    35  				Computed: true,
    36  			},
    37  
    38  			"name": &schema.Schema{
    39  				Type:          schema.TypeString,
    40  				Optional:      true,
    41  				Computed:      true,
    42  				ForceNew:      true,
    43  				ConflictsWith: []string{"name_prefix"},
    44  				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
    45  					// https://github.com/boto/botocore/blob/2485f5c/botocore/data/iam/2010-05-08/service-2.json#L8196-L8201
    46  					value := v.(string)
    47  					if len(value) > 128 {
    48  						errors = append(errors, fmt.Errorf(
    49  							"%q cannot be longer than 128 characters", k))
    50  					}
    51  					if !regexp.MustCompile("^[\\w+=,.@-]+$").MatchString(value) {
    52  						errors = append(errors, fmt.Errorf(
    53  							"%q must match [\\w+=,.@-]", k))
    54  					}
    55  					return
    56  				},
    57  			},
    58  
    59  			"name_prefix": &schema.Schema{
    60  				Type:     schema.TypeString,
    61  				Optional: true,
    62  				ForceNew: true,
    63  				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
    64  					// https://github.com/boto/botocore/blob/2485f5c/botocore/data/iam/2010-05-08/service-2.json#L8196-L8201
    65  					value := v.(string)
    66  					if len(value) > 64 {
    67  						errors = append(errors, fmt.Errorf(
    68  							"%q cannot be longer than 64 characters, name is limited to 128", k))
    69  					}
    70  					if !regexp.MustCompile("^[\\w+=,.@-]+$").MatchString(value) {
    71  						errors = append(errors, fmt.Errorf(
    72  							"%q must match [\\w+=,.@-]", k))
    73  					}
    74  					return
    75  				},
    76  			},
    77  
    78  			"path": &schema.Schema{
    79  				Type:     schema.TypeString,
    80  				Optional: true,
    81  				Default:  "/",
    82  				ForceNew: true,
    83  			},
    84  
    85  			"roles": &schema.Schema{
    86  				Type:     schema.TypeSet,
    87  				Required: true,
    88  				Elem:     &schema.Schema{Type: schema.TypeString},
    89  				Set:      schema.HashString,
    90  			},
    91  		},
    92  	}
    93  }
    94  
    95  func resourceAwsIamInstanceProfileCreate(d *schema.ResourceData, meta interface{}) error {
    96  	iamconn := meta.(*AWSClient).iamconn
    97  
    98  	var name string
    99  	if v, ok := d.GetOk("name"); ok {
   100  		name = v.(string)
   101  	} else if v, ok := d.GetOk("name_prefix"); ok {
   102  		name = resource.PrefixedUniqueId(v.(string))
   103  	} else {
   104  		name = resource.UniqueId()
   105  	}
   106  
   107  	request := &iam.CreateInstanceProfileInput{
   108  		InstanceProfileName: aws.String(name),
   109  		Path:                aws.String(d.Get("path").(string)),
   110  	}
   111  
   112  	var err error
   113  	response, err := iamconn.CreateInstanceProfile(request)
   114  	if err == nil {
   115  		err = instanceProfileReadResult(d, response.InstanceProfile)
   116  	}
   117  	if err != nil {
   118  		return fmt.Errorf("Error creating IAM instance profile %s: %s", name, err)
   119  	}
   120  
   121  	return instanceProfileSetRoles(d, iamconn)
   122  }
   123  
   124  func instanceProfileAddRole(iamconn *iam.IAM, profileName, roleName string) error {
   125  	request := &iam.AddRoleToInstanceProfileInput{
   126  		InstanceProfileName: aws.String(profileName),
   127  		RoleName:            aws.String(roleName),
   128  	}
   129  
   130  	_, err := iamconn.AddRoleToInstanceProfile(request)
   131  	return err
   132  }
   133  
   134  func instanceProfileRemoveRole(iamconn *iam.IAM, profileName, roleName string) error {
   135  	request := &iam.RemoveRoleFromInstanceProfileInput{
   136  		InstanceProfileName: aws.String(profileName),
   137  		RoleName:            aws.String(roleName),
   138  	}
   139  
   140  	_, err := iamconn.RemoveRoleFromInstanceProfile(request)
   141  	if iamerr, ok := err.(awserr.Error); ok && iamerr.Code() == "NoSuchEntity" {
   142  		return nil
   143  	}
   144  	return err
   145  }
   146  
   147  func instanceProfileSetRoles(d *schema.ResourceData, iamconn *iam.IAM) error {
   148  	oldInterface, newInterface := d.GetChange("roles")
   149  	oldRoles := oldInterface.(*schema.Set)
   150  	newRoles := newInterface.(*schema.Set)
   151  
   152  	currentRoles := schema.CopySet(oldRoles)
   153  
   154  	d.Partial(true)
   155  
   156  	for _, role := range oldRoles.Difference(newRoles).List() {
   157  		err := instanceProfileRemoveRole(iamconn, d.Id(), role.(string))
   158  		if err != nil {
   159  			return fmt.Errorf("Error removing role %s from IAM instance profile %s: %s", role, d.Id(), err)
   160  		}
   161  		currentRoles.Remove(role)
   162  		d.Set("roles", currentRoles)
   163  		d.SetPartial("roles")
   164  	}
   165  
   166  	for _, role := range newRoles.Difference(oldRoles).List() {
   167  		err := instanceProfileAddRole(iamconn, d.Id(), role.(string))
   168  		if err != nil {
   169  			return fmt.Errorf("Error adding role %s to IAM instance profile %s: %s", role, d.Id(), err)
   170  		}
   171  		currentRoles.Add(role)
   172  		d.Set("roles", currentRoles)
   173  		d.SetPartial("roles")
   174  	}
   175  
   176  	d.Partial(false)
   177  
   178  	return nil
   179  }
   180  
   181  func instanceProfileRemoveAllRoles(d *schema.ResourceData, iamconn *iam.IAM) error {
   182  	for _, role := range d.Get("roles").(*schema.Set).List() {
   183  		err := instanceProfileRemoveRole(iamconn, d.Id(), role.(string))
   184  		if err != nil {
   185  			return fmt.Errorf("Error removing role %s from IAM instance profile %s: %s", role, d.Id(), err)
   186  		}
   187  	}
   188  	return nil
   189  }
   190  
   191  func resourceAwsIamInstanceProfileUpdate(d *schema.ResourceData, meta interface{}) error {
   192  	iamconn := meta.(*AWSClient).iamconn
   193  
   194  	if !d.HasChange("roles") {
   195  		return nil
   196  	}
   197  
   198  	return instanceProfileSetRoles(d, iamconn)
   199  }
   200  
   201  func resourceAwsIamInstanceProfileRead(d *schema.ResourceData, meta interface{}) error {
   202  	iamconn := meta.(*AWSClient).iamconn
   203  
   204  	request := &iam.GetInstanceProfileInput{
   205  		InstanceProfileName: aws.String(d.Id()),
   206  	}
   207  
   208  	result, err := iamconn.GetInstanceProfile(request)
   209  	if err != nil {
   210  		if iamerr, ok := err.(awserr.Error); ok && iamerr.Code() == "NoSuchEntity" {
   211  			d.SetId("")
   212  			return nil
   213  		}
   214  		return fmt.Errorf("Error reading IAM instance profile %s: %s", d.Id(), err)
   215  	}
   216  
   217  	return instanceProfileReadResult(d, result.InstanceProfile)
   218  }
   219  
   220  func resourceAwsIamInstanceProfileDelete(d *schema.ResourceData, meta interface{}) error {
   221  	iamconn := meta.(*AWSClient).iamconn
   222  
   223  	if err := instanceProfileRemoveAllRoles(d, iamconn); err != nil {
   224  		return err
   225  	}
   226  
   227  	request := &iam.DeleteInstanceProfileInput{
   228  		InstanceProfileName: aws.String(d.Id()),
   229  	}
   230  	_, err := iamconn.DeleteInstanceProfile(request)
   231  	if err != nil {
   232  		return fmt.Errorf("Error deleting IAM instance profile %s: %s", d.Id(), err)
   233  	}
   234  	d.SetId("")
   235  	return nil
   236  }
   237  
   238  func instanceProfileReadResult(d *schema.ResourceData, result *iam.InstanceProfile) error {
   239  	d.SetId(*result.InstanceProfileName)
   240  	if err := d.Set("name", result.InstanceProfileName); err != nil {
   241  		return err
   242  	}
   243  	if err := d.Set("arn", result.Arn); err != nil {
   244  		return err
   245  	}
   246  	if err := d.Set("path", result.Path); err != nil {
   247  		return err
   248  	}
   249  
   250  	roles := &schema.Set{F: schema.HashString}
   251  	for _, role := range result.Roles {
   252  		roles.Add(*role.RoleName)
   253  	}
   254  	if err := d.Set("roles", roles); err != nil {
   255  		return err
   256  	}
   257  
   258  	return nil
   259  }