github.com/rahart/packer@v0.12.2-0.20161229105310-282bb6ad370f/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  		creds = credentials.NewChainCredentials([]credentials.Provider{
    49  			&credentials.StaticProvider{Value: credentials.Value{
    50  				AccessKeyID:     c.AccessKey,
    51  				SecretAccessKey: c.SecretKey,
    52  				SessionToken:    c.Token,
    53  			}},
    54  			&credentials.EnvProvider{},
    55  			&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
    56  			&ec2rolecreds.EC2RoleProvider{
    57  				Client: ec2metadata.New(session.New(config)),
    58  			},
    59  		})
    60  	}
    61  	return config.WithCredentials(creds), nil
    62  }
    63  
    64  // Region returns the aws.Region object for access to AWS services, requesting
    65  // the region from the instance metadata if possible.
    66  func (c *AccessConfig) Region() (string, error) {
    67  	if c.RawRegion != "" {
    68  		if !c.SkipValidation {
    69  			if valid := ValidateRegion(c.RawRegion); valid == false {
    70  				return "", fmt.Errorf("Not a valid region: %s", c.RawRegion)
    71  			}
    72  		}
    73  		return c.RawRegion, nil
    74  	}
    75  
    76  	md, err := GetInstanceMetaData("placement/availability-zone")
    77  	if err != nil {
    78  		return "", err
    79  	}
    80  
    81  	region := strings.TrimRightFunc(string(md), unicode.IsLetter)
    82  	return region, nil
    83  }
    84  
    85  func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
    86  	var errs []error
    87  	if c.RawRegion != "" && !c.SkipValidation {
    88  		if valid := ValidateRegion(c.RawRegion); valid == false {
    89  			errs = append(errs, fmt.Errorf("Unknown region: %s", c.RawRegion))
    90  		}
    91  	}
    92  
    93  	if len(errs) > 0 {
    94  		return errs
    95  	}
    96  
    97  	return nil
    98  }
    99  
   100  func GetInstanceMetaData(path string) (contents []byte, err error) {
   101  	url := "http://169.254.169.254/latest/meta-data/" + path
   102  
   103  	resp, err := http.Get(url)
   104  	if err != nil {
   105  		return
   106  	}
   107  	defer resp.Body.Close()
   108  
   109  	if resp.StatusCode != 200 {
   110  		err = fmt.Errorf("Code %d returned for url %s", resp.StatusCode, url)
   111  		return
   112  	}
   113  
   114  	body, err := ioutil.ReadAll(resp.Body)
   115  	if err != nil {
   116  		return
   117  	}
   118  	return []byte(body), err
   119  }