github.com/marksheahan/packer@v0.10.2-0.20160613200515-1acb2d6645a0/builder/amazon/common/access_config.go (about)

     1  package common
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"strings"
     8  	"unicode"
     9  
    10  	"github.com/aws/aws-sdk-go/aws"
    11  	"github.com/aws/aws-sdk-go/aws/credentials"
    12  	"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
    13  	"github.com/aws/aws-sdk-go/aws/ec2metadata"
    14  	"github.com/aws/aws-sdk-go/aws/session"
    15  	"github.com/mitchellh/packer/template/interpolate"
    16  )
    17  
    18  // AccessConfig is for common configuration related to AWS access
    19  type AccessConfig struct {
    20  	AccessKey      string `mapstructure:"access_key"`
    21  	SecretKey      string `mapstructure:"secret_key"`
    22  	RawRegion      string `mapstructure:"region"`
    23  	SkipValidation bool   `mapstructure:"skip_region_validation"`
    24  	Token          string `mapstructure:"token"`
    25  	ProfileName    string `mapstructure:"profile"`
    26  }
    27  
    28  // Config returns a valid aws.Config object for access to AWS services, or
    29  // an error if the authentication and region couldn't be resolved
    30  func (c *AccessConfig) Config() (*aws.Config, error) {
    31  	var creds *credentials.Credentials
    32  
    33  	region, err := c.Region()
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	config := aws.NewConfig().WithRegion(region).WithMaxRetries(11)
    38  	if c.ProfileName != "" {
    39  		profile, err := NewFromProfile(c.ProfileName)
    40  		if err != nil {
    41  			return nil, err
    42  		}
    43  		creds, err = profile.CredentialsFromProfile(config)
    44  		if err != nil {
    45  			return nil, err
    46  		}
    47  	} else {
    48  		sess := session.New(config)
    49  		creds = credentials.NewChainCredentials([]credentials.Provider{
    50  			&credentials.StaticProvider{Value: credentials.Value{
    51  				AccessKeyID:     c.AccessKey,
    52  				SecretAccessKey: c.SecretKey,
    53  				SessionToken:    c.Token,
    54  			}},
    55  			&credentials.EnvProvider{},
    56  			&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
    57  			&ec2rolecreds.EC2RoleProvider{
    58  				Client: ec2metadata.New(sess),
    59  			},
    60  		})
    61  	}
    62  	return config.WithCredentials(creds), nil
    63  }
    64  
    65  // Region returns the aws.Region object for access to AWS services, requesting
    66  // the region from the instance metadata if possible.
    67  func (c *AccessConfig) Region() (string, error) {
    68  	if c.RawRegion != "" {
    69  		if !c.SkipValidation {
    70  			if valid := ValidateRegion(c.RawRegion); valid == false {
    71  				return "", fmt.Errorf("Not a valid region: %s", c.RawRegion)
    72  			}
    73  		}
    74  		return c.RawRegion, nil
    75  	}
    76  
    77  	md, err := GetInstanceMetaData("placement/availability-zone")
    78  	if err != nil {
    79  		return "", err
    80  	}
    81  
    82  	region := strings.TrimRightFunc(string(md), unicode.IsLetter)
    83  	return region, nil
    84  }
    85  
    86  func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
    87  	var errs []error
    88  	if c.RawRegion != "" && !c.SkipValidation {
    89  		if valid := ValidateRegion(c.RawRegion); valid == false {
    90  			errs = append(errs, fmt.Errorf("Unknown region: %s", c.RawRegion))
    91  		}
    92  	}
    93  
    94  	if len(errs) > 0 {
    95  		return errs
    96  	}
    97  
    98  	return nil
    99  }
   100  
   101  func GetInstanceMetaData(path string) (contents []byte, err error) {
   102  	url := "http://169.254.169.254/latest/meta-data/" + path
   103  
   104  	resp, err := http.Get(url)
   105  	if err != nil {
   106  		return
   107  	}
   108  	defer resp.Body.Close()
   109  
   110  	if resp.StatusCode != 200 {
   111  		err = fmt.Errorf("Code %d returned for url %s", resp.StatusCode, url)
   112  		return
   113  	}
   114  
   115  	body, err := ioutil.ReadAll(resp.Body)
   116  	if err != nil {
   117  		return
   118  	}
   119  	return []byte(body), err
   120  }