Merge pull request #4996 from hashicorp/mwhooker/4613
builder/amazon: Support Assume Role with MFA and ECS Task Roles
This commit is contained in:
commit
8dae6b60c1
|
@ -9,7 +9,6 @@ import (
|
|||
"log"
|
||||
"runtime"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
"github.com/hashicorp/packer/common"
|
||||
|
@ -182,12 +181,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
return nil, errors.New("The amazon-chroot builder only works on Linux environments.")
|
||||
}
|
||||
|
||||
config, err := b.config.Config()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
session, err := session.NewSession(config)
|
||||
session, err := b.config.Session()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -4,8 +4,9 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/packer/builder/amazon/common"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/mitchellh/multistep"
|
||||
)
|
||||
|
@ -19,9 +20,11 @@ func (s *StepInstanceInfo) Run(state multistep.StateBag) multistep.StepAction {
|
|||
|
||||
// Get our own instance ID
|
||||
ui.Say("Gathering information about this EC2 instance...")
|
||||
instanceIdBytes, err := common.GetInstanceMetaData("instance-id")
|
||||
|
||||
sess := session.New()
|
||||
ec2meta := ec2metadata.New(sess)
|
||||
identity, err := ec2meta.GetInstanceIdentityDocument()
|
||||
if err != nil {
|
||||
log.Printf("Error: %s", err)
|
||||
err := fmt.Errorf(
|
||||
"Error retrieving the ID of the instance Packer is running on.\n" +
|
||||
"Please verify Packer is running on a proper AWS EC2 instance.")
|
||||
|
@ -29,12 +32,10 @@ func (s *StepInstanceInfo) Run(state multistep.StateBag) multistep.StepAction {
|
|||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
instanceId := string(instanceIdBytes)
|
||||
log.Printf("Instance ID: %s", instanceId)
|
||||
log.Printf("Instance ID: %s", identity.InstanceID)
|
||||
|
||||
// Query the entire instance metadata
|
||||
instancesResp, err := ec2conn.DescribeInstances(&ec2.DescribeInstancesInput{InstanceIds: []*string{&instanceId}})
|
||||
instancesResp, err := ec2conn.DescribeInstances(&ec2.DescribeInstancesInput{InstanceIds: []*string{&identity.InstanceID}})
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error getting instance data: %s", err)
|
||||
state.Put("error", err)
|
||||
|
|
|
@ -2,15 +2,11 @@ package common
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"unicode"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
@ -18,53 +14,69 @@ import (
|
|||
// AccessConfig is for common configuration related to AWS access
|
||||
type AccessConfig struct {
|
||||
AccessKey string `mapstructure:"access_key"`
|
||||
SecretKey string `mapstructure:"secret_key"`
|
||||
CustomEndpointEc2 string `mapstructure:"custom_endpoint_ec2"`
|
||||
MFACode string `mapstructure:"mfa_code"`
|
||||
ProfileName string `mapstructure:"profile"`
|
||||
RawRegion string `mapstructure:"region"`
|
||||
SecretKey string `mapstructure:"secret_key"`
|
||||
SkipValidation bool `mapstructure:"skip_region_validation"`
|
||||
Token string `mapstructure:"token"`
|
||||
ProfileName string `mapstructure:"profile"`
|
||||
CustomEndpointEc2 string `mapstructure:"custom_endpoint_ec2"`
|
||||
session *session.Session
|
||||
}
|
||||
|
||||
// Config returns a valid aws.Config object for access to AWS services, or
|
||||
// an error if the authentication and region couldn't be resolved
|
||||
func (c *AccessConfig) Config() (*aws.Config, error) {
|
||||
var creds *credentials.Credentials
|
||||
func (c *AccessConfig) Session() (*session.Session, error) {
|
||||
if c.session != nil {
|
||||
return c.session, nil
|
||||
}
|
||||
|
||||
region, err := c.Region()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config := aws.NewConfig().WithRegion(region).WithMaxRetries(11)
|
||||
|
||||
if c.CustomEndpointEc2 != "" {
|
||||
config.Endpoint = &c.CustomEndpointEc2
|
||||
}
|
||||
|
||||
if c.ProfileName != "" {
|
||||
profile, err := NewFromProfile(c.ProfileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if err := os.Setenv("AWS_PROFILE", c.ProfileName); err != nil {
|
||||
log.Printf("Set env error: %s", err)
|
||||
}
|
||||
creds, err = profile.CredentialsFromProfile(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
creds = credentials.NewChainCredentials([]credentials.Provider{
|
||||
&credentials.StaticProvider{Value: credentials.Value{
|
||||
|
||||
config := aws.NewConfig().WithRegion(region).WithMaxRetries(11).WithCredentialsChainVerboseErrors(true)
|
||||
|
||||
if c.CustomEndpointEc2 != "" {
|
||||
config = config.WithEndpoint(c.CustomEndpointEc2)
|
||||
}
|
||||
|
||||
if c.AccessKey != "" {
|
||||
creds := credentials.NewChainCredentials(
|
||||
[]credentials.Provider{
|
||||
&credentials.StaticProvider{
|
||||
Value: credentials.Value{
|
||||
AccessKeyID: c.AccessKey,
|
||||
SecretAccessKey: c.SecretKey,
|
||||
SessionToken: c.Token,
|
||||
}},
|
||||
&credentials.EnvProvider{},
|
||||
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
|
||||
&ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(session.New(config)),
|
||||
},
|
||||
},
|
||||
})
|
||||
config = config.WithCredentials(creds)
|
||||
}
|
||||
return config.WithCredentials(creds), nil
|
||||
|
||||
opts := session.Options{
|
||||
SharedConfigState: session.SharedConfigEnable,
|
||||
Config: *config,
|
||||
}
|
||||
if c.MFACode != "" {
|
||||
opts.AssumeRoleTokenProvider = func() (string, error) {
|
||||
return c.MFACode, nil
|
||||
}
|
||||
}
|
||||
c.session, err = session.NewSessionWithOptions(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c.session, nil
|
||||
}
|
||||
|
||||
// Region returns the aws.Region object for access to AWS services, requesting
|
||||
|
@ -79,13 +91,7 @@ func (c *AccessConfig) Region() (string, error) {
|
|||
return c.RawRegion, nil
|
||||
}
|
||||
|
||||
md, err := GetInstanceMetaData("placement/availability-zone")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
region := strings.TrimRightFunc(string(md), unicode.IsLetter)
|
||||
return region, nil
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
|
@ -102,24 +108,3 @@ func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetInstanceMetaData(path string) (contents []byte, err error) {
|
||||
url := "http://169.254.169.254/latest/meta-data/" + path
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
err = fmt.Errorf("Code %d returned for url %s", resp.StatusCode, url)
|
||||
return
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return body, err
|
||||
}
|
||||
|
|
|
@ -1,156 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
"github.com/go-ini/ini"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
)
|
||||
|
||||
type CLIConfig struct {
|
||||
ProfileName string
|
||||
SourceProfile string
|
||||
|
||||
AssumeRoleInput *sts.AssumeRoleInput
|
||||
SourceCredentials *credentials.Credentials
|
||||
|
||||
profileCfg *ini.Section
|
||||
profileCred *ini.Section
|
||||
}
|
||||
|
||||
// Return a new CLIConfig with stored profile settings
|
||||
func NewFromProfile(name string) (*CLIConfig, error) {
|
||||
c := &CLIConfig{}
|
||||
c.AssumeRoleInput = new(sts.AssumeRoleInput)
|
||||
err := c.Prepare(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sessName, err := c.getSessionName(c.profileCfg.Key("role_session_name").Value())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.AssumeRoleInput.RoleSessionName = aws.String(sessName)
|
||||
arn := c.profileCfg.Key("role_arn").Value()
|
||||
if arn != "" {
|
||||
c.AssumeRoleInput.RoleArn = aws.String(arn)
|
||||
}
|
||||
id := c.profileCfg.Key("external_id").Value()
|
||||
if id != "" {
|
||||
c.AssumeRoleInput.ExternalId = aws.String(id)
|
||||
}
|
||||
c.SourceCredentials = credentials.NewStaticCredentials(
|
||||
c.profileCred.Key("aws_access_key_id").Value(),
|
||||
c.profileCred.Key("aws_secret_access_key").Value(),
|
||||
c.profileCred.Key("aws_session_token").Value(),
|
||||
)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Return AWS Credentials using current profile. Must supply source config.
|
||||
func (c *CLIConfig) CredentialsFromProfile(conf *aws.Config) (*credentials.Credentials, error) {
|
||||
// If the profile name is equal to the source profile, there is no role to assume so return
|
||||
// the source credentials as they were captured.
|
||||
if c.ProfileName == c.SourceProfile {
|
||||
return c.SourceCredentials, nil
|
||||
}
|
||||
srcCfg := aws.NewConfig().Copy(conf).WithCredentials(c.SourceCredentials)
|
||||
session, err := session.NewSession(srcCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
svc := sts.New(session)
|
||||
res, err := svc.AssumeRole(c.AssumeRoleInput)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return credentials.NewStaticCredentials(
|
||||
*res.Credentials.AccessKeyId,
|
||||
*res.Credentials.SecretAccessKey,
|
||||
*res.Credentials.SessionToken,
|
||||
), nil
|
||||
}
|
||||
|
||||
// Sets params in the struct based on the file section
|
||||
func (c *CLIConfig) Prepare(name string) error {
|
||||
var err error
|
||||
c.ProfileName = name
|
||||
c.profileCfg, err = configFromName(c.ProfileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.SourceProfile = c.profileCfg.Key("source_profile").Value()
|
||||
if c.SourceProfile == "" {
|
||||
c.SourceProfile = c.ProfileName
|
||||
}
|
||||
c.profileCred, err = credsFromName(c.SourceProfile)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *CLIConfig) getSessionName(rawName string) (string, error) {
|
||||
if rawName == "" {
|
||||
name := "packer-"
|
||||
host, err := os.Hostname()
|
||||
if err != nil {
|
||||
return name, err
|
||||
}
|
||||
return fmt.Sprintf("%s%s", name, host), nil
|
||||
} else {
|
||||
return rawName, nil
|
||||
}
|
||||
}
|
||||
|
||||
func configFromName(name string) (*ini.Section, error) {
|
||||
filePath := os.Getenv("AWS_CONFIG_FILE")
|
||||
if filePath == "" {
|
||||
home, err := homedir.Dir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filePath = path.Join(home, ".aws", "config")
|
||||
}
|
||||
file, err := readFile(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
profileName := fmt.Sprintf("profile %s", name)
|
||||
cfg, err := file.GetSection(profileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func credsFromName(name string) (*ini.Section, error) {
|
||||
filePath := os.Getenv("AWS_SHARED_CREDENTIALS_FILE")
|
||||
if filePath == "" {
|
||||
home, err := homedir.Dir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filePath = path.Join(home, ".aws", "credentials")
|
||||
}
|
||||
file, err := readFile(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg, err := file.GetSection(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func readFile(path string) (*ini.File, error) {
|
||||
cfg, err := ini.Load(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
)
|
||||
|
||||
func init() {
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", "")
|
||||
os.Setenv("AWS_ACCESS_KEY", "")
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", "")
|
||||
os.Setenv("AWS_SECRET_KEY", "")
|
||||
os.Setenv("AWS_CONFIG_FILE", "")
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", "")
|
||||
}
|
||||
|
||||
func testCLIConfig() *CLIConfig {
|
||||
return &CLIConfig{}
|
||||
}
|
||||
|
||||
func TestCLIConfigNewFromProfile(t *testing.T) {
|
||||
tmpDir := mockConfig(t)
|
||||
|
||||
c, err := NewFromProfile("testing2")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if c.AssumeRoleInput.RoleArn != nil {
|
||||
t.Errorf("RoleArn should be nil. Instead %p", c.AssumeRoleInput.RoleArn)
|
||||
}
|
||||
if c.AssumeRoleInput.ExternalId != nil {
|
||||
t.Errorf("ExternalId should be nil. Instead %p", c.AssumeRoleInput.ExternalId)
|
||||
}
|
||||
|
||||
mockConfigClose(t, tmpDir)
|
||||
}
|
||||
|
||||
func TestAssumeRole(t *testing.T) {
|
||||
tmpDir := mockConfig(t)
|
||||
|
||||
c, err := NewFromProfile("testing1")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
// Role
|
||||
e := "arn:aws:iam::123456789011:role/rolename"
|
||||
a := *c.AssumeRoleInput.RoleArn
|
||||
if e != a {
|
||||
t.Errorf("RoleArn value should be %s. Instead %s", e, a)
|
||||
}
|
||||
// Session
|
||||
a = *c.AssumeRoleInput.RoleSessionName
|
||||
e = "testsession"
|
||||
if e != a {
|
||||
t.Errorf("RoleSessionName value should be %s. Instead %s", e, a)
|
||||
}
|
||||
|
||||
config := aws.NewConfig()
|
||||
_, err = c.CredentialsFromProfile(config)
|
||||
if err == nil {
|
||||
t.Error("Should have errored")
|
||||
}
|
||||
mockConfigClose(t, tmpDir)
|
||||
}
|
||||
|
||||
func mockConfig(t *testing.T) string {
|
||||
time := time.Now().UnixNano()
|
||||
dir, err := ioutil.TempDir("", strconv.FormatInt(time, 10))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
cfg := []byte(`[profile testing1]
|
||||
region=us-west-2
|
||||
source_profile=testingcredentials
|
||||
role_arn = arn:aws:iam::123456789011:role/rolename
|
||||
role_session_name = testsession
|
||||
|
||||
[profile testing2]
|
||||
region=us-west-2
|
||||
`)
|
||||
cfgFile := path.Join(dir, "config")
|
||||
err = ioutil.WriteFile(cfgFile, cfg, 0644)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
os.Setenv("AWS_CONFIG_FILE", cfgFile)
|
||||
|
||||
crd := []byte(`[testingcredentials]
|
||||
aws_access_key_id = foo
|
||||
aws_secret_access_key = bar
|
||||
|
||||
[testing2]
|
||||
aws_access_key_id = baz
|
||||
aws_secret_access_key = qux
|
||||
`)
|
||||
crdFile := path.Join(dir, "credentials")
|
||||
err = ioutil.WriteFile(crdFile, crd, 0644)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", crdFile)
|
||||
|
||||
return dir
|
||||
}
|
||||
|
||||
func mockConfigClose(t *testing.T, dir string) {
|
||||
err := os.RemoveAll(dir)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
|
||||
"github.com/hashicorp/packer/packer"
|
||||
|
@ -91,21 +90,18 @@ func amiRegionCopy(state multistep.StateBag, config *AccessConfig, name string,
|
|||
isEncrypted := false
|
||||
|
||||
// Connect to the region where the AMI will be copied to
|
||||
awsConfig, err := config.Config()
|
||||
session, err := config.Session()
|
||||
if err != nil {
|
||||
return "", snapshotIds, err
|
||||
}
|
||||
awsConfig.Region = aws.String(target)
|
||||
|
||||
session, err := session.NewSession(awsConfig)
|
||||
if err != nil {
|
||||
return "", snapshotIds, err
|
||||
}
|
||||
regionconn := ec2.New(session)
|
||||
// if we've provided a map of key ids to regions, use those keys.
|
||||
if len(keyID) > 0 {
|
||||
isEncrypted = true
|
||||
}
|
||||
regionconn := ec2.New(session.Copy(&aws.Config{
|
||||
Region: aws.String(target)},
|
||||
))
|
||||
|
||||
resp, err := regionconn.CopyImage(&ec2.CopyImageInput{
|
||||
SourceRegion: &source,
|
||||
SourceImageId: &imageId,
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
"github.com/hashicorp/packer/common"
|
||||
|
@ -78,12 +77,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
}
|
||||
|
||||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
config, err := b.config.Config()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
session, err := session.NewSession(config)
|
||||
session, err := b.config.Session()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/packer/builder/amazon/common"
|
||||
builderT "github.com/hashicorp/packer/helper/builder/testing"
|
||||
|
@ -255,15 +254,11 @@ func testAccPreCheck(t *testing.T) {
|
|||
|
||||
func testEC2Conn() (*ec2.EC2, error) {
|
||||
access := &common.AccessConfig{RawRegion: "us-east-1"}
|
||||
config, err := access.Config()
|
||||
session, err := access.Session()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
session, err := session.NewSession(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ec2.New(session), nil
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/errwrap"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
"github.com/hashicorp/packer/common"
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
|
@ -94,17 +92,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
}
|
||||
|
||||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
awsConfig, err := b.config.Config()
|
||||
session, err := b.config.Session()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
awsSession, err := session.NewSession(awsConfig)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error creating AWS Session: {{err}}", err)
|
||||
}
|
||||
|
||||
ec2conn := ec2.New(awsSession)
|
||||
ec2conn := ec2.New(session)
|
||||
|
||||
// If the subnet is specified but not the VpcId or AZ, try to determine them automatically
|
||||
if b.config.SubnetId != "" && (b.config.AvailabilityZone == "" || b.config.VpcId == "") {
|
||||
|
|
|
@ -6,9 +6,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/errwrap"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
"github.com/hashicorp/packer/common"
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
|
@ -72,16 +70,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
}
|
||||
|
||||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
config, err := b.config.Config()
|
||||
session, err := b.config.Session()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
session, err := session.NewSession(config)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error creating AWS Session: {{err}}", err)
|
||||
}
|
||||
|
||||
ec2conn := ec2.New(session)
|
||||
|
||||
// If the subnet is specified but not the VpcId or AZ, try to determine them automatically
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
"github.com/hashicorp/packer/common"
|
||||
|
@ -164,12 +163,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
}
|
||||
|
||||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
config, err := b.config.Config()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
session, err := session.NewSession(config)
|
||||
session, err := b.config.Session()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -38,7 +38,8 @@ func (s *StepUploadBundle) Run(state multistep.StateBag) multistep.StepAction {
|
|||
|
||||
accessKey := config.AccessKey
|
||||
secretKey := config.SecretKey
|
||||
accessConfig, err := config.AccessConfig.Config()
|
||||
session, err := config.AccessConfig.Session()
|
||||
accessConfig := session.Config
|
||||
if err == nil && accessKey == "" && secretKey == "" {
|
||||
credentials, err := accessConfig.Credentials.Get()
|
||||
if err == nil {
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
|
@ -99,10 +98,11 @@ func (p *PostProcessor) Configure(raws ...interface{}) error {
|
|||
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
|
||||
var err error
|
||||
|
||||
config, err := p.config.Config()
|
||||
session, err := p.config.Session()
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
config := session.Config
|
||||
|
||||
// Render this key since we didn't in the configure phase
|
||||
p.config.S3Key, err = interpolate.Render(p.config.S3Key, &p.config.ctx)
|
||||
|
@ -126,13 +126,6 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac
|
|||
return nil, false, fmt.Errorf("No OVA file found in artifact from builder")
|
||||
}
|
||||
|
||||
// Set up the AWS session
|
||||
log.Println("Creating AWS session")
|
||||
session, err := session.NewSession(config)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
// open the source file
|
||||
log.Printf("Opening file %s to upload", source)
|
||||
file, err := os.Open(source)
|
||||
|
|
|
@ -0,0 +1,665 @@
|
|||
Release v1.7.1 (2017-02-24)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/elasticsearchservice`: Updates service API, documentation, paginators, and examples
|
||||
* Added three new API calls to existing Amazon Elasticsearch service to expose Amazon Elasticsearch imposed limits to customers.
|
||||
|
||||
Release v1.7.0 (2017-02-23)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/ec2`: Updates service API
|
||||
* New EC2 I3 instance type
|
||||
|
||||
SDK Bug
|
||||
---
|
||||
* `service/s3/s3manager`: Adding support for SSE (#1097)
|
||||
* Fixes SSE fields not being applied to a part during multi part upload.
|
||||
|
||||
SDK Feature
|
||||
---
|
||||
* `aws/session`: Add support for AssumeRoles with MFA (#1088)
|
||||
* Adds support for assuming IAM roles with MFA enabled. A TokenProvider func was added to stscreds.AssumeRoleProvider that will be called each time the role's credentials need to be refreshed. A basic token provider that sources the MFA token from stdin as stscreds.StdinTokenProvider.
|
||||
* `aws/session`: Update SDK examples and docs to use session.Must (#1099)
|
||||
* Updates the SDK's example and docs to use session.Must where possible to highlight its usage as apposed to session error checking that is most cases errors will be terminal to the application anyways.
|
||||
Release v1.6.27 (2017-02-22)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/clouddirectory`: Updates service documentation
|
||||
* ListObjectAttributes documentation updated based on forum feedback
|
||||
* `service/elasticbeanstalk`: Updates service API, documentation, and paginators
|
||||
* Elastic Beanstalk adds support for creating and managing custom platform.
|
||||
* `service/gamelift`: Updates service API, documentation, and paginators
|
||||
* Allow developers to configure global queues for creating GameSessions. Allow PlayerData on PlayerSessions to store player-specific data.
|
||||
* `service/route53`: Updates service API, documentation, and examples
|
||||
* Added support for operations CreateVPCAssociationAuthorization and DeleteVPCAssociationAuthorization to throw a ConcurrentModification error when a conflicting modification occurs in parallel to the authorizations in place for a given hosted zone.
|
||||
|
||||
Release v1.6.26 (2017-02-21)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/ec2`: Updates service API and documentation
|
||||
* Added the billingProduct parameter to the RegisterImage API.
|
||||
|
||||
Release v1.6.25 (2017-02-17)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/directconnect`: Updates service API, documentation, and paginators
|
||||
* This update will introduce the ability for Direct Connect customers to take advantage of Link Aggregation (LAG). This allows you to bundle many individual physical interfaces into a single logical interface, referred to as a LAG. This makes administration much simpler as the majority of configuration is done on the LAG while you are free to add or remove physical interfaces from the bundle as bandwidth demand increases or decreases. A concrete example of the simplification added by LAG is that customers need only a single BGP session as opposed to one session per physical connection.
|
||||
|
||||
Release v1.6.24 (2017-02-16)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/cognitoidentity`: Updates service API, documentation, and paginators
|
||||
* Allow createIdentityPool and updateIdentityPool API to set server side token check value on identity pool
|
||||
* `service/configservice`: Updates service API and documentation
|
||||
* AWS Config now supports a new test mode for the PutEvaluations API. Set the TestMode parameter to true in your custom rule to verify whether your AWS Lambda function will deliver evaluation results to AWS Config. No updates occur to your existing evaluations, and evaluation results are not sent to AWS Config.
|
||||
|
||||
Release v1.6.23 (2017-02-15)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/kms`: Updates service API, documentation, paginators, and examples
|
||||
* his release of AWS Key Management Service introduces the ability to tag keys. Tagging keys can help you organize your keys and track your KMS costs in the cost allocation report. This release also increases the maximum length of a key ID to accommodate ARNs that include a long key alias.
|
||||
|
||||
Release v1.6.22 (2017-02-14)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/ec2`: Updates service API, documentation, and paginators
|
||||
* Adds support for the new Modify Volumes apis.
|
||||
|
||||
Release v1.6.21 (2017-02-11)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/storagegateway`: Updates service API, documentation, and paginators
|
||||
* File gateway mode in AWS Storage gateway provides access to objects in S3 as files on a Network File System (NFS) mount point. This is done by creating Nfs file shares using existing APIs CreateNfsFileShare. Using the feature in this update, the customer can restrict the clients that have read/write access to the gateway by specifying the list of clients as a list of IP addresses or CIDR blocks. This list can be specified using the API CreateNfsFileShare while creating new file shares, or UpdateNfsFileShare while update existing file shares. To find out the list of clients that have access, the existing API DescribeNfsFileShare will now output the list of clients that have access.
|
||||
|
||||
Release v1.6.20 (2017-02-09)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/ec2`: Updates service API and documentation
|
||||
* This feature allows customers to associate an IAM profile to running instances that do not have any.
|
||||
* `service/rekognition`: Updates service API and documentation
|
||||
* DetectFaces and IndexFaces operations now return an estimate of the age of the face as an age range.
|
||||
|
||||
SDK Features
|
||||
---
|
||||
* `aws/endpoints`: Add option to resolve unknown endpoints (#1074)
|
||||
Release v1.6.19 (2017-02-08)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `aws/endpoints`: Updated Regions and Endpoints metadata.
|
||||
* `service/glacier`: Updates service examples
|
||||
* Doc Update
|
||||
* `service/lexruntimeservice`: Adds new service
|
||||
* Preview release
|
||||
|
||||
SDK Bug Fixes
|
||||
---
|
||||
* `private/protocol/json`: Fixes json to throw an error if a float number is (+/-)Inf and NaN (#1068)
|
||||
* `private/model/api`: Fix documentation error listing (#1067)
|
||||
|
||||
SDK Features
|
||||
---
|
||||
* `private/model`: Add service response error code generation (#1061)
|
||||
|
||||
Release v1.6.18 (2017-01-27)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/clouddirectory`: Adds new service
|
||||
* Amazon Cloud Directory is a highly scalable, high performance, multi-tenant directory service in the cloud. Its web-based directories make it easy for you to organize and manage application resources such as users, groups, locations, devices, policies, and the rich relationships between them.
|
||||
* `service/codedeploy`: Updates service API, documentation, and paginators
|
||||
* This release of AWS CodeDeploy introduces support for blue/green deployments. In a blue/green deployment, the current set of instances in a deployment group is replaced by new instances that have the latest application revision installed on them. After traffic is rerouted behind a load balancer to the replacement instances, the original instances can be terminated automatically or kept running for other uses.
|
||||
* `service/ec2`: Updates service API and documentation
|
||||
* Adds instance health check functionality to replace unhealthy EC2 Spot fleet instances with fresh ones.
|
||||
* `service/rds`: Updates service API and documentation
|
||||
* Snapshot Engine Version Upgrade
|
||||
|
||||
Release v1.6.17 (2017-01-25)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/elbv2`: Updates service API, documentation, and paginators
|
||||
* Application Load Balancers now support native Internet Protocol version 6 (IPv6) in an Amazon Virtual Private Cloud (VPC). With this ability, clients can now connect to the Application Load Balancer in a dual-stack mode via either IPv4 or IPv6.
|
||||
* `service/rds`: Updates service API and documentation
|
||||
* Cross Region Read Replica Copying (CreateDBInstanceReadReplica)
|
||||
|
||||
Release v1.6.16 (2017-01-24)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/codebuild`: Updates service documentation and paginators
|
||||
* Documentation updates
|
||||
* `service/codecommit`: Updates service API, documentation, and paginators
|
||||
* AWS CodeCommit now includes the option to view the differences between a commit and its parent commit from within the console. You can view the differences inline (Unified view) or side by side (Split view). To view information about the differences between a commit and something other than its parent, you can use the AWS CLI and the get-differences and get-blob commands, or you can use the GetDifferences and GetBlob APIs.
|
||||
* `service/ecs`: Updates service API and documentation
|
||||
* Amazon ECS now supports a state for container instances that can be used to drain a container instance in preparation for maintenance or cluster scale down.
|
||||
|
||||
Release v1.6.15 (2017-01-20)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/acm`: Updates service API, documentation, and paginators
|
||||
* Update for AWS Certificate Manager: Updated response elements for DescribeCertificate API in support of managed renewal
|
||||
* `service/health`: Updates service documentation
|
||||
|
||||
Release v1.6.14 (2017-01-19)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/ec2`: Updates service API, documentation, and paginators
|
||||
* Amazon EC2 Spot instances now support dedicated tenancy, providing the ability to run Spot instances single-tenant manner on physically isolated hardware within a VPC to satisfy security, privacy, or other compliance requirements. Dedicated Spot instances can be requested using RequestSpotInstances and RequestSpotFleet.
|
||||
|
||||
Release v1.6.13 (2017-01-18)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/rds`: Updates service API, documentation, and paginators
|
||||
|
||||
Release v1.6.12 (2017-01-17)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/dynamodb`: Updates service API, documentation, and paginators
|
||||
* Tagging Support for Amazon DynamoDB Tables and Indexes
|
||||
* `aws/endpoints`: Updated Regions and Endpoints metadata.
|
||||
* `service/glacier`: Updates service API, paginators, and examples
|
||||
* Doc-only Update for Glacier: Added code snippets
|
||||
* `service/polly`: Updates service documentation and examples
|
||||
* Doc-only update for Amazon Polly -- added snippets
|
||||
* `service/rekognition`: Updates service documentation and paginators
|
||||
* Added code samples to Rekognition reference topics.
|
||||
* `service/route53`: Updates service API and paginators
|
||||
* Add ca-central-1 and eu-west-2 enum values to CloudWatchRegion enum
|
||||
|
||||
Release v1.6.11 (2017-01-16)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/configservice`: Updates service API, documentation, and paginators
|
||||
* `service/costandusagereportservice`: Adds new service
|
||||
* The AWS Cost and Usage Report Service API allows you to enable and disable the Cost & Usage report, as well as modify the report name, the data granularity, and the delivery preferences.
|
||||
* `service/dynamodb`: Updates service API, documentation, and examples
|
||||
* Snippets for the DynamoDB API.
|
||||
* `service/elasticache`: Updates service API, documentation, and examples
|
||||
* Adds new code examples.
|
||||
* `aws/endpoints`: Updated Regions and Endpoints metadata.
|
||||
|
||||
Release v1.6.10 (2017-01-04)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/configservice`: Updates service API and documentation
|
||||
* AWSConfig is planning to add support for OversizedConfigurationItemChangeNotification message type in putConfigRule. After this release customers can use/write rules based on OversizedConfigurationItemChangeNotification mesage type.
|
||||
* `service/efs`: Updates service API, documentation, and examples
|
||||
* Doc-only Update for EFS: Added code snippets
|
||||
* `service/iam`: Updates service documentation and examples
|
||||
* `service/lambda`: Updates service documentation and examples
|
||||
* Doc only updates for Lambda: Added code snippets
|
||||
* `service/marketplacecommerceanalytics`: Updates service API and documentation
|
||||
* Added support for data set disbursed_amount_by_instance_hours, with historical data available starting 2012-09-04. New data is published to this data set every 30 days.
|
||||
* `service/rds`: Updates service documentation
|
||||
* Updated documentation for CopyDBSnapshot.
|
||||
* `service/rekognition`: Updates service documentation and examples
|
||||
* Doc-only Update for Rekognition: Added code snippets
|
||||
* `service/snowball`: Updates service examples
|
||||
* `service/dynamodbstreams`: Updates service API and examples
|
||||
* Doc-only Update for DynamoDB Streams: Added code snippets
|
||||
|
||||
SDK Feature
|
||||
---
|
||||
* `private/model/api`: Increasing the readability of code generated files. (#1024)
|
||||
Release v1.6.9 (2016-12-30)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/codedeploy`: Updates service API and documentation
|
||||
* CodeDeploy will support Iam Session Arns in addition to Iam User Arns for on premise host authentication.
|
||||
* `service/ecs`: Updates service API and documentation
|
||||
* Amazon EC2 Container Service (ECS) now supports the ability to customize the placement of tasks on container instances.
|
||||
* `aws/endpoints`: Updated Regions and Endpoints metadata.
|
||||
|
||||
Release v1.6.8 (2016-12-22)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/apigateway`: Updates service API and documentation
|
||||
* Amazon API Gateway is adding support for generating SDKs in more languages. This update introduces two new operations used to dynamically discover these SDK types and what configuration each type accepts.
|
||||
* `service/directoryservice`: Updates service documentation
|
||||
* Added code snippets for the DS SDKs
|
||||
* `service/elasticbeanstalk`: Updates service API and documentation
|
||||
* `service/iam`: Updates service API and documentation
|
||||
* Adds service-specific credentials to IAM service to make it easier to onboard CodeCommit customers. These are username/password credentials that work with a single service.
|
||||
* `service/kms`: Updates service API, documentation, and examples
|
||||
* Update docs and add SDK examples
|
||||
|
||||
Release v1.6.7 (2016-12-22)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/ecr`: Updates service API and documentation
|
||||
* `aws/endpoints`: Updated Regions and Endpoints metadata.
|
||||
* `service/rds`: Updates service API and documentation
|
||||
* Cross Region Encrypted Snapshot Copying (CopyDBSnapshot)
|
||||
|
||||
Release v1.6.6 (2016-12-20)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `aws/endpoints`: Updated Regions and Endpoints metadata.
|
||||
* `service/firehose`: Updates service API, documentation, and examples
|
||||
* Processing feature enables users to process and modify records before Amazon Firehose delivers them to destinations.
|
||||
* `service/route53`: Updates service API and documentation
|
||||
* Enum updates for eu-west-2 and ca-central-1
|
||||
* `service/storagegateway`: Updates service API, documentation, and examples
|
||||
* File gateway is a new mode in the AWS Storage Gateway that support a file interface into S3, alongside the current block-based volume and VTL storage. File gateway combines a service and virtual software appliance, enabling you to store and retrieve objects in Amazon S3 using industry standard file protocols such as NFS. The software appliance, or gateway, is deployed into your on-premises environment as a virtual machine (VM) running on VMware ESXi. The gateway provides access to objects in S3 as files on a Network File System (NFS) mount point.
|
||||
|
||||
Release v1.6.5 (2016-12-19)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/cloudformation`: Updates service documentation
|
||||
* Minor doc update for CloudFormation.
|
||||
* `service/cloudtrail`: Updates service paginators
|
||||
* `service/cognitoidentity`: Updates service API and documentation
|
||||
* We are adding Groups to Cognito user pools. Developers can perform CRUD operations on groups, add and remove users from groups, list users in groups, etc. We are adding fine-grained role-based access control for Cognito identity pools. Developers can configure an identity pool to get the IAM role from an authenticated user's token, or they can configure rules that will map a user to a different role
|
||||
* `service/applicationdiscoveryservice`: Updates service API and documentation
|
||||
* Adds new APIs to group discovered servers into Applications with get summary and neighbors. Includes additional filters for ListConfigurations and DescribeAgents API.
|
||||
* `service/inspector`: Updates service API, documentation, and examples
|
||||
* Doc-only Update for Inspector: Adding SDK code snippets for Inspector
|
||||
* `service/sqs`: Updates service documentation
|
||||
|
||||
SDK Bug Fixes
|
||||
---
|
||||
* `aws/request`: Add PriorRequestNotComplete to throttle retry codes (#1011)
|
||||
* Fixes: Not retrying when PriorRequestNotComplete #1009
|
||||
|
||||
SDK Feature
|
||||
---
|
||||
* `private/model/api`: Adds crosslinking to service documentation (#1010)
|
||||
|
||||
Release v1.6.4 (2016-12-15)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/cognitoidentityprovider`: Updates service API and documentation
|
||||
* `aws/endpoints`: Updated Regions and Endpoints metadata.
|
||||
* `service/ssm`: Updates service API and documentation
|
||||
* This will provide customers with access to the Patch Baseline and Patch Compliance APIs.
|
||||
|
||||
SDK Bug Fixes
|
||||
---
|
||||
* `service/route53`: Fix URL path cleaning for Route53 API requests (#1006)
|
||||
* Fixes: SerializationError when using Route53 ChangeResourceRecordSets #1005
|
||||
* `aws/request`: Add PriorRequestNotComplete to throttle retry codes (#1002)
|
||||
* Fixes: Not retrying when PriorRequestNotComplete #1001
|
||||
|
||||
Release v1.6.3 (2016-12-14)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/batch`: Adds new service
|
||||
* AWS Batch is a batch computing service that lets customers define queues and compute environments and then submit work as batch jobs.
|
||||
* `service/databasemigrationservice`: Updates service API and documentation
|
||||
* Adds support for SSL enabled Oracle endpoints and task modification.
|
||||
* `service/elasticbeanstalk`: Updates service documentation
|
||||
* `aws/endpoints`: Updated Regions and Endpoints metadata.
|
||||
* `service/cloudwatchlogs`: Updates service API and documentation
|
||||
* Add support for associating LogGroups with AWSTagris tags
|
||||
* `service/marketplacecommerceanalytics`: Updates service API and documentation
|
||||
* Add new enum to DataSetType: sales_compensation_billed_revenue
|
||||
* `service/rds`: Updates service documentation
|
||||
* Doc-only Update for RDS: New versions available in CreateDBInstance
|
||||
* `service/sts`: Updates service documentation
|
||||
* Adding Code Snippet Examples for SDKs for STS
|
||||
|
||||
SDK Bug Fixes
|
||||
---
|
||||
* `aws/request`: Fix retrying timeout requests (#981)
|
||||
* Fixes: Requests Retrying is broken if the error was caused due to a client timeout #947
|
||||
* `aws/request`: Fix for Go 1.8 request incorrectly sent with body (#991)
|
||||
* Fixes: service/route53: ListHostedZones hangs and then fails with go1.8 #984
|
||||
* private/protocol/rest: Use RawPath instead of Opaque (#993)
|
||||
* Fixes: HTTP2 request failing with REST protocol services, e.g AWS X-Ray
|
||||
* private/model/api: Generate REST-JSON JSONVersion correctly (#998)
|
||||
* Fixes: REST-JSON protocol service code missing JSONVersion metadata.
|
||||
|
||||
Release v1.6.2 (2016-12-08)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/cloudfront`: Add lambda function associations to cache behaviors
|
||||
* `service/codepipeline`: This is a doc-only update request to incorporate some recent minor revisions to the doc content.
|
||||
* `service/rds`: Updates service API and documentation
|
||||
* `service/wafregional`: With this new feature, customers can use AWS WAF directly on Application Load Balancers in a VPC within available regions to protect their websites and web services from malicious attacks such as SQL injection, Cross Site Scripting, bad bots, etc.
|
||||
|
||||
Release v1.6.1 (2016-12-07)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/config`: Updates service API
|
||||
* `service/s3`: Updates service API
|
||||
* `service/sqs`: Updates service API and documentation
|
||||
|
||||
Release v1.6.0 (2016-12-06)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/config`: Updates service API and documentation
|
||||
* `service/ec2`: Updates service API
|
||||
* `service/sts`: Updates service API, documentation, and examples
|
||||
|
||||
SDK Bug Fixes
|
||||
---
|
||||
* private/protocol/xml/xmlutil: Fix SDK XML unmarshaler #975
|
||||
* Fixes GetBucketACL Grantee required type always nil. #916
|
||||
|
||||
SDK Feature
|
||||
---
|
||||
* aws/endpoints: Add endpoint metadata to SDK #961
|
||||
* Adds Region and Endpoint metadata to the SDK. This allows you to enumerate regions and endpoint metadata based on a defined model embedded in the SDK.
|
||||
|
||||
Release v1.5.13 (2016-12-01)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/apigateway`: Updates service API and documentation
|
||||
* `service/appstream`: Adds new service
|
||||
* `service/codebuild`: Adds new service
|
||||
* `service/directconnect`: Updates service API and documentation
|
||||
* `service/ec2`: Adds new service
|
||||
* `service/elasticbeanstalk`: Updates service API and documentation
|
||||
* `service/health`: Adds new service
|
||||
* `service/lambda`: Updates service API and documentation
|
||||
* `service/opsworkscm`: Adds new service
|
||||
* `service/pinpoint`: Adds new service
|
||||
* `service/shield`: Adds new service
|
||||
* `service/ssm`: Updates service API and documentation
|
||||
* `service/states`: Adds new service
|
||||
* `service/xray`: Adds new service
|
||||
|
||||
Release v1.5.12 (2016-11-30)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/lightsail`: Adds new service
|
||||
* `service/polly`: Adds new service
|
||||
* `service/rekognition`: Adds new service
|
||||
* `service/snowball`: Updates service API and documentation
|
||||
|
||||
Release v1.5.11 (2016-11-29)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
`service/s3`: Updates service API and documentation
|
||||
|
||||
Release v1.5.10 (2016-11-22)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/cloudformation`: Updates service API and documentation
|
||||
* `service/glacier`: Updates service API, documentation, and examples
|
||||
* `service/route53`: Updates service API and documentation
|
||||
* `service/s3`: Updates service API and documentation
|
||||
|
||||
SDK Bug Fixes
|
||||
---
|
||||
* `private/protocol/xml/xmlutil`: Fixes xml marshaler to unmarshal properly
|
||||
into tagged fields
|
||||
[#916](https://github.com/aws/aws-sdk-go/issues/916)
|
||||
|
||||
Release v1.5.9 (2016-11-22)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/cloudtrail`: Updates service API and documentation
|
||||
* `service/ecs`: Updates service API and documentation
|
||||
|
||||
Release v1.5.8 (2016-11-18)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/application-autoscaling`: Updates service API and documentation
|
||||
* `service/elasticmapreduce`: Updates service API and documentation
|
||||
* `service/elastictranscoder`: Updates service API, documentation, and examples
|
||||
* `service/gamelift`: Updates service API and documentation
|
||||
* `service/lambda`: Updates service API and documentation
|
||||
|
||||
Release v1.5.7 (2016-11-18)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/apigateway`: Updates service API and documentation
|
||||
* `service/meteringmarketplace`: Updates service API and documentation
|
||||
* `service/monitoring`: Updates service API and documentation
|
||||
* `service/sqs`: Updates service API, documentation, and examples
|
||||
|
||||
Release v1.5.6 (2016-11-16)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
`service/route53`: Updates service API and documentation
|
||||
`service/servicecatalog`: Updates service API and documentation
|
||||
|
||||
Release v1.5.5 (2016-11-15)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/ds`: Updates service API and documentation
|
||||
* `service/elasticache`: Updates service API and documentation
|
||||
* `service/kinesis`: Updates service API and documentation
|
||||
|
||||
Release v1.5.4 (2016-11-15)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/cognito-idp`: Updates service API and documentation
|
||||
|
||||
Release v1.5.3 (2016-11-11)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/cloudformation`: Updates service documentation and examples
|
||||
* `service/logs`: Updates service API and documentation
|
||||
|
||||
Release v1.5.2 (2016-11-03)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/directconnect`: Updates service API and documentation
|
||||
|
||||
Release v1.5.1 (2016-11-02)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/email`: Updates service API and documentation
|
||||
|
||||
Release v1.5.0 (2016-11-01)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/cloudformation`: Updates service API and documentation
|
||||
* `service/ecr`: Updates service paginators
|
||||
|
||||
SDK Feature Updates
|
||||
---
|
||||
* `private/model/api`: Add generated setters for API parameters (#918)
|
||||
* Adds setters to the SDK's API parameter types, and are a convenience method that reduce the need to use `aws.String` and like utility.
|
||||
|
||||
Release v1.4.22 (2016-10-25)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/elasticloadbalancingv2`: Updates service documentation.
|
||||
* `service/autoscaling`: Updates service documentation.
|
||||
|
||||
Release v1.4.21 (2016-10-24)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/sms`: AWS Server Migration Service (SMS) is an agentless service which makes it easier and faster for you to migrate thousands of on-premises workloads to AWS. AWS SMS allows you to automate, schedule, and track incremental replications of live server volumes, making it easier for you to coordinate large-scale server migrations.
|
||||
* `service/ecs`: Updates documentation.
|
||||
|
||||
SDK Feature Updates
|
||||
---
|
||||
* `private/models/api`: Improve code generation of documentation.
|
||||
|
||||
Release v1.4.20 (2016-10-20)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/budgets`: Adds new service, AWS Budgets.
|
||||
* `service/waf`: Updates service documentation.
|
||||
|
||||
Release v1.4.19 (2016-10-18)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/cloudfront`: Updates service API and documentation.
|
||||
* Ability to use Amazon CloudFront to deliver your content both via IPv6 and IPv4 using HTTP/HTTPS.
|
||||
* `service/configservice`: Update service API and documentation.
|
||||
* `service/iot`: Updates service API and documentation.
|
||||
* `service/kinesisanalytics`: Updates service API and documentation.
|
||||
* Whenever Amazon Kinesis Analytics is not able to detect schema for the given streaming source on DiscoverInputSchema API, we would return the raw records that was sampled to detect the schema.
|
||||
* `service/rds`: Updates service API and documentation.
|
||||
* Amazon Aurora integrates with other AWS services to allow you to extend your Aurora DB cluster to utilize other capabilities in the AWS cloud. Permission to access other AWS services is granted by creating an IAM role with the necessary permissions, and then associating the role with your DB cluster.
|
||||
|
||||
SDK Feature Updates
|
||||
---
|
||||
* `service/dynamodb/dynamodbattribute`: Add UnmarshalListOfMaps #897
|
||||
* Adds support for unmarshaling a list of maps. This is useful for unmarshaling the DynamoDB AttributeValue list of maps returned by APIs like Query and Scan.
|
||||
|
||||
Release v1.4.18 (2016-10-17)
|
||||
===
|
||||
|
||||
Service Model Updates
|
||||
---
|
||||
* `service/route53`: Updates service API and documentation.
|
||||
|
||||
Release v1.4.17
|
||||
===
|
||||
|
||||
Service Model Updates
|
||||
---
|
||||
* `service/acm`: Update service API, and documentation.
|
||||
* This change allows users to import third-party SSL/TLS certificates into ACM.
|
||||
* `service/elasticbeanstalk`: Update service API, documentation, and pagination.
|
||||
* Elastic Beanstalk DescribeApplicationVersions API is being updated to support pagination.
|
||||
* `service/gamelift`: Update service API, and documentation.
|
||||
* New APIs to protect game developer resource (builds, alias, fleets, instances, game sessions and player sessions) against abuse.
|
||||
|
||||
SDK Features
|
||||
---
|
||||
* `service/s3`: Add support for accelerate with dualstack [#887](https://github.com/aws/aws-sdk-go/issues/887)
|
||||
|
||||
Release v1.4.16 (2016-10-13)
|
||||
===
|
||||
|
||||
Service Model Updates
|
||||
---
|
||||
* `service/ecr`: Update Amazon EC2 Container Registry service model
|
||||
* DescribeImages is a new api used to expose image metadata which today includes image size and image creation timestamp.
|
||||
* `service/elasticache`: Update Amazon ElastiCache service model
|
||||
* Elasticache is launching a new major engine release of Redis, 3.2 (providing stability updates and new command sets over 2.8), as well as ElasticSupport for enabling Redis Cluster in 3.2, which provides support for multiple node groups to horizontally scale data, as well as superior engine failover capabilities
|
||||
|
||||
SDK Bug Fixes
|
||||
---
|
||||
* `aws/session`: Skip shared config on read errors [#883](https://github.com/aws/aws-sdk-go/issues/883)
|
||||
* `aws/signer/v4`: Add support for URL.EscapedPath to signer [#885](https://github.com/aws/aws-sdk-go/issues/885)
|
||||
|
||||
SDK Features
|
||||
---
|
||||
* `private/model/api`: Add docs for errors to API operations [#881](https://github.com/aws/aws-sdk-go/issues/881)
|
||||
* `private/model/api`: Improve field and waiter doc strings [#879](https://github.com/aws/aws-sdk-go/issues/879)
|
||||
* `service/dynamodb/dynamodbattribute`: Allow multiple struct tag elements [#886](https://github.com/aws/aws-sdk-go/issues/886)
|
||||
* Add build tags to internal SDK tools [#880](https://github.com/aws/aws-sdk-go/issues/880)
|
||||
|
||||
Release v1.4.15 (2016-10-06)
|
||||
===
|
||||
|
||||
Service Model Updates
|
||||
---
|
||||
* `service/cognitoidentityprovider`: Update Amazon Cognito Identity Provider service model
|
||||
* `service/devicefarm`: Update AWS Device Farm documentation
|
||||
* `service/opsworks`: Update AWS OpsWorks service model
|
||||
* `service/s3`: Update Amazon Simple Storage Service model
|
||||
* `service/waf`: Update AWS WAF service model
|
||||
|
||||
SDK Bug Fixes
|
||||
---
|
||||
* `aws/request`: Fix HTTP Request Body race condition [#874](https://github.com/aws/aws-sdk-go/issues/874)
|
||||
|
||||
SDK Feature Updates
|
||||
---
|
||||
* `aws/ec2metadata`: Add support for EC2 User Data [#872](https://github.com/aws/aws-sdk-go/issues/872)
|
||||
* `aws/signer/v4`: Remove logic determining if request needs to be resigned [#876](https://github.com/aws/aws-sdk-go/issues/876)
|
||||
|
||||
Release v1.4.14 (2016-09-29)
|
||||
===
|
||||
* `service/ec2`: api, documentation, and paginators updates.
|
||||
* `service/s3`: api and documentation updates.
|
||||
|
||||
Release v1.4.13 (2016-09-27)
|
||||
===
|
||||
* `service/codepipeline`: documentation updates.
|
||||
* `service/cloudformation`: api and documentation updates.
|
||||
* `service/kms`: documentation updates.
|
||||
* `service/elasticfilesystem`: documentation updates.
|
||||
* `service/snowball`: documentation updates.
|
|
@ -0,0 +1,122 @@
|
|||
Contributing to the AWS SDK for Go
|
||||
|
||||
We work hard to provide a high-quality and useful SDK, and we greatly value
|
||||
feedback and contributions from our community. Whether it's a bug report,
|
||||
new feature, correction, or additional documentation, we welcome your issues
|
||||
and pull requests. Please read through this document before submitting any
|
||||
issues or pull requests to ensure we have all the necessary information to
|
||||
effectively respond to your bug report or contribution.
|
||||
|
||||
|
||||
## Filing Bug Reports
|
||||
|
||||
You can file bug reports against the SDK on the [GitHub issues][issues] page.
|
||||
|
||||
If you are filing a report for a bug or regression in the SDK, it's extremely
|
||||
helpful to provide as much information as possible when opening the original
|
||||
issue. This helps us reproduce and investigate the possible bug without having
|
||||
to wait for this extra information to be provided. Please read the following
|
||||
guidelines prior to filing a bug report.
|
||||
|
||||
1. Search through existing [issues][] to ensure that your specific issue has
|
||||
not yet been reported. If it is a common issue, it is likely there is
|
||||
already a bug report for your problem.
|
||||
|
||||
2. Ensure that you have tested the latest version of the SDK. Although you
|
||||
may have an issue against an older version of the SDK, we cannot provide
|
||||
bug fixes for old versions. It's also possible that the bug may have been
|
||||
fixed in the latest release.
|
||||
|
||||
3. Provide as much information about your environment, SDK version, and
|
||||
relevant dependencies as possible. For example, let us know what version
|
||||
of Go you are using, which and version of the operating system, and the
|
||||
the environment your code is running in. e.g Container.
|
||||
|
||||
4. Provide a minimal test case that reproduces your issue or any error
|
||||
information you related to your problem. We can provide feedback much
|
||||
more quickly if we know what operations you are calling in the SDK. If
|
||||
you cannot provide a full test case, provide as much code as you can
|
||||
to help us diagnose the problem. Any relevant information should be provided
|
||||
as well, like whether this is a persistent issue, or if it only occurs
|
||||
some of the time.
|
||||
|
||||
|
||||
## Submitting Pull Requests
|
||||
|
||||
We are always happy to receive code and documentation contributions to the SDK.
|
||||
Please be aware of the following notes prior to opening a pull request:
|
||||
|
||||
1. The SDK is released under the [Apache license][license]. Any code you submit
|
||||
will be released under that license. For substantial contributions, we may
|
||||
ask you to sign a [Contributor License Agreement (CLA)][cla].
|
||||
|
||||
2. If you would like to implement support for a significant feature that is not
|
||||
yet available in the SDK, please talk to us beforehand to avoid any
|
||||
duplication of effort.
|
||||
|
||||
3. Wherever possible, pull requests should contain tests as appropriate.
|
||||
Bugfixes should contain tests that exercise the corrected behavior (i.e., the
|
||||
test should fail without the bugfix and pass with it), and new features
|
||||
should be accompanied by tests exercising the feature.
|
||||
|
||||
4. Pull requests that contain failing tests will not be merged until the test
|
||||
failures are addressed. Pull requests that cause a significant drop in the
|
||||
SDK's test coverage percentage are unlikely to be merged until tests have
|
||||
been added.
|
||||
|
||||
### Testing
|
||||
|
||||
To run the tests locally, running the `make unit` command will `go get` the
|
||||
SDK's testing dependencies, and run vet, link and unit tests for the SDK.
|
||||
|
||||
```
|
||||
make unit
|
||||
```
|
||||
|
||||
Standard go testing functionality is supported as well. To test SDK code that
|
||||
is tagged with `codegen` you'll need to set the build tag in the go test
|
||||
command. The `make unit` command will do this automatically.
|
||||
|
||||
```
|
||||
go test -tags codegen ./private/...
|
||||
```
|
||||
|
||||
See the `Makefile` for additional testing tags that can be used in testing.
|
||||
|
||||
To test on multiple platform the SDK includes several DockerFiles under the
|
||||
`awstesting/sandbox` folder, and associated make recipes to to execute
|
||||
unit testing within environments configured for specific Go versions.
|
||||
|
||||
```
|
||||
make sandbox-test-go18
|
||||
```
|
||||
|
||||
To run all sandbox environments use the following make recipe
|
||||
|
||||
```
|
||||
# Optionally update the Go tip that will be used during the batch testing
|
||||
make update-aws-golang-tip
|
||||
|
||||
# Run all SDK tests for supported Go versions in sandboxes
|
||||
make sandbox-test
|
||||
```
|
||||
|
||||
In addition the sandbox environment include make recipes for interactive modes
|
||||
so you can run command within the Docker container and context of the SDK.
|
||||
|
||||
```
|
||||
make sandbox-go18
|
||||
```
|
||||
|
||||
### Changelog
|
||||
|
||||
You can see all release changes in the `CHANGELOG.md` file at the root of the
|
||||
repository. The release notes added to this file will contain service client
|
||||
updates, and major SDK changes.
|
||||
|
||||
[issues]: https://github.com/aws/aws-sdk-go/issues
|
||||
[pr]: https://github.com/aws/aws-sdk-go/pulls
|
||||
[license]: http://aws.amazon.com/apache2.0/
|
||||
[cla]: http://en.wikipedia.org/wiki/Contributor_License_Agreement
|
||||
[releasenotes]: https://github.com/aws/aws-sdk-go/releases
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
LINTIGNOREDOT='awstesting/integration.+should not use dot imports'
|
||||
LINTIGNOREDOC='service/[^/]+/(api|service|waiters)\.go:.+(comment on exported|should have comment or be unexported)'
|
||||
LINTIGNORECONST='service/[^/]+/(api|service|waiters)\.go:.+(type|struct field|const|func) ([^ ]+) should be ([^ ]+)'
|
||||
LINTIGNORESTUTTER='service/[^/]+/(api|service)\.go:.+(and that stutters)'
|
||||
LINTIGNOREINFLECT='service/[^/]+/(api|errors|service)\.go:.+(method|const) .+ should be '
|
||||
LINTIGNOREINFLECTS3UPLOAD='service/s3/s3manager/upload\.go:.+struct field SSEKMSKeyId should be '
|
||||
LINTIGNOREDEPS='vendor/.+\.go'
|
||||
UNIT_TEST_TAGS="example codegen"
|
||||
|
||||
SDK_WITH_VENDOR_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/src")
|
||||
SDK_ONLY_PKGS=$(shell go list ./... | grep -v "/vendor/")
|
||||
SDK_UNIT_TEST_ONLY_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/")
|
||||
SDK_GO_1_4=$(shell go version | grep "go1.4")
|
||||
SDK_GO_1_5=$(shell go version | grep "go1.5")
|
||||
SDK_GO_VERSION=$(shell go version | awk '''{print $$3}''' | tr -d '''\n''')
|
||||
|
||||
all: get-deps generate unit
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " api_info to print a list of services and versions"
|
||||
@echo " docs to build SDK documentation"
|
||||
@echo " build to go build the SDK"
|
||||
@echo " unit to run unit tests"
|
||||
@echo " integration to run integration tests"
|
||||
@echo " performance to run performance tests"
|
||||
@echo " verify to verify tests"
|
||||
@echo " lint to lint the SDK"
|
||||
@echo " vet to vet the SDK"
|
||||
@echo " generate to go generate and make services"
|
||||
@echo " gen-test to generate protocol tests"
|
||||
@echo " gen-services to generate services"
|
||||
@echo " get-deps to go get the SDK dependencies"
|
||||
@echo " get-deps-tests to get the SDK's test dependencies"
|
||||
@echo " get-deps-verify to get the SDK's verification dependencies"
|
||||
|
||||
generate: gen-test gen-endpoints gen-services
|
||||
|
||||
gen-test: gen-protocol-test
|
||||
|
||||
gen-services:
|
||||
go generate ./service
|
||||
|
||||
gen-protocol-test:
|
||||
go generate ./private/protocol/...
|
||||
|
||||
gen-endpoints:
|
||||
go generate ./models/endpoints/
|
||||
|
||||
build:
|
||||
@echo "go build SDK and vendor packages"
|
||||
@go build ${SDK_ONLY_PKGS}
|
||||
|
||||
unit: get-deps-tests build verify
|
||||
@echo "go test SDK and vendor packages"
|
||||
@go test -tags ${UNIT_TEST_TAGS} $(SDK_UNIT_TEST_ONLY_PKGS)
|
||||
|
||||
unit-with-race-cover: get-deps-tests build verify
|
||||
@echo "go test SDK and vendor packages"
|
||||
@go test -tags ${UNIT_TEST_TAGS} -race -cpu=1,2,4 $(SDK_UNIT_TEST_ONLY_PKGS)
|
||||
|
||||
integration: get-deps-tests integ-custom smoke-tests performance
|
||||
|
||||
integ-custom:
|
||||
go test -tags "integration" ./awstesting/integration/customizations/...
|
||||
|
||||
smoke-tests: get-deps-tests
|
||||
gucumber -go-tags "integration" ./awstesting/integration/smoke
|
||||
|
||||
performance: get-deps-tests
|
||||
AWS_TESTING_LOG_RESULTS=${log-detailed} AWS_TESTING_REGION=$(region) AWS_TESTING_DB_TABLE=$(table) gucumber -go-tags "integration" ./awstesting/performance
|
||||
|
||||
sandbox-tests: sandbox-test-go15 sandbox-test-go15-novendorexp sandbox-test-go16 sandbox-test-go17 sandbox-test-go18 sandbox-test-gotip
|
||||
|
||||
sandbox-build-go15:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.5 -t "aws-sdk-go-1.5" .
|
||||
sandbox-go15: sandbox-build-go15
|
||||
docker run -i -t aws-sdk-go-1.5 bash
|
||||
sandbox-test-go15: sandbox-build-go15
|
||||
docker run -t aws-sdk-go-1.5
|
||||
|
||||
sandbox-build-go15-novendorexp:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.5-novendorexp -t "aws-sdk-go-1.5-novendorexp" .
|
||||
sandbox-go15-novendorexp: sandbox-build-go15-novendorexp
|
||||
docker run -i -t aws-sdk-go-1.5-novendorexp bash
|
||||
sandbox-test-go15-novendorexp: sandbox-build-go15-novendorexp
|
||||
docker run -t aws-sdk-go-1.5-novendorexp
|
||||
|
||||
sandbox-build-go16:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.6 -t "aws-sdk-go-1.6" .
|
||||
sandbox-go16: sandbox-build-go16
|
||||
docker run -i -t aws-sdk-go-1.6 bash
|
||||
sandbox-test-go16: sandbox-build-go16
|
||||
docker run -t aws-sdk-go-1.6
|
||||
|
||||
sandbox-build-go17:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.7 -t "aws-sdk-go-1.7" .
|
||||
sandbox-go17: sandbox-build-go17
|
||||
docker run -i -t aws-sdk-go-1.7 bash
|
||||
sandbox-test-go17: sandbox-build-go17
|
||||
docker run -t aws-sdk-go-1.7
|
||||
|
||||
sandbox-build-go18:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.8 -t "aws-sdk-go-1.8" .
|
||||
sandbox-go18: sandbox-build-go18
|
||||
docker run -i -t aws-sdk-go-1.8 bash
|
||||
sandbox-test-go18: sandbox-build-go18
|
||||
docker run -t aws-sdk-go-1.8
|
||||
|
||||
sandbox-build-gotip:
|
||||
@echo "Run make update-aws-golang-tip, if this test fails because missing aws-golang:tip container"
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.gotip -t "aws-sdk-go-tip" .
|
||||
sandbox-gotip: sandbox-build-gotip
|
||||
docker run -i -t aws-sdk-go-tip bash
|
||||
sandbox-test-gotip: sandbox-build-gotip
|
||||
docker run -t aws-sdk-go-tip
|
||||
|
||||
update-aws-golang-tip:
|
||||
docker build --no-cache=true -f ./awstesting/sandbox/Dockerfile.golang-tip -t "aws-golang:tip" .
|
||||
|
||||
verify: get-deps-verify lint vet
|
||||
|
||||
lint:
|
||||
@echo "go lint SDK and vendor packages"
|
||||
@lint=`if [ \( -z "${SDK_GO_1_4}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then golint ./...; else echo "skipping golint"; fi`; \
|
||||
lint=`echo "$$lint" | grep -E -v -e ${LINTIGNOREDOT} -e ${LINTIGNOREDOC} -e ${LINTIGNORECONST} -e ${LINTIGNORESTUTTER} -e ${LINTIGNOREINFLECT} -e ${LINTIGNOREDEPS} -e ${LINTIGNOREINFLECTS3UPLOAD}`; \
|
||||
echo "$$lint"; \
|
||||
if [ "$$lint" != "" ] && [ "$$lint" != "skipping golint" ]; then exit 1; fi
|
||||
|
||||
SDK_BASE_FOLDERS=$(shell ls -d */ | grep -v vendor | grep -v awsmigrate)
|
||||
ifneq (,$(findstring go1.4, ${SDK_GO_VERSION}))
|
||||
GO_VET_CMD=echo skipping go vet, ${SDK_GO_VERSION}
|
||||
else ifneq (,$(findstring go1.6, ${SDK_GO_VERSION}))
|
||||
GO_VET_CMD=go tool vet --all -shadow -example=false
|
||||
else
|
||||
GO_VET_CMD=go tool vet --all -shadow
|
||||
endif
|
||||
|
||||
vet:
|
||||
${GO_VET_CMD} ${SDK_BASE_FOLDERS}
|
||||
|
||||
get-deps: get-deps-tests get-deps-verify
|
||||
@echo "go get SDK dependencies"
|
||||
@go get -v $(SDK_ONLY_PKGS)
|
||||
|
||||
get-deps-tests:
|
||||
@echo "go get SDK testing dependencies"
|
||||
go get github.com/gucumber/gucumber/cmd/gucumber
|
||||
go get github.com/stretchr/testify
|
||||
go get github.com/smartystreets/goconvey
|
||||
go get golang.org/x/net/html
|
||||
|
||||
get-deps-verify:
|
||||
@echo "go get SDK verification utilities"
|
||||
@if [ \( -z "${SDK_GO_1_4}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then go get github.com/golang/lint/golint; else echo "skipped getting golint"; fi
|
||||
|
||||
bench:
|
||||
@echo "go bench SDK packages"
|
||||
@go test -run NONE -bench . -benchmem -tags 'bench' $(SDK_ONLY_PKGS)
|
||||
|
||||
bench-protocol:
|
||||
@echo "go bench SDK protocol marshallers"
|
||||
@go test -run NONE -bench . -benchmem -tags 'bench' ./private/protocol/...
|
||||
|
||||
docs:
|
||||
@echo "generate SDK docs"
|
||||
@# This env variable, DOCS, is for internal use
|
||||
@if [ -z ${AWS_DOC_GEN_TOOL} ]; then\
|
||||
rm -rf doc && bundle install && bundle exec yard;\
|
||||
else\
|
||||
$(AWS_DOC_GEN_TOOL) `pwd`;\
|
||||
fi
|
||||
|
||||
api_info:
|
||||
@go run private/model/cli/api-info/api-info.go
|
|
@ -0,0 +1,136 @@
|
|||
# AWS SDK for Go
|
||||
|
||||
<span style="display: inline-block;">
|
||||
[![API Reference](http://img.shields.io/badge/api-reference-blue.svg)](http://docs.aws.amazon.com/sdk-for-go/api)
|
||||
[![Join the chat at https://gitter.im/aws/aws-sdk-go](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/aws/aws-sdk-go?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[![Build Status](https://img.shields.io/travis/aws/aws-sdk-go.svg)](https://travis-ci.org/aws/aws-sdk-go)
|
||||
[![Apache V2 License](http://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt)
|
||||
</span>
|
||||
|
||||
aws-sdk-go is the official AWS SDK for the Go programming language.
|
||||
|
||||
Checkout our [release notes](https://github.com/aws/aws-sdk-go/releases) for information about the latest bug fixes, updates, and features added to the SDK.
|
||||
|
||||
## Installing
|
||||
|
||||
If you are using Go 1.5 with the `GO15VENDOREXPERIMENT=1` vendoring flag, or 1.6 and higher you can use the following command to retrieve the SDK. The SDK's non-testing dependencies will be included and are vendored in the `vendor` folder.
|
||||
|
||||
go get -u github.com/aws/aws-sdk-go
|
||||
|
||||
Otherwise if your Go environment does not have vendoring support enabled, or you do not want to include the vendored SDK's dependencies you can use the following command to retrieve the SDK and its non-testing dependencies using `go get`.
|
||||
|
||||
go get -u github.com/aws/aws-sdk-go/aws/...
|
||||
go get -u github.com/aws/aws-sdk-go/service/...
|
||||
|
||||
If you're looking to retrieve just the SDK without any dependencies use the following command.
|
||||
|
||||
go get -d github.com/aws/aws-sdk-go/
|
||||
|
||||
These two processes will still include the `vendor` folder and it should be deleted if its not going to be used by your environment.
|
||||
|
||||
rm -rf $GOPATH/src/github.com/aws/aws-sdk-go/vendor
|
||||
|
||||
## Getting Help
|
||||
|
||||
Please use these community resources for getting help. We use the GitHub issues for tracking bugs and feature requests.
|
||||
* Ask a question on [StackOverflow](http://stackoverflow.com/) and tag it with the [`aws-sdk-go`](http://stackoverflow.com/questions/tagged/aws-sdk-go) tag.
|
||||
* Come join the AWS SDK for Go community chat on [gitter](https://gitter.im/aws/aws-sdk-go).
|
||||
* Open a support ticket with [AWS Support](http://docs.aws.amazon.com/awssupport/latest/user/getting-started.html).
|
||||
* If you think you may of found a bug, please open an [issue](https://github.com/aws/aws-sdk-go/issues/new).
|
||||
|
||||
## Opening Issues
|
||||
|
||||
If you encounter a bug with the AWS SDK for Go we would like to hear about it. Search the [existing issues]( https://github.com/aws/aws-sdk-go/issues) and see if others are also experiencing the issue before opening a new issue. Please include the version of AWS SDK for Go, Go language, and OS you’re using. Please also include repro case when appropriate.
|
||||
|
||||
The GitHub issues are intended for bug reports and feature requests. For help and questions with using AWS SDK for GO please make use of the resources listed in the [Getting Help]( https://github.com/aws/aws-sdk-go#getting-help) section. Keeping the list of open issues lean will help us respond in a timely manner.
|
||||
|
||||
## Reference Documentation
|
||||
|
||||
[`Getting Started Guide`](https://aws.amazon.com/sdk-for-go/) - This document is a general introduction how to configure and make requests with the SDK. If this is your first time using the SDK, this documentation and the API documentation will help you get started. This document focuses on the syntax and behavior of the SDK. The [Service Developer Guide](https://aws.amazon.com/documentation/) will help you get started using specific AWS services.
|
||||
|
||||
[`SDK API Reference Documentation`](https://docs.aws.amazon.com/sdk-for-go/api/) - Use this document to look up all API operation input and output parameters for AWS services supported by the SDK. The API reference also includes documentation of the SDK, and examples how to using the SDK, service client API operations, and API operation require parameters.
|
||||
|
||||
[`Service Developer Guide`](https://aws.amazon.com/documentation/) - Use this documentation to learn how to interface with an AWS service. These are great guides both, if you're getting started with a service, or looking for more information on a service. You should not need this document for coding, though in some cases, services may supply helpful samples that you might want to look out for.
|
||||
|
||||
[`SDK Examples`](https://github.com/aws/aws-sdk-go/tree/master/example) - Included in the SDK's repo are a several hand crafted examples using the SDK features and AWS services.
|
||||
|
||||
## Configuring Credentials
|
||||
|
||||
Before using the SDK, ensure that you've configured credentials. The best
|
||||
way to configure credentials on a development machine is to use the
|
||||
`~/.aws/credentials` file, which might look like:
|
||||
|
||||
```
|
||||
[default]
|
||||
aws_access_key_id = AKID1234567890
|
||||
aws_secret_access_key = MY-SECRET-KEY
|
||||
```
|
||||
|
||||
You can learn more about the credentials file from this
|
||||
[blog post](http://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs).
|
||||
|
||||
Alternatively, you can set the following environment variables:
|
||||
|
||||
```
|
||||
AWS_ACCESS_KEY_ID=AKID1234567890
|
||||
AWS_SECRET_ACCESS_KEY=MY-SECRET-KEY
|
||||
```
|
||||
|
||||
### AWS shared config file (`~/.aws/config`)
|
||||
The AWS SDK for Go added support the shared config file in release [v1.3.0](https://github.com/aws/aws-sdk-go/releases/tag/v1.3.0). You can opt into enabling support for the shared config by setting the environment variable `AWS_SDK_LOAD_CONFIG` to a truthy value. See the [Session](https://github.com/aws/aws-sdk-go/wiki/sessions) wiki for more information about this feature.
|
||||
|
||||
## Using the Go SDK
|
||||
|
||||
To use a service in the SDK, create a service variable by calling the `New()`
|
||||
function. Once you have a service client, you can call API operations which each
|
||||
return response data and a possible error.
|
||||
|
||||
To list a set of instance IDs from EC2, you could run:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sess, err := session.NewSession()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create an EC2 service object in the "us-west-2" region
|
||||
// Note that you can also configure your region globally by
|
||||
// exporting the AWS_REGION environment variable
|
||||
svc := ec2.New(sess, &aws.Config{Region: aws.String("us-west-2")})
|
||||
|
||||
// Call the DescribeInstances Operation
|
||||
resp, err := svc.DescribeInstances(nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// resp has all of the response data, pull out instance IDs:
|
||||
fmt.Println("> Number of reservation sets: ", len(resp.Reservations))
|
||||
for idx, res := range resp.Reservations {
|
||||
fmt.Println(" > Number of instances: ", len(res.Instances))
|
||||
for _, inst := range resp.Reservations[idx].Instances {
|
||||
fmt.Println(" - Instance ID: ", *inst.InstanceId)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can find more information and operations in our
|
||||
[API documentation](http://docs.aws.amazon.com/sdk-for-go/api/).
|
||||
|
||||
## License
|
||||
|
||||
This SDK is distributed under the
|
||||
[Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0),
|
||||
see LICENSE.txt and NOTICE.txt for more information.
|
|
@ -106,8 +106,8 @@ func rValuesAtPath(v interface{}, path string, createPath, caseSensitive, nilTer
|
|||
|
||||
if indexStar || index != nil {
|
||||
nextvals = []reflect.Value{}
|
||||
for _, value := range values {
|
||||
value := reflect.Indirect(value)
|
||||
for _, valItem := range values {
|
||||
value := reflect.Indirect(valItem)
|
||||
if value.Kind() != reflect.Slice {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -61,6 +61,12 @@ func prettify(v reflect.Value, indent int, buf *bytes.Buffer) {
|
|||
|
||||
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
|
||||
case reflect.Slice:
|
||||
strtype := v.Type().String()
|
||||
if strtype == "[]uint8" {
|
||||
fmt.Fprintf(buf, "<binary> len %d", v.Len())
|
||||
break
|
||||
}
|
||||
|
||||
nl, id, id2 := "", "", ""
|
||||
if v.Len() > 3 {
|
||||
nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2)
|
||||
|
|
|
@ -2,7 +2,6 @@ package client
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http/httputil"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
|
@ -14,7 +13,9 @@ import (
|
|||
type Config struct {
|
||||
Config *aws.Config
|
||||
Handlers request.Handlers
|
||||
Endpoint, SigningRegion string
|
||||
Endpoint string
|
||||
SigningRegion string
|
||||
SigningName string
|
||||
}
|
||||
|
||||
// ConfigProvider provides a generic way for a service client to receive
|
||||
|
@ -23,6 +24,13 @@ type ConfigProvider interface {
|
|||
ClientConfig(serviceName string, cfgs ...*aws.Config) Config
|
||||
}
|
||||
|
||||
// ConfigNoResolveEndpointProvider same as ConfigProvider except it will not
|
||||
// resolve the endpoint automatically. The service client's endpoint must be
|
||||
// provided via the aws.Config.Endpoint field.
|
||||
type ConfigNoResolveEndpointProvider interface {
|
||||
ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) Config
|
||||
}
|
||||
|
||||
// A Client implements the base client request and response handling
|
||||
// used by all service clients.
|
||||
type Client struct {
|
||||
|
@ -104,8 +112,7 @@ func logRequest(r *request.Request) {
|
|||
// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
|
||||
// Body as a NoOpCloser and will not be reset after read by the HTTP
|
||||
// client reader.
|
||||
r.Body.Seek(r.BodyStart, 0)
|
||||
r.HTTPRequest.Body = ioutil.NopCloser(r.Body)
|
||||
r.ResetBody()
|
||||
}
|
||||
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.ClientInfo.ServiceName, r.Operation.Name, string(dumpedBody)))
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||
)
|
||||
|
||||
// UseServiceDefaultRetries instructs the config to use the service's own
|
||||
|
@ -21,9 +22,9 @@ type RequestRetryer interface{}
|
|||
//
|
||||
// // Create Session with MaxRetry configuration to be shared by multiple
|
||||
// // service clients.
|
||||
// sess, err := session.NewSession(&aws.Config{
|
||||
// sess := session.Must(session.NewSession(&aws.Config{
|
||||
// MaxRetries: aws.Int(3),
|
||||
// })
|
||||
// }))
|
||||
//
|
||||
// // Create S3 service client with a specific Region.
|
||||
// svc := s3.New(sess, &aws.Config{
|
||||
|
@ -48,6 +49,10 @@ type Config struct {
|
|||
// endpoint for a client.
|
||||
Endpoint *string
|
||||
|
||||
// The resolver to use for looking up endpoints for AWS service clients
|
||||
// to use based on region.
|
||||
EndpointResolver endpoints.Resolver
|
||||
|
||||
// The region to send requests to. This parameter is required and must
|
||||
// be configured globally or on a per-client basis unless otherwise
|
||||
// noted. A full list of regions is found in the "Regions and Endpoints"
|
||||
|
@ -137,9 +142,6 @@ type Config struct {
|
|||
// accelerate enabled. If the bucket is not enabled for accelerate an error
|
||||
// will be returned. The bucket name must be DNS compatible to also work
|
||||
// with accelerate.
|
||||
//
|
||||
// Not compatible with UseDualStack requests will fail if both flags are
|
||||
// specified.
|
||||
S3UseAccelerate *bool
|
||||
|
||||
// Set this to `true` to disable the EC2Metadata client from overriding the
|
||||
|
@ -152,7 +154,8 @@ type Config struct {
|
|||
// the EC2Metadata overriding the timeout for default credentials chain.
|
||||
//
|
||||
// Example:
|
||||
// sess, err := session.NewSession(aws.NewConfig().WithEC2MetadataDiableTimeoutOverride(true))
|
||||
// sess := session.Must(session.NewSession(aws.NewConfig()
|
||||
// .WithEC2MetadataDiableTimeoutOverride(true)))
|
||||
//
|
||||
// svc := s3.New(sess)
|
||||
//
|
||||
|
@ -172,7 +175,7 @@ type Config struct {
|
|||
//
|
||||
// Only supported with.
|
||||
//
|
||||
// sess, err := session.NewSession()
|
||||
// sess := session.Must(session.NewSession())
|
||||
//
|
||||
// svc := s3.New(sess, &aws.Config{
|
||||
// UseDualStack: aws.Bool(true),
|
||||
|
@ -185,6 +188,21 @@ type Config struct {
|
|||
// the delay of a request see the aws/client.DefaultRetryer and
|
||||
// aws/request.Retryer.
|
||||
SleepDelay func(time.Duration)
|
||||
|
||||
// DisableRestProtocolURICleaning will not clean the URL path when making rest protocol requests.
|
||||
// Will default to false. This would only be used for empty directory names in s3 requests.
|
||||
//
|
||||
// Example:
|
||||
// sess := session.Must(session.NewSession(&aws.Config{
|
||||
// DisableRestProtocolURICleaning: aws.Bool(true),
|
||||
// }))
|
||||
//
|
||||
// svc := s3.New(sess)
|
||||
// out, err := svc.GetObject(&s3.GetObjectInput {
|
||||
// Bucket: aws.String("bucketname"),
|
||||
// Key: aws.String("//foo//bar//moo"),
|
||||
// })
|
||||
DisableRestProtocolURICleaning *bool
|
||||
}
|
||||
|
||||
// NewConfig returns a new Config pointer that can be chained with builder
|
||||
|
@ -192,9 +210,9 @@ type Config struct {
|
|||
//
|
||||
// // Create Session with MaxRetry configuration to be shared by multiple
|
||||
// // service clients.
|
||||
// sess, err := session.NewSession(aws.NewConfig().
|
||||
// sess := session.Must(session.NewSession(aws.NewConfig().
|
||||
// WithMaxRetries(3),
|
||||
// )
|
||||
// ))
|
||||
//
|
||||
// // Create S3 service client with a specific Region.
|
||||
// svc := s3.New(sess, aws.NewConfig().
|
||||
|
@ -225,6 +243,13 @@ func (c *Config) WithEndpoint(endpoint string) *Config {
|
|||
return c
|
||||
}
|
||||
|
||||
// WithEndpointResolver sets a config EndpointResolver value returning a
|
||||
// Config pointer for chaining.
|
||||
func (c *Config) WithEndpointResolver(resolver endpoints.Resolver) *Config {
|
||||
c.EndpointResolver = resolver
|
||||
return c
|
||||
}
|
||||
|
||||
// WithRegion sets a config Region value returning a Config pointer for
|
||||
// chaining.
|
||||
func (c *Config) WithRegion(region string) *Config {
|
||||
|
@ -347,6 +372,10 @@ func mergeInConfig(dst *Config, other *Config) {
|
|||
dst.Endpoint = other.Endpoint
|
||||
}
|
||||
|
||||
if other.EndpointResolver != nil {
|
||||
dst.EndpointResolver = other.EndpointResolver
|
||||
}
|
||||
|
||||
if other.Region != nil {
|
||||
dst.Region = other.Region
|
||||
}
|
||||
|
@ -406,6 +435,10 @@ func mergeInConfig(dst *Config, other *Config) {
|
|||
if other.SleepDelay != nil {
|
||||
dst.SleepDelay = other.SleepDelay
|
||||
}
|
||||
|
||||
if other.DisableRestProtocolURICleaning != nil {
|
||||
dst.DisableRestProtocolURICleaning = other.DisableRestProtocolURICleaning
|
||||
}
|
||||
}
|
||||
|
||||
// Copy will return a shallow copy of the Config object. If any additional
|
||||
|
|
|
@ -10,9 +10,11 @@ import (
|
|||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
|
@ -67,6 +69,34 @@ var SDKVersionUserAgentHandler = request.NamedHandler{
|
|||
|
||||
var reStatusCode = regexp.MustCompile(`^(\d{3})`)
|
||||
|
||||
// ValidateReqSigHandler is a request handler to ensure that the request's
|
||||
// signature doesn't expire before it is sent. This can happen when a request
|
||||
// is built and signed signficantly before it is sent. Or significant delays
|
||||
// occur whne retrying requests that would cause the signature to expire.
|
||||
var ValidateReqSigHandler = request.NamedHandler{
|
||||
Name: "core.ValidateReqSigHandler",
|
||||
Fn: func(r *request.Request) {
|
||||
// Unsigned requests are not signed
|
||||
if r.Config.Credentials == credentials.AnonymousCredentials {
|
||||
return
|
||||
}
|
||||
|
||||
signedTime := r.Time
|
||||
if !r.LastSignedAt.IsZero() {
|
||||
signedTime = r.LastSignedAt
|
||||
}
|
||||
|
||||
// 10 minutes to allow for some clock skew/delays in transmission.
|
||||
// Would be improved with aws/aws-sdk-go#423
|
||||
if signedTime.Add(10 * time.Minute).After(time.Now()) {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("request expired, resigning")
|
||||
r.Sign()
|
||||
},
|
||||
}
|
||||
|
||||
// SendHandler is a request handler to send service request using HTTP client.
|
||||
var SendHandler = request.NamedHandler{Name: "core.SendHandler", Fn: func(r *request.Request) {
|
||||
var err error
|
||||
|
|
|
@ -34,7 +34,7 @@ var (
|
|||
//
|
||||
// Example of ChainProvider to be used with an EnvProvider and EC2RoleProvider.
|
||||
// In this example EnvProvider will first check if any credentials are available
|
||||
// vai the environment variables. If there are none ChainProvider will check
|
||||
// via the environment variables. If there are none ChainProvider will check
|
||||
// the next Provider in the list, EC2RoleProvider in this case. If EC2RoleProvider
|
||||
// does not return any credentials ChainProvider will return the error
|
||||
// ErrNoValidProvidersFoundInChain
|
||||
|
|
2
vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go
generated
vendored
2
vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go
generated
vendored
|
@ -111,7 +111,7 @@ func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// A ec2RoleCredRespBody provides the shape for unmarshalling credential
|
||||
// A ec2RoleCredRespBody provides the shape for unmarshaling credential
|
||||
// request responses.
|
||||
type ec2RoleCredRespBody struct {
|
||||
// Success State
|
||||
|
|
155
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go
generated
vendored
155
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go
generated
vendored
|
@ -1,7 +1,81 @@
|
|||
// Package stscreds are credential Providers to retrieve STS AWS credentials.
|
||||
//
|
||||
// STS provides multiple ways to retrieve credentials which can be used when making
|
||||
// future AWS service API operation calls.
|
||||
/*
|
||||
Package stscreds are credential Providers to retrieve STS AWS credentials.
|
||||
|
||||
STS provides multiple ways to retrieve credentials which can be used when making
|
||||
future AWS service API operation calls.
|
||||
|
||||
The SDK will ensure that per instance of credentials.Credentials all requests
|
||||
to refresh the credentials will be synchronized. But, the SDK is unable to
|
||||
ensure synchronous usage of the AssumeRoleProvider if the value is shared
|
||||
between multiple Credentials, Sessions or service clients.
|
||||
|
||||
Assume Role
|
||||
|
||||
To assume an IAM role using STS with the SDK you can create a new Credentials
|
||||
with the SDKs's stscreds package.
|
||||
|
||||
// Initial credentials loaded from SDK's default credential chain. Such as
|
||||
// the environment, shared credentials (~/.aws/credentials), or EC2 Instance
|
||||
// Role. These credentials will be used to to make the STS Assume Role API.
|
||||
sess := session.Must(session.NewSession())
|
||||
|
||||
// Create the credentials from AssumeRoleProvider to assume the role
|
||||
// referenced by the "myRoleARN" ARN.
|
||||
creds := stscreds.NewCredentials(sess, "myRoleArn")
|
||||
|
||||
// Create service client value configured for credentials
|
||||
// from assumed role.
|
||||
svc := s3.New(sess, &aws.Config{Credentials: creds})
|
||||
|
||||
Assume Role with static MFA Token
|
||||
|
||||
To assume an IAM role with a MFA token you can either specify a MFA token code
|
||||
directly or provide a function to prompt the user each time the credentials
|
||||
need to refresh the role's credentials. Specifying the TokenCode should be used
|
||||
for short lived operations that will not need to be refreshed, and when you do
|
||||
not want to have direct control over the user provides their MFA token.
|
||||
|
||||
With TokenCode the AssumeRoleProvider will be not be able to refresh the role's
|
||||
credentials.
|
||||
|
||||
// Create the credentials from AssumeRoleProvider to assume the role
|
||||
// referenced by the "myRoleARN" ARN using the MFA token code provided.
|
||||
creds := stscreds.NewCredentials(sess, "myRoleArn", func(p *stscreds.AssumeRoleProvider) {
|
||||
p.SerialNumber = aws.String("myTokenSerialNumber")
|
||||
p.TokenCode = aws.String("00000000")
|
||||
})
|
||||
|
||||
// Create service client value configured for credentials
|
||||
// from assumed role.
|
||||
svc := s3.New(sess, &aws.Config{Credentials: creds})
|
||||
|
||||
Assume Role with MFA Token Provider
|
||||
|
||||
To assume an IAM role with MFA for longer running tasks where the credentials
|
||||
may need to be refreshed setting the TokenProvider field of AssumeRoleProvider
|
||||
will allow the credential provider to prompt for new MFA token code when the
|
||||
role's credentials need to be refreshed.
|
||||
|
||||
The StdinTokenProvider function is available to prompt on stdin to retrieve
|
||||
the MFA token code from the user. You can also implement custom prompts by
|
||||
satisfing the TokenProvider function signature.
|
||||
|
||||
Using StdinTokenProvider with multiple AssumeRoleProviders, or Credentials will
|
||||
have undesirable results as the StdinTokenProvider will not be synchronized. A
|
||||
single Credentials with an AssumeRoleProvider can be shared safely.
|
||||
|
||||
// Create the credentials from AssumeRoleProvider to assume the role
|
||||
// referenced by the "myRoleARN" ARN. Prompting for MFA token from stdin.
|
||||
creds := stscreds.NewCredentials(sess, "myRoleArn", func(p *stscreds.AssumeRoleProvider) {
|
||||
p.SerialNumber = aws.String("myTokenSerialNumber")
|
||||
p.TokenProvider = stscreds.StdinTokenProvider
|
||||
})
|
||||
|
||||
// Create service client value configured for credentials
|
||||
// from assumed role.
|
||||
svc := s3.New(sess, &aws.Config{Credentials: creds})
|
||||
|
||||
*/
|
||||
package stscreds
|
||||
|
||||
import (
|
||||
|
@ -9,11 +83,31 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
)
|
||||
|
||||
// StdinTokenProvider will prompt on stdout and read from stdin for a string value.
|
||||
// An error is returned if reading from stdin fails.
|
||||
//
|
||||
// Use this function go read MFA tokens from stdin. The function makes no attempt
|
||||
// to make atomic prompts from stdin across multiple gorouties.
|
||||
//
|
||||
// Using StdinTokenProvider with multiple AssumeRoleProviders, or Credentials will
|
||||
// have undesirable results as the StdinTokenProvider will not be synchronized. A
|
||||
// single Credentials with an AssumeRoleProvider can be shared safely
|
||||
//
|
||||
// Will wait forever until something is provided on the stdin.
|
||||
func StdinTokenProvider() (string, error) {
|
||||
var v string
|
||||
fmt.Printf("Assume Role MFA token code: ")
|
||||
_, err := fmt.Scanln(&v)
|
||||
|
||||
return v, err
|
||||
}
|
||||
|
||||
// ProviderName provides a name of AssumeRole provider
|
||||
const ProviderName = "AssumeRoleProvider"
|
||||
|
||||
|
@ -27,8 +121,15 @@ type AssumeRoler interface {
|
|||
var DefaultDuration = time.Duration(15) * time.Minute
|
||||
|
||||
// AssumeRoleProvider retrieves temporary credentials from the STS service, and
|
||||
// keeps track of their expiration time. This provider must be used explicitly,
|
||||
// as it is not included in the credentials chain.
|
||||
// keeps track of their expiration time.
|
||||
//
|
||||
// This credential provider will be used by the SDKs default credential change
|
||||
// when shared configuration is enabled, and the shared config or shared credentials
|
||||
// file configure assume role. See Session docs for how to do this.
|
||||
//
|
||||
// AssumeRoleProvider does not provide any synchronization and it is not safe
|
||||
// to share this value across multiple Credentials, Sessions, or service clients
|
||||
// without also sharing the same Credentials instance.
|
||||
type AssumeRoleProvider struct {
|
||||
credentials.Expiry
|
||||
|
||||
|
@ -65,8 +166,23 @@ type AssumeRoleProvider struct {
|
|||
// assumed requires MFA (that is, if the policy includes a condition that tests
|
||||
// for MFA). If the role being assumed requires MFA and if the TokenCode value
|
||||
// is missing or expired, the AssumeRole call returns an "access denied" error.
|
||||
//
|
||||
// If SerialNumber is set and neither TokenCode nor TokenProvider are also
|
||||
// set an error will be returned.
|
||||
TokenCode *string
|
||||
|
||||
// Async method of providing MFA token code for assuming an IAM role with MFA.
|
||||
// The value returned by the function will be used as the TokenCode in the Retrieve
|
||||
// call. See StdinTokenProvider for a provider that prompts and reads from stdin.
|
||||
//
|
||||
// This token provider will be called when ever the assumed role's
|
||||
// credentials need to be refreshed when SerialNumber is also set and
|
||||
// TokenCode is not set.
|
||||
//
|
||||
// If both TokenCode and TokenProvider is set, TokenProvider will be used and
|
||||
// TokenCode is ignored.
|
||||
TokenProvider func() (string, error)
|
||||
|
||||
// ExpiryWindow will allow the credentials to trigger refreshing prior to
|
||||
// the credentials actually expiring. This is beneficial so race conditions
|
||||
// with expiring credentials do not cause request to fail unexpectedly
|
||||
|
@ -85,6 +201,10 @@ type AssumeRoleProvider struct {
|
|||
//
|
||||
// Takes a Config provider to create the STS client. The ConfigProvider is
|
||||
// satisfied by the session.Session type.
|
||||
//
|
||||
// It is safe to share the returned Credentials with multiple Sessions and
|
||||
// service clients. All access to the credentials and refreshing them
|
||||
// will be synchronized.
|
||||
func NewCredentials(c client.ConfigProvider, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials {
|
||||
p := &AssumeRoleProvider{
|
||||
Client: sts.New(c),
|
||||
|
@ -103,7 +223,11 @@ func NewCredentials(c client.ConfigProvider, roleARN string, options ...func(*As
|
|||
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
|
||||
// role will be named after a nanosecond timestamp of this operation.
|
||||
//
|
||||
// Takes an AssumeRoler which can be satisfiede by the STS client.
|
||||
// Takes an AssumeRoler which can be satisfied by the STS client.
|
||||
//
|
||||
// It is safe to share the returned Credentials with multiple Sessions and
|
||||
// service clients. All access to the credentials and refreshing them
|
||||
// will be synchronized.
|
||||
func NewCredentialsWithClient(svc AssumeRoler, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials {
|
||||
p := &AssumeRoleProvider{
|
||||
Client: svc,
|
||||
|
@ -139,12 +263,25 @@ func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) {
|
|||
if p.Policy != nil {
|
||||
input.Policy = p.Policy
|
||||
}
|
||||
if p.SerialNumber != nil && p.TokenCode != nil {
|
||||
if p.SerialNumber != nil {
|
||||
if p.TokenCode != nil {
|
||||
input.SerialNumber = p.SerialNumber
|
||||
input.TokenCode = p.TokenCode
|
||||
} else if p.TokenProvider != nil {
|
||||
input.SerialNumber = p.SerialNumber
|
||||
code, err := p.TokenProvider()
|
||||
if err != nil {
|
||||
return credentials.Value{ProviderName: ProviderName}, err
|
||||
}
|
||||
input.TokenCode = aws.String(code)
|
||||
} else {
|
||||
return credentials.Value{ProviderName: ProviderName},
|
||||
awserr.New("AssumeRoleTokenNotAvailable",
|
||||
"assume role with MFA enabled, but neither TokenCode nor TokenProvider are set", nil)
|
||||
}
|
||||
}
|
||||
roleOutput, err := p.Client.AssumeRole(input)
|
||||
|
||||
roleOutput, err := p.Client.AssumeRole(input)
|
||||
if err != nil {
|
||||
return credentials.Value{ProviderName: ProviderName}, err
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/endpointcreds"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/endpoints"
|
||||
)
|
||||
|
||||
// A Defaults provides a collection of default values for SDK clients.
|
||||
|
@ -56,7 +56,8 @@ func Config() *aws.Config {
|
|||
WithMaxRetries(aws.UseServiceDefaultRetries).
|
||||
WithLogger(aws.NewDefaultLogger()).
|
||||
WithLogLevel(aws.LogOff).
|
||||
WithSleepDelay(time.Sleep)
|
||||
WithSleepDelay(time.Sleep).
|
||||
WithEndpointResolver(endpoints.DefaultResolver())
|
||||
}
|
||||
|
||||
// Handlers returns the default request handlers.
|
||||
|
@ -72,6 +73,7 @@ func Handlers() request.Handlers {
|
|||
handlers.Build.PushBackNamed(corehandlers.SDKVersionUserAgentHandler)
|
||||
handlers.Build.AfterEachFn = request.HandlerListStopOnError
|
||||
handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
|
||||
handlers.Send.PushBackNamed(corehandlers.ValidateReqSigHandler)
|
||||
handlers.Send.PushBackNamed(corehandlers.SendHandler)
|
||||
handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
|
||||
handlers.ValidateResponse.PushBackNamed(corehandlers.ValidateResponseHandler)
|
||||
|
@ -119,11 +121,14 @@ func ecsCredProvider(cfg aws.Config, handlers request.Handlers, uri string) cred
|
|||
}
|
||||
|
||||
func ec2RoleProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider {
|
||||
endpoint, signingRegion := endpoints.EndpointForRegion(ec2metadata.ServiceName,
|
||||
aws.StringValue(cfg.Region), true, false)
|
||||
resolver := cfg.EndpointResolver
|
||||
if resolver == nil {
|
||||
resolver = endpoints.DefaultResolver()
|
||||
}
|
||||
|
||||
e, _ := resolver.EndpointFor(endpoints.Ec2metadataServiceID, "")
|
||||
return &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.NewClient(cfg, handlers, endpoint, signingRegion),
|
||||
Client: ec2metadata.NewClient(cfg, handlers, e.URL, e.SigningRegion),
|
||||
ExpiryWindow: 5 * time.Minute,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package ec2metadata
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -27,6 +28,27 @@ func (c *EC2Metadata) GetMetadata(p string) (string, error) {
|
|||
return output.Content, req.Send()
|
||||
}
|
||||
|
||||
// GetUserData returns the userdata that was configured for the service. If
|
||||
// there is no user-data setup for the EC2 instance a "NotFoundError" error
|
||||
// code will be returned.
|
||||
func (c *EC2Metadata) GetUserData() (string, error) {
|
||||
op := &request.Operation{
|
||||
Name: "GetUserData",
|
||||
HTTPMethod: "GET",
|
||||
HTTPPath: path.Join("/", "user-data"),
|
||||
}
|
||||
|
||||
output := &metadataOutput{}
|
||||
req := c.NewRequest(op, nil, output)
|
||||
req.Handlers.UnmarshalError.PushBack(func(r *request.Request) {
|
||||
if r.HTTPResponse.StatusCode == http.StatusNotFound {
|
||||
r.Error = awserr.New("NotFoundError", "user-data not found", r.Error)
|
||||
}
|
||||
})
|
||||
|
||||
return output.Content, req.Send()
|
||||
}
|
||||
|
||||
// GetDynamicData uses the path provided to request information from the EC2
|
||||
// instance metadata service for dynamic data. The content will be returned
|
||||
// as a string, or error if the request failed.
|
||||
|
@ -111,7 +133,7 @@ func (c *EC2Metadata) Available() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// An EC2IAMInfo provides the shape for unmarshalling
|
||||
// An EC2IAMInfo provides the shape for unmarshaling
|
||||
// an IAM info from the metadata API
|
||||
type EC2IAMInfo struct {
|
||||
Code string
|
||||
|
@ -120,7 +142,7 @@ type EC2IAMInfo struct {
|
|||
InstanceProfileID string
|
||||
}
|
||||
|
||||
// An EC2InstanceIdentityDocument provides the shape for unmarshalling
|
||||
// An EC2InstanceIdentityDocument provides the shape for unmarshaling
|
||||
// an instance identity document
|
||||
type EC2InstanceIdentityDocument struct {
|
||||
DevpayProductCodes []string `json:"devpayProductCodes"`
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
package endpoints
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
)
|
||||
|
||||
type modelDefinition map[string]json.RawMessage
|
||||
|
||||
// A DecodeModelOptions are the options for how the endpoints model definition
|
||||
// are decoded.
|
||||
type DecodeModelOptions struct {
|
||||
SkipCustomizations bool
|
||||
}
|
||||
|
||||
// Set combines all of the option functions together.
|
||||
func (d *DecodeModelOptions) Set(optFns ...func(*DecodeModelOptions)) {
|
||||
for _, fn := range optFns {
|
||||
fn(d)
|
||||
}
|
||||
}
|
||||
|
||||
// DecodeModel unmarshals a Regions and Endpoint model definition file into
|
||||
// a endpoint Resolver. If the file format is not supported, or an error occurs
|
||||
// when unmarshaling the model an error will be returned.
|
||||
//
|
||||
// Casting the return value of this func to a EnumPartitions will
|
||||
// allow you to get a list of the partitions in the order the endpoints
|
||||
// will be resolved in.
|
||||
//
|
||||
// resolver, err := endpoints.DecodeModel(reader)
|
||||
//
|
||||
// partitions := resolver.(endpoints.EnumPartitions).Partitions()
|
||||
// for _, p := range partitions {
|
||||
// // ... inspect partitions
|
||||
// }
|
||||
func DecodeModel(r io.Reader, optFns ...func(*DecodeModelOptions)) (Resolver, error) {
|
||||
var opts DecodeModelOptions
|
||||
opts.Set(optFns...)
|
||||
|
||||
// Get the version of the partition file to determine what
|
||||
// unmarshaling model to use.
|
||||
modelDef := modelDefinition{}
|
||||
if err := json.NewDecoder(r).Decode(&modelDef); err != nil {
|
||||
return nil, newDecodeModelError("failed to decode endpoints model", err)
|
||||
}
|
||||
|
||||
var version string
|
||||
if b, ok := modelDef["version"]; ok {
|
||||
version = string(b)
|
||||
} else {
|
||||
return nil, newDecodeModelError("endpoints version not found in model", nil)
|
||||
}
|
||||
|
||||
if version == "3" {
|
||||
return decodeV3Endpoints(modelDef, opts)
|
||||
}
|
||||
|
||||
return nil, newDecodeModelError(
|
||||
fmt.Sprintf("endpoints version %s, not supported", version), nil)
|
||||
}
|
||||
|
||||
func decodeV3Endpoints(modelDef modelDefinition, opts DecodeModelOptions) (Resolver, error) {
|
||||
b, ok := modelDef["partitions"]
|
||||
if !ok {
|
||||
return nil, newDecodeModelError("endpoints model missing partitions", nil)
|
||||
}
|
||||
|
||||
ps := partitions{}
|
||||
if err := json.Unmarshal(b, &ps); err != nil {
|
||||
return nil, newDecodeModelError("failed to decode endpoints model", err)
|
||||
}
|
||||
|
||||
if opts.SkipCustomizations {
|
||||
return ps, nil
|
||||
}
|
||||
|
||||
// Customization
|
||||
for i := 0; i < len(ps); i++ {
|
||||
p := &ps[i]
|
||||
custAddEC2Metadata(p)
|
||||
custAddS3DualStack(p)
|
||||
custRmIotDataService(p)
|
||||
}
|
||||
|
||||
return ps, nil
|
||||
}
|
||||
|
||||
func custAddS3DualStack(p *partition) {
|
||||
if p.ID != "aws" {
|
||||
return
|
||||
}
|
||||
|
||||
s, ok := p.Services["s3"]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
s.Defaults.HasDualStack = boxedTrue
|
||||
s.Defaults.DualStackHostname = "{service}.dualstack.{region}.{dnsSuffix}"
|
||||
|
||||
p.Services["s3"] = s
|
||||
}
|
||||
|
||||
func custAddEC2Metadata(p *partition) {
|
||||
p.Services["ec2metadata"] = service{
|
||||
IsRegionalized: boxedFalse,
|
||||
PartitionEndpoint: "aws-global",
|
||||
Endpoints: endpoints{
|
||||
"aws-global": endpoint{
|
||||
Hostname: "169.254.169.254/latest",
|
||||
Protocols: []string{"http"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func custRmIotDataService(p *partition) {
|
||||
delete(p.Services, "data.iot")
|
||||
}
|
||||
|
||||
type decodeModelError struct {
|
||||
awsError
|
||||
}
|
||||
|
||||
func newDecodeModelError(msg string, err error) decodeModelError {
|
||||
return decodeModelError{
|
||||
awsError: awserr.New("DecodeEndpointsModelError", msg, err),
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,66 @@
|
|||
// Package endpoints provides the types and functionality for defining regions
|
||||
// and endpoints, as well as querying those definitions.
|
||||
//
|
||||
// The SDK's Regions and Endpoints metadata is code generated into the endpoints
|
||||
// package, and is accessible via the DefaultResolver function. This function
|
||||
// returns a endpoint Resolver will search the metadata and build an associated
|
||||
// endpoint if one is found. The default resolver will search all partitions
|
||||
// known by the SDK. e.g AWS Standard (aws), AWS China (aws-cn), and
|
||||
// AWS GovCloud (US) (aws-us-gov).
|
||||
// .
|
||||
//
|
||||
// Enumerating Regions and Endpoint Metadata
|
||||
//
|
||||
// Casting the Resolver returned by DefaultResolver to a EnumPartitions interface
|
||||
// will allow you to get access to the list of underlying Partitions with the
|
||||
// Partitions method. This is helpful if you want to limit the SDK's endpoint
|
||||
// resolving to a single partition, or enumerate regions, services, and endpoints
|
||||
// in the partition.
|
||||
//
|
||||
// resolver := endpoints.DefaultResolver()
|
||||
// partitions := resolver.(endpoints.EnumPartitions).Partitions()
|
||||
//
|
||||
// for _, p := range partitions {
|
||||
// fmt.Println("Regions for", p.Name)
|
||||
// for id, _ := range p.Regions() {
|
||||
// fmt.Println("*", id)
|
||||
// }
|
||||
//
|
||||
// fmt.Println("Services for", p.Name)
|
||||
// for id, _ := range p.Services() {
|
||||
// fmt.Println("*", id)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Using Custom Endpoints
|
||||
//
|
||||
// The endpoints package also gives you the ability to use your own logic how
|
||||
// endpoints are resolved. This is a great way to define a custom endpoint
|
||||
// for select services, without passing that logic down through your code.
|
||||
//
|
||||
// If a type implements the Resolver interface it can be used to resolve
|
||||
// endpoints. To use this with the SDK's Session and Config set the value
|
||||
// of the type to the EndpointsResolver field of aws.Config when initializing
|
||||
// the session, or service client.
|
||||
//
|
||||
// In addition the ResolverFunc is a wrapper for a func matching the signature
|
||||
// of Resolver.EndpointFor, converting it to a type that satisfies the
|
||||
// Resolver interface.
|
||||
//
|
||||
//
|
||||
// myCustomResolver := func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
|
||||
// if service == endpoints.S3ServiceID {
|
||||
// return endpoints.ResolvedEndpoint{
|
||||
// URL: "s3.custom.endpoint.com",
|
||||
// SigningRegion: "custom-signing-region",
|
||||
// }, nil
|
||||
// }
|
||||
//
|
||||
// return endpoints.DefaultResolver().EndpointFor(service, region, optFns...)
|
||||
// }
|
||||
//
|
||||
// sess := session.Must(session.NewSession(&aws.Config{
|
||||
// Region: aws.String("us-west-2"),
|
||||
// EndpointResolver: endpoints.ResolverFunc(myCustomResolver),
|
||||
// }))
|
||||
package endpoints
|
|
@ -0,0 +1,397 @@
|
|||
package endpoints
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
)
|
||||
|
||||
// Options provide the configuration needed to direct how the
|
||||
// endpoints will be resolved.
|
||||
type Options struct {
|
||||
// DisableSSL forces the endpoint to be resolved as HTTP.
|
||||
// instead of HTTPS if the service supports it.
|
||||
DisableSSL bool
|
||||
|
||||
// Sets the resolver to resolve the endpoint as a dualstack endpoint
|
||||
// for the service. If dualstack support for a service is not known and
|
||||
// StrictMatching is not enabled a dualstack endpoint for the service will
|
||||
// be returned. This endpoint may not be valid. If StrictMatching is
|
||||
// enabled only services that are known to support dualstack will return
|
||||
// dualstack endpoints.
|
||||
UseDualStack bool
|
||||
|
||||
// Enables strict matching of services and regions resolved endpoints.
|
||||
// If the partition doesn't enumerate the exact service and region an
|
||||
// error will be returned. This option will prevent returning endpoints
|
||||
// that look valid, but may not resolve to any real endpoint.
|
||||
StrictMatching bool
|
||||
|
||||
// Enables resolving a service endpoint based on the region provided if the
|
||||
// service does not exist. The service endpoint ID will be used as the service
|
||||
// domain name prefix. By default the endpoint resolver requires the service
|
||||
// to be known when resolving endpoints.
|
||||
//
|
||||
// If resolving an endpoint on the partition list the provided region will
|
||||
// be used to determine which partition's domain name pattern to the service
|
||||
// endpoint ID with. If both the service and region are unkonwn and resolving
|
||||
// the endpoint on partition list an UnknownEndpointError error will be returned.
|
||||
//
|
||||
// If resolving and endpoint on a partition specific resolver that partition's
|
||||
// domain name pattern will be used with the service endpoint ID. If both
|
||||
// region and service do not exist when resolving an endpoint on a specific
|
||||
// partition the partition's domain pattern will be used to combine the
|
||||
// endpoint and region together.
|
||||
//
|
||||
// This option is ignored if StrictMatching is enabled.
|
||||
ResolveUnknownService bool
|
||||
}
|
||||
|
||||
// Set combines all of the option functions together.
|
||||
func (o *Options) Set(optFns ...func(*Options)) {
|
||||
for _, fn := range optFns {
|
||||
fn(o)
|
||||
}
|
||||
}
|
||||
|
||||
// DisableSSLOption sets the DisableSSL options. Can be used as a functional
|
||||
// option when resolving endpoints.
|
||||
func DisableSSLOption(o *Options) {
|
||||
o.DisableSSL = true
|
||||
}
|
||||
|
||||
// UseDualStackOption sets the UseDualStack option. Can be used as a functional
|
||||
// option when resolving endpoints.
|
||||
func UseDualStackOption(o *Options) {
|
||||
o.UseDualStack = true
|
||||
}
|
||||
|
||||
// StrictMatchingOption sets the StrictMatching option. Can be used as a functional
|
||||
// option when resolving endpoints.
|
||||
func StrictMatchingOption(o *Options) {
|
||||
o.StrictMatching = true
|
||||
}
|
||||
|
||||
// ResolveUnknownServiceOption sets the ResolveUnknownService option. Can be used
|
||||
// as a functional option when resolving endpoints.
|
||||
func ResolveUnknownServiceOption(o *Options) {
|
||||
o.ResolveUnknownService = true
|
||||
}
|
||||
|
||||
// A Resolver provides the interface for functionality to resolve endpoints.
|
||||
// The build in Partition and DefaultResolver return value satisfy this interface.
|
||||
type Resolver interface {
|
||||
EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error)
|
||||
}
|
||||
|
||||
// ResolverFunc is a helper utility that wraps a function so it satisfies the
|
||||
// Resolver interface. This is useful when you want to add additional endpoint
|
||||
// resolving logic, or stub out specific endpoints with custom values.
|
||||
type ResolverFunc func(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error)
|
||||
|
||||
// EndpointFor wraps the ResolverFunc function to satisfy the Resolver interface.
|
||||
func (fn ResolverFunc) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||
return fn(service, region, opts...)
|
||||
}
|
||||
|
||||
var schemeRE = regexp.MustCompile("^([^:]+)://")
|
||||
|
||||
// AddScheme adds the HTTP or HTTPS schemes to a endpoint URL if there is no
|
||||
// scheme. If disableSSL is true HTTP will set HTTP instead of the default HTTPS.
|
||||
//
|
||||
// If disableSSL is set, it will only set the URL's scheme if the URL does not
|
||||
// contain a scheme.
|
||||
func AddScheme(endpoint string, disableSSL bool) string {
|
||||
if !schemeRE.MatchString(endpoint) {
|
||||
scheme := "https"
|
||||
if disableSSL {
|
||||
scheme = "http"
|
||||
}
|
||||
endpoint = fmt.Sprintf("%s://%s", scheme, endpoint)
|
||||
}
|
||||
|
||||
return endpoint
|
||||
}
|
||||
|
||||
// EnumPartitions a provides a way to retrieve the underlying partitions that
|
||||
// make up the SDK's default Resolver, or any resolver decoded from a model
|
||||
// file.
|
||||
//
|
||||
// Use this interface with DefaultResolver and DecodeModels to get the list of
|
||||
// Partitions.
|
||||
type EnumPartitions interface {
|
||||
Partitions() []Partition
|
||||
}
|
||||
|
||||
// A Partition provides the ability to enumerate the partition's regions
|
||||
// and services.
|
||||
type Partition struct {
|
||||
id string
|
||||
p *partition
|
||||
}
|
||||
|
||||
// ID returns the identifier of the partition.
|
||||
func (p *Partition) ID() string { return p.id }
|
||||
|
||||
// EndpointFor attempts to resolve the endpoint based on service and region.
|
||||
// See Options for information on configuring how the endpoint is resolved.
|
||||
//
|
||||
// If the service cannot be found in the metadata the UnknownServiceError
|
||||
// error will be returned. This validation will occur regardless if
|
||||
// StrictMatching is enabled. To enable resolving unknown services set the
|
||||
// "ResolveUnknownService" option to true. When StrictMatching is disabled
|
||||
// this option allows the partition resolver to resolve a endpoint based on
|
||||
// the service endpoint ID provided.
|
||||
//
|
||||
// When resolving endpoints you can choose to enable StrictMatching. This will
|
||||
// require the provided service and region to be known by the partition.
|
||||
// If the endpoint cannot be strictly resolved an error will be returned. This
|
||||
// mode is useful to ensure the endpoint resolved is valid. Without
|
||||
// StrictMatching enabled the endpoint returned my look valid but may not work.
|
||||
// StrictMatching requires the SDK to be updated if you want to take advantage
|
||||
// of new regions and services expansions.
|
||||
//
|
||||
// Errors that can be returned.
|
||||
// * UnknownServiceError
|
||||
// * UnknownEndpointError
|
||||
func (p *Partition) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||
return p.p.EndpointFor(service, region, opts...)
|
||||
}
|
||||
|
||||
// Regions returns a map of Regions indexed by their ID. This is useful for
|
||||
// enumerating over the regions in a partition.
|
||||
func (p *Partition) Regions() map[string]Region {
|
||||
rs := map[string]Region{}
|
||||
for id := range p.p.Regions {
|
||||
rs[id] = Region{
|
||||
id: id,
|
||||
p: p.p,
|
||||
}
|
||||
}
|
||||
|
||||
return rs
|
||||
}
|
||||
|
||||
// Services returns a map of Service indexed by their ID. This is useful for
|
||||
// enumerating over the services in a partition.
|
||||
func (p *Partition) Services() map[string]Service {
|
||||
ss := map[string]Service{}
|
||||
for id := range p.p.Services {
|
||||
ss[id] = Service{
|
||||
id: id,
|
||||
p: p.p,
|
||||
}
|
||||
}
|
||||
|
||||
return ss
|
||||
}
|
||||
|
||||
// A Region provides information about a region, and ability to resolve an
|
||||
// endpoint from the context of a region, given a service.
|
||||
type Region struct {
|
||||
id, desc string
|
||||
p *partition
|
||||
}
|
||||
|
||||
// ID returns the region's identifier.
|
||||
func (r *Region) ID() string { return r.id }
|
||||
|
||||
// ResolveEndpoint resolves an endpoint from the context of the region given
|
||||
// a service. See Partition.EndpointFor for usage and errors that can be returned.
|
||||
func (r *Region) ResolveEndpoint(service string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||
return r.p.EndpointFor(service, r.id, opts...)
|
||||
}
|
||||
|
||||
// Services returns a list of all services that are known to be in this region.
|
||||
func (r *Region) Services() map[string]Service {
|
||||
ss := map[string]Service{}
|
||||
for id, s := range r.p.Services {
|
||||
if _, ok := s.Endpoints[r.id]; ok {
|
||||
ss[id] = Service{
|
||||
id: id,
|
||||
p: r.p,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ss
|
||||
}
|
||||
|
||||
// A Service provides information about a service, and ability to resolve an
|
||||
// endpoint from the context of a service, given a region.
|
||||
type Service struct {
|
||||
id string
|
||||
p *partition
|
||||
}
|
||||
|
||||
// ID returns the identifier for the service.
|
||||
func (s *Service) ID() string { return s.id }
|
||||
|
||||
// ResolveEndpoint resolves an endpoint from the context of a service given
|
||||
// a region. See Partition.EndpointFor for usage and errors that can be returned.
|
||||
func (s *Service) ResolveEndpoint(region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||
return s.p.EndpointFor(s.id, region, opts...)
|
||||
}
|
||||
|
||||
// Endpoints returns a map of Endpoints indexed by their ID for all known
|
||||
// endpoints for a service.
|
||||
func (s *Service) Endpoints() map[string]Endpoint {
|
||||
es := map[string]Endpoint{}
|
||||
for id := range s.p.Services[s.id].Endpoints {
|
||||
es[id] = Endpoint{
|
||||
id: id,
|
||||
serviceID: s.id,
|
||||
p: s.p,
|
||||
}
|
||||
}
|
||||
|
||||
return es
|
||||
}
|
||||
|
||||
// A Endpoint provides information about endpoints, and provides the ability
|
||||
// to resolve that endpoint for the service, and the region the endpoint
|
||||
// represents.
|
||||
type Endpoint struct {
|
||||
id string
|
||||
serviceID string
|
||||
p *partition
|
||||
}
|
||||
|
||||
// ID returns the identifier for an endpoint.
|
||||
func (e *Endpoint) ID() string { return e.id }
|
||||
|
||||
// ServiceID returns the identifier the endpoint belongs to.
|
||||
func (e *Endpoint) ServiceID() string { return e.serviceID }
|
||||
|
||||
// ResolveEndpoint resolves an endpoint from the context of a service and
|
||||
// region the endpoint represents. See Partition.EndpointFor for usage and
|
||||
// errors that can be returned.
|
||||
func (e *Endpoint) ResolveEndpoint(opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||
return e.p.EndpointFor(e.serviceID, e.id, opts...)
|
||||
}
|
||||
|
||||
// A ResolvedEndpoint is an endpoint that has been resolved based on a partition
|
||||
// service, and region.
|
||||
type ResolvedEndpoint struct {
|
||||
// The endpoint URL
|
||||
URL string
|
||||
|
||||
// The region that should be used for signing requests.
|
||||
SigningRegion string
|
||||
|
||||
// The service name that should be used for signing requests.
|
||||
SigningName string
|
||||
|
||||
// The signing method that should be used for signing requests.
|
||||
SigningMethod string
|
||||
}
|
||||
|
||||
// So that the Error interface type can be included as an anonymous field
|
||||
// in the requestError struct and not conflict with the error.Error() method.
|
||||
type awsError awserr.Error
|
||||
|
||||
// A EndpointNotFoundError is returned when in StrictMatching mode, and the
|
||||
// endpoint for the service and region cannot be found in any of the partitions.
|
||||
type EndpointNotFoundError struct {
|
||||
awsError
|
||||
Partition string
|
||||
Service string
|
||||
Region string
|
||||
}
|
||||
|
||||
//// NewEndpointNotFoundError builds and returns NewEndpointNotFoundError.
|
||||
//func NewEndpointNotFoundError(p, s, r string) EndpointNotFoundError {
|
||||
// return EndpointNotFoundError{
|
||||
// awsError: awserr.New("EndpointNotFoundError", "unable to find endpoint", nil),
|
||||
// Partition: p,
|
||||
// Service: s,
|
||||
// Region: r,
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//// Error returns string representation of the error.
|
||||
//func (e EndpointNotFoundError) Error() string {
|
||||
// extra := fmt.Sprintf("partition: %q, service: %q, region: %q",
|
||||
// e.Partition, e.Service, e.Region)
|
||||
// return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr())
|
||||
//}
|
||||
//
|
||||
//// String returns the string representation of the error.
|
||||
//func (e EndpointNotFoundError) String() string {
|
||||
// return e.Error()
|
||||
//}
|
||||
|
||||
// A UnknownServiceError is returned when the service does not resolve to an
|
||||
// endpoint. Includes a list of all known services for the partition. Returned
|
||||
// when a partition does not support the service.
|
||||
type UnknownServiceError struct {
|
||||
awsError
|
||||
Partition string
|
||||
Service string
|
||||
Known []string
|
||||
}
|
||||
|
||||
// NewUnknownServiceError builds and returns UnknownServiceError.
|
||||
func NewUnknownServiceError(p, s string, known []string) UnknownServiceError {
|
||||
return UnknownServiceError{
|
||||
awsError: awserr.New("UnknownServiceError",
|
||||
"could not resolve endpoint for unknown service", nil),
|
||||
Partition: p,
|
||||
Service: s,
|
||||
Known: known,
|
||||
}
|
||||
}
|
||||
|
||||
// String returns the string representation of the error.
|
||||
func (e UnknownServiceError) Error() string {
|
||||
extra := fmt.Sprintf("partition: %q, service: %q",
|
||||
e.Partition, e.Service)
|
||||
if len(e.Known) > 0 {
|
||||
extra += fmt.Sprintf(", known: %v", e.Known)
|
||||
}
|
||||
return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr())
|
||||
}
|
||||
|
||||
// String returns the string representation of the error.
|
||||
func (e UnknownServiceError) String() string {
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
// A UnknownEndpointError is returned when in StrictMatching mode and the
|
||||
// service is valid, but the region does not resolve to an endpoint. Includes
|
||||
// a list of all known endpoints for the service.
|
||||
type UnknownEndpointError struct {
|
||||
awsError
|
||||
Partition string
|
||||
Service string
|
||||
Region string
|
||||
Known []string
|
||||
}
|
||||
|
||||
// NewUnknownEndpointError builds and returns UnknownEndpointError.
|
||||
func NewUnknownEndpointError(p, s, r string, known []string) UnknownEndpointError {
|
||||
return UnknownEndpointError{
|
||||
awsError: awserr.New("UnknownEndpointError",
|
||||
"could not resolve endpoint", nil),
|
||||
Partition: p,
|
||||
Service: s,
|
||||
Region: r,
|
||||
Known: known,
|
||||
}
|
||||
}
|
||||
|
||||
// String returns the string representation of the error.
|
||||
func (e UnknownEndpointError) Error() string {
|
||||
extra := fmt.Sprintf("partition: %q, service: %q, region: %q",
|
||||
e.Partition, e.Service, e.Region)
|
||||
if len(e.Known) > 0 {
|
||||
extra += fmt.Sprintf(", known: %v", e.Known)
|
||||
}
|
||||
return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr())
|
||||
}
|
||||
|
||||
// String returns the string representation of the error.
|
||||
func (e UnknownEndpointError) String() string {
|
||||
return e.Error()
|
||||
}
|
|
@ -0,0 +1,303 @@
|
|||
package endpoints
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type partitions []partition
|
||||
|
||||
func (ps partitions) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||
var opt Options
|
||||
opt.Set(opts...)
|
||||
|
||||
for i := 0; i < len(ps); i++ {
|
||||
if !ps[i].canResolveEndpoint(service, region, opt.StrictMatching) {
|
||||
continue
|
||||
}
|
||||
|
||||
return ps[i].EndpointFor(service, region, opts...)
|
||||
}
|
||||
|
||||
// If loose matching fallback to first partition format to use
|
||||
// when resolving the endpoint.
|
||||
if !opt.StrictMatching && len(ps) > 0 {
|
||||
return ps[0].EndpointFor(service, region, opts...)
|
||||
}
|
||||
|
||||
return ResolvedEndpoint{}, NewUnknownEndpointError("all partitions", service, region, []string{})
|
||||
}
|
||||
|
||||
// Partitions satisfies the EnumPartitions interface and returns a list
|
||||
// of Partitions representing each partition represented in the SDK's
|
||||
// endpoints model.
|
||||
func (ps partitions) Partitions() []Partition {
|
||||
parts := make([]Partition, 0, len(ps))
|
||||
for i := 0; i < len(ps); i++ {
|
||||
parts = append(parts, ps[i].Partition())
|
||||
}
|
||||
|
||||
return parts
|
||||
}
|
||||
|
||||
type partition struct {
|
||||
ID string `json:"partition"`
|
||||
Name string `json:"partitionName"`
|
||||
DNSSuffix string `json:"dnsSuffix"`
|
||||
RegionRegex regionRegex `json:"regionRegex"`
|
||||
Defaults endpoint `json:"defaults"`
|
||||
Regions regions `json:"regions"`
|
||||
Services services `json:"services"`
|
||||
}
|
||||
|
||||
func (p partition) Partition() Partition {
|
||||
return Partition{
|
||||
id: p.ID,
|
||||
p: &p,
|
||||
}
|
||||
}
|
||||
|
||||
func (p partition) canResolveEndpoint(service, region string, strictMatch bool) bool {
|
||||
s, hasService := p.Services[service]
|
||||
_, hasEndpoint := s.Endpoints[region]
|
||||
|
||||
if hasEndpoint && hasService {
|
||||
return true
|
||||
}
|
||||
|
||||
if strictMatch {
|
||||
return false
|
||||
}
|
||||
|
||||
return p.RegionRegex.MatchString(region)
|
||||
}
|
||||
|
||||
func (p partition) EndpointFor(service, region string, opts ...func(*Options)) (resolved ResolvedEndpoint, err error) {
|
||||
var opt Options
|
||||
opt.Set(opts...)
|
||||
|
||||
s, hasService := p.Services[service]
|
||||
if !(hasService || opt.ResolveUnknownService) {
|
||||
// Only return error if the resolver will not fallback to creating
|
||||
// endpoint based on service endpoint ID passed in.
|
||||
return resolved, NewUnknownServiceError(p.ID, service, serviceList(p.Services))
|
||||
}
|
||||
|
||||
e, hasEndpoint := s.endpointForRegion(region)
|
||||
if !hasEndpoint && opt.StrictMatching {
|
||||
return resolved, NewUnknownEndpointError(p.ID, service, region, endpointList(s.Endpoints))
|
||||
}
|
||||
|
||||
defs := []endpoint{p.Defaults, s.Defaults}
|
||||
return e.resolve(service, region, p.DNSSuffix, defs, opt), nil
|
||||
}
|
||||
|
||||
func serviceList(ss services) []string {
|
||||
list := make([]string, 0, len(ss))
|
||||
for k := range ss {
|
||||
list = append(list, k)
|
||||
}
|
||||
return list
|
||||
}
|
||||
func endpointList(es endpoints) []string {
|
||||
list := make([]string, 0, len(es))
|
||||
for k := range es {
|
||||
list = append(list, k)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
type regionRegex struct {
|
||||
*regexp.Regexp
|
||||
}
|
||||
|
||||
func (rr *regionRegex) UnmarshalJSON(b []byte) (err error) {
|
||||
// Strip leading and trailing quotes
|
||||
regex, err := strconv.Unquote(string(b))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to strip quotes from regex, %v", err)
|
||||
}
|
||||
|
||||
rr.Regexp, err = regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to unmarshal region regex, %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type regions map[string]region
|
||||
|
||||
type region struct {
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type services map[string]service
|
||||
|
||||
type service struct {
|
||||
PartitionEndpoint string `json:"partitionEndpoint"`
|
||||
IsRegionalized boxedBool `json:"isRegionalized,omitempty"`
|
||||
Defaults endpoint `json:"defaults"`
|
||||
Endpoints endpoints `json:"endpoints"`
|
||||
}
|
||||
|
||||
func (s *service) endpointForRegion(region string) (endpoint, bool) {
|
||||
if s.IsRegionalized == boxedFalse {
|
||||
return s.Endpoints[s.PartitionEndpoint], region == s.PartitionEndpoint
|
||||
}
|
||||
|
||||
if e, ok := s.Endpoints[region]; ok {
|
||||
return e, true
|
||||
}
|
||||
|
||||
// Unable to find any matching endpoint, return
|
||||
// blank that will be used for generic endpoint creation.
|
||||
return endpoint{}, false
|
||||
}
|
||||
|
||||
type endpoints map[string]endpoint
|
||||
|
||||
type endpoint struct {
|
||||
Hostname string `json:"hostname"`
|
||||
Protocols []string `json:"protocols"`
|
||||
CredentialScope credentialScope `json:"credentialScope"`
|
||||
|
||||
// Custom fields not modeled
|
||||
HasDualStack boxedBool `json:"-"`
|
||||
DualStackHostname string `json:"-"`
|
||||
|
||||
// Signature Version not used
|
||||
SignatureVersions []string `json:"signatureVersions"`
|
||||
|
||||
// SSLCommonName not used.
|
||||
SSLCommonName string `json:"sslCommonName"`
|
||||
}
|
||||
|
||||
const (
|
||||
defaultProtocol = "https"
|
||||
defaultSigner = "v4"
|
||||
)
|
||||
|
||||
var (
|
||||
protocolPriority = []string{"https", "http"}
|
||||
signerPriority = []string{"v4", "v2"}
|
||||
)
|
||||
|
||||
func getByPriority(s []string, p []string, def string) string {
|
||||
if len(s) == 0 {
|
||||
return def
|
||||
}
|
||||
|
||||
for i := 0; i < len(p); i++ {
|
||||
for j := 0; j < len(s); j++ {
|
||||
if s[j] == p[i] {
|
||||
return s[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s[0]
|
||||
}
|
||||
|
||||
func (e endpoint) resolve(service, region, dnsSuffix string, defs []endpoint, opts Options) ResolvedEndpoint {
|
||||
var merged endpoint
|
||||
for _, def := range defs {
|
||||
merged.mergeIn(def)
|
||||
}
|
||||
merged.mergeIn(e)
|
||||
e = merged
|
||||
|
||||
hostname := e.Hostname
|
||||
|
||||
// Offset the hostname for dualstack if enabled
|
||||
if opts.UseDualStack && e.HasDualStack == boxedTrue {
|
||||
hostname = e.DualStackHostname
|
||||
}
|
||||
|
||||
u := strings.Replace(hostname, "{service}", service, 1)
|
||||
u = strings.Replace(u, "{region}", region, 1)
|
||||
u = strings.Replace(u, "{dnsSuffix}", dnsSuffix, 1)
|
||||
|
||||
scheme := getEndpointScheme(e.Protocols, opts.DisableSSL)
|
||||
u = fmt.Sprintf("%s://%s", scheme, u)
|
||||
|
||||
signingRegion := e.CredentialScope.Region
|
||||
if len(signingRegion) == 0 {
|
||||
signingRegion = region
|
||||
}
|
||||
signingName := e.CredentialScope.Service
|
||||
if len(signingName) == 0 {
|
||||
signingName = service
|
||||
}
|
||||
|
||||
return ResolvedEndpoint{
|
||||
URL: u,
|
||||
SigningRegion: signingRegion,
|
||||
SigningName: signingName,
|
||||
SigningMethod: getByPriority(e.SignatureVersions, signerPriority, defaultSigner),
|
||||
}
|
||||
}
|
||||
|
||||
func getEndpointScheme(protocols []string, disableSSL bool) string {
|
||||
if disableSSL {
|
||||
return "http"
|
||||
}
|
||||
|
||||
return getByPriority(protocols, protocolPriority, defaultProtocol)
|
||||
}
|
||||
|
||||
func (e *endpoint) mergeIn(other endpoint) {
|
||||
if len(other.Hostname) > 0 {
|
||||
e.Hostname = other.Hostname
|
||||
}
|
||||
if len(other.Protocols) > 0 {
|
||||
e.Protocols = other.Protocols
|
||||
}
|
||||
if len(other.SignatureVersions) > 0 {
|
||||
e.SignatureVersions = other.SignatureVersions
|
||||
}
|
||||
if len(other.CredentialScope.Region) > 0 {
|
||||
e.CredentialScope.Region = other.CredentialScope.Region
|
||||
}
|
||||
if len(other.CredentialScope.Service) > 0 {
|
||||
e.CredentialScope.Service = other.CredentialScope.Service
|
||||
}
|
||||
if len(other.SSLCommonName) > 0 {
|
||||
e.SSLCommonName = other.SSLCommonName
|
||||
}
|
||||
if other.HasDualStack != boxedBoolUnset {
|
||||
e.HasDualStack = other.HasDualStack
|
||||
}
|
||||
if len(other.DualStackHostname) > 0 {
|
||||
e.DualStackHostname = other.DualStackHostname
|
||||
}
|
||||
}
|
||||
|
||||
type credentialScope struct {
|
||||
Region string `json:"region"`
|
||||
Service string `json:"service"`
|
||||
}
|
||||
|
||||
type boxedBool int
|
||||
|
||||
func (b *boxedBool) UnmarshalJSON(buf []byte) error {
|
||||
v, err := strconv.ParseBool(string(buf))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v {
|
||||
*b = boxedTrue
|
||||
} else {
|
||||
*b = boxedFalse
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
boxedBoolUnset boxedBool = iota
|
||||
boxedFalse
|
||||
boxedTrue
|
||||
)
|
334
vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model_codegen.go
generated
vendored
Normal file
334
vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model_codegen.go
generated
vendored
Normal file
|
@ -0,0 +1,334 @@
|
|||
// +build codegen
|
||||
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
"text/template"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// A CodeGenOptions are the options for code generating the endpoints into
|
||||
// Go code from the endpoints model definition.
|
||||
type CodeGenOptions struct {
|
||||
// Options for how the model will be decoded.
|
||||
DecodeModelOptions DecodeModelOptions
|
||||
}
|
||||
|
||||
// Set combines all of the option functions together
|
||||
func (d *CodeGenOptions) Set(optFns ...func(*CodeGenOptions)) {
|
||||
for _, fn := range optFns {
|
||||
fn(d)
|
||||
}
|
||||
}
|
||||
|
||||
// CodeGenModel given a endpoints model file will decode it and attempt to
|
||||
// generate Go code from the model definition. Error will be returned if
|
||||
// the code is unable to be generated, or decoded.
|
||||
func CodeGenModel(modelFile io.Reader, outFile io.Writer, optFns ...func(*CodeGenOptions)) error {
|
||||
var opts CodeGenOptions
|
||||
opts.Set(optFns...)
|
||||
|
||||
resolver, err := DecodeModel(modelFile, func(d *DecodeModelOptions) {
|
||||
*d = opts.DecodeModelOptions
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl := template.Must(template.New("tmpl").Funcs(funcMap).Parse(v3Tmpl))
|
||||
if err := tmpl.ExecuteTemplate(outFile, "defaults", resolver); err != nil {
|
||||
return fmt.Errorf("failed to execute template, %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func toSymbol(v string) string {
|
||||
out := []rune{}
|
||||
for _, c := range strings.Title(v) {
|
||||
if !(unicode.IsNumber(c) || unicode.IsLetter(c)) {
|
||||
continue
|
||||
}
|
||||
|
||||
out = append(out, c)
|
||||
}
|
||||
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func quoteString(v string) string {
|
||||
return fmt.Sprintf("%q", v)
|
||||
}
|
||||
|
||||
func regionConstName(p, r string) string {
|
||||
return toSymbol(p) + toSymbol(r)
|
||||
}
|
||||
|
||||
func partitionGetter(id string) string {
|
||||
return fmt.Sprintf("%sPartition", toSymbol(id))
|
||||
}
|
||||
|
||||
func partitionVarName(id string) string {
|
||||
return fmt.Sprintf("%sPartition", strings.ToLower(toSymbol(id)))
|
||||
}
|
||||
|
||||
func listPartitionNames(ps partitions) string {
|
||||
names := []string{}
|
||||
switch len(ps) {
|
||||
case 1:
|
||||
return ps[0].Name
|
||||
case 2:
|
||||
return fmt.Sprintf("%s and %s", ps[0].Name, ps[1].Name)
|
||||
default:
|
||||
for i, p := range ps {
|
||||
if i == len(ps)-1 {
|
||||
names = append(names, "and "+p.Name)
|
||||
} else {
|
||||
names = append(names, p.Name)
|
||||
}
|
||||
}
|
||||
return strings.Join(names, ", ")
|
||||
}
|
||||
}
|
||||
|
||||
func boxedBoolIfSet(msg string, v boxedBool) string {
|
||||
switch v {
|
||||
case boxedTrue:
|
||||
return fmt.Sprintf(msg, "boxedTrue")
|
||||
case boxedFalse:
|
||||
return fmt.Sprintf(msg, "boxedFalse")
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func stringIfSet(msg, v string) string {
|
||||
if len(v) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return fmt.Sprintf(msg, v)
|
||||
}
|
||||
|
||||
func stringSliceIfSet(msg string, vs []string) string {
|
||||
if len(vs) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
names := []string{}
|
||||
for _, v := range vs {
|
||||
names = append(names, `"`+v+`"`)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(msg, strings.Join(names, ","))
|
||||
}
|
||||
|
||||
func endpointIsSet(v endpoint) bool {
|
||||
return !reflect.DeepEqual(v, endpoint{})
|
||||
}
|
||||
|
||||
func serviceSet(ps partitions) map[string]struct{} {
|
||||
set := map[string]struct{}{}
|
||||
for _, p := range ps {
|
||||
for id := range p.Services {
|
||||
set[id] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
var funcMap = template.FuncMap{
|
||||
"ToSymbol": toSymbol,
|
||||
"QuoteString": quoteString,
|
||||
"RegionConst": regionConstName,
|
||||
"PartitionGetter": partitionGetter,
|
||||
"PartitionVarName": partitionVarName,
|
||||
"ListPartitionNames": listPartitionNames,
|
||||
"BoxedBoolIfSet": boxedBoolIfSet,
|
||||
"StringIfSet": stringIfSet,
|
||||
"StringSliceIfSet": stringSliceIfSet,
|
||||
"EndpointIsSet": endpointIsSet,
|
||||
"ServicesSet": serviceSet,
|
||||
}
|
||||
|
||||
const v3Tmpl = `
|
||||
{{ define "defaults" -}}
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
{{ template "partition consts" . }}
|
||||
|
||||
{{ range $_, $partition := . }}
|
||||
{{ template "partition region consts" $partition }}
|
||||
{{ end }}
|
||||
|
||||
{{ template "service consts" . }}
|
||||
|
||||
{{ template "endpoint resolvers" . }}
|
||||
{{- end }}
|
||||
|
||||
{{ define "partition consts" }}
|
||||
// Partition identifiers
|
||||
const (
|
||||
{{ range $_, $p := . -}}
|
||||
{{ ToSymbol $p.ID }}PartitionID = {{ QuoteString $p.ID }} // {{ $p.Name }} partition.
|
||||
{{ end -}}
|
||||
)
|
||||
{{- end }}
|
||||
|
||||
{{ define "partition region consts" }}
|
||||
// {{ .Name }} partition's regions.
|
||||
const (
|
||||
{{ range $id, $region := .Regions -}}
|
||||
{{ ToSymbol $id }}RegionID = {{ QuoteString $id }} // {{ $region.Description }}.
|
||||
{{ end -}}
|
||||
)
|
||||
{{- end }}
|
||||
|
||||
{{ define "service consts" }}
|
||||
// Service identifiers
|
||||
const (
|
||||
{{ $serviceSet := ServicesSet . -}}
|
||||
{{ range $id, $_ := $serviceSet -}}
|
||||
{{ ToSymbol $id }}ServiceID = {{ QuoteString $id }} // {{ ToSymbol $id }}.
|
||||
{{ end -}}
|
||||
)
|
||||
{{- end }}
|
||||
|
||||
{{ define "endpoint resolvers" }}
|
||||
// DefaultResolver returns an Endpoint resolver that will be able
|
||||
// to resolve endpoints for: {{ ListPartitionNames . }}.
|
||||
//
|
||||
// Casting the return value of this func to a EnumPartitions will
|
||||
// allow you to get a list of the partitions in the order the endpoints
|
||||
// will be resolved in.
|
||||
//
|
||||
// resolver := endpoints.DefaultResolver()
|
||||
// partitions := resolver.(endpoints.EnumPartitions).Partitions()
|
||||
// for _, p := range partitions {
|
||||
// // ... inspect partitions
|
||||
// }
|
||||
func DefaultResolver() Resolver {
|
||||
return defaultPartitions
|
||||
}
|
||||
|
||||
var defaultPartitions = partitions{
|
||||
{{ range $_, $partition := . -}}
|
||||
{{ PartitionVarName $partition.ID }},
|
||||
{{ end }}
|
||||
}
|
||||
|
||||
{{ range $_, $partition := . -}}
|
||||
{{ $name := PartitionGetter $partition.ID -}}
|
||||
// {{ $name }} returns the Resolver for {{ $partition.Name }}.
|
||||
func {{ $name }}() Partition {
|
||||
return {{ PartitionVarName $partition.ID }}.Partition()
|
||||
}
|
||||
var {{ PartitionVarName $partition.ID }} = {{ template "gocode Partition" $partition }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ define "default partitions" }}
|
||||
func DefaultPartitions() []Partition {
|
||||
return []partition{
|
||||
{{ range $_, $partition := . -}}
|
||||
// {{ ToSymbol $partition.ID}}Partition(),
|
||||
{{ end }}
|
||||
}
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
{{ define "gocode Partition" -}}
|
||||
partition{
|
||||
{{ StringIfSet "ID: %q,\n" .ID -}}
|
||||
{{ StringIfSet "Name: %q,\n" .Name -}}
|
||||
{{ StringIfSet "DNSSuffix: %q,\n" .DNSSuffix -}}
|
||||
RegionRegex: {{ template "gocode RegionRegex" .RegionRegex }},
|
||||
{{ if EndpointIsSet .Defaults -}}
|
||||
Defaults: {{ template "gocode Endpoint" .Defaults }},
|
||||
{{- end }}
|
||||
Regions: {{ template "gocode Regions" .Regions }},
|
||||
Services: {{ template "gocode Services" .Services }},
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{ define "gocode RegionRegex" -}}
|
||||
regionRegex{
|
||||
Regexp: func() *regexp.Regexp{
|
||||
reg, _ := regexp.Compile({{ QuoteString .Regexp.String }})
|
||||
return reg
|
||||
}(),
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{ define "gocode Regions" -}}
|
||||
regions{
|
||||
{{ range $id, $region := . -}}
|
||||
"{{ $id }}": {{ template "gocode Region" $region }},
|
||||
{{ end -}}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{ define "gocode Region" -}}
|
||||
region{
|
||||
{{ StringIfSet "Description: %q,\n" .Description -}}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{ define "gocode Services" -}}
|
||||
services{
|
||||
{{ range $id, $service := . -}}
|
||||
"{{ $id }}": {{ template "gocode Service" $service }},
|
||||
{{ end }}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{ define "gocode Service" -}}
|
||||
service{
|
||||
{{ StringIfSet "PartitionEndpoint: %q,\n" .PartitionEndpoint -}}
|
||||
{{ BoxedBoolIfSet "IsRegionalized: %s,\n" .IsRegionalized -}}
|
||||
{{ if EndpointIsSet .Defaults -}}
|
||||
Defaults: {{ template "gocode Endpoint" .Defaults -}},
|
||||
{{- end }}
|
||||
{{ if .Endpoints -}}
|
||||
Endpoints: {{ template "gocode Endpoints" .Endpoints }},
|
||||
{{- end }}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{ define "gocode Endpoints" -}}
|
||||
endpoints{
|
||||
{{ range $id, $endpoint := . -}}
|
||||
"{{ $id }}": {{ template "gocode Endpoint" $endpoint }},
|
||||
{{ end }}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{ define "gocode Endpoint" -}}
|
||||
endpoint{
|
||||
{{ StringIfSet "Hostname: %q,\n" .Hostname -}}
|
||||
{{ StringIfSet "SSLCommonName: %q,\n" .SSLCommonName -}}
|
||||
{{ StringSliceIfSet "Protocols: []string{%s},\n" .Protocols -}}
|
||||
{{ StringSliceIfSet "SignatureVersions: []string{%s},\n" .SignatureVersions -}}
|
||||
{{ if or .CredentialScope.Region .CredentialScope.Service -}}
|
||||
CredentialScope: credentialScope{
|
||||
{{ StringIfSet "Region: %q,\n" .CredentialScope.Region -}}
|
||||
{{ StringIfSet "Service: %q,\n" .CredentialScope.Service -}}
|
||||
},
|
||||
{{- end }}
|
||||
{{ BoxedBoolIfSet "HasDualStack: %s,\n" .HasDualStack -}}
|
||||
{{ StringIfSet "DualStackHostname: %q,\n" .DualStackHostname -}}
|
||||
|
||||
}
|
||||
{{- end }}
|
||||
`
|
|
@ -1,5 +1,3 @@
|
|||
// +build go1.5
|
||||
|
||||
package request
|
||||
|
||||
import (
|
||||
|
@ -9,20 +7,13 @@ import (
|
|||
)
|
||||
|
||||
func copyHTTPRequest(r *http.Request, body io.ReadCloser) *http.Request {
|
||||
req := &http.Request{
|
||||
URL: &url.URL{},
|
||||
Header: http.Header{},
|
||||
Close: r.Close,
|
||||
Body: body,
|
||||
Host: r.Host,
|
||||
Method: r.Method,
|
||||
Proto: r.Proto,
|
||||
ContentLength: r.ContentLength,
|
||||
// Cancel will be deprecated in 1.7 and will be replaced with Context
|
||||
Cancel: r.Cancel,
|
||||
}
|
||||
|
||||
req := new(http.Request)
|
||||
*req = *r
|
||||
req.URL = &url.URL{}
|
||||
*req.URL = *r.URL
|
||||
req.Body = body
|
||||
|
||||
req.Header = http.Header{}
|
||||
for k, v := range r.Header {
|
||||
for _, vv := range v {
|
||||
req.Header.Add(k, vv)
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
// +build !go1.5
|
||||
|
||||
package request
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func copyHTTPRequest(r *http.Request, body io.ReadCloser) *http.Request {
|
||||
req := &http.Request{
|
||||
URL: &url.URL{},
|
||||
Header: http.Header{},
|
||||
Close: r.Close,
|
||||
Body: body,
|
||||
Host: r.Host,
|
||||
Method: r.Method,
|
||||
Proto: r.Proto,
|
||||
ContentLength: r.ContentLength,
|
||||
}
|
||||
|
||||
*req.URL = *r.URL
|
||||
for k, v := range r.Header {
|
||||
for _, vv := range v {
|
||||
req.Header.Add(k, vv)
|
||||
}
|
||||
}
|
||||
|
||||
return req
|
||||
}
|
|
@ -9,7 +9,7 @@ import (
|
|||
// with retrying requests
|
||||
type offsetReader struct {
|
||||
buf io.ReadSeeker
|
||||
lock sync.RWMutex
|
||||
lock sync.Mutex
|
||||
closed bool
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,8 @@ func newOffsetReader(buf io.ReadSeeker, offset int64) *offsetReader {
|
|||
return reader
|
||||
}
|
||||
|
||||
// Close is a thread-safe close. Uses the write lock.
|
||||
// Close will close the instance of the offset reader's access to
|
||||
// the underlying io.ReadSeeker.
|
||||
func (o *offsetReader) Close() error {
|
||||
o.lock.Lock()
|
||||
defer o.lock.Unlock()
|
||||
|
@ -29,10 +30,10 @@ func (o *offsetReader) Close() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Read is a thread-safe read using a read lock.
|
||||
// Read is a thread-safe read of the underlying io.ReadSeeker
|
||||
func (o *offsetReader) Read(p []byte) (int, error) {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
o.lock.Lock()
|
||||
defer o.lock.Unlock()
|
||||
|
||||
if o.closed {
|
||||
return 0, io.EOF
|
||||
|
@ -41,6 +42,14 @@ func (o *offsetReader) Read(p []byte) (int, error) {
|
|||
return o.buf.Read(p)
|
||||
}
|
||||
|
||||
// Seek is a thread-safe seeking operation.
|
||||
func (o *offsetReader) Seek(offset int64, whence int) (int64, error) {
|
||||
o.lock.Lock()
|
||||
defer o.lock.Unlock()
|
||||
|
||||
return o.buf.Seek(offset, whence)
|
||||
}
|
||||
|
||||
// CloseAndCopy will return a new offsetReader with a copy of the old buffer
|
||||
// and close the old buffer.
|
||||
func (o *offsetReader) CloseAndCopy(offset int64) *offsetReader {
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
|
@ -42,6 +42,12 @@ type Request struct {
|
|||
LastSignedAt time.Time
|
||||
|
||||
built bool
|
||||
|
||||
// Need to persist an intermideant body betweend the input Body and HTTP
|
||||
// request body because the HTTP Client's transport can maintain a reference
|
||||
// to the HTTP request's body after the client has returned. This value is
|
||||
// safe to use concurrently and rewraps the input Body for each HTTP request.
|
||||
safeBody *offsetReader
|
||||
}
|
||||
|
||||
// An Operation is the service API operation to be made.
|
||||
|
@ -50,6 +56,8 @@ type Operation struct {
|
|||
HTTPMethod string
|
||||
HTTPPath string
|
||||
*Paginator
|
||||
|
||||
BeforePresignFn func(r *Request) error
|
||||
}
|
||||
|
||||
// Paginator keeps track of pagination configuration for an API operation.
|
||||
|
@ -135,8 +143,8 @@ func (r *Request) SetStringBody(s string) {
|
|||
|
||||
// SetReaderBody will set the request's body reader.
|
||||
func (r *Request) SetReaderBody(reader io.ReadSeeker) {
|
||||
r.HTTPRequest.Body = newOffsetReader(reader, 0)
|
||||
r.Body = reader
|
||||
r.ResetBody()
|
||||
}
|
||||
|
||||
// Presign returns the request's signed URL. Error will be returned
|
||||
|
@ -144,6 +152,15 @@ func (r *Request) SetReaderBody(reader io.ReadSeeker) {
|
|||
func (r *Request) Presign(expireTime time.Duration) (string, error) {
|
||||
r.ExpireTime = expireTime
|
||||
r.NotHoist = false
|
||||
|
||||
if r.Operation.BeforePresignFn != nil {
|
||||
r = r.copy()
|
||||
err := r.Operation.BeforePresignFn(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
r.Sign()
|
||||
if r.Error != nil {
|
||||
return "", r.Error
|
||||
|
@ -220,6 +237,99 @@ func (r *Request) Sign() error {
|
|||
return r.Error
|
||||
}
|
||||
|
||||
// ResetBody rewinds the request body backto its starting position, and
|
||||
// set's the HTTP Request body reference. When the body is read prior
|
||||
// to being sent in the HTTP request it will need to be rewound.
|
||||
func (r *Request) ResetBody() {
|
||||
if r.safeBody != nil {
|
||||
r.safeBody.Close()
|
||||
}
|
||||
|
||||
r.safeBody = newOffsetReader(r.Body, r.BodyStart)
|
||||
|
||||
// Go 1.8 tightened and clarified the rules code needs to use when building
|
||||
// requests with the http package. Go 1.8 removed the automatic detection
|
||||
// of if the Request.Body was empty, or actually had bytes in it. The SDK
|
||||
// always sets the Request.Body even if it is empty and should not actually
|
||||
// be sent. This is incorrect.
|
||||
//
|
||||
// Go 1.8 did add a http.NoBody value that the SDK can use to tell the http
|
||||
// client that the request really should be sent without a body. The
|
||||
// Request.Body cannot be set to nil, which is preferable, because the
|
||||
// field is exported and could introduce nil pointer dereferences for users
|
||||
// of the SDK if they used that field.
|
||||
//
|
||||
// Related golang/go#18257
|
||||
l, err := computeBodyLength(r.Body)
|
||||
if err != nil {
|
||||
r.Error = awserr.New("SerializationError", "failed to compute request body size", err)
|
||||
return
|
||||
}
|
||||
|
||||
if l == 0 {
|
||||
r.HTTPRequest.Body = noBodyReader
|
||||
} else if l > 0 {
|
||||
r.HTTPRequest.Body = r.safeBody
|
||||
} else {
|
||||
// Hack to prevent sending bodies for methods where the body
|
||||
// should be ignored by the server. Sending bodies on these
|
||||
// methods without an associated ContentLength will cause the
|
||||
// request to socket timeout because the server does not handle
|
||||
// Transfer-Encoding: chunked bodies for these methods.
|
||||
//
|
||||
// This would only happen if a aws.ReaderSeekerCloser was used with
|
||||
// a io.Reader that was not also an io.Seeker.
|
||||
switch r.Operation.HTTPMethod {
|
||||
case "GET", "HEAD", "DELETE":
|
||||
r.HTTPRequest.Body = noBodyReader
|
||||
default:
|
||||
r.HTTPRequest.Body = r.safeBody
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempts to compute the length of the body of the reader using the
|
||||
// io.Seeker interface. If the value is not seekable because of being
|
||||
// a ReaderSeekerCloser without an unerlying Seeker -1 will be returned.
|
||||
// If no error occurs the length of the body will be returned.
|
||||
func computeBodyLength(r io.ReadSeeker) (int64, error) {
|
||||
seekable := true
|
||||
// Determine if the seeker is actually seekable. ReaderSeekerCloser
|
||||
// hides the fact that a io.Readers might not actually be seekable.
|
||||
switch v := r.(type) {
|
||||
case aws.ReaderSeekerCloser:
|
||||
seekable = v.IsSeeker()
|
||||
case *aws.ReaderSeekerCloser:
|
||||
seekable = v.IsSeeker()
|
||||
}
|
||||
if !seekable {
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
curOffset, err := r.Seek(0, 1)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
endOffset, err := r.Seek(0, 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
_, err = r.Seek(curOffset, 0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return endOffset - curOffset, nil
|
||||
}
|
||||
|
||||
// GetBody will return an io.ReadSeeker of the Request's underlying
|
||||
// input body with a concurrency safe wrapper.
|
||||
func (r *Request) GetBody() io.ReadSeeker {
|
||||
return r.safeBody
|
||||
}
|
||||
|
||||
// Send will send the request returning error if errors are encountered.
|
||||
//
|
||||
// Send will sign the request prior to sending. All Send Handlers will
|
||||
|
@ -231,6 +341,8 @@ func (r *Request) Sign() error {
|
|||
//
|
||||
// readLoop() and getConn(req *Request, cm connectMethod)
|
||||
// https://github.com/golang/go/blob/master/src/net/http/transport.go
|
||||
//
|
||||
// Send will not close the request.Request's body.
|
||||
func (r *Request) Send() error {
|
||||
for {
|
||||
if aws.BoolValue(r.Retryable) {
|
||||
|
@ -239,21 +351,15 @@ func (r *Request) Send() error {
|
|||
r.ClientInfo.ServiceName, r.Operation.Name, r.RetryCount))
|
||||
}
|
||||
|
||||
var body io.ReadCloser
|
||||
if reader, ok := r.HTTPRequest.Body.(*offsetReader); ok {
|
||||
body = reader.CloseAndCopy(r.BodyStart)
|
||||
} else {
|
||||
if r.Config.Logger != nil {
|
||||
r.Config.Logger.Log("Request body type has been overwritten. May cause race conditions")
|
||||
}
|
||||
r.Body.Seek(r.BodyStart, 0)
|
||||
body = ioutil.NopCloser(r.Body)
|
||||
}
|
||||
// The previous http.Request will have a reference to the r.Body
|
||||
// and the HTTP Client's Transport may still be reading from
|
||||
// the request's body even though the Client's Do returned.
|
||||
r.HTTPRequest = copyHTTPRequest(r.HTTPRequest, nil)
|
||||
r.ResetBody()
|
||||
|
||||
r.HTTPRequest = copyHTTPRequest(r.HTTPRequest, body)
|
||||
// Closing response body to ensure that no response body is leaked
|
||||
// between retry attempts.
|
||||
if r.HTTPResponse != nil && r.HTTPResponse.Body != nil {
|
||||
// Closing response body. Since we are setting a new request to send off, this
|
||||
// response will get squashed and leaked.
|
||||
r.HTTPResponse.Body.Close()
|
||||
}
|
||||
}
|
||||
|
@ -267,7 +373,7 @@ func (r *Request) Send() error {
|
|||
|
||||
r.Handlers.Send.Run(r)
|
||||
if r.Error != nil {
|
||||
if strings.Contains(r.Error.Error(), "net/http: request canceled") {
|
||||
if !shouldRetryCancel(r) {
|
||||
return r.Error
|
||||
}
|
||||
|
||||
|
@ -281,7 +387,6 @@ func (r *Request) Send() error {
|
|||
debugLogReqError(r, "Send Request", true, err)
|
||||
continue
|
||||
}
|
||||
|
||||
r.Handlers.UnmarshalMeta.Run(r)
|
||||
r.Handlers.ValidateResponse.Run(r)
|
||||
if r.Error != nil {
|
||||
|
@ -316,6 +421,17 @@ func (r *Request) Send() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// copy will copy a request which will allow for local manipulation of the
|
||||
// request.
|
||||
func (r *Request) copy() *Request {
|
||||
req := &Request{}
|
||||
*req = *r
|
||||
req.Handlers = r.Handlers.Copy()
|
||||
op := *r.Operation
|
||||
req.Operation = &op
|
||||
return req
|
||||
}
|
||||
|
||||
// AddToUserAgent adds the string to the end of the request's current user agent.
|
||||
func AddToUserAgent(r *Request, s string) {
|
||||
curUA := r.HTTPRequest.Header.Get("User-Agent")
|
||||
|
@ -324,3 +440,26 @@ func AddToUserAgent(r *Request, s string) {
|
|||
}
|
||||
r.HTTPRequest.Header.Set("User-Agent", s)
|
||||
}
|
||||
|
||||
func shouldRetryCancel(r *Request) bool {
|
||||
awsErr, ok := r.Error.(awserr.Error)
|
||||
timeoutErr := false
|
||||
errStr := r.Error.Error()
|
||||
if ok {
|
||||
err := awsErr.OrigErr()
|
||||
netErr, netOK := err.(net.Error)
|
||||
timeoutErr = netOK && netErr.Temporary()
|
||||
if urlErr, ok := err.(*url.Error); !timeoutErr && ok {
|
||||
errStr = urlErr.Err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
// There can be two types of canceled errors here.
|
||||
// The first being a net.Error and the other being an error.
|
||||
// If the request was timed out, we want to continue the retry
|
||||
// process. Otherwise, return the canceled error.
|
||||
return timeoutErr ||
|
||||
(errStr != "net/http: request canceled" &&
|
||||
errStr != "net/http: request canceled while waiting for connection")
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// +build !go1.8
|
||||
|
||||
package request
|
||||
|
||||
import "io"
|
||||
|
||||
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF
|
||||
// and Close always returns nil. It can be used in an outgoing client
|
||||
// request to explicitly signal that a request has zero bytes.
|
||||
// An alternative, however, is to simply set Request.Body to nil.
|
||||
//
|
||||
// Copy of Go 1.8 NoBody type from net/http/http.go
|
||||
type noBody struct{}
|
||||
|
||||
func (noBody) Read([]byte) (int, error) { return 0, io.EOF }
|
||||
func (noBody) Close() error { return nil }
|
||||
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil }
|
||||
|
||||
// Is an empty reader that will trigger the Go HTTP client to not include
|
||||
// and body in the HTTP request.
|
||||
var noBodyReader = noBody{}
|
|
@ -0,0 +1,9 @@
|
|||
// +build go1.8
|
||||
|
||||
package request
|
||||
|
||||
import "net/http"
|
||||
|
||||
// Is a http.NoBody reader instructing Go HTTP client to not include
|
||||
// and body in the HTTP request.
|
||||
var noBodyReader = http.NoBody
|
|
@ -38,6 +38,7 @@ var throttleCodes = map[string]struct{}{
|
|||
"RequestThrottled": {},
|
||||
"LimitExceededException": {}, // Deleting 10+ DynamoDb tables at once
|
||||
"TooManyRequestsException": {}, // Lambda functions
|
||||
"PriorRequestNotComplete": {}, // Route53
|
||||
}
|
||||
|
||||
// credsExpiredCodes is a collection of error codes which signify the credentials
|
||||
|
|
|
@ -45,16 +45,16 @@ region, and profile loaded from the environment and shared config automatically.
|
|||
Requires the AWS_PROFILE to be set, or "default" is used.
|
||||
|
||||
// Create Session
|
||||
sess, err := session.NewSession()
|
||||
sess := session.Must(session.NewSession())
|
||||
|
||||
// Create a Session with a custom region
|
||||
sess, err := session.NewSession(&aws.Config{Region: aws.String("us-east-1")})
|
||||
sess := session.Must(session.NewSession(&aws.Config{
|
||||
Region: aws.String("us-east-1"),
|
||||
}))
|
||||
|
||||
// Create a S3 client instance from a session
|
||||
sess, err := session.NewSession()
|
||||
if err != nil {
|
||||
// Handle Session creation error
|
||||
}
|
||||
sess := session.Must(session.NewSession())
|
||||
|
||||
svc := s3.New(sess)
|
||||
|
||||
Create Session With Option Overrides
|
||||
|
@ -66,24 +66,26 @@ through code instead of being driven by environment variables only.
|
|||
Use NewSessionWithOptions when you want to provide the config profile, or
|
||||
override the shared config state (AWS_SDK_LOAD_CONFIG).
|
||||
|
||||
// Equivalent to session.New
|
||||
sess, err := session.NewSessionWithOptions(session.Options{})
|
||||
// Equivalent to session.NewSession()
|
||||
sess := session.Must(session.NewSessionWithOptions(session.Options{
|
||||
// Options
|
||||
}))
|
||||
|
||||
// Specify profile to load for the session's config
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
sess := session.Must(session.NewSessionWithOptions(session.Options{
|
||||
Profile: "profile_name",
|
||||
})
|
||||
}))
|
||||
|
||||
// Specify profile for config and region for requests
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
sess := session.Must(session.NewSessionWithOptions(session.Options{
|
||||
Config: aws.Config{Region: aws.String("us-east-1")},
|
||||
Profile: "profile_name",
|
||||
})
|
||||
}))
|
||||
|
||||
// Force enable Shared Config support
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
sess := session.Must(session.NewSessionWithOptions(session.Options{
|
||||
SharedConfigState: SharedConfigEnable,
|
||||
})
|
||||
}))
|
||||
|
||||
Adding Handlers
|
||||
|
||||
|
@ -93,7 +95,8 @@ handler logs every request and its payload made by a service client:
|
|||
|
||||
// Create a session, and add additional handlers for all service
|
||||
// clients created with the Session to inherit. Adds logging handler.
|
||||
sess, err := session.NewSession()
|
||||
sess := session.Must(session.NewSession())
|
||||
|
||||
sess.Handlers.Send.PushFront(func(r *request.Request) {
|
||||
// Log every request made and its payload
|
||||
logger.Println("Request: %s/%s, Payload: %s",
|
||||
|
@ -138,15 +141,14 @@ the other two fields are also provided.
|
|||
|
||||
Assume Role values allow you to configure the SDK to assume an IAM role using
|
||||
a set of credentials provided in a config file via the source_profile field.
|
||||
Both "role_arn" and "source_profile" are required. The SDK does not support
|
||||
assuming a role with MFA token Via the Session's constructor. You can use the
|
||||
stscreds.AssumeRoleProvider credentials provider to specify custom
|
||||
configuration and support for MFA.
|
||||
Both "role_arn" and "source_profile" are required. The SDK supports assuming
|
||||
a role with MFA token if the session option AssumeRoleTokenProvider
|
||||
is set.
|
||||
|
||||
role_arn = arn:aws:iam::<account_number>:role/<role_name>
|
||||
source_profile = profile_with_creds
|
||||
external_id = 1234
|
||||
mfa_serial = not supported!
|
||||
mfa_serial = <serial or mfa arn>
|
||||
role_session_name = session_name
|
||||
|
||||
Region is the region the SDK should use for looking up AWS service endpoints
|
||||
|
@ -154,6 +156,37 @@ and signing requests.
|
|||
|
||||
region = us-east-1
|
||||
|
||||
Assume Role with MFA token
|
||||
|
||||
To create a session with support for assuming an IAM role with MFA set the
|
||||
session option AssumeRoleTokenProvider to a function that will prompt for the
|
||||
MFA token code when the SDK assumes the role and refreshes the role's credentials.
|
||||
This allows you to configure the SDK via the shared config to assumea role
|
||||
with MFA tokens.
|
||||
|
||||
In order for the SDK to assume a role with MFA the SharedConfigState
|
||||
session option must be set to SharedConfigEnable, or AWS_SDK_LOAD_CONFIG
|
||||
environment variable set.
|
||||
|
||||
The shared configuration instructs the SDK to assume an IAM role with MFA
|
||||
when the mfa_serial configuration field is set in the shared config
|
||||
(~/.aws/config) or shared credentials (~/.aws/credentials) file.
|
||||
|
||||
If mfa_serial is set in the configuration, the SDK will assume the role, and
|
||||
the AssumeRoleTokenProvider session option is not set an an error will
|
||||
be returned when creating the session.
|
||||
|
||||
sess := session.Must(session.NewSessionWithOptions(session.Options{
|
||||
AssumeRoleTokenProvider: stscreds.StdinTokenProvider,
|
||||
}))
|
||||
|
||||
// Create service client value configured for credentials
|
||||
// from assumed role.
|
||||
svc := s3.New(sess)
|
||||
|
||||
To setup assume role outside of a session see the stscrds.AssumeRoleProvider
|
||||
documentation.
|
||||
|
||||
Environment Variables
|
||||
|
||||
When a Session is created several environment variables can be set to adjust
|
||||
|
|
|
@ -10,8 +10,8 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/endpoints"
|
||||
)
|
||||
|
||||
// A Session provides a central location to create service clients from and
|
||||
|
@ -34,17 +34,17 @@ type Session struct {
|
|||
// If the AWS_SDK_LOAD_CONFIG environment is set to a truthy value, the New
|
||||
// method could now encounter an error when loading the configuration. When
|
||||
// The environment variable is set, and an error occurs, New will return a
|
||||
// session that will fail all requests reporting the error that occured while
|
||||
// session that will fail all requests reporting the error that occurred while
|
||||
// loading the session. Use NewSession to get the error when creating the
|
||||
// session.
|
||||
//
|
||||
// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
|
||||
// the shared config file (~/.aws/config) will also be loaded, in addition to
|
||||
// the shared credentials file (~/.aws/config). Values set in both the
|
||||
// the shared credentials file (~/.aws/credentials). Values set in both the
|
||||
// shared config, and shared credentials will be taken from the shared
|
||||
// credentials file.
|
||||
//
|
||||
// Deprecated: Use NewSession functiions to create sessions instead. NewSession
|
||||
// Deprecated: Use NewSession functions to create sessions instead. NewSession
|
||||
// has the same functionality as New except an error can be returned when the
|
||||
// func is called instead of waiting to receive an error until a request is made.
|
||||
func New(cfgs ...*aws.Config) *Session {
|
||||
|
@ -52,14 +52,14 @@ func New(cfgs ...*aws.Config) *Session {
|
|||
envCfg := loadEnvConfig()
|
||||
|
||||
if envCfg.EnableSharedConfig {
|
||||
s, err := newSession(envCfg, cfgs...)
|
||||
s, err := newSession(Options{}, envCfg, cfgs...)
|
||||
if err != nil {
|
||||
// Old session.New expected all errors to be discovered when
|
||||
// a request is made, and would report the errors then. This
|
||||
// needs to be replicated if an error occurs while creating
|
||||
// the session.
|
||||
msg := "failed to create session with AWS_SDK_LOAD_CONFIG enabled. " +
|
||||
"Use session.NewSession to handle errors occuring during session creation."
|
||||
"Use session.NewSession to handle errors occurring during session creation."
|
||||
|
||||
// Session creation failed, need to report the error and prevent
|
||||
// any requests from succeeding.
|
||||
|
@ -73,7 +73,7 @@ func New(cfgs ...*aws.Config) *Session {
|
|||
return s
|
||||
}
|
||||
|
||||
return oldNewSession(cfgs...)
|
||||
return deprecatedNewSession(cfgs...)
|
||||
}
|
||||
|
||||
// NewSession returns a new Session created from SDK defaults, config files,
|
||||
|
@ -83,18 +83,18 @@ func New(cfgs ...*aws.Config) *Session {
|
|||
//
|
||||
// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
|
||||
// the shared config file (~/.aws/config) will also be loaded in addition to
|
||||
// the shared credentials file (~/.aws/config). Values set in both the
|
||||
// the shared credentials file (~/.aws/credentials). Values set in both the
|
||||
// shared config, and shared credentials will be taken from the shared
|
||||
// credentials file. Enabling the Shared Config will also allow the Session
|
||||
// to be built with retrieving credentials with AssumeRole set in the config.
|
||||
//
|
||||
// See the NewSessionWithOptions func for information on how to override or
|
||||
// control through code how the Session will be created. Such as specifing the
|
||||
// control through code how the Session will be created. Such as specifying the
|
||||
// config profile, and controlling if shared config is enabled or not.
|
||||
func NewSession(cfgs ...*aws.Config) (*Session, error) {
|
||||
envCfg := loadEnvConfig()
|
||||
|
||||
return newSession(envCfg, cfgs...)
|
||||
return newSession(Options{}, envCfg, cfgs...)
|
||||
}
|
||||
|
||||
// SharedConfigState provides the ability to optionally override the state
|
||||
|
@ -124,7 +124,7 @@ type Options struct {
|
|||
// Provides config values for the SDK to use when creating service clients
|
||||
// and making API requests to services. Any value set in with this field
|
||||
// will override the associated value provided by the SDK defaults,
|
||||
// environment or config files where relevent.
|
||||
// environment or config files where relevant.
|
||||
//
|
||||
// If not set, configuration values from from SDK defaults, environment,
|
||||
// config will be used.
|
||||
|
@ -147,6 +147,26 @@ type Options struct {
|
|||
// will allow you to override the AWS_SDK_LOAD_CONFIG environment variable
|
||||
// and enable or disable the shared config functionality.
|
||||
SharedConfigState SharedConfigState
|
||||
|
||||
// When the SDK's shared config is configured to assume a role with MFA
|
||||
// this option is required in order to provide the mechanism that will
|
||||
// retrieve the MFA token. There is no default value for this field. If
|
||||
// it is not set an error will be returned when creating the session.
|
||||
//
|
||||
// This token provider will be called when ever the assumed role's
|
||||
// credentials need to be refreshed. Within the context of service clients
|
||||
// all sharing the same session the SDK will ensure calls to the token
|
||||
// provider are atomic. When sharing a token provider across multiple
|
||||
// sessions additional synchronization logic is needed to ensure the
|
||||
// token providers do not introduce race conditions. It is recommend to
|
||||
// share the session where possible.
|
||||
//
|
||||
// stscreds.StdinTokenProvider is a basic implementation that will prompt
|
||||
// from stdin for the MFA token code.
|
||||
//
|
||||
// This field is only used if the shared configuration is enabled, and
|
||||
// the config enables assume role wit MFA via the mfa_serial field.
|
||||
AssumeRoleTokenProvider func() (string, error)
|
||||
}
|
||||
|
||||
// NewSessionWithOptions returns a new Session created from SDK defaults, config files,
|
||||
|
@ -155,31 +175,36 @@ type Options struct {
|
|||
//
|
||||
// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
|
||||
// the shared config file (~/.aws/config) will also be loaded in addition to
|
||||
// the shared credentials file (~/.aws/config). Values set in both the
|
||||
// the shared credentials file (~/.aws/credentials). Values set in both the
|
||||
// shared config, and shared credentials will be taken from the shared
|
||||
// credentials file. Enabling the Shared Config will also allow the Session
|
||||
// to be built with retrieving credentials with AssumeRole set in the config.
|
||||
//
|
||||
// // Equivalent to session.New
|
||||
// sess, err := session.NewSessionWithOptions(session.Options{})
|
||||
// sess := session.Must(session.NewSessionWithOptions(session.Options{}))
|
||||
//
|
||||
// // Specify profile to load for the session's config
|
||||
// sess, err := session.NewSessionWithOptions(session.Options{
|
||||
// sess := session.Must(session.NewSessionWithOptions(session.Options{
|
||||
// Profile: "profile_name",
|
||||
// })
|
||||
// }))
|
||||
//
|
||||
// // Specify profile for config and region for requests
|
||||
// sess, err := session.NewSessionWithOptions(session.Options{
|
||||
// sess := session.Must(session.NewSessionWithOptions(session.Options{
|
||||
// Config: aws.Config{Region: aws.String("us-east-1")},
|
||||
// Profile: "profile_name",
|
||||
// })
|
||||
// }))
|
||||
//
|
||||
// // Force enable Shared Config support
|
||||
// sess, err := session.NewSessionWithOptions(session.Options{
|
||||
// sess := session.Must(session.NewSessionWithOptions(session.Options{
|
||||
// SharedConfigState: SharedConfigEnable,
|
||||
// })
|
||||
// }))
|
||||
func NewSessionWithOptions(opts Options) (*Session, error) {
|
||||
envCfg := loadEnvConfig()
|
||||
var envCfg envConfig
|
||||
if opts.SharedConfigState == SharedConfigEnable {
|
||||
envCfg = loadSharedEnvConfig()
|
||||
} else {
|
||||
envCfg = loadEnvConfig()
|
||||
}
|
||||
|
||||
if len(opts.Profile) > 0 {
|
||||
envCfg.Profile = opts.Profile
|
||||
|
@ -192,7 +217,7 @@ func NewSessionWithOptions(opts Options) (*Session, error) {
|
|||
envCfg.EnableSharedConfig = true
|
||||
}
|
||||
|
||||
return newSession(envCfg, &opts.Config)
|
||||
return newSession(opts, envCfg, &opts.Config)
|
||||
}
|
||||
|
||||
// Must is a helper function to ensure the Session is valid and there was no
|
||||
|
@ -210,13 +235,18 @@ func Must(sess *Session, err error) *Session {
|
|||
return sess
|
||||
}
|
||||
|
||||
func oldNewSession(cfgs ...*aws.Config) *Session {
|
||||
func deprecatedNewSession(cfgs ...*aws.Config) *Session {
|
||||
cfg := defaults.Config()
|
||||
handlers := defaults.Handlers()
|
||||
|
||||
// Apply the passed in configs so the configuration can be applied to the
|
||||
// default credential chain
|
||||
cfg.MergeIn(cfgs...)
|
||||
if cfg.EndpointResolver == nil {
|
||||
// An endpoint resolver is required for a session to be able to provide
|
||||
// endpoints for service client configurations.
|
||||
cfg.EndpointResolver = endpoints.DefaultResolver()
|
||||
}
|
||||
cfg.Credentials = defaults.CredChain(cfg, handlers)
|
||||
|
||||
// Reapply any passed in configs to override credentials if set
|
||||
|
@ -232,7 +262,7 @@ func oldNewSession(cfgs ...*aws.Config) *Session {
|
|||
return s
|
||||
}
|
||||
|
||||
func newSession(envCfg envConfig, cfgs ...*aws.Config) (*Session, error) {
|
||||
func newSession(opts Options, envCfg envConfig, cfgs ...*aws.Config) (*Session, error) {
|
||||
cfg := defaults.Config()
|
||||
handlers := defaults.Handlers()
|
||||
|
||||
|
@ -256,7 +286,9 @@ func newSession(envCfg envConfig, cfgs ...*aws.Config) (*Session, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
mergeConfigSrcs(cfg, userCfg, envCfg, sharedCfg, handlers)
|
||||
if err := mergeConfigSrcs(cfg, userCfg, envCfg, sharedCfg, handlers, opts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := &Session{
|
||||
Config: cfg,
|
||||
|
@ -268,7 +300,7 @@ func newSession(envCfg envConfig, cfgs ...*aws.Config) (*Session, error) {
|
|||
return s, nil
|
||||
}
|
||||
|
||||
func mergeConfigSrcs(cfg, userCfg *aws.Config, envCfg envConfig, sharedCfg sharedConfig, handlers request.Handlers) {
|
||||
func mergeConfigSrcs(cfg, userCfg *aws.Config, envCfg envConfig, sharedCfg sharedConfig, handlers request.Handlers, sessOpts Options) error {
|
||||
// Merge in user provided configuration
|
||||
cfg.MergeIn(userCfg)
|
||||
|
||||
|
@ -292,6 +324,11 @@ func mergeConfigSrcs(cfg, userCfg *aws.Config, envCfg envConfig, sharedCfg share
|
|||
cfgCp.Credentials = credentials.NewStaticCredentialsFromCreds(
|
||||
sharedCfg.AssumeRoleSource.Creds,
|
||||
)
|
||||
if len(sharedCfg.AssumeRole.MFASerial) > 0 && sessOpts.AssumeRoleTokenProvider == nil {
|
||||
// AssumeRole Token provider is required if doing Assume Role
|
||||
// with MFA.
|
||||
return AssumeRoleTokenProviderNotSetError{}
|
||||
}
|
||||
cfg.Credentials = stscreds.NewCredentials(
|
||||
&Session{
|
||||
Config: &cfgCp,
|
||||
|
@ -301,11 +338,16 @@ func mergeConfigSrcs(cfg, userCfg *aws.Config, envCfg envConfig, sharedCfg share
|
|||
func(opt *stscreds.AssumeRoleProvider) {
|
||||
opt.RoleSessionName = sharedCfg.AssumeRole.RoleSessionName
|
||||
|
||||
// Assume role with external ID
|
||||
if len(sharedCfg.AssumeRole.ExternalID) > 0 {
|
||||
opt.ExternalID = aws.String(sharedCfg.AssumeRole.ExternalID)
|
||||
}
|
||||
|
||||
// MFA not supported
|
||||
// Assume role with MFA
|
||||
if len(sharedCfg.AssumeRole.MFASerial) > 0 {
|
||||
opt.SerialNumber = aws.String(sharedCfg.AssumeRole.MFASerial)
|
||||
opt.TokenProvider = sessOpts.AssumeRoleTokenProvider
|
||||
}
|
||||
},
|
||||
)
|
||||
} else if len(sharedCfg.Creds.AccessKeyID) > 0 {
|
||||
|
@ -326,6 +368,33 @@ func mergeConfigSrcs(cfg, userCfg *aws.Config, envCfg envConfig, sharedCfg share
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssumeRoleTokenProviderNotSetError is an error returned when creating a session when the
|
||||
// MFAToken option is not set when shared config is configured load assume a
|
||||
// role with an MFA token.
|
||||
type AssumeRoleTokenProviderNotSetError struct{}
|
||||
|
||||
// Code is the short id of the error.
|
||||
func (e AssumeRoleTokenProviderNotSetError) Code() string {
|
||||
return "AssumeRoleTokenProviderNotSetError"
|
||||
}
|
||||
|
||||
// Message is the description of the error
|
||||
func (e AssumeRoleTokenProviderNotSetError) Message() string {
|
||||
return fmt.Sprintf("assume role with MFA enabled, but AssumeRoleTokenProvider session option not set.")
|
||||
}
|
||||
|
||||
// OrigErr is the underlying error that caused the failure.
|
||||
func (e AssumeRoleTokenProviderNotSetError) OrigErr() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Error satisfies the error interface.
|
||||
func (e AssumeRoleTokenProviderNotSetError) Error() string {
|
||||
return awserr.SprintError(e.Code(), e.Message(), "", nil)
|
||||
}
|
||||
|
||||
type credProviderError struct {
|
||||
|
@ -370,19 +439,67 @@ func (s *Session) Copy(cfgs ...*aws.Config) *Session {
|
|||
// configure the service client instances. Passing the Session to the service
|
||||
// client's constructor (New) will use this method to configure the client.
|
||||
func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config {
|
||||
// Backwards compatibility, the error will be eaten if user calls ClientConfig
|
||||
// directly. All SDK services will use ClientconfigWithError.
|
||||
cfg, _ := s.clientConfigWithErr(serviceName, cfgs...)
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
func (s *Session) clientConfigWithErr(serviceName string, cfgs ...*aws.Config) (client.Config, error) {
|
||||
s = s.Copy(cfgs...)
|
||||
endpoint, signingRegion := endpoints.NormalizeEndpoint(
|
||||
aws.StringValue(s.Config.Endpoint),
|
||||
serviceName,
|
||||
aws.StringValue(s.Config.Region),
|
||||
aws.BoolValue(s.Config.DisableSSL),
|
||||
aws.BoolValue(s.Config.UseDualStack),
|
||||
|
||||
var resolved endpoints.ResolvedEndpoint
|
||||
var err error
|
||||
|
||||
region := aws.StringValue(s.Config.Region)
|
||||
|
||||
if endpoint := aws.StringValue(s.Config.Endpoint); len(endpoint) != 0 {
|
||||
resolved.URL = endpoints.AddScheme(endpoint, aws.BoolValue(s.Config.DisableSSL))
|
||||
resolved.SigningRegion = region
|
||||
} else {
|
||||
resolved, err = s.Config.EndpointResolver.EndpointFor(
|
||||
serviceName, region,
|
||||
func(opt *endpoints.Options) {
|
||||
opt.DisableSSL = aws.BoolValue(s.Config.DisableSSL)
|
||||
opt.UseDualStack = aws.BoolValue(s.Config.UseDualStack)
|
||||
|
||||
// Support the condition where the service is modeled but its
|
||||
// endpoint metadata is not available.
|
||||
opt.ResolveUnknownService = true
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return client.Config{
|
||||
Config: s.Config,
|
||||
Handlers: s.Handlers,
|
||||
Endpoint: endpoint,
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: resolved.URL,
|
||||
SigningRegion: resolved.SigningRegion,
|
||||
SigningName: resolved.SigningName,
|
||||
}, err
|
||||
}
|
||||
|
||||
// ClientConfigNoResolveEndpoint is the same as ClientConfig with the exception
|
||||
// that the EndpointResolver will not be used to resolve the endpoint. The only
|
||||
// endpoint set must come from the aws.Config.Endpoint field.
|
||||
func (s *Session) ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) client.Config {
|
||||
s = s.Copy(cfgs...)
|
||||
|
||||
var resolved endpoints.ResolvedEndpoint
|
||||
|
||||
region := aws.StringValue(s.Config.Region)
|
||||
|
||||
if ep := aws.StringValue(s.Config.Endpoint); len(ep) > 0 {
|
||||
resolved.URL = endpoints.AddScheme(ep, aws.BoolValue(s.Config.DisableSSL))
|
||||
resolved.SigningRegion = region
|
||||
}
|
||||
|
||||
return client.Config{
|
||||
Config: s.Config,
|
||||
Handlers: s.Handlers,
|
||||
Endpoint: resolved.URL,
|
||||
SigningRegion: resolved.SigningRegion,
|
||||
SigningName: resolved.SigningName,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package session
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
|
@ -105,12 +105,13 @@ func loadSharedConfigIniFiles(filenames []string) ([]sharedConfigFile, error) {
|
|||
files := make([]sharedConfigFile, 0, len(filenames))
|
||||
|
||||
for _, filename := range filenames {
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
// Trim files from the list that don't exist.
|
||||
b, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
// Skip files which can't be opened and read for whatever reason
|
||||
continue
|
||||
}
|
||||
|
||||
f, err := ini.Load(filename)
|
||||
f, err := ini.Load(b)
|
||||
if err != nil {
|
||||
return nil, SharedConfigLoadError{Filename: filename}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// +build go1.5
|
||||
|
||||
package v4
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getURIPath(u *url.URL) string {
|
||||
var uri string
|
||||
|
||||
if len(u.Opaque) > 0 {
|
||||
uri = "/" + strings.Join(strings.Split(u.Opaque, "/")[3:], "/")
|
||||
} else {
|
||||
uri = u.EscapedPath()
|
||||
}
|
||||
|
||||
if len(uri) == 0 {
|
||||
uri = "/"
|
||||
}
|
||||
|
||||
return uri
|
||||
}
|
|
@ -2,6 +2,56 @@
|
|||
//
|
||||
// Provides request signing for request that need to be signed with
|
||||
// AWS V4 Signatures.
|
||||
//
|
||||
// Standalone Signer
|
||||
//
|
||||
// Generally using the signer outside of the SDK should not require any additional
|
||||
// logic when using Go v1.5 or higher. The signer does this by taking advantage
|
||||
// of the URL.EscapedPath method. If your request URI requires additional escaping
|
||||
// you many need to use the URL.Opaque to define what the raw URI should be sent
|
||||
// to the service as.
|
||||
//
|
||||
// The signer will first check the URL.Opaque field, and use its value if set.
|
||||
// The signer does require the URL.Opaque field to be set in the form of:
|
||||
//
|
||||
// "//<hostname>/<path>"
|
||||
//
|
||||
// // e.g.
|
||||
// "//example.com/some/path"
|
||||
//
|
||||
// The leading "//" and hostname are required or the URL.Opaque escaping will
|
||||
// not work correctly.
|
||||
//
|
||||
// If URL.Opaque is not set the signer will fallback to the URL.EscapedPath()
|
||||
// method and using the returned value. If you're using Go v1.4 you must set
|
||||
// URL.Opaque if the URI path needs escaping. If URL.Opaque is not set with
|
||||
// Go v1.5 the signer will fallback to URL.Path.
|
||||
//
|
||||
// AWS v4 signature validation requires that the canonical string's URI path
|
||||
// element must be the URI escaped form of the HTTP request's path.
|
||||
// http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
||||
//
|
||||
// The Go HTTP client will perform escaping automatically on the request. Some
|
||||
// of these escaping may cause signature validation errors because the HTTP
|
||||
// request differs from the URI path or query that the signature was generated.
|
||||
// https://golang.org/pkg/net/url/#URL.EscapedPath
|
||||
//
|
||||
// Because of this, it is recommended that when using the signer outside of the
|
||||
// SDK that explicitly escaping the request prior to being signed is preferable,
|
||||
// and will help prevent signature validation errors. This can be done by setting
|
||||
// the URL.Opaque or URL.RawPath. The SDK will use URL.Opaque first and then
|
||||
// call URL.EscapedPath() if Opaque is not set.
|
||||
//
|
||||
// If signing a request intended for HTTP2 server, and you're using Go 1.6.2
|
||||
// through 1.7.4 you should use the URL.RawPath as the pre-escaped form of the
|
||||
// request URL. https://github.com/golang/go/issues/16847 points to a bug in
|
||||
// Go pre 1.8 that failes to make HTTP2 requests using absolute URL in the HTTP
|
||||
// message. URL.Opaque generally will force Go to make requests with absolute URL.
|
||||
// URL.RawPath does not do this, but RawPath must be a valid escaping of Path
|
||||
// or url.EscapedPath will ignore the RawPath escaping.
|
||||
//
|
||||
// Test `TestStandaloneSign` provides a complete example of using the signer
|
||||
// outside of the SDK and pre-escaping the URI path.
|
||||
package v4
|
||||
|
||||
import (
|
||||
|
@ -11,6 +61,7 @@ import (
|
|||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
|
@ -38,6 +89,7 @@ var ignoredHeaders = rules{
|
|||
mapRule{
|
||||
"Authorization": struct{}{},
|
||||
"User-Agent": struct{}{},
|
||||
"X-Amzn-Trace-Id": struct{}{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -119,6 +171,25 @@ type Signer struct {
|
|||
// request's query string.
|
||||
DisableHeaderHoisting bool
|
||||
|
||||
// Disables the automatic escaping of the URI path of the request for the
|
||||
// siganture's canonical string's path. For services that do not need additional
|
||||
// escaping then use this to disable the signer escaping the path.
|
||||
//
|
||||
// S3 is an example of a service that does not need additional escaping.
|
||||
//
|
||||
// http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
||||
DisableURIPathEscaping bool
|
||||
|
||||
// Disales the automatical setting of the HTTP request's Body field with the
|
||||
// io.ReadSeeker passed in to the signer. This is useful if you're using a
|
||||
// custom wrapper around the body for the io.ReadSeeker and want to preserve
|
||||
// the Body value on the Request.Body.
|
||||
//
|
||||
// This does run the risk of signing a request with a body that will not be
|
||||
// sent in the request. Need to ensure that the underlying data of the Body
|
||||
// values are the same.
|
||||
DisableRequestBodyOverwrite bool
|
||||
|
||||
// currentTimeFn returns the time value which represents the current time.
|
||||
// This value should only be used for testing. If it is nil the default
|
||||
// time.Now will be used.
|
||||
|
@ -150,6 +221,8 @@ type signingCtx struct {
|
|||
ExpireTime time.Duration
|
||||
SignedHeaderVals http.Header
|
||||
|
||||
DisableURIPathEscaping bool
|
||||
|
||||
credValues credentials.Value
|
||||
isPresign bool
|
||||
formattedTime string
|
||||
|
@ -175,6 +248,12 @@ type signingCtx struct {
|
|||
// is not needed as the full request context will be captured by the http.Request
|
||||
// value. It is included for reference though.
|
||||
//
|
||||
// Sign will set the request's Body to be the `body` parameter passed in. If
|
||||
// the body is not already an io.ReadCloser, it will be wrapped within one. If
|
||||
// a `nil` body parameter passed to Sign, the request's Body field will be
|
||||
// also set to nil. Its important to note that this functionality will not
|
||||
// change the request's ContentLength of the request.
|
||||
//
|
||||
// Sign differs from Presign in that it will sign the request using HTTP
|
||||
// header values. This type of signing is intended for http.Request values that
|
||||
// will not be shared, or are shared in a way the header values on the request
|
||||
|
@ -237,14 +316,14 @@ func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, regi
|
|||
isPresign: exp != 0,
|
||||
ServiceName: service,
|
||||
Region: region,
|
||||
DisableURIPathEscaping: v4.DisableURIPathEscaping,
|
||||
}
|
||||
|
||||
for key := range ctx.Query {
|
||||
sort.Strings(ctx.Query[key])
|
||||
}
|
||||
|
||||
if ctx.isRequestSigned() {
|
||||
if !v4.Credentials.IsExpired() && currentTimeFn().Before(ctx.Time.Add(10*time.Minute)) {
|
||||
// If the request is already signed, and the credentials have not
|
||||
// expired, and the request is not too old ignore the signing request.
|
||||
return ctx.SignedHeaderVals, nil
|
||||
}
|
||||
ctx.Time = currentTimeFn()
|
||||
ctx.handlePresignRemoval()
|
||||
}
|
||||
|
@ -258,6 +337,20 @@ func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, regi
|
|||
ctx.assignAmzQueryValues()
|
||||
ctx.build(v4.DisableHeaderHoisting)
|
||||
|
||||
// If the request is not presigned the body should be attached to it. This
|
||||
// prevents the confusion of wanting to send a signed request without
|
||||
// the body the request was signed for attached.
|
||||
if !(v4.DisableRequestBodyOverwrite || ctx.isPresign) {
|
||||
var reader io.ReadCloser
|
||||
if body != nil {
|
||||
var ok bool
|
||||
if reader, ok = body.(io.ReadCloser); !ok {
|
||||
reader = ioutil.NopCloser(body)
|
||||
}
|
||||
}
|
||||
r.Body = reader
|
||||
}
|
||||
|
||||
if v4.Debug.Matches(aws.LogDebugWithSigning) {
|
||||
v4.logSigningInfo(ctx)
|
||||
}
|
||||
|
@ -338,6 +431,14 @@ func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time
|
|||
v4.Logger = req.Config.Logger
|
||||
v4.DisableHeaderHoisting = req.NotHoist
|
||||
v4.currentTimeFn = curTimeFn
|
||||
if name == "s3" {
|
||||
// S3 service should not have any escaping applied
|
||||
v4.DisableURIPathEscaping = true
|
||||
}
|
||||
// Prevents setting the HTTPRequest's Body. Since the Body could be
|
||||
// wrapped in a custom io.Closer that we do not want to be stompped
|
||||
// on top of by the signer.
|
||||
v4.DisableRequestBodyOverwrite = true
|
||||
})
|
||||
|
||||
signingTime := req.Time
|
||||
|
@ -345,7 +446,9 @@ func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time
|
|||
signingTime = req.LastSignedAt
|
||||
}
|
||||
|
||||
signedHeaders, err := v4.signWithBody(req.HTTPRequest, req.Body, name, region, req.ExpireTime, signingTime)
|
||||
signedHeaders, err := v4.signWithBody(req.HTTPRequest, req.GetBody(),
|
||||
name, region, req.ExpireTime, signingTime,
|
||||
)
|
||||
if err != nil {
|
||||
req.Error = err
|
||||
req.SignedHeaderVals = nil
|
||||
|
@ -356,7 +459,7 @@ func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time
|
|||
req.LastSignedAt = curTimeFn()
|
||||
}
|
||||
|
||||
const logSignInfoMsg = `DEBUG: Request Signiture:
|
||||
const logSignInfoMsg = `DEBUG: Request Signature:
|
||||
---[ CANONICAL STRING ]-----------------------------
|
||||
%s
|
||||
---[ STRING TO SIGN ]--------------------------------
|
||||
|
@ -492,17 +595,10 @@ func (ctx *signingCtx) buildCanonicalHeaders(r rule, header http.Header) {
|
|||
|
||||
func (ctx *signingCtx) buildCanonicalString() {
|
||||
ctx.Request.URL.RawQuery = strings.Replace(ctx.Query.Encode(), "+", "%20", -1)
|
||||
uri := ctx.Request.URL.Opaque
|
||||
if uri != "" {
|
||||
uri = "/" + strings.Join(strings.Split(uri, "/")[3:], "/")
|
||||
} else {
|
||||
uri = ctx.Request.URL.Path
|
||||
}
|
||||
if uri == "" {
|
||||
uri = "/"
|
||||
}
|
||||
|
||||
if ctx.ServiceName != "s3" {
|
||||
uri := getURIPath(ctx.Request.URL)
|
||||
|
||||
if !ctx.DisableURIPathEscaping {
|
||||
uri = rest.EscapePath(uri, false)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,13 @@ import (
|
|||
"sync"
|
||||
)
|
||||
|
||||
// ReadSeekCloser wraps a io.Reader returning a ReaderSeekerCloser
|
||||
// ReadSeekCloser wraps a io.Reader returning a ReaderSeekerCloser. Should
|
||||
// only be used with an io.Reader that is also an io.Seeker. Doing so may
|
||||
// cause request signature errors, or request body's not sent for GET, HEAD
|
||||
// and DELETE HTTP methods.
|
||||
//
|
||||
// Deprecated: Should only be used with io.ReadSeeker. If using for
|
||||
// S3 PutObject to stream content use s3manager.Uploader instead.
|
||||
func ReadSeekCloser(r io.Reader) ReaderSeekerCloser {
|
||||
return ReaderSeekerCloser{r}
|
||||
}
|
||||
|
@ -44,6 +50,12 @@ func (r ReaderSeekerCloser) Seek(offset int64, whence int) (int64, error) {
|
|||
return int64(0), nil
|
||||
}
|
||||
|
||||
// IsSeeker returns if the underlying reader is also a seeker.
|
||||
func (r ReaderSeekerCloser) IsSeeker() bool {
|
||||
_, ok := r.r.(io.Seeker)
|
||||
return ok
|
||||
}
|
||||
|
||||
// Close closes the ReaderSeekerCloser.
|
||||
//
|
||||
// If the ReaderSeekerCloser is not an io.Closer nothing will be done.
|
||||
|
@ -102,5 +114,5 @@ func (b *WriteAtBuffer) WriteAt(p []byte, pos int64) (n int, err error) {
|
|||
func (b *WriteAtBuffer) Bytes() []byte {
|
||||
b.m.Lock()
|
||||
defer b.m.Unlock()
|
||||
return b.buf[:len(b.buf):len(b.buf)]
|
||||
return b.buf
|
||||
}
|
||||
|
|
|
@ -5,4 +5,4 @@ package aws
|
|||
const SDKName = "aws-sdk-go"
|
||||
|
||||
// SDKVersion is the version of this SDK
|
||||
const SDKVersion = "1.4.6"
|
||||
const SDKVersion = "1.7.1"
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
// Package endpoints validates regional endpoints for services.
|
||||
package endpoints
|
||||
|
||||
//go:generate go run ../model/cli/gen-endpoints/main.go endpoints.json endpoints_map.go
|
||||
//go:generate gofmt -s -w endpoints_map.go
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NormalizeEndpoint takes and endpoint and service API information to return a
|
||||
// normalized endpoint and signing region. If the endpoint is not an empty string
|
||||
// the service name and region will be used to look up the service's API endpoint.
|
||||
// If the endpoint is provided the scheme will be added if it is not present.
|
||||
func NormalizeEndpoint(endpoint, serviceName, region string, disableSSL, useDualStack bool) (normEndpoint, signingRegion string) {
|
||||
if endpoint == "" {
|
||||
return EndpointForRegion(serviceName, region, disableSSL, useDualStack)
|
||||
}
|
||||
|
||||
return AddScheme(endpoint, disableSSL), ""
|
||||
}
|
||||
|
||||
// EndpointForRegion returns an endpoint and its signing region for a service and region.
|
||||
// if the service and region pair are not found endpoint and signingRegion will be empty.
|
||||
func EndpointForRegion(svcName, region string, disableSSL, useDualStack bool) (endpoint, signingRegion string) {
|
||||
dualStackField := ""
|
||||
if useDualStack {
|
||||
dualStackField = "/dualstack"
|
||||
}
|
||||
|
||||
derivedKeys := []string{
|
||||
region + "/" + svcName + dualStackField,
|
||||
region + "/*" + dualStackField,
|
||||
"*/" + svcName + dualStackField,
|
||||
"*/*" + dualStackField,
|
||||
}
|
||||
|
||||
for _, key := range derivedKeys {
|
||||
if val, ok := endpointsMap.Endpoints[key]; ok {
|
||||
ep := val.Endpoint
|
||||
ep = strings.Replace(ep, "{region}", region, -1)
|
||||
ep = strings.Replace(ep, "{service}", svcName, -1)
|
||||
|
||||
endpoint = ep
|
||||
signingRegion = val.SigningRegion
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return AddScheme(endpoint, disableSSL), signingRegion
|
||||
}
|
||||
|
||||
// Regular expression to determine if the endpoint string is prefixed with a scheme.
|
||||
var schemeRE = regexp.MustCompile("^([^:]+)://")
|
||||
|
||||
// AddScheme adds the HTTP or HTTPS schemes to a endpoint URL if there is no
|
||||
// scheme. If disableSSL is true HTTP will be added instead of the default HTTPS.
|
||||
func AddScheme(endpoint string, disableSSL bool) string {
|
||||
if endpoint != "" && !schemeRE.MatchString(endpoint) {
|
||||
scheme := "https"
|
||||
if disableSSL {
|
||||
scheme = "http"
|
||||
}
|
||||
endpoint = fmt.Sprintf("%s://%s", scheme, endpoint)
|
||||
}
|
||||
|
||||
return endpoint
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
{
|
||||
"version": 2,
|
||||
"endpoints": {
|
||||
"*/*": {
|
||||
"endpoint": "{service}.{region}.amazonaws.com"
|
||||
},
|
||||
"cn-north-1/*": {
|
||||
"endpoint": "{service}.{region}.amazonaws.com.cn",
|
||||
"signatureVersion": "v4"
|
||||
},
|
||||
"cn-north-1/ec2metadata": {
|
||||
"endpoint": "http://169.254.169.254/latest"
|
||||
},
|
||||
"us-gov-west-1/iam": {
|
||||
"endpoint": "iam.us-gov.amazonaws.com"
|
||||
},
|
||||
"us-gov-west-1/sts": {
|
||||
"endpoint": "sts.us-gov-west-1.amazonaws.com"
|
||||
},
|
||||
"us-gov-west-1/s3": {
|
||||
"endpoint": "s3-{region}.amazonaws.com"
|
||||
},
|
||||
"us-gov-west-1/ec2metadata": {
|
||||
"endpoint": "http://169.254.169.254/latest"
|
||||
},
|
||||
"*/cloudfront": {
|
||||
"endpoint": "cloudfront.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"*/cloudsearchdomain": {
|
||||
"endpoint": "",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"*/data.iot": {
|
||||
"endpoint": "",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"*/ec2metadata": {
|
||||
"endpoint": "http://169.254.169.254/latest"
|
||||
},
|
||||
"*/iam": {
|
||||
"endpoint": "iam.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"*/importexport": {
|
||||
"endpoint": "importexport.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"*/route53": {
|
||||
"endpoint": "route53.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"*/sts": {
|
||||
"endpoint": "sts.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"*/waf": {
|
||||
"endpoint": "waf.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"us-east-1/sdb": {
|
||||
"endpoint": "sdb.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"*/s3": {
|
||||
"endpoint": "s3-{region}.amazonaws.com"
|
||||
},
|
||||
"*/s3/dualstack": {
|
||||
"endpoint": "s3.dualstack.{region}.amazonaws.com"
|
||||
},
|
||||
"us-east-1/s3": {
|
||||
"endpoint": "s3.amazonaws.com"
|
||||
},
|
||||
"eu-central-1/s3": {
|
||||
"endpoint": "{service}.{region}.amazonaws.com"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
package endpoints
|
||||
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
|
||||
type endpointStruct struct {
|
||||
Version int
|
||||
Endpoints map[string]endpointEntry
|
||||
}
|
||||
|
||||
type endpointEntry struct {
|
||||
Endpoint string
|
||||
SigningRegion string
|
||||
}
|
||||
|
||||
var endpointsMap = endpointStruct{
|
||||
Version: 2,
|
||||
Endpoints: map[string]endpointEntry{
|
||||
"*/*": {
|
||||
Endpoint: "{service}.{region}.amazonaws.com",
|
||||
},
|
||||
"*/cloudfront": {
|
||||
Endpoint: "cloudfront.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"*/cloudsearchdomain": {
|
||||
Endpoint: "",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"*/data.iot": {
|
||||
Endpoint: "",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"*/ec2metadata": {
|
||||
Endpoint: "http://169.254.169.254/latest",
|
||||
},
|
||||
"*/iam": {
|
||||
Endpoint: "iam.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"*/importexport": {
|
||||
Endpoint: "importexport.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"*/route53": {
|
||||
Endpoint: "route53.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"*/s3": {
|
||||
Endpoint: "s3-{region}.amazonaws.com",
|
||||
},
|
||||
"*/s3/dualstack": {
|
||||
Endpoint: "s3.dualstack.{region}.amazonaws.com",
|
||||
},
|
||||
"*/sts": {
|
||||
Endpoint: "sts.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"*/waf": {
|
||||
Endpoint: "waf.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"cn-north-1/*": {
|
||||
Endpoint: "{service}.{region}.amazonaws.com.cn",
|
||||
},
|
||||
"cn-north-1/ec2metadata": {
|
||||
Endpoint: "http://169.254.169.254/latest",
|
||||
},
|
||||
"eu-central-1/s3": {
|
||||
Endpoint: "{service}.{region}.amazonaws.com",
|
||||
},
|
||||
"us-east-1/s3": {
|
||||
Endpoint: "s3.amazonaws.com",
|
||||
},
|
||||
"us-east-1/sdb": {
|
||||
Endpoint: "sdb.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"us-gov-west-1/ec2metadata": {
|
||||
Endpoint: "http://169.254.169.254/latest",
|
||||
},
|
||||
"us-gov-west-1/iam": {
|
||||
Endpoint: "iam.us-gov.amazonaws.com",
|
||||
},
|
||||
"us-gov-west-1/s3": {
|
||||
Endpoint: "s3-{region}.amazonaws.com",
|
||||
},
|
||||
"us-gov-west-1/sts": {
|
||||
Endpoint: "sts.us-gov-west-1.amazonaws.com",
|
||||
},
|
||||
},
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
// Package ec2query provides serialization of AWS EC2 requests and responses.
|
||||
package ec2query
|
||||
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/ec2.json build_test.go
|
||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/ec2.json build_test.go
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package ec2query
|
||||
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/ec2.json unmarshal_test.go
|
||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/ec2.json unmarshal_test.go
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
|
|
@ -4,7 +4,9 @@ package jsonutil
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
@ -25,6 +27,7 @@ func BuildJSON(v interface{}) ([]byte, error) {
|
|||
}
|
||||
|
||||
func buildAny(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error {
|
||||
origVal := value
|
||||
value = reflect.Indirect(value)
|
||||
if !value.IsValid() {
|
||||
return nil
|
||||
|
@ -61,7 +64,7 @@ func buildAny(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) err
|
|||
case "map":
|
||||
return buildMap(value, buf, tag)
|
||||
default:
|
||||
return buildScalar(value, buf, tag)
|
||||
return buildScalar(origVal, buf, tag)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,6 +90,10 @@ func buildStruct(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag)
|
|||
first := true
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
member := value.Field(i)
|
||||
|
||||
// This allocates the most memory.
|
||||
// Additionally, we cannot skip nil fields due to
|
||||
// idempotency auto filling.
|
||||
field := t.Field(i)
|
||||
|
||||
if field.PkgPath != "" {
|
||||
|
@ -98,6 +105,9 @@ func buildStruct(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag)
|
|||
if field.Tag.Get("location") != "" {
|
||||
continue // ignore non-body elements
|
||||
}
|
||||
if field.Tag.Get("ignore") != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if protocol.CanSetIdempotencyToken(member, field) {
|
||||
token := protocol.GetIdempotencyToken()
|
||||
|
@ -179,21 +189,32 @@ func buildMap(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) err
|
|||
return nil
|
||||
}
|
||||
|
||||
func buildScalar(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error {
|
||||
switch value.Kind() {
|
||||
func buildScalar(v reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error {
|
||||
// prevents allocation on the heap.
|
||||
scratch := [64]byte{}
|
||||
switch value := reflect.Indirect(v); value.Kind() {
|
||||
case reflect.String:
|
||||
writeString(value.String(), buf)
|
||||
case reflect.Bool:
|
||||
buf.WriteString(strconv.FormatBool(value.Bool()))
|
||||
if value.Bool() {
|
||||
buf.WriteString("true")
|
||||
} else {
|
||||
buf.WriteString("false")
|
||||
}
|
||||
case reflect.Int64:
|
||||
buf.WriteString(strconv.FormatInt(value.Int(), 10))
|
||||
buf.Write(strconv.AppendInt(scratch[:0], value.Int(), 10))
|
||||
case reflect.Float64:
|
||||
buf.WriteString(strconv.FormatFloat(value.Float(), 'f', -1, 64))
|
||||
f := value.Float()
|
||||
if math.IsInf(f, 0) || math.IsNaN(f) {
|
||||
return &json.UnsupportedValueError{Value: v, Str: strconv.FormatFloat(f, 'f', -1, 64)}
|
||||
}
|
||||
buf.Write(strconv.AppendFloat(scratch[:0], f, 'f', -1, 64))
|
||||
default:
|
||||
switch value.Type() {
|
||||
case timeType:
|
||||
converted := value.Interface().(time.Time)
|
||||
buf.WriteString(strconv.FormatInt(converted.UTC().Unix(), 10))
|
||||
converted := v.Interface().(*time.Time)
|
||||
|
||||
buf.Write(strconv.AppendInt(scratch[:0], converted.UTC().Unix(), 10))
|
||||
case byteSliceType:
|
||||
if !value.IsNil() {
|
||||
converted := value.Interface().([]byte)
|
||||
|
@ -219,27 +240,31 @@ func buildScalar(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag)
|
|||
return nil
|
||||
}
|
||||
|
||||
var hex = "0123456789abcdef"
|
||||
|
||||
func writeString(s string, buf *bytes.Buffer) {
|
||||
buf.WriteByte('"')
|
||||
for _, r := range s {
|
||||
if r == '"' {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == '"' {
|
||||
buf.WriteString(`\"`)
|
||||
} else if r == '\\' {
|
||||
} else if s[i] == '\\' {
|
||||
buf.WriteString(`\\`)
|
||||
} else if r == '\b' {
|
||||
} else if s[i] == '\b' {
|
||||
buf.WriteString(`\b`)
|
||||
} else if r == '\f' {
|
||||
} else if s[i] == '\f' {
|
||||
buf.WriteString(`\f`)
|
||||
} else if r == '\r' {
|
||||
} else if s[i] == '\r' {
|
||||
buf.WriteString(`\r`)
|
||||
} else if r == '\t' {
|
||||
} else if s[i] == '\t' {
|
||||
buf.WriteString(`\t`)
|
||||
} else if r == '\n' {
|
||||
} else if s[i] == '\n' {
|
||||
buf.WriteString(`\n`)
|
||||
} else if r < 32 {
|
||||
fmt.Fprintf(buf, "\\u%0.4x", r)
|
||||
} else if s[i] < 32 {
|
||||
buf.WriteString("\\u00")
|
||||
buf.WriteByte(hex[s[i]>>4])
|
||||
buf.WriteByte(hex[s[i]&0xF])
|
||||
} else {
|
||||
buf.WriteRune(r)
|
||||
buf.WriteByte(s[i])
|
||||
}
|
||||
}
|
||||
buf.WriteByte('"')
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
// requests and responses.
|
||||
package jsonrpc
|
||||
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/json.json build_test.go
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/json.json unmarshal_test.go
|
||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/json.json build_test.go
|
||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/json.json unmarshal_test.go
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Package query provides serialization of AWS query requests, and responses.
|
||||
package query
|
||||
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/query.json build_test.go
|
||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/query.json build_test.go
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
|
|
@ -76,6 +76,10 @@ func (q *queryParser) parseStruct(v url.Values, value reflect.Value, prefix stri
|
|||
if field.PkgPath != "" {
|
||||
continue // ignore unexported fields
|
||||
}
|
||||
if field.Tag.Get("ignore") != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
if protocol.CanSetIdempotencyToken(value.Field(i), field) {
|
||||
token := protocol.GetIdempotencyToken()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package query
|
||||
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/query.json unmarshal_test.go
|
||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/query.json unmarshal_test.go
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
@ -46,14 +47,29 @@ var BuildHandler = request.NamedHandler{Name: "awssdk.rest.Build", Fn: Build}
|
|||
func Build(r *request.Request) {
|
||||
if r.ParamsFilled() {
|
||||
v := reflect.ValueOf(r.Params).Elem()
|
||||
buildLocationElements(r, v)
|
||||
buildLocationElements(r, v, false)
|
||||
buildBody(r, v)
|
||||
}
|
||||
}
|
||||
|
||||
func buildLocationElements(r *request.Request, v reflect.Value) {
|
||||
// BuildAsGET builds the REST component of a service request with the ability to hoist
|
||||
// data from the body.
|
||||
func BuildAsGET(r *request.Request) {
|
||||
if r.ParamsFilled() {
|
||||
v := reflect.ValueOf(r.Params).Elem()
|
||||
buildLocationElements(r, v, true)
|
||||
buildBody(r, v)
|
||||
}
|
||||
}
|
||||
|
||||
func buildLocationElements(r *request.Request, v reflect.Value, buildGETQuery bool) {
|
||||
query := r.HTTPRequest.URL.Query()
|
||||
|
||||
// Setup the raw path to match the base path pattern. This is needed
|
||||
// so that when the path is mutated a custom escaped version can be
|
||||
// stored in RawPath that will be used by the Go client.
|
||||
r.HTTPRequest.URL.RawPath = r.HTTPRequest.URL.Path
|
||||
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
m := v.Field(i)
|
||||
if n := v.Type().Field(i).Name; n[0:1] == strings.ToLower(n[0:1]) {
|
||||
|
@ -72,6 +88,9 @@ func buildLocationElements(r *request.Request, v reflect.Value) {
|
|||
if !m.IsValid() {
|
||||
continue
|
||||
}
|
||||
if field.Tag.Get("ignore") != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
var err error
|
||||
switch field.Tag.Get("location") {
|
||||
|
@ -83,6 +102,10 @@ func buildLocationElements(r *request.Request, v reflect.Value) {
|
|||
err = buildURI(r.HTTPRequest.URL, m, name)
|
||||
case "querystring":
|
||||
err = buildQueryString(query, m, name)
|
||||
default:
|
||||
if buildGETQuery {
|
||||
err = buildQueryString(query, m, name)
|
||||
}
|
||||
}
|
||||
r.Error = err
|
||||
}
|
||||
|
@ -92,7 +115,9 @@ func buildLocationElements(r *request.Request, v reflect.Value) {
|
|||
}
|
||||
|
||||
r.HTTPRequest.URL.RawQuery = query.Encode()
|
||||
updatePath(r.HTTPRequest.URL, r.HTTPRequest.URL.Path)
|
||||
if !aws.BoolValue(r.Config.DisableRestProtocolURICleaning) {
|
||||
cleanPath(r.HTTPRequest.URL)
|
||||
}
|
||||
}
|
||||
|
||||
func buildBody(r *request.Request, v reflect.Value) {
|
||||
|
@ -156,10 +181,11 @@ func buildURI(u *url.URL, v reflect.Value, name string) error {
|
|||
return awserr.New("SerializationError", "failed to encode REST request", err)
|
||||
}
|
||||
|
||||
uri := u.Path
|
||||
uri = strings.Replace(uri, "{"+name+"}", EscapePath(value, true), -1)
|
||||
uri = strings.Replace(uri, "{"+name+"+}", EscapePath(value, false), -1)
|
||||
u.Path = uri
|
||||
u.Path = strings.Replace(u.Path, "{"+name+"}", value, -1)
|
||||
u.Path = strings.Replace(u.Path, "{"+name+"+}", value, -1)
|
||||
|
||||
u.RawPath = strings.Replace(u.RawPath, "{"+name+"}", EscapePath(value, true), -1)
|
||||
u.RawPath = strings.Replace(u.RawPath, "{"+name+"+}", EscapePath(value, false), -1)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -193,25 +219,17 @@ func buildQueryString(query url.Values, v reflect.Value, name string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func updatePath(url *url.URL, urlPath string) {
|
||||
scheme, query := url.Scheme, url.RawQuery
|
||||
func cleanPath(u *url.URL) {
|
||||
hasSlash := strings.HasSuffix(u.Path, "/")
|
||||
|
||||
hasSlash := strings.HasSuffix(urlPath, "/")
|
||||
// clean up path, removing duplicate `/`
|
||||
u.Path = path.Clean(u.Path)
|
||||
u.RawPath = path.Clean(u.RawPath)
|
||||
|
||||
// clean up path
|
||||
urlPath = path.Clean(urlPath)
|
||||
if hasSlash && !strings.HasSuffix(urlPath, "/") {
|
||||
urlPath += "/"
|
||||
if hasSlash && !strings.HasSuffix(u.Path, "/") {
|
||||
u.Path += "/"
|
||||
u.RawPath += "/"
|
||||
}
|
||||
|
||||
// get formatted URL minus scheme so we can build this into Opaque
|
||||
url.Scheme, url.Path, url.RawQuery = "", "", ""
|
||||
s := url.String()
|
||||
url.Scheme = scheme
|
||||
url.RawQuery = query
|
||||
|
||||
// build opaque URI
|
||||
url.Opaque = s + urlPath
|
||||
}
|
||||
|
||||
// EscapePath escapes part of a URL path in Amazon style
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -11,7 +12,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
@ -70,10 +70,16 @@ func unmarshalBody(r *request.Request, v reflect.Value) {
|
|||
}
|
||||
default:
|
||||
switch payload.Type().String() {
|
||||
case "io.ReadSeeker":
|
||||
payload.Set(reflect.ValueOf(aws.ReadSeekCloser(r.HTTPResponse.Body)))
|
||||
case "aws.ReadSeekCloser", "io.ReadCloser":
|
||||
case "io.ReadCloser":
|
||||
payload.Set(reflect.ValueOf(r.HTTPResponse.Body))
|
||||
case "io.ReadSeeker":
|
||||
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
||||
if err != nil {
|
||||
r.Error = awserr.New("SerializationError",
|
||||
"failed to read response body", err)
|
||||
return
|
||||
}
|
||||
payload.Set(reflect.ValueOf(ioutil.NopCloser(bytes.NewReader(b))))
|
||||
default:
|
||||
io.Copy(ioutil.Discard, r.HTTPResponse.Body)
|
||||
defer r.HTTPResponse.Body.Close()
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
// requests and responses.
|
||||
package restxml
|
||||
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/rest-xml.json build_test.go
|
||||
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/rest-xml.json unmarshal_test.go
|
||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/rest-xml.json build_test.go
|
||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/rest-xml.json unmarshal_test.go
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
|
|
@ -127,6 +127,10 @@ func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag refl
|
|||
if field.PkgPath != "" {
|
||||
continue // ignore unexported fields
|
||||
}
|
||||
if field.Tag.Get("ignore") != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
mTag := field.Tag
|
||||
if mTag.Get("location") != "" { // skip non-body members
|
||||
|
|
|
@ -111,11 +111,8 @@ func parseStruct(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
|
|||
elems := node.Children[name]
|
||||
|
||||
if elems == nil { // try to find the field in attributes
|
||||
for _, a := range node.Attr {
|
||||
if name == a.Name.Local {
|
||||
// turn this into a text node for de-serializing
|
||||
elems = []*XMLNode{{Text: a.Value}}
|
||||
}
|
||||
if val, ok := node.findElem(name); ok {
|
||||
elems = []*XMLNode{{Text: val}}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
37
vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go
generated
vendored
37
vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go
generated
vendored
|
@ -2,6 +2,7 @@ package xmlutil
|
|||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
)
|
||||
|
@ -12,6 +13,9 @@ type XMLNode struct {
|
|||
Children map[string][]*XMLNode `json:",omitempty"`
|
||||
Text string `json:",omitempty"`
|
||||
Attr []xml.Attr `json:",omitempty"`
|
||||
|
||||
namespaces map[string]string
|
||||
parent *XMLNode
|
||||
}
|
||||
|
||||
// NewXMLElement returns a pointer to a new XMLNode initialized to default values.
|
||||
|
@ -59,21 +63,54 @@ func XMLToStruct(d *xml.Decoder, s *xml.StartElement) (*XMLNode, error) {
|
|||
slice = []*XMLNode{}
|
||||
}
|
||||
node, e := XMLToStruct(d, &el)
|
||||
out.findNamespaces()
|
||||
if e != nil {
|
||||
return out, e
|
||||
}
|
||||
node.Name = typed.Name
|
||||
node.findNamespaces()
|
||||
tempOut := *out
|
||||
// Save into a temp variable, simply because out gets squashed during
|
||||
// loop iterations
|
||||
node.parent = &tempOut
|
||||
slice = append(slice, node)
|
||||
out.Children[name] = slice
|
||||
case xml.EndElement:
|
||||
if s != nil && s.Name.Local == typed.Name.Local { // matching end token
|
||||
return out, nil
|
||||
}
|
||||
out = &XMLNode{}
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (n *XMLNode) findNamespaces() {
|
||||
ns := map[string]string{}
|
||||
for _, a := range n.Attr {
|
||||
if a.Name.Space == "xmlns" {
|
||||
ns[a.Value] = a.Name.Local
|
||||
}
|
||||
}
|
||||
|
||||
n.namespaces = ns
|
||||
}
|
||||
|
||||
func (n *XMLNode) findElem(name string) (string, bool) {
|
||||
for node := n; node != nil; node = node.parent {
|
||||
for _, a := range node.Attr {
|
||||
namespace := a.Name.Space
|
||||
if v, ok := node.namespaces[namespace]; ok {
|
||||
namespace = v
|
||||
}
|
||||
if name == fmt.Sprintf("%s:%s", namespace, a.Name.Local) {
|
||||
return a.Value, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// StructToXML writes an XMLNode to a xml.Encoder as tokens.
|
||||
func StructToXML(e *xml.Encoder, node *XMLNode, sorted bool) error {
|
||||
e.EncodeToken(xml.StartElement{Name: node.Name, Attr: node.Attr})
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
// Package sdk is the official AWS SDK for the Go programming language.
|
||||
//
|
||||
// See our Developer Guide for information for on getting started and using
|
||||
// the SDK.
|
||||
//
|
||||
// https://github.com/aws/aws-sdk-go/wiki
|
||||
package sdk
|
File diff suppressed because it is too large
Load Diff
|
@ -5,8 +5,8 @@ import (
|
|||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/endpoints"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -39,12 +39,20 @@ func fillPresignedURL(r *request.Request) {
|
|||
WithRegion(aws.StringValue(origParams.SourceRegion)))
|
||||
|
||||
clientInfo := r.ClientInfo
|
||||
clientInfo.Endpoint, clientInfo.SigningRegion = endpoints.EndpointForRegion(
|
||||
clientInfo.ServiceName,
|
||||
aws.StringValue(cfg.Region),
|
||||
aws.BoolValue(cfg.DisableSSL),
|
||||
aws.BoolValue(cfg.UseDualStack),
|
||||
resolved, err := r.Config.EndpointResolver.EndpointFor(
|
||||
clientInfo.ServiceName, aws.StringValue(cfg.Region),
|
||||
func(opt *endpoints.Options) {
|
||||
opt.DisableSSL = aws.BoolValue(cfg.DisableSSL)
|
||||
opt.UseDualStack = aws.BoolValue(cfg.UseDualStack)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
r.Error = err
|
||||
return
|
||||
}
|
||||
|
||||
clientInfo.Endpoint = resolved.URL
|
||||
clientInfo.SigningRegion = resolved.SigningRegion
|
||||
|
||||
// Presign a CopySnapshot request with modified params
|
||||
req := request.New(*cfg, clientInfo, r.Handlers, r.Retryer, r.Operation, newParams, r.Data)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
|
||||
package ec2
|
|
@ -15,8 +15,9 @@ import (
|
|||
// in the Amazon Web Services (AWS) cloud. Using Amazon EC2 eliminates your
|
||||
// need to invest in hardware up front, so you can develop and deploy applications
|
||||
// faster.
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15
|
||||
type EC2 struct {
|
||||
*client.Client
|
||||
}
|
||||
|
@ -27,8 +28,11 @@ var initClient func(*client.Client)
|
|||
// Used for custom request initialization logic
|
||||
var initRequest func(*request.Request)
|
||||
|
||||
// A ServiceName is the name of the service the client will make API calls to.
|
||||
const ServiceName = "ec2"
|
||||
// Service information constants
|
||||
const (
|
||||
ServiceName = "ec2" // Service endpoint prefix API calls made to.
|
||||
EndpointsID = ServiceName // Service ID for Regions and Endpoints metadata.
|
||||
)
|
||||
|
||||
// New creates a new instance of the EC2 client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
|
@ -41,20 +45,21 @@ const ServiceName = "ec2"
|
|||
// // Create a EC2 client with additional configuration
|
||||
// svc := ec2.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2 {
|
||||
c := p.ClientConfig(ServiceName, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
c := p.ClientConfig(EndpointsID, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *EC2 {
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *EC2 {
|
||||
svc := &EC2{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: ServiceName,
|
||||
SigningName: signingName,
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2016-04-01",
|
||||
APIVersion: "2016-11-15",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
|
|
|
@ -6,6 +6,10 @@ import (
|
|||
"github.com/aws/aws-sdk-go/private/waiter"
|
||||
)
|
||||
|
||||
// WaitUntilBundleTaskComplete uses the Amazon EC2 API operation
|
||||
// DescribeBundleTasks to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilBundleTaskComplete(input *DescribeBundleTasksInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeBundleTasks",
|
||||
|
@ -35,6 +39,10 @@ func (c *EC2) WaitUntilBundleTaskComplete(input *DescribeBundleTasksInput) error
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilConversionTaskCancelled uses the Amazon EC2 API operation
|
||||
// DescribeConversionTasks to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilConversionTaskCancelled(input *DescribeConversionTasksInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeConversionTasks",
|
||||
|
@ -58,6 +66,10 @@ func (c *EC2) WaitUntilConversionTaskCancelled(input *DescribeConversionTasksInp
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilConversionTaskCompleted uses the Amazon EC2 API operation
|
||||
// DescribeConversionTasks to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilConversionTaskCompleted(input *DescribeConversionTasksInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeConversionTasks",
|
||||
|
@ -93,6 +105,10 @@ func (c *EC2) WaitUntilConversionTaskCompleted(input *DescribeConversionTasksInp
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilConversionTaskDeleted uses the Amazon EC2 API operation
|
||||
// DescribeConversionTasks to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilConversionTaskDeleted(input *DescribeConversionTasksInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeConversionTasks",
|
||||
|
@ -116,6 +132,10 @@ func (c *EC2) WaitUntilConversionTaskDeleted(input *DescribeConversionTasksInput
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilCustomerGatewayAvailable uses the Amazon EC2 API operation
|
||||
// DescribeCustomerGateways to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilCustomerGatewayAvailable(input *DescribeCustomerGatewaysInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeCustomerGateways",
|
||||
|
@ -151,6 +171,10 @@ func (c *EC2) WaitUntilCustomerGatewayAvailable(input *DescribeCustomerGatewaysI
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilExportTaskCancelled uses the Amazon EC2 API operation
|
||||
// DescribeExportTasks to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilExportTaskCancelled(input *DescribeExportTasksInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeExportTasks",
|
||||
|
@ -174,6 +198,10 @@ func (c *EC2) WaitUntilExportTaskCancelled(input *DescribeExportTasksInput) erro
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilExportTaskCompleted uses the Amazon EC2 API operation
|
||||
// DescribeExportTasks to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilExportTaskCompleted(input *DescribeExportTasksInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeExportTasks",
|
||||
|
@ -197,6 +225,10 @@ func (c *EC2) WaitUntilExportTaskCompleted(input *DescribeExportTasksInput) erro
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilImageAvailable uses the Amazon EC2 API operation
|
||||
// DescribeImages to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilImageAvailable(input *DescribeImagesInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeImages",
|
||||
|
@ -226,6 +258,10 @@ func (c *EC2) WaitUntilImageAvailable(input *DescribeImagesInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilImageExists uses the Amazon EC2 API operation
|
||||
// DescribeImages to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilImageExists(input *DescribeImagesInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeImages",
|
||||
|
@ -255,6 +291,10 @@ func (c *EC2) WaitUntilImageExists(input *DescribeImagesInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilInstanceExists uses the Amazon EC2 API operation
|
||||
// DescribeInstances to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilInstanceExists(input *DescribeInstancesInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeInstances",
|
||||
|
@ -284,6 +324,10 @@ func (c *EC2) WaitUntilInstanceExists(input *DescribeInstancesInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilInstanceRunning uses the Amazon EC2 API operation
|
||||
// DescribeInstances to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilInstanceRunning(input *DescribeInstancesInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeInstances",
|
||||
|
@ -331,6 +375,10 @@ func (c *EC2) WaitUntilInstanceRunning(input *DescribeInstancesInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilInstanceStatusOk uses the Amazon EC2 API operation
|
||||
// DescribeInstanceStatus to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilInstanceStatusOk(input *DescribeInstanceStatusInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeInstanceStatus",
|
||||
|
@ -360,6 +408,10 @@ func (c *EC2) WaitUntilInstanceStatusOk(input *DescribeInstanceStatusInput) erro
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilInstanceStopped uses the Amazon EC2 API operation
|
||||
// DescribeInstances to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilInstanceStopped(input *DescribeInstancesInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeInstances",
|
||||
|
@ -395,6 +447,10 @@ func (c *EC2) WaitUntilInstanceStopped(input *DescribeInstancesInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilInstanceTerminated uses the Amazon EC2 API operation
|
||||
// DescribeInstances to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilInstanceTerminated(input *DescribeInstancesInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeInstances",
|
||||
|
@ -430,6 +486,10 @@ func (c *EC2) WaitUntilInstanceTerminated(input *DescribeInstancesInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilKeyPairExists uses the Amazon EC2 API operation
|
||||
// DescribeKeyPairs to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilKeyPairExists(input *DescribeKeyPairsInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeKeyPairs",
|
||||
|
@ -438,7 +498,7 @@ func (c *EC2) WaitUntilKeyPairExists(input *DescribeKeyPairsInput) error {
|
|||
Acceptors: []waiter.WaitAcceptor{
|
||||
{
|
||||
State: "success",
|
||||
Matcher: "pathAll",
|
||||
Matcher: "path",
|
||||
Argument: "length(KeyPairs[].KeyName) > `0`",
|
||||
Expected: true,
|
||||
},
|
||||
|
@ -459,6 +519,10 @@ func (c *EC2) WaitUntilKeyPairExists(input *DescribeKeyPairsInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilNatGatewayAvailable uses the Amazon EC2 API operation
|
||||
// DescribeNatGateways to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilNatGatewayAvailable(input *DescribeNatGatewaysInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeNatGateways",
|
||||
|
@ -506,6 +570,10 @@ func (c *EC2) WaitUntilNatGatewayAvailable(input *DescribeNatGatewaysInput) erro
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilNetworkInterfaceAvailable uses the Amazon EC2 API operation
|
||||
// DescribeNetworkInterfaces to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilNetworkInterfaceAvailable(input *DescribeNetworkInterfacesInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeNetworkInterfaces",
|
||||
|
@ -535,6 +603,10 @@ func (c *EC2) WaitUntilNetworkInterfaceAvailable(input *DescribeNetworkInterface
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilPasswordDataAvailable uses the Amazon EC2 API operation
|
||||
// GetPasswordData to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilPasswordDataAvailable(input *GetPasswordDataInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "GetPasswordData",
|
||||
|
@ -558,6 +630,10 @@ func (c *EC2) WaitUntilPasswordDataAvailable(input *GetPasswordDataInput) error
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilSnapshotCompleted uses the Amazon EC2 API operation
|
||||
// DescribeSnapshots to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilSnapshotCompleted(input *DescribeSnapshotsInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeSnapshots",
|
||||
|
@ -581,6 +657,10 @@ func (c *EC2) WaitUntilSnapshotCompleted(input *DescribeSnapshotsInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilSpotInstanceRequestFulfilled uses the Amazon EC2 API operation
|
||||
// DescribeSpotInstanceRequests to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilSpotInstanceRequestFulfilled(input *DescribeSpotInstanceRequestsInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeSpotInstanceRequests",
|
||||
|
@ -628,6 +708,10 @@ func (c *EC2) WaitUntilSpotInstanceRequestFulfilled(input *DescribeSpotInstanceR
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilSubnetAvailable uses the Amazon EC2 API operation
|
||||
// DescribeSubnets to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilSubnetAvailable(input *DescribeSubnetsInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeSubnets",
|
||||
|
@ -651,6 +735,10 @@ func (c *EC2) WaitUntilSubnetAvailable(input *DescribeSubnetsInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilSystemStatusOk uses the Amazon EC2 API operation
|
||||
// DescribeInstanceStatus to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilSystemStatusOk(input *DescribeInstanceStatusInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeInstanceStatus",
|
||||
|
@ -674,6 +762,10 @@ func (c *EC2) WaitUntilSystemStatusOk(input *DescribeInstanceStatusInput) error
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilVolumeAvailable uses the Amazon EC2 API operation
|
||||
// DescribeVolumes to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilVolumeAvailable(input *DescribeVolumesInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeVolumes",
|
||||
|
@ -703,6 +795,10 @@ func (c *EC2) WaitUntilVolumeAvailable(input *DescribeVolumesInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilVolumeDeleted uses the Amazon EC2 API operation
|
||||
// DescribeVolumes to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilVolumeDeleted(input *DescribeVolumesInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeVolumes",
|
||||
|
@ -732,6 +828,10 @@ func (c *EC2) WaitUntilVolumeDeleted(input *DescribeVolumesInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilVolumeInUse uses the Amazon EC2 API operation
|
||||
// DescribeVolumes to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilVolumeInUse(input *DescribeVolumesInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeVolumes",
|
||||
|
@ -761,6 +861,10 @@ func (c *EC2) WaitUntilVolumeInUse(input *DescribeVolumesInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilVpcAvailable uses the Amazon EC2 API operation
|
||||
// DescribeVpcs to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilVpcAvailable(input *DescribeVpcsInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeVpcs",
|
||||
|
@ -784,6 +888,10 @@ func (c *EC2) WaitUntilVpcAvailable(input *DescribeVpcsInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilVpcExists uses the Amazon EC2 API operation
|
||||
// DescribeVpcs to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilVpcExists(input *DescribeVpcsInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeVpcs",
|
||||
|
@ -813,6 +921,43 @@ func (c *EC2) WaitUntilVpcExists(input *DescribeVpcsInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilVpcPeeringConnectionDeleted uses the Amazon EC2 API operation
|
||||
// DescribeVpcPeeringConnections to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilVpcPeeringConnectionDeleted(input *DescribeVpcPeeringConnectionsInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeVpcPeeringConnections",
|
||||
Delay: 15,
|
||||
MaxAttempts: 40,
|
||||
Acceptors: []waiter.WaitAcceptor{
|
||||
{
|
||||
State: "success",
|
||||
Matcher: "pathAll",
|
||||
Argument: "VpcPeeringConnections[].Status.Code",
|
||||
Expected: "deleted",
|
||||
},
|
||||
{
|
||||
State: "success",
|
||||
Matcher: "error",
|
||||
Argument: "",
|
||||
Expected: "InvalidVpcPeeringConnectionID.NotFound",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
w := waiter.Waiter{
|
||||
Client: c,
|
||||
Input: input,
|
||||
Config: waiterCfg,
|
||||
}
|
||||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilVpcPeeringConnectionExists uses the Amazon EC2 API operation
|
||||
// DescribeVpcPeeringConnections to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilVpcPeeringConnectionExists(input *DescribeVpcPeeringConnectionsInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeVpcPeeringConnections",
|
||||
|
@ -842,6 +987,10 @@ func (c *EC2) WaitUntilVpcPeeringConnectionExists(input *DescribeVpcPeeringConne
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilVpnConnectionAvailable uses the Amazon EC2 API operation
|
||||
// DescribeVpnConnections to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilVpnConnectionAvailable(input *DescribeVpnConnectionsInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeVpnConnections",
|
||||
|
@ -877,6 +1026,10 @@ func (c *EC2) WaitUntilVpnConnectionAvailable(input *DescribeVpnConnectionsInput
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilVpnConnectionDeleted uses the Amazon EC2 API operation
|
||||
// DescribeVpnConnections to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *EC2) WaitUntilVpnConnectionDeleted(input *DescribeVpnConnectionsInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "DescribeVpnConnections",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,121 @@
|
|||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
|
||||
package ecr
|
||||
|
||||
const (
|
||||
|
||||
// ErrCodeEmptyUploadException for service response error code
|
||||
// "EmptyUploadException".
|
||||
//
|
||||
// The specified layer upload does not contain any layer parts.
|
||||
ErrCodeEmptyUploadException = "EmptyUploadException"
|
||||
|
||||
// ErrCodeImageAlreadyExistsException for service response error code
|
||||
// "ImageAlreadyExistsException".
|
||||
//
|
||||
// The specified image has already been pushed, and there are no changes to
|
||||
// the manifest or image tag since the last push.
|
||||
ErrCodeImageAlreadyExistsException = "ImageAlreadyExistsException"
|
||||
|
||||
// ErrCodeImageNotFoundException for service response error code
|
||||
// "ImageNotFoundException".
|
||||
//
|
||||
// The image requested does not exist in the specified repository.
|
||||
ErrCodeImageNotFoundException = "ImageNotFoundException"
|
||||
|
||||
// ErrCodeInvalidLayerException for service response error code
|
||||
// "InvalidLayerException".
|
||||
//
|
||||
// The layer digest calculation performed by Amazon ECR upon receipt of the
|
||||
// image layer does not match the digest specified.
|
||||
ErrCodeInvalidLayerException = "InvalidLayerException"
|
||||
|
||||
// ErrCodeInvalidLayerPartException for service response error code
|
||||
// "InvalidLayerPartException".
|
||||
//
|
||||
// The layer part size is not valid, or the first byte specified is not consecutive
|
||||
// to the last byte of a previous layer part upload.
|
||||
ErrCodeInvalidLayerPartException = "InvalidLayerPartException"
|
||||
|
||||
// ErrCodeInvalidParameterException for service response error code
|
||||
// "InvalidParameterException".
|
||||
//
|
||||
// The specified parameter is invalid. Review the available parameters for the
|
||||
// API request.
|
||||
ErrCodeInvalidParameterException = "InvalidParameterException"
|
||||
|
||||
// ErrCodeLayerAlreadyExistsException for service response error code
|
||||
// "LayerAlreadyExistsException".
|
||||
//
|
||||
// The image layer already exists in the associated repository.
|
||||
ErrCodeLayerAlreadyExistsException = "LayerAlreadyExistsException"
|
||||
|
||||
// ErrCodeLayerInaccessibleException for service response error code
|
||||
// "LayerInaccessibleException".
|
||||
//
|
||||
// The specified layer is not available because it is not associated with an
|
||||
// image. Unassociated image layers may be cleaned up at any time.
|
||||
ErrCodeLayerInaccessibleException = "LayerInaccessibleException"
|
||||
|
||||
// ErrCodeLayerPartTooSmallException for service response error code
|
||||
// "LayerPartTooSmallException".
|
||||
//
|
||||
// Layer parts must be at least 5 MiB in size.
|
||||
ErrCodeLayerPartTooSmallException = "LayerPartTooSmallException"
|
||||
|
||||
// ErrCodeLayersNotFoundException for service response error code
|
||||
// "LayersNotFoundException".
|
||||
//
|
||||
// The specified layers could not be found, or the specified layer is not valid
|
||||
// for this repository.
|
||||
ErrCodeLayersNotFoundException = "LayersNotFoundException"
|
||||
|
||||
// ErrCodeLimitExceededException for service response error code
|
||||
// "LimitExceededException".
|
||||
//
|
||||
// The operation did not succeed because it would have exceeded a service limit
|
||||
// for your account. For more information, see Amazon ECR Default Service Limits
|
||||
// (http://docs.aws.amazon.com/AmazonECR/latest/userguide/service_limits.html)
|
||||
// in the Amazon EC2 Container Registry User Guide.
|
||||
ErrCodeLimitExceededException = "LimitExceededException"
|
||||
|
||||
// ErrCodeRepositoryAlreadyExistsException for service response error code
|
||||
// "RepositoryAlreadyExistsException".
|
||||
//
|
||||
// The specified repository already exists in the specified registry.
|
||||
ErrCodeRepositoryAlreadyExistsException = "RepositoryAlreadyExistsException"
|
||||
|
||||
// ErrCodeRepositoryNotEmptyException for service response error code
|
||||
// "RepositoryNotEmptyException".
|
||||
//
|
||||
// The specified repository contains images. To delete a repository that contains
|
||||
// images, you must force the deletion with the force parameter.
|
||||
ErrCodeRepositoryNotEmptyException = "RepositoryNotEmptyException"
|
||||
|
||||
// ErrCodeRepositoryNotFoundException for service response error code
|
||||
// "RepositoryNotFoundException".
|
||||
//
|
||||
// The specified repository could not be found. Check the spelling of the specified
|
||||
// repository and ensure that you are performing operations on the correct registry.
|
||||
ErrCodeRepositoryNotFoundException = "RepositoryNotFoundException"
|
||||
|
||||
// ErrCodeRepositoryPolicyNotFoundException for service response error code
|
||||
// "RepositoryPolicyNotFoundException".
|
||||
//
|
||||
// The specified repository and registry combination does not have an associated
|
||||
// repository policy.
|
||||
ErrCodeRepositoryPolicyNotFoundException = "RepositoryPolicyNotFoundException"
|
||||
|
||||
// ErrCodeServerException for service response error code
|
||||
// "ServerException".
|
||||
//
|
||||
// These errors are usually caused by a server-side issue.
|
||||
ErrCodeServerException = "ServerException"
|
||||
|
||||
// ErrCodeUploadNotFoundException for service response error code
|
||||
// "UploadNotFoundException".
|
||||
//
|
||||
// The upload could not be found, or the specified upload id is not valid for
|
||||
// this repository.
|
||||
ErrCodeUploadNotFoundException = "UploadNotFoundException"
|
||||
)
|
|
@ -17,8 +17,9 @@ import (
|
|||
// ECR supports private Docker repositories with resource-based permissions
|
||||
// using AWS IAM so that specific users or Amazon EC2 instances can access repositories
|
||||
// and images. Developers can use the Docker CLI to author and manage images.
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
// Please also see https://docs.aws.amazon.com/goto/WebAPI/ecr-2015-09-21
|
||||
type ECR struct {
|
||||
*client.Client
|
||||
}
|
||||
|
@ -29,8 +30,11 @@ var initClient func(*client.Client)
|
|||
// Used for custom request initialization logic
|
||||
var initRequest func(*request.Request)
|
||||
|
||||
// A ServiceName is the name of the service the client will make API calls to.
|
||||
const ServiceName = "ecr"
|
||||
// Service information constants
|
||||
const (
|
||||
ServiceName = "ecr" // Service endpoint prefix API calls made to.
|
||||
EndpointsID = ServiceName // Service ID for Regions and Endpoints metadata.
|
||||
)
|
||||
|
||||
// New creates a new instance of the ECR client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
|
@ -43,17 +47,18 @@ const ServiceName = "ecr"
|
|||
// // Create a ECR client with additional configuration
|
||||
// svc := ecr.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *ECR {
|
||||
c := p.ClientConfig(ServiceName, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
c := p.ClientConfig(EndpointsID, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *ECR {
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *ECR {
|
||||
svc := &ECR{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: ServiceName,
|
||||
SigningName: signingName,
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2015-09-21",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,48 @@
|
|||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
|
||||
package s3
|
||||
|
||||
const (
|
||||
|
||||
// ErrCodeBucketAlreadyExists for service response error code
|
||||
// "BucketAlreadyExists".
|
||||
//
|
||||
// The requested bucket name is not available. The bucket namespace is shared
|
||||
// by all users of the system. Please select a different name and try again.
|
||||
ErrCodeBucketAlreadyExists = "BucketAlreadyExists"
|
||||
|
||||
// ErrCodeBucketAlreadyOwnedByYou for service response error code
|
||||
// "BucketAlreadyOwnedByYou".
|
||||
ErrCodeBucketAlreadyOwnedByYou = "BucketAlreadyOwnedByYou"
|
||||
|
||||
// ErrCodeNoSuchBucket for service response error code
|
||||
// "NoSuchBucket".
|
||||
//
|
||||
// The specified bucket does not exist.
|
||||
ErrCodeNoSuchBucket = "NoSuchBucket"
|
||||
|
||||
// ErrCodeNoSuchKey for service response error code
|
||||
// "NoSuchKey".
|
||||
//
|
||||
// The specified key does not exist.
|
||||
ErrCodeNoSuchKey = "NoSuchKey"
|
||||
|
||||
// ErrCodeNoSuchUpload for service response error code
|
||||
// "NoSuchUpload".
|
||||
//
|
||||
// The specified multipart upload does not exist.
|
||||
ErrCodeNoSuchUpload = "NoSuchUpload"
|
||||
|
||||
// ErrCodeObjectAlreadyInActiveTierError for service response error code
|
||||
// "ObjectAlreadyInActiveTierError".
|
||||
//
|
||||
// This operation is not allowed against this storage tier
|
||||
ErrCodeObjectAlreadyInActiveTierError = "ObjectAlreadyInActiveTierError"
|
||||
|
||||
// ErrCodeObjectNotInActiveTierError for service response error code
|
||||
// "ObjectNotInActiveTierError".
|
||||
//
|
||||
// The source object of the COPY operation is not in the active tier and is
|
||||
// only stored in Amazon Glacier.
|
||||
ErrCodeObjectNotInActiveTierError = "ObjectNotInActiveTierError"
|
||||
)
|
|
@ -37,14 +37,6 @@ var accelerateOpBlacklist = operationBlacklist{
|
|||
func updateEndpointForS3Config(r *request.Request) {
|
||||
forceHostStyle := aws.BoolValue(r.Config.S3ForcePathStyle)
|
||||
accelerate := aws.BoolValue(r.Config.S3UseAccelerate)
|
||||
useDualStack := aws.BoolValue(r.Config.UseDualStack)
|
||||
|
||||
if useDualStack && accelerate {
|
||||
r.Error = awserr.New("InvalidParameterException",
|
||||
fmt.Sprintf("configuration aws.Config.UseDualStack is not compatible with aws.Config.Accelerate"),
|
||||
nil)
|
||||
return
|
||||
}
|
||||
|
||||
if accelerate && accelerateOpBlacklist.Continue(r) {
|
||||
if forceHostStyle {
|
||||
|
@ -75,6 +67,10 @@ func updateEndpointForHostStyle(r *request.Request) {
|
|||
moveBucketToHost(r.HTTPRequest.URL, bucket)
|
||||
}
|
||||
|
||||
var (
|
||||
accelElem = []byte("s3-accelerate.dualstack.")
|
||||
)
|
||||
|
||||
func updateEndpointForAccelerate(r *request.Request) {
|
||||
bucket, ok := bucketNameFromReqParams(r.Params)
|
||||
if !ok {
|
||||
|
@ -86,13 +82,31 @@ func updateEndpointForAccelerate(r *request.Request) {
|
|||
|
||||
if !hostCompatibleBucketName(r.HTTPRequest.URL, bucket) {
|
||||
r.Error = awserr.New("InvalidParameterException",
|
||||
fmt.Sprintf("bucket name %s is not compatibile with S3 Accelerate", bucket),
|
||||
fmt.Sprintf("bucket name %s is not compatible with S3 Accelerate", bucket),
|
||||
nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Change endpoint from s3(-[a-z0-1-])?.amazonaws.com to s3-accelerate.amazonaws.com
|
||||
r.HTTPRequest.URL.Host = replaceHostRegion(r.HTTPRequest.URL.Host, "accelerate")
|
||||
parts := strings.Split(r.HTTPRequest.URL.Host, ".")
|
||||
if len(parts) < 3 {
|
||||
r.Error = awserr.New("InvalidParameterExecption",
|
||||
fmt.Sprintf("unable to update endpoint host for S3 accelerate, hostname invalid, %s",
|
||||
r.HTTPRequest.URL.Host), nil)
|
||||
return
|
||||
}
|
||||
|
||||
if parts[0] == "s3" || strings.HasPrefix(parts[0], "s3-") {
|
||||
parts[0] = "s3-accelerate"
|
||||
}
|
||||
for i := 1; i+1 < len(parts); i++ {
|
||||
if parts[i] == aws.StringValue(r.Config.Region) {
|
||||
parts = append(parts[:i], parts[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
r.HTTPRequest.URL.Host = strings.Join(parts, ".")
|
||||
|
||||
moveBucketToHost(r.HTTPRequest.URL, bucket)
|
||||
}
|
||||
|
||||
|
@ -146,28 +160,3 @@ func moveBucketToHost(u *url.URL, bucket string) {
|
|||
u.Path = "/"
|
||||
}
|
||||
}
|
||||
|
||||
const s3HostPrefix = "s3"
|
||||
|
||||
// replaceHostRegion replaces the S3 region string in the host with the
|
||||
// value provided. If v is empty the host prefix returned will be s3.
|
||||
func replaceHostRegion(host, v string) string {
|
||||
if !strings.HasPrefix(host, s3HostPrefix) {
|
||||
return host
|
||||
}
|
||||
|
||||
suffix := host[len(s3HostPrefix):]
|
||||
for i := len(s3HostPrefix); i < len(host); i++ {
|
||||
if host[i] == '.' {
|
||||
// Trim until '.' leave the it in place.
|
||||
suffix = host[i:]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(v) == 0 {
|
||||
return fmt.Sprintf("s3%s", suffix)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("s3-%s%s", v, suffix)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
|
||||
// Package s3iface provides an interface for the Amazon Simple Storage Service.
|
||||
// Package s3iface provides an interface to enable mocking the Amazon Simple Storage Service service client
|
||||
// for testing your code.
|
||||
//
|
||||
// It is important to note that this interface will have breaking changes
|
||||
// when the service model is updated and adds new API operations, paginators,
|
||||
// and waiters.
|
||||
package s3iface
|
||||
|
||||
import (
|
||||
|
@ -8,7 +13,51 @@ import (
|
|||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
)
|
||||
|
||||
// S3API is the interface type for s3.S3.
|
||||
// S3API provides an interface to enable mocking the
|
||||
// s3.S3 service client's API operation,
|
||||
// paginators, and waiters. This make unit testing your code that calls out
|
||||
// to the SDK's service client's calls easier.
|
||||
//
|
||||
// The best way to use this interface is so the SDK's service client's calls
|
||||
// can be stubbed out for unit testing your code with the SDK without needing
|
||||
// to inject custom request handlers into the the SDK's request pipeline.
|
||||
//
|
||||
// // myFunc uses an SDK service client to make a request to
|
||||
// // Amazon Simple Storage Service.
|
||||
// func myFunc(svc s3iface.S3API) bool {
|
||||
// // Make svc.AbortMultipartUpload request
|
||||
// }
|
||||
//
|
||||
// func main() {
|
||||
// sess := session.New()
|
||||
// svc := s3.New(sess)
|
||||
//
|
||||
// myFunc(svc)
|
||||
// }
|
||||
//
|
||||
// In your _test.go file:
|
||||
//
|
||||
// // Define a mock struct to be used in your unit tests of myFunc.
|
||||
// type mockS3Client struct {
|
||||
// s3iface.S3API
|
||||
// }
|
||||
// func (m *mockS3Client) AbortMultipartUpload(input *s3.AbortMultipartUploadInput) (*s3.AbortMultipartUploadOutput, error) {
|
||||
// // mock response/functionality
|
||||
// }
|
||||
//
|
||||
// func TestMyFunc(t *testing.T) {
|
||||
// // Setup Test
|
||||
// mockSvc := &mockS3Client{}
|
||||
//
|
||||
// myfunc(mockSvc)
|
||||
//
|
||||
// // Verify myFunc's functionality
|
||||
// }
|
||||
//
|
||||
// It is important to note that this interface will have breaking changes
|
||||
// when the service model is updated and adds new API operations, paginators,
|
||||
// and waiters. Its suggested to use the pattern above for testing, or using
|
||||
// tooling to generate mocks to satisfy the interfaces.
|
||||
type S3API interface {
|
||||
AbortMultipartUploadRequest(*s3.AbortMultipartUploadInput) (*request.Request, *s3.AbortMultipartUploadOutput)
|
||||
|
||||
|
@ -34,14 +83,26 @@ type S3API interface {
|
|||
|
||||
DeleteBucket(*s3.DeleteBucketInput) (*s3.DeleteBucketOutput, error)
|
||||
|
||||
DeleteBucketAnalyticsConfigurationRequest(*s3.DeleteBucketAnalyticsConfigurationInput) (*request.Request, *s3.DeleteBucketAnalyticsConfigurationOutput)
|
||||
|
||||
DeleteBucketAnalyticsConfiguration(*s3.DeleteBucketAnalyticsConfigurationInput) (*s3.DeleteBucketAnalyticsConfigurationOutput, error)
|
||||
|
||||
DeleteBucketCorsRequest(*s3.DeleteBucketCorsInput) (*request.Request, *s3.DeleteBucketCorsOutput)
|
||||
|
||||
DeleteBucketCors(*s3.DeleteBucketCorsInput) (*s3.DeleteBucketCorsOutput, error)
|
||||
|
||||
DeleteBucketInventoryConfigurationRequest(*s3.DeleteBucketInventoryConfigurationInput) (*request.Request, *s3.DeleteBucketInventoryConfigurationOutput)
|
||||
|
||||
DeleteBucketInventoryConfiguration(*s3.DeleteBucketInventoryConfigurationInput) (*s3.DeleteBucketInventoryConfigurationOutput, error)
|
||||
|
||||
DeleteBucketLifecycleRequest(*s3.DeleteBucketLifecycleInput) (*request.Request, *s3.DeleteBucketLifecycleOutput)
|
||||
|
||||
DeleteBucketLifecycle(*s3.DeleteBucketLifecycleInput) (*s3.DeleteBucketLifecycleOutput, error)
|
||||
|
||||
DeleteBucketMetricsConfigurationRequest(*s3.DeleteBucketMetricsConfigurationInput) (*request.Request, *s3.DeleteBucketMetricsConfigurationOutput)
|
||||
|
||||
DeleteBucketMetricsConfiguration(*s3.DeleteBucketMetricsConfigurationInput) (*s3.DeleteBucketMetricsConfigurationOutput, error)
|
||||
|
||||
DeleteBucketPolicyRequest(*s3.DeleteBucketPolicyInput) (*request.Request, *s3.DeleteBucketPolicyOutput)
|
||||
|
||||
DeleteBucketPolicy(*s3.DeleteBucketPolicyInput) (*s3.DeleteBucketPolicyOutput, error)
|
||||
|
@ -62,6 +123,10 @@ type S3API interface {
|
|||
|
||||
DeleteObject(*s3.DeleteObjectInput) (*s3.DeleteObjectOutput, error)
|
||||
|
||||
DeleteObjectTaggingRequest(*s3.DeleteObjectTaggingInput) (*request.Request, *s3.DeleteObjectTaggingOutput)
|
||||
|
||||
DeleteObjectTagging(*s3.DeleteObjectTaggingInput) (*s3.DeleteObjectTaggingOutput, error)
|
||||
|
||||
DeleteObjectsRequest(*s3.DeleteObjectsInput) (*request.Request, *s3.DeleteObjectsOutput)
|
||||
|
||||
DeleteObjects(*s3.DeleteObjectsInput) (*s3.DeleteObjectsOutput, error)
|
||||
|
@ -74,10 +139,18 @@ type S3API interface {
|
|||
|
||||
GetBucketAcl(*s3.GetBucketAclInput) (*s3.GetBucketAclOutput, error)
|
||||
|
||||
GetBucketAnalyticsConfigurationRequest(*s3.GetBucketAnalyticsConfigurationInput) (*request.Request, *s3.GetBucketAnalyticsConfigurationOutput)
|
||||
|
||||
GetBucketAnalyticsConfiguration(*s3.GetBucketAnalyticsConfigurationInput) (*s3.GetBucketAnalyticsConfigurationOutput, error)
|
||||
|
||||
GetBucketCorsRequest(*s3.GetBucketCorsInput) (*request.Request, *s3.GetBucketCorsOutput)
|
||||
|
||||
GetBucketCors(*s3.GetBucketCorsInput) (*s3.GetBucketCorsOutput, error)
|
||||
|
||||
GetBucketInventoryConfigurationRequest(*s3.GetBucketInventoryConfigurationInput) (*request.Request, *s3.GetBucketInventoryConfigurationOutput)
|
||||
|
||||
GetBucketInventoryConfiguration(*s3.GetBucketInventoryConfigurationInput) (*s3.GetBucketInventoryConfigurationOutput, error)
|
||||
|
||||
GetBucketLifecycleRequest(*s3.GetBucketLifecycleInput) (*request.Request, *s3.GetBucketLifecycleOutput)
|
||||
|
||||
GetBucketLifecycle(*s3.GetBucketLifecycleInput) (*s3.GetBucketLifecycleOutput, error)
|
||||
|
@ -94,6 +167,10 @@ type S3API interface {
|
|||
|
||||
GetBucketLogging(*s3.GetBucketLoggingInput) (*s3.GetBucketLoggingOutput, error)
|
||||
|
||||
GetBucketMetricsConfigurationRequest(*s3.GetBucketMetricsConfigurationInput) (*request.Request, *s3.GetBucketMetricsConfigurationOutput)
|
||||
|
||||
GetBucketMetricsConfiguration(*s3.GetBucketMetricsConfigurationInput) (*s3.GetBucketMetricsConfigurationOutput, error)
|
||||
|
||||
GetBucketNotificationRequest(*s3.GetBucketNotificationConfigurationRequest) (*request.Request, *s3.NotificationConfigurationDeprecated)
|
||||
|
||||
GetBucketNotification(*s3.GetBucketNotificationConfigurationRequest) (*s3.NotificationConfigurationDeprecated, error)
|
||||
|
@ -134,6 +211,10 @@ type S3API interface {
|
|||
|
||||
GetObjectAcl(*s3.GetObjectAclInput) (*s3.GetObjectAclOutput, error)
|
||||
|
||||
GetObjectTaggingRequest(*s3.GetObjectTaggingInput) (*request.Request, *s3.GetObjectTaggingOutput)
|
||||
|
||||
GetObjectTagging(*s3.GetObjectTaggingInput) (*s3.GetObjectTaggingOutput, error)
|
||||
|
||||
GetObjectTorrentRequest(*s3.GetObjectTorrentInput) (*request.Request, *s3.GetObjectTorrentOutput)
|
||||
|
||||
GetObjectTorrent(*s3.GetObjectTorrentInput) (*s3.GetObjectTorrentOutput, error)
|
||||
|
@ -146,6 +227,18 @@ type S3API interface {
|
|||
|
||||
HeadObject(*s3.HeadObjectInput) (*s3.HeadObjectOutput, error)
|
||||
|
||||
ListBucketAnalyticsConfigurationsRequest(*s3.ListBucketAnalyticsConfigurationsInput) (*request.Request, *s3.ListBucketAnalyticsConfigurationsOutput)
|
||||
|
||||
ListBucketAnalyticsConfigurations(*s3.ListBucketAnalyticsConfigurationsInput) (*s3.ListBucketAnalyticsConfigurationsOutput, error)
|
||||
|
||||
ListBucketInventoryConfigurationsRequest(*s3.ListBucketInventoryConfigurationsInput) (*request.Request, *s3.ListBucketInventoryConfigurationsOutput)
|
||||
|
||||
ListBucketInventoryConfigurations(*s3.ListBucketInventoryConfigurationsInput) (*s3.ListBucketInventoryConfigurationsOutput, error)
|
||||
|
||||
ListBucketMetricsConfigurationsRequest(*s3.ListBucketMetricsConfigurationsInput) (*request.Request, *s3.ListBucketMetricsConfigurationsOutput)
|
||||
|
||||
ListBucketMetricsConfigurations(*s3.ListBucketMetricsConfigurationsInput) (*s3.ListBucketMetricsConfigurationsOutput, error)
|
||||
|
||||
ListBucketsRequest(*s3.ListBucketsInput) (*request.Request, *s3.ListBucketsOutput)
|
||||
|
||||
ListBuckets(*s3.ListBucketsInput) (*s3.ListBucketsOutput, error)
|
||||
|
@ -188,10 +281,18 @@ type S3API interface {
|
|||
|
||||
PutBucketAcl(*s3.PutBucketAclInput) (*s3.PutBucketAclOutput, error)
|
||||
|
||||
PutBucketAnalyticsConfigurationRequest(*s3.PutBucketAnalyticsConfigurationInput) (*request.Request, *s3.PutBucketAnalyticsConfigurationOutput)
|
||||
|
||||
PutBucketAnalyticsConfiguration(*s3.PutBucketAnalyticsConfigurationInput) (*s3.PutBucketAnalyticsConfigurationOutput, error)
|
||||
|
||||
PutBucketCorsRequest(*s3.PutBucketCorsInput) (*request.Request, *s3.PutBucketCorsOutput)
|
||||
|
||||
PutBucketCors(*s3.PutBucketCorsInput) (*s3.PutBucketCorsOutput, error)
|
||||
|
||||
PutBucketInventoryConfigurationRequest(*s3.PutBucketInventoryConfigurationInput) (*request.Request, *s3.PutBucketInventoryConfigurationOutput)
|
||||
|
||||
PutBucketInventoryConfiguration(*s3.PutBucketInventoryConfigurationInput) (*s3.PutBucketInventoryConfigurationOutput, error)
|
||||
|
||||
PutBucketLifecycleRequest(*s3.PutBucketLifecycleInput) (*request.Request, *s3.PutBucketLifecycleOutput)
|
||||
|
||||
PutBucketLifecycle(*s3.PutBucketLifecycleInput) (*s3.PutBucketLifecycleOutput, error)
|
||||
|
@ -204,6 +305,10 @@ type S3API interface {
|
|||
|
||||
PutBucketLogging(*s3.PutBucketLoggingInput) (*s3.PutBucketLoggingOutput, error)
|
||||
|
||||
PutBucketMetricsConfigurationRequest(*s3.PutBucketMetricsConfigurationInput) (*request.Request, *s3.PutBucketMetricsConfigurationOutput)
|
||||
|
||||
PutBucketMetricsConfiguration(*s3.PutBucketMetricsConfigurationInput) (*s3.PutBucketMetricsConfigurationOutput, error)
|
||||
|
||||
PutBucketNotificationRequest(*s3.PutBucketNotificationInput) (*request.Request, *s3.PutBucketNotificationOutput)
|
||||
|
||||
PutBucketNotification(*s3.PutBucketNotificationInput) (*s3.PutBucketNotificationOutput, error)
|
||||
|
@ -244,6 +349,10 @@ type S3API interface {
|
|||
|
||||
PutObjectAcl(*s3.PutObjectAclInput) (*s3.PutObjectAclOutput, error)
|
||||
|
||||
PutObjectTaggingRequest(*s3.PutObjectTaggingInput) (*request.Request, *s3.PutObjectTaggingOutput)
|
||||
|
||||
PutObjectTagging(*s3.PutObjectTaggingInput) (*s3.PutObjectTaggingOutput, error)
|
||||
|
||||
RestoreObjectRequest(*s3.RestoreObjectInput) (*request.Request, *s3.RestoreObjectOutput)
|
||||
|
||||
RestoreObject(*s3.RestoreObjectInput) (*s3.RestoreObjectOutput, error)
|
||||
|
@ -255,6 +364,14 @@ type S3API interface {
|
|||
UploadPartCopyRequest(*s3.UploadPartCopyInput) (*request.Request, *s3.UploadPartCopyOutput)
|
||||
|
||||
UploadPartCopy(*s3.UploadPartCopyInput) (*s3.UploadPartCopyOutput, error)
|
||||
|
||||
WaitUntilBucketExists(*s3.HeadBucketInput) error
|
||||
|
||||
WaitUntilBucketNotExists(*s3.HeadBucketInput) error
|
||||
|
||||
WaitUntilObjectExists(*s3.HeadObjectInput) error
|
||||
|
||||
WaitUntilObjectNotExists(*s3.HeadObjectInput) error
|
||||
}
|
||||
|
||||
var _ S3API = (*s3.S3)(nil)
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
|
@ -49,13 +50,13 @@ type Downloader struct {
|
|||
//
|
||||
// Example:
|
||||
// // The session the S3 Downloader will use
|
||||
// sess, err := session.NewSession()
|
||||
// sess := session.Must(session.NewSession())
|
||||
//
|
||||
// // Create a downloader with the session and default options
|
||||
// downloader := s3manager.NewDownloader(sess)
|
||||
//
|
||||
// // Create a downloader with the session and custom options
|
||||
// downloader := s3manager.NewDownloader(sess, func(d *s3manager.Uploader) {
|
||||
// downloader := s3manager.NewDownloader(sess, func(d *s3manager.Downloader) {
|
||||
// d.PartSize = 64 * 1024 * 1024 // 64MB per part
|
||||
// })
|
||||
func NewDownloader(c client.ConfigProvider, options ...func(*Downloader)) *Downloader {
|
||||
|
@ -78,7 +79,7 @@ func NewDownloader(c client.ConfigProvider, options ...func(*Downloader)) *Downl
|
|||
//
|
||||
// Example:
|
||||
// // The session the S3 Downloader will use
|
||||
// sess, err := session.NewSession()
|
||||
// sess := session.Must(session.NewSession())
|
||||
//
|
||||
// // The S3 client the S3 Downloader will use
|
||||
// s3Svc := s3.new(sess)
|
||||
|
@ -87,7 +88,7 @@ func NewDownloader(c client.ConfigProvider, options ...func(*Downloader)) *Downl
|
|||
// downloader := s3manager.NewDownloaderWithClient(s3Svc)
|
||||
//
|
||||
// // Create a downloader with the s3 client and custom options
|
||||
// downloader := s3manager.NewDownloaderWithClient(s3Svc, func(d *s3manager.Uploader) {
|
||||
// downloader := s3manager.NewDownloaderWithClient(s3Svc, func(d *s3manager.Downloader) {
|
||||
// d.PartSize = 64 * 1024 * 1024 // 64MB per part
|
||||
// })
|
||||
func NewDownloaderWithClient(svc s3iface.S3API, options ...func(*Downloader)) *Downloader {
|
||||
|
@ -103,12 +104,16 @@ func NewDownloaderWithClient(svc s3iface.S3API, options ...func(*Downloader)) *D
|
|||
return d
|
||||
}
|
||||
|
||||
type maxRetrier interface {
|
||||
MaxRetries() int
|
||||
}
|
||||
|
||||
// Download downloads an object in S3 and writes the payload into w using
|
||||
// concurrent GET requests.
|
||||
//
|
||||
// Additional functional options can be provided to configure the individual
|
||||
// upload. These options are copies of the Uploader instance Upload is called from.
|
||||
// Modifying the options will not impact the original Uploader instance.
|
||||
// download. These options are copies of the Downloader instance Download is called from.
|
||||
// Modifying the options will not impact the original Downloader instance.
|
||||
//
|
||||
// It is safe to call this method concurrently across goroutines.
|
||||
//
|
||||
|
@ -121,6 +126,19 @@ func (d Downloader) Download(w io.WriterAt, input *s3.GetObjectInput, options ..
|
|||
option(&impl.ctx)
|
||||
}
|
||||
|
||||
if s, ok := d.S3.(maxRetrier); ok {
|
||||
impl.partBodyMaxRetries = s.MaxRetries()
|
||||
}
|
||||
|
||||
impl.totalBytes = -1
|
||||
if impl.ctx.Concurrency == 0 {
|
||||
impl.ctx.Concurrency = DefaultDownloadConcurrency
|
||||
}
|
||||
|
||||
if impl.ctx.PartSize == 0 {
|
||||
impl.ctx.PartSize = DefaultDownloadPartSize
|
||||
}
|
||||
|
||||
return impl.download()
|
||||
}
|
||||
|
||||
|
@ -138,26 +156,13 @@ type downloader struct {
|
|||
totalBytes int64
|
||||
written int64
|
||||
err error
|
||||
}
|
||||
|
||||
// init initializes the downloader with default options.
|
||||
func (d *downloader) init() {
|
||||
d.totalBytes = -1
|
||||
|
||||
if d.ctx.Concurrency == 0 {
|
||||
d.ctx.Concurrency = DefaultDownloadConcurrency
|
||||
}
|
||||
|
||||
if d.ctx.PartSize == 0 {
|
||||
d.ctx.PartSize = DefaultDownloadPartSize
|
||||
}
|
||||
partBodyMaxRetries int
|
||||
}
|
||||
|
||||
// download performs the implementation of the object download across ranged
|
||||
// GETs.
|
||||
func (d *downloader) download() (n int64, err error) {
|
||||
d.init()
|
||||
|
||||
// Spin off first worker to check additional header information
|
||||
d.getChunk()
|
||||
|
||||
|
@ -214,49 +219,82 @@ func (d *downloader) downloadPart(ch chan dlchunk) {
|
|||
defer d.wg.Done()
|
||||
for {
|
||||
chunk, ok := <-ch
|
||||
if !ok {
|
||||
if !ok || d.getErr() != nil {
|
||||
break
|
||||
}
|
||||
|
||||
if err := d.downloadChunk(chunk); err != nil {
|
||||
d.setErr(err)
|
||||
break
|
||||
}
|
||||
d.downloadChunk(chunk)
|
||||
}
|
||||
}
|
||||
|
||||
// getChunk grabs a chunk of data from the body.
|
||||
// Not thread safe. Should only used when grabbing data on a single thread.
|
||||
func (d *downloader) getChunk() {
|
||||
chunk := dlchunk{w: d.w, start: d.pos, size: d.ctx.PartSize}
|
||||
d.pos += d.ctx.PartSize
|
||||
d.downloadChunk(chunk)
|
||||
}
|
||||
|
||||
// downloadChunk downloads the chunk froom s3
|
||||
func (d *downloader) downloadChunk(chunk dlchunk) {
|
||||
if d.getErr() != nil {
|
||||
return
|
||||
}
|
||||
// Get the next byte range of data
|
||||
in := &s3.GetObjectInput{}
|
||||
awsutil.Copy(in, d.in)
|
||||
rng := fmt.Sprintf("bytes=%d-%d",
|
||||
chunk.start, chunk.start+chunk.size-1)
|
||||
in.Range = &rng
|
||||
|
||||
req, resp := d.ctx.S3.GetObjectRequest(in)
|
||||
req.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("S3Manager"))
|
||||
err := req.Send()
|
||||
chunk := dlchunk{w: d.w, start: d.pos, size: d.ctx.PartSize}
|
||||
d.pos += d.ctx.PartSize
|
||||
|
||||
if err != nil {
|
||||
d.setErr(err)
|
||||
} else {
|
||||
d.setTotalBytes(resp) // Set total if not yet set.
|
||||
|
||||
n, err := io.Copy(&chunk, resp.Body)
|
||||
resp.Body.Close()
|
||||
|
||||
if err != nil {
|
||||
if err := d.downloadChunk(chunk); err != nil {
|
||||
d.setErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
// downloadChunk downloads the chunk froom s3
|
||||
func (d *downloader) downloadChunk(chunk dlchunk) error {
|
||||
in := &s3.GetObjectInput{}
|
||||
awsutil.Copy(in, d.in)
|
||||
|
||||
// Get the next byte range of data
|
||||
rng := fmt.Sprintf("bytes=%d-%d", chunk.start, chunk.start+chunk.size-1)
|
||||
in.Range = &rng
|
||||
|
||||
var n int64
|
||||
var err error
|
||||
for retry := 0; retry <= d.partBodyMaxRetries; retry++ {
|
||||
req, resp := d.ctx.S3.GetObjectRequest(in)
|
||||
req.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("S3Manager"))
|
||||
|
||||
err = req.Send()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.setTotalBytes(resp) // Set total if not yet set.
|
||||
|
||||
n, err = io.Copy(&chunk, resp.Body)
|
||||
resp.Body.Close()
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
chunk.cur = 0
|
||||
logMessage(d.ctx.S3, aws.LogDebugWithRequestRetries,
|
||||
fmt.Sprintf("DEBUG: object part body download interrupted %s, err, %v, retrying attempt %d",
|
||||
aws.StringValue(in.Key), err, retry))
|
||||
}
|
||||
|
||||
d.incrWritten(n)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func logMessage(svc s3iface.S3API, level aws.LogLevelType, msg string) {
|
||||
s, ok := svc.(*s3.S3)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if s.Config.Logger == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if s.Config.LogLevel.Matches(level) {
|
||||
s.Config.Logger.Log(msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -175,6 +175,9 @@ type UploadInput struct {
|
|||
// The type of storage to use for the object. Defaults to 'STANDARD'.
|
||||
StorageClass *string `location:"header" locationName:"x-amz-storage-class" type:"string"`
|
||||
|
||||
// The tag-set for the object. The tag-set must be encoded as URL Query parameters
|
||||
Tagging *string `location:"header" locationName:"x-amz-tagging" type:"string"`
|
||||
|
||||
// If the bucket is configured as a website, redirects requests for this object
|
||||
// to another object in the same bucket or to an external URL. Amazon S3 stores
|
||||
// the value of this header in the object metadata.
|
||||
|
@ -238,7 +241,7 @@ type Uploader struct {
|
|||
//
|
||||
// Example:
|
||||
// // The session the S3 Uploader will use
|
||||
// sess, err := session.NewSession()
|
||||
// sess := session.Must(session.NewSession())
|
||||
//
|
||||
// // Create an uploader with the session and default options
|
||||
// uploader := s3manager.NewUploader(sess)
|
||||
|
@ -269,7 +272,7 @@ func NewUploader(c client.ConfigProvider, options ...func(*Uploader)) *Uploader
|
|||
//
|
||||
// Example:
|
||||
// // The session the S3 Uploader will use
|
||||
// sess, err := session.NewSession()
|
||||
// sess := session.Must(session.NewSession())
|
||||
//
|
||||
// // S3 service client the Upload manager will use.
|
||||
// s3Svc := s3.New(sess)
|
||||
|
@ -409,8 +412,12 @@ func (u *uploader) initSize() {
|
|||
// does not need to be wrapped in a mutex because nextReader is only called
|
||||
// from the main thread.
|
||||
func (u *uploader) nextReader() (io.ReadSeeker, int, error) {
|
||||
type readerAtSeeker interface {
|
||||
io.ReaderAt
|
||||
io.ReadSeeker
|
||||
}
|
||||
switch r := u.in.Body.(type) {
|
||||
case io.ReaderAt:
|
||||
case readerAtSeeker:
|
||||
var err error
|
||||
|
||||
n := u.ctx.PartSize
|
||||
|
@ -605,6 +612,8 @@ func (u *multiuploader) send(c chunk) error {
|
|||
Key: u.in.Key,
|
||||
Body: c.buf,
|
||||
UploadId: &u.uploadID,
|
||||
SSECustomerAlgorithm: u.in.SSECustomerAlgorithm,
|
||||
SSECustomerKey: u.in.SSECustomerKey,
|
||||
PartNumber: &c.num,
|
||||
})
|
||||
req.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("S3Manager"))
|
||||
|
|
|
@ -12,8 +12,9 @@ import (
|
|||
)
|
||||
|
||||
// S3 is a client for Amazon S3.
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01
|
||||
type S3 struct {
|
||||
*client.Client
|
||||
}
|
||||
|
@ -24,8 +25,11 @@ var initClient func(*client.Client)
|
|||
// Used for custom request initialization logic
|
||||
var initRequest func(*request.Request)
|
||||
|
||||
// A ServiceName is the name of the service the client will make API calls to.
|
||||
const ServiceName = "s3"
|
||||
// Service information constants
|
||||
const (
|
||||
ServiceName = "s3" // Service endpoint prefix API calls made to.
|
||||
EndpointsID = ServiceName // Service ID for Regions and Endpoints metadata.
|
||||
)
|
||||
|
||||
// New creates a new instance of the S3 client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
|
@ -38,17 +42,18 @@ const ServiceName = "s3"
|
|||
// // Create a S3 client with additional configuration
|
||||
// svc := s3.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *S3 {
|
||||
c := p.ClientConfig(ServiceName, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
c := p.ClientConfig(EndpointsID, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *S3 {
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *S3 {
|
||||
svc := &S3{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: ServiceName,
|
||||
SigningName: signingName,
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2006-03-01",
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
@ -17,8 +16,8 @@ func copyMultipartStatusOKUnmarhsalError(r *request.Request) {
|
|||
return
|
||||
}
|
||||
body := bytes.NewReader(b)
|
||||
r.HTTPResponse.Body = aws.ReadSeekCloser(body)
|
||||
defer r.HTTPResponse.Body.(aws.ReaderSeekerCloser).Seek(0, 0)
|
||||
r.HTTPResponse.Body = ioutil.NopCloser(body)
|
||||
defer body.Seek(0, 0)
|
||||
|
||||
if body.Len() == 0 {
|
||||
// If there is no body don't attempt to parse the body.
|
||||
|
|
|
@ -6,6 +6,10 @@ import (
|
|||
"github.com/aws/aws-sdk-go/private/waiter"
|
||||
)
|
||||
|
||||
// WaitUntilBucketExists uses the Amazon S3 API operation
|
||||
// HeadBucket to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *S3) WaitUntilBucketExists(input *HeadBucketInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "HeadBucket",
|
||||
|
@ -47,6 +51,10 @@ func (c *S3) WaitUntilBucketExists(input *HeadBucketInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilBucketNotExists uses the Amazon S3 API operation
|
||||
// HeadBucket to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *S3) WaitUntilBucketNotExists(input *HeadBucketInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "HeadBucket",
|
||||
|
@ -70,6 +78,10 @@ func (c *S3) WaitUntilBucketNotExists(input *HeadBucketInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilObjectExists uses the Amazon S3 API operation
|
||||
// HeadObject to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *S3) WaitUntilObjectExists(input *HeadObjectInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "HeadObject",
|
||||
|
@ -99,6 +111,10 @@ func (c *S3) WaitUntilObjectExists(input *HeadObjectInput) error {
|
|||
return w.Wait()
|
||||
}
|
||||
|
||||
// WaitUntilObjectNotExists uses the Amazon S3 API operation
|
||||
// HeadObject to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *S3) WaitUntilObjectNotExists(input *HeadObjectInput) error {
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "HeadObject",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,73 @@
|
|||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
|
||||
package sts
|
||||
|
||||
const (
|
||||
|
||||
// ErrCodeExpiredTokenException for service response error code
|
||||
// "ExpiredTokenException".
|
||||
//
|
||||
// The web identity token that was passed is expired or is not valid. Get a
|
||||
// new identity token from the identity provider and then retry the request.
|
||||
ErrCodeExpiredTokenException = "ExpiredTokenException"
|
||||
|
||||
// ErrCodeIDPCommunicationErrorException for service response error code
|
||||
// "IDPCommunicationError".
|
||||
//
|
||||
// The request could not be fulfilled because the non-AWS identity provider
|
||||
// (IDP) that was asked to verify the incoming identity token could not be reached.
|
||||
// This is often a transient error caused by network conditions. Retry the request
|
||||
// a limited number of times so that you don't exceed the request rate. If the
|
||||
// error persists, the non-AWS identity provider might be down or not responding.
|
||||
ErrCodeIDPCommunicationErrorException = "IDPCommunicationError"
|
||||
|
||||
// ErrCodeIDPRejectedClaimException for service response error code
|
||||
// "IDPRejectedClaim".
|
||||
//
|
||||
// The identity provider (IdP) reported that authentication failed. This might
|
||||
// be because the claim is invalid.
|
||||
//
|
||||
// If this error is returned for the AssumeRoleWithWebIdentity operation, it
|
||||
// can also mean that the claim has expired or has been explicitly revoked.
|
||||
ErrCodeIDPRejectedClaimException = "IDPRejectedClaim"
|
||||
|
||||
// ErrCodeInvalidAuthorizationMessageException for service response error code
|
||||
// "InvalidAuthorizationMessageException".
|
||||
//
|
||||
// The error returned if the message passed to DecodeAuthorizationMessage was
|
||||
// invalid. This can happen if the token contains invalid characters, such as
|
||||
// linebreaks.
|
||||
ErrCodeInvalidAuthorizationMessageException = "InvalidAuthorizationMessageException"
|
||||
|
||||
// ErrCodeInvalidIdentityTokenException for service response error code
|
||||
// "InvalidIdentityToken".
|
||||
//
|
||||
// The web identity token that was passed could not be validated by AWS. Get
|
||||
// a new identity token from the identity provider and then retry the request.
|
||||
ErrCodeInvalidIdentityTokenException = "InvalidIdentityToken"
|
||||
|
||||
// ErrCodeMalformedPolicyDocumentException for service response error code
|
||||
// "MalformedPolicyDocument".
|
||||
//
|
||||
// The request was rejected because the policy document was malformed. The error
|
||||
// message describes the specific error.
|
||||
ErrCodeMalformedPolicyDocumentException = "MalformedPolicyDocument"
|
||||
|
||||
// ErrCodePackedPolicyTooLargeException for service response error code
|
||||
// "PackedPolicyTooLarge".
|
||||
//
|
||||
// The request was rejected because the policy document was too large. The error
|
||||
// message describes how big the policy document is, in packed form, as a percentage
|
||||
// of what the API allows.
|
||||
ErrCodePackedPolicyTooLargeException = "PackedPolicyTooLarge"
|
||||
|
||||
// ErrCodeRegionDisabledException for service response error code
|
||||
// "RegionDisabledException".
|
||||
//
|
||||
// STS is not activated in the requested region for the account that is being
|
||||
// asked to generate credentials. The account administrator must use the IAM
|
||||
// console to activate STS in that region. For more information, see Activating
|
||||
// and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
|
||||
// in the IAM User Guide.
|
||||
ErrCodeRegionDisabledException = "RegionDisabledException"
|
||||
)
|
|
@ -56,8 +56,9 @@ import (
|
|||
// successfully made to STS, who made the request, when it was made, and so
|
||||
// on. To learn more about CloudTrail, including how to turn it on and find
|
||||
// your log files, see the AWS CloudTrail User Guide (http://docs.aws.amazon.com/awscloudtrail/latest/userguide/what_is_cloud_trail_top_level.html).
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15
|
||||
type STS struct {
|
||||
*client.Client
|
||||
}
|
||||
|
@ -68,8 +69,11 @@ var initClient func(*client.Client)
|
|||
// Used for custom request initialization logic
|
||||
var initRequest func(*request.Request)
|
||||
|
||||
// A ServiceName is the name of the service the client will make API calls to.
|
||||
const ServiceName = "sts"
|
||||
// Service information constants
|
||||
const (
|
||||
ServiceName = "sts" // Service endpoint prefix API calls made to.
|
||||
EndpointsID = ServiceName // Service ID for Regions and Endpoints metadata.
|
||||
)
|
||||
|
||||
// New creates a new instance of the STS client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
|
@ -82,17 +86,18 @@ const ServiceName = "sts"
|
|||
// // Create a STS client with additional configuration
|
||||
// svc := sts.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *STS {
|
||||
c := p.ClientConfig(ServiceName, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
c := p.ClientConfig(EndpointsID, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *STS {
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *STS {
|
||||
svc := &STS{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: ServiceName,
|
||||
SigningName: signingName,
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2011-06-15",
|
||||
|
|
|
@ -100,196 +100,233 @@
|
|||
"revision": "4239b77079c7b5d1243b7b4736304ce8ddb6f0f2"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "mocMTDVyOtc9Q4qXF6zuJpivR9c=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "ZjwjHipLn1qcBhMcS7iakI6xnwA=",
|
||||
"path": "github.com/aws/aws-sdk-go",
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "D7lKOBHog4Y/ETUWhgmTCcNyzHc=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/aws",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "Y9W+4GimK4Fuxq+vyIskVYFRnX4=",
|
||||
"comment": "v1.4.6",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/aws/awserr",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "ppmwInOtC5Mj/dBBWVxL0KPEI0I=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "yyYr41HZ1Aq0hWc3J5ijXwYEcac=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/aws/awsutil",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "H/tMKHZU+Qka6RtYiGB50s2uA0s=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "iThCyNRL/oQFD9CF2SYgBGl+aww=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/aws/client",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "ieAJ+Cvp/PKv1LpUEnUXpc3OI6E=",
|
||||
"comment": "v1.4.6",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/aws/client/metadata",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "gNWirlrTfSLbOe421hISBAhTqa4=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "Fl8vRSCY0MbM04cmiz/0MID+goA=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/aws/corehandlers",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "dNZNaOPfBPnzE2CBnfhXXZ9g9jU=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "zu5C95rmCZff6NYZb62lEaT5ibE=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/aws/credentials",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "KQiUK/zr3mqnAXD7x/X55/iNme0=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "u3GOAJLmdvbuNUeUEcZSEAOeL/0=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "NUJUTWlc1sV8b7WjfiYc4JZbXl0=",
|
||||
"comment": "v1.4.6",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "4Ipx+5xN0gso+cENC2MHMWmQlR4=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "6cj/zsRmcxkE1TLS+v910GbQYg0=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/aws/credentials/stscreds",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "nCMd1XKjgV21bEl7J8VZFqTV8PE=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "lqh3fG7wCochvB4iHAZJuhhEJW0=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/aws/defaults",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "U0SthWum+t9ACanK7SDJOg3dO6M=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "/EXbk/z2TWjWc1Hvb4QYs3Wmhb8=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/aws/ec2metadata",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "NyUg1P8ZS/LHAAQAk/4C5O4X3og=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "JTrzEDPXL3pUUH+dMCixz9T9rLY=",
|
||||
"path": "github.com/aws/aws-sdk-go/aws/endpoints",
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "M78rTxU55Qagqr3MYj91im2031E=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/aws/request",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "44uohX3kLsfZHHOqunr+qJnSCdw=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "u6tKvFGcRQ1xtby1ONjgyUTgcpg=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/aws/session",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "7lla+sckQeF18wORAGuU2fFMlp4=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "0FvPLvkBUpTElfUc/FZtPsJfuV0=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/aws/signer/v4",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "Bm6UrYb2QCzpYseLwwgw6aetgRc=",
|
||||
"comment": "v1.4.6",
|
||||
"path": "github.com/aws/aws-sdk-go/private/endpoints",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "wk7EyvDaHwb5qqoOP/4d3cV0708=",
|
||||
"comment": "v1.4.6",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/private/protocol",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "uNmSKXAF8B9HWEciW+iyUwZ99qQ=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "1QmQ3FqV37w0Zi44qv8pA1GeR0A=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/private/protocol/ec2query",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "pNeF0Ey7TfBArH5LBQhKOQXQbLY=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "O6hcK24yI6w7FA+g4Pbr+eQ7pys=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "H9TymcQkQnXSXSVfjggiiS4bpzM=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "R00RL5jJXRYq1iiK1+PGvMfvXyM=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/private/protocol/jsonrpc",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "isoix7lTx4qIq2zI2xFADtti5SI=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "ZqY5RWavBLWTo6j9xqdyBEaNFRk=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/private/protocol/query",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "5xzix1R8prUyWxgLnzUQoxTsfik=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "hqTEmgtchF9SwVTW0IQId2eLUKM=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/private/protocol/query/queryutil",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "TW/7U+/8ormL7acf6z2rv2hDD+s=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "szZSLm3BlYkL3vqlZhNAlYk8iwM=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/private/protocol/rest",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "Y6Db2GGfGD9LPpcJIPj8vXE8BbQ=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "ODo+ko8D6unAxZuN1jGzMcN4QCc=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/private/protocol/restxml",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "eUEkjyMPAuekKBE4ou+nM9tXEas=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "lZ1z4xAbT8euCzKoAsnEYic60VE=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "Eo9yODN5U99BK0pMzoqnBm7PCrY=",
|
||||
"comment": "v1.4.6",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/private/waiter",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "7KfnvRLqjHtG8OFBk3/LM4n6rPo=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "ecCVL8+SptmQlojrGtL8mQdaJ6E=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/service/ec2",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "RUfkmRJpf1l6rHJfh/86gtG4Was=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "B6qHy1+Rrp9lQCBR/JDRT72kuCI=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/service/ecr",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "imxJucuPrgaPRMPtAgsu+Y7soB4=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "eEWM4wKzVbRqAwIy3MdMCDUGs2s=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/service/s3",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "HBr74u7wII+7Xu4wb12f5+fDi5k=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "B3FgQ8T7ewtG+q0uLnofdFfp/TE=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/service/s3/s3iface",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "rXToYcA5MwoyuBQAvfe2gIEbDDU=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "Tr7Q8zpGveIlcort1+Og9hhG+hk=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/service/s3/s3manager",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "nH/itbdeFHpl4ysegdtgww9bFSA=",
|
||||
"comment": "v1.4.6",
|
||||
"checksumSHA1": "Knj17ZMPWkGYTm2hZxEgnuboMM4=",
|
||||
"comment": "v1.7.1",
|
||||
"path": "github.com/aws/aws-sdk-go/service/sts",
|
||||
"revision": "6ac30507cca29249f4d49af45a8efc98b84088ee"
|
||||
"revision": "1bd588c8b2dba4da57dd4664b2b2750d260a5915",
|
||||
"revisionTime": "2017-02-24T22:28:38Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "7SbTaY0kaYxgQrG3/9cjrI+BcyU=",
|
||||
|
|
|
@ -205,6 +205,9 @@ each category, the available configuration keys are alphabetized.
|
|||
|
||||
- `root_device_name` (string) - The root device name. For example, `xvda`.
|
||||
|
||||
- `mfa_code` (string) - The MFA [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm)
|
||||
code. This should probably be a user variable since it changes all the time.
|
||||
|
||||
- `mount_path` (string) - The path where the volume will be mounted. This is
|
||||
where the chroot environment will be. This defaults to
|
||||
`/mnt/packer-amazon-chroot-volumes/{{.Device}}`. This is a configuration template
|
||||
|
|
|
@ -195,6 +195,9 @@ builder.
|
|||
preserved when booting from the AMI built with Packer. See
|
||||
`ami_block_device_mappings`, above, for details.
|
||||
|
||||
- `mfa_code` (string) - The MFA [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm)
|
||||
code. This should probably be a user variable since it changes all the time.
|
||||
|
||||
- `region_kms_key_ids` (map of strings) - a map of regions to copy the ami to,
|
||||
along with the custom kms key id to use for encryption for that region.
|
||||
Keys must match the regions provided in `ami_regions`. If you just want to
|
||||
|
|
|
@ -188,6 +188,9 @@ builder.
|
|||
preserved when booting from the AMI built with packer. See
|
||||
`ami_block_device_mappings`, above, for details.
|
||||
|
||||
- `mfa_code` (string) - The MFA [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm)
|
||||
code. This should probably be a user variable since it changes all the time.
|
||||
|
||||
- `region_kms_key_ids` (map of strings) - a map of regions to copy the ami to,
|
||||
along with the custom kms key id to use for encryption for that region.
|
||||
Keys must match the regions provided in `ami_regions`. If you just want to
|
||||
|
|
|
@ -115,6 +115,9 @@ builder.
|
|||
profile](https://docs.aws.amazon.com/IAM/latest/UserGuide/instance-profiles.html)
|
||||
to launch the EC2 instance with.
|
||||
|
||||
- `mfa_code` (string) - The MFA [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm)
|
||||
code. This should probably be a user variable since it changes all the time.
|
||||
|
||||
- `region_kms_key_ids` (map of strings) - a map of regions to copy the ami to,
|
||||
along with the custom kms key id to use for encryption for that region.
|
||||
Keys must match the regions provided in `ami_regions`. If you just want to
|
||||
|
|
|
@ -211,6 +211,9 @@ builder.
|
|||
preserved when booting from the AMI built with Packer. See
|
||||
`ami_block_device_mappings`, above, for details.
|
||||
|
||||
- `mfa_code` (string) - The MFA [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm)
|
||||
code. This should probably be a user variable since it changes all the time.
|
||||
|
||||
- `region_kms_key_ids` (map of strings) - a map of regions to copy the ami to,
|
||||
along with the custom kms key id to use for encryption for that region.
|
||||
Keys must match the regions provided in `ami_regions`. If you just want to
|
||||
|
|
|
@ -70,37 +70,24 @@ Credentials are resolved in the following order:
|
|||
|
||||
### Automatic Lookup
|
||||
|
||||
If no AWS credentials are found in a packer template, we proceed on to the
|
||||
following steps:
|
||||
Packer depends on the [AWS
|
||||
SDK](https://aws.amazon.com/documentation/sdk-for-go/) to perform automatic
|
||||
lookup using _credential chains_. In short, the SDK looks for credentials in
|
||||
the following order:
|
||||
|
||||
1. Lookup via environment variables.
|
||||
- First `AWS_ACCESS_KEY_ID`, then `AWS_ACCESS_KEY`
|
||||
- First `AWS_SECRET_ACCESS_KEY`, then `AWS_SECRET_KEY`
|
||||
1. Environment variables.
|
||||
2. Shared credentials file.
|
||||
3. If your application is running on an Amazon EC2 instance, IAM role for Amazon EC2.
|
||||
|
||||
2. Look for [local AWS configuration
|
||||
files](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-config-files)
|
||||
- Looks for the credentials file in the `AWS_SHARED_CREDENTIALS_FILE`
|
||||
environment variable, and if that's empty, use the default credentials
|
||||
file (`.aws/credentials`) in the user's home directory.
|
||||
- Uses the profile name set in the `AWS_PROFILE` environment variable. If
|
||||
the environment variable is not set, uses "default" as the profile name.
|
||||
Please refer to the SDK's documentation on [specifying
|
||||
credentials](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#id2) for more information.
|
||||
|
||||
3. Lookup an IAM role for the current EC2 instance (if you're running in EC2)
|
||||
|
||||
~> **Subtle details of automatic lookup may change over time.** The most
|
||||
reliable way to specify your configuration is by setting them in template
|
||||
variables (directly or indirectly), or by using the `AWS_ACCESS_KEY_ID` and
|
||||
`AWS_SECRET_ACCESS_KEY` environment variables.
|
||||
|
||||
Environment variables provide the best portability, allowing you to run your
|
||||
packer build on your workstation, in Atlas, or on another build server.
|
||||
|
||||
## Using an IAM Instance Profile
|
||||
## Using an IAM Task or Instance Role
|
||||
|
||||
If AWS keys are not specified in the template, a
|
||||
[credentials](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-config-files)
|
||||
file or through environment variables Packer will use credentials provided by
|
||||
the instance's IAM profile, if it has one.
|
||||
[shared credentials file](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-config-files)
|
||||
or through environment variables Packer will use credentials provided by
|
||||
the task's or instance's IAM role, if it has one.
|
||||
|
||||
The following policy document provides the minimal set permissions necessary for
|
||||
Packer to work:
|
||||
|
|
|
@ -43,22 +43,48 @@ Required:
|
|||
|
||||
Optional:
|
||||
|
||||
- `s3_key_name` (string) - The name of the key in `s3_bucket_name` where the OVA file will be copied to for import. If not specified, this will default to "packer-import-{{timestamp}}.ova". This key (ie, the uploaded OVA) will be removed after import, unless `skip_clean` is `true`.
|
||||
- `ami_description` (string) - The description to set for the resulting
|
||||
imported AMI. By default this description is generated by the AMI import
|
||||
process.
|
||||
|
||||
- `skip_clean` (boolean) - Whether we should skip removing the OVA file uploaded to S3 after the import process has completed. "true" means that we should leave it in the S3 bucket, "false" means to clean it out. Defaults to `false`.
|
||||
- `ami_groups` (array of strings) - A list of groups that have access to
|
||||
launch the imported AMI. By default no groups have permission to launch the
|
||||
AMI. `all` will make the AMI publically accessible. AWS currently doesn't
|
||||
accept any value other than "all".
|
||||
|
||||
- `ami_name` (string) - The name of the ami within the console. If not specified, this will default to something like `ami-import-sfwerwf`. Please note, specifying this option will result in a slightly longer execution time.
|
||||
- `ami_name` (string) - The name of the ami within the console. If not
|
||||
specified, this will default to something like `ami-import-sfwerwf`.
|
||||
Please note, specifying this option will result in a slightly longer
|
||||
execution time.
|
||||
|
||||
- `ami_users` (array of strings) - A list of account IDs that have access to
|
||||
launch the imported AMI. By default no additional users other than the user
|
||||
importing the AMI has permission to launch it.
|
||||
|
||||
- `license_type` (string) - The license type to be used for the Amazon Machine
|
||||
Image (AMI) after importing. Valid values: `AWS` or `BYOL` (default).
|
||||
For more details regarding licensing, see
|
||||
[Prerequisites](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/VMImportPrerequisites.html)
|
||||
in the VM Import/Export User Guide.
|
||||
|
||||
- `mfa_code` (string) - The MFA [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm)
|
||||
code. This should probably be a user variable since it changes all the time.
|
||||
|
||||
- `s3_key_name` (string) - The name of the key in `s3_bucket_name` where the
|
||||
OVA file will be copied to for import. If not specified, this will default
|
||||
to "packer-import-{{timestamp}}.ova". This key (ie, the uploaded OVA) will
|
||||
be removed after import, unless `skip_clean` is `true`.
|
||||
|
||||
- `skip_clean` (boolean) - Whether we should skip removing the OVA file uploaded to S3 after the
|
||||
import process has completed. "true" means that we should leave it in the S3 bucket, "false" means to clean it out. Defaults to `false`.
|
||||
|
||||
- `tags` (object of key/value strings) - Tags applied to the created AMI and
|
||||
relevant snapshots.
|
||||
|
||||
- `ami_users` (array of strings) - A list of account IDs that have access to launch the imported AMI. By default no additional users other than the user importing the AMI has permission to launch it.
|
||||
|
||||
- `ami_groups` (array of strings) - A list of groups that have access to launch the imported AMI. By default no groups have permission to launch the AMI. `all` will make the AMI publically accessible. AWS currently doesn't accept any value other than "all".
|
||||
|
||||
- `ami_description` (string) - The description to set for the resulting imported AMI. By default this description is generated by the AMI import process.
|
||||
|
||||
- `license_type` (string) - The license type to be used for the Amazon Machine Image (AMI) after importing. Valid values: `AWS` or `BYOL` (default). For more details regarding licensing, see [Prerequisites](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/VMImportPrerequisites.html) in the VM Import/Export User Guide.
|
||||
- `token` (string) - The access token to use. This is different from the
|
||||
access key and secret key. If you're not sure what this is, then you
|
||||
probably don't need it. This will also be read from the `AWS_SESSION_TOKEN`
|
||||
environmental variable.
|
||||
|
||||
## Basic Example
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue