diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 0fa31d37287..88a811aa68e 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -62,6 +62,16 @@ "Comment": "v1.0.7", "Rev": "bf2f8fe7f45e68017086d069498638893feddf64" }, + { + "ImportPath": "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil", + "Comment": "v1.0.7", + "Rev": "bf2f8fe7f45e68017086d069498638893feddf64" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/private/protocol/jsonrpc", + "Comment": "v1.0.7", + "Rev": "bf2f8fe7f45e68017086d069498638893feddf64" + }, { "ImportPath": "github.com/aws/aws-sdk-go/private/protocol/query", "Comment": "v1.0.7", @@ -97,6 +107,11 @@ "Comment": "v1.0.7", "Rev": "bf2f8fe7f45e68017086d069498638893feddf64" }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/ecr", + "Comment": "v1.0.7", + "Rev": "bf2f8fe7f45e68017086d069498638893feddf64" + }, { "ImportPath": "github.com/aws/aws-sdk-go/service/elb", "Comment": "v1.0.7", diff --git a/Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/json/jsonutil/build.go b/Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/json/jsonutil/build.go new file mode 100644 index 00000000000..870707c6a69 --- /dev/null +++ b/Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/json/jsonutil/build.go @@ -0,0 +1,243 @@ +// Package jsonutil provides JSON serialisation of AWS requests and responses. +package jsonutil + +import ( + "bytes" + "encoding/base64" + "fmt" + "reflect" + "sort" + "strconv" + "time" +) + +var timeType = reflect.ValueOf(time.Time{}).Type() +var byteSliceType = reflect.ValueOf([]byte{}).Type() + +// BuildJSON builds a JSON string for a given object v. +func BuildJSON(v interface{}) ([]byte, error) { + var buf bytes.Buffer + + err := buildAny(reflect.ValueOf(v), &buf, "") + return buf.Bytes(), err +} + +func buildAny(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { + value = reflect.Indirect(value) + if !value.IsValid() { + return nil + } + + vtype := value.Type() + + t := tag.Get("type") + if t == "" { + switch vtype.Kind() { + case reflect.Struct: + // also it can't be a time object + if value.Type() != timeType { + t = "structure" + } + case reflect.Slice: + // also it can't be a byte slice + if _, ok := value.Interface().([]byte); !ok { + t = "list" + } + case reflect.Map: + t = "map" + } + } + + switch t { + case "structure": + if field, ok := vtype.FieldByName("_"); ok { + tag = field.Tag + } + return buildStruct(value, buf, tag) + case "list": + return buildList(value, buf, tag) + case "map": + return buildMap(value, buf, tag) + default: + return buildScalar(value, buf, tag) + } +} + +func buildStruct(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { + if !value.IsValid() { + return nil + } + + // unwrap payloads + if payload := tag.Get("payload"); payload != "" { + field, _ := value.Type().FieldByName(payload) + tag = field.Tag + value = elemOf(value.FieldByName(payload)) + + if !value.IsValid() { + return nil + } + } + + buf.WriteByte('{') + + t := value.Type() + first := true + for i := 0; i < t.NumField(); i++ { + member := value.Field(i) + if (member.Kind() == reflect.Ptr || member.Kind() == reflect.Slice || member.Kind() == reflect.Map) && member.IsNil() { + continue // ignore unset fields + } + + field := t.Field(i) + if field.PkgPath != "" { + continue // ignore unexported fields + } + if field.Tag.Get("json") == "-" { + continue + } + if field.Tag.Get("location") != "" { + continue // ignore non-body elements + } + + if first { + first = false + } else { + buf.WriteByte(',') + } + + // figure out what this field is called + name := field.Name + if locName := field.Tag.Get("locationName"); locName != "" { + name = locName + } + + fmt.Fprintf(buf, "%q:", name) + + err := buildAny(member, buf, field.Tag) + if err != nil { + return err + } + + } + + buf.WriteString("}") + + return nil +} + +func buildList(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { + buf.WriteString("[") + + for i := 0; i < value.Len(); i++ { + buildAny(value.Index(i), buf, "") + + if i < value.Len()-1 { + buf.WriteString(",") + } + } + + buf.WriteString("]") + + return nil +} + +type sortedValues []reflect.Value + +func (sv sortedValues) Len() int { return len(sv) } +func (sv sortedValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } +func (sv sortedValues) Less(i, j int) bool { return sv[i].String() < sv[j].String() } + +func buildMap(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { + buf.WriteString("{") + + var sv sortedValues = value.MapKeys() + sort.Sort(sv) + + for i, k := range sv { + if i > 0 { + buf.WriteByte(',') + } + + fmt.Fprintf(buf, "%q:", k) + buildAny(value.MapIndex(k), buf, "") + } + + buf.WriteString("}") + + return nil +} + +func buildScalar(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { + switch value.Kind() { + case reflect.String: + writeString(value.String(), buf) + case reflect.Bool: + buf.WriteString(strconv.FormatBool(value.Bool())) + case reflect.Int64: + buf.WriteString(strconv.FormatInt(value.Int(), 10)) + case reflect.Float64: + buf.WriteString(strconv.FormatFloat(value.Float(), 'f', -1, 64)) + default: + switch value.Type() { + case timeType: + converted := value.Interface().(time.Time) + buf.WriteString(strconv.FormatInt(converted.UTC().Unix(), 10)) + case byteSliceType: + if !value.IsNil() { + converted := value.Interface().([]byte) + buf.WriteByte('"') + if len(converted) < 1024 { + // for small buffers, using Encode directly is much faster. + dst := make([]byte, base64.StdEncoding.EncodedLen(len(converted))) + base64.StdEncoding.Encode(dst, converted) + buf.Write(dst) + } else { + // for large buffers, avoid unnecessary extra temporary + // buffer space. + enc := base64.NewEncoder(base64.StdEncoding, buf) + enc.Write(converted) + enc.Close() + } + buf.WriteByte('"') + } + default: + return fmt.Errorf("unsupported JSON value %v (%s)", value.Interface(), value.Type()) + } + } + return nil +} + +func writeString(s string, buf *bytes.Buffer) { + buf.WriteByte('"') + for _, r := range s { + if r == '"' { + buf.WriteString(`\"`) + } else if r == '\\' { + buf.WriteString(`\\`) + } else if r == '\b' { + buf.WriteString(`\b`) + } else if r == '\f' { + buf.WriteString(`\f`) + } else if r == '\r' { + buf.WriteString(`\r`) + } else if r == '\t' { + buf.WriteString(`\t`) + } else if r == '\n' { + buf.WriteString(`\n`) + } else if r < 32 { + fmt.Fprintf(buf, "\\u%0.4x", r) + } else { + buf.WriteRune(r) + } + } + buf.WriteByte('"') +} + +// Returns the reflection element of a value, if it is a pointer. +func elemOf(value reflect.Value) reflect.Value { + for value.Kind() == reflect.Ptr { + value = value.Elem() + } + return value +} diff --git a/Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/json/jsonutil/unmarshal.go b/Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/json/jsonutil/unmarshal.go new file mode 100644 index 00000000000..fea53561366 --- /dev/null +++ b/Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/json/jsonutil/unmarshal.go @@ -0,0 +1,213 @@ +package jsonutil + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "reflect" + "time" +) + +// UnmarshalJSON reads a stream and unmarshals the results in object v. +func UnmarshalJSON(v interface{}, stream io.Reader) error { + var out interface{} + + b, err := ioutil.ReadAll(stream) + if err != nil { + return err + } + + if len(b) == 0 { + return nil + } + + if err := json.Unmarshal(b, &out); err != nil { + return err + } + + return unmarshalAny(reflect.ValueOf(v), out, "") +} + +func unmarshalAny(value reflect.Value, data interface{}, tag reflect.StructTag) error { + vtype := value.Type() + if vtype.Kind() == reflect.Ptr { + vtype = vtype.Elem() // check kind of actual element type + } + + t := tag.Get("type") + if t == "" { + switch vtype.Kind() { + case reflect.Struct: + // also it can't be a time object + if _, ok := value.Interface().(*time.Time); !ok { + t = "structure" + } + case reflect.Slice: + // also it can't be a byte slice + if _, ok := value.Interface().([]byte); !ok { + t = "list" + } + case reflect.Map: + t = "map" + } + } + + switch t { + case "structure": + if field, ok := vtype.FieldByName("_"); ok { + tag = field.Tag + } + return unmarshalStruct(value, data, tag) + case "list": + return unmarshalList(value, data, tag) + case "map": + return unmarshalMap(value, data, tag) + default: + return unmarshalScalar(value, data, tag) + } +} + +func unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTag) error { + if data == nil { + return nil + } + mapData, ok := data.(map[string]interface{}) + if !ok { + return fmt.Errorf("JSON value is not a structure (%#v)", data) + } + + t := value.Type() + if value.Kind() == reflect.Ptr { + if value.IsNil() { // create the structure if it's nil + s := reflect.New(value.Type().Elem()) + value.Set(s) + value = s + } + + value = value.Elem() + t = t.Elem() + } + + // unwrap any payloads + if payload := tag.Get("payload"); payload != "" { + field, _ := t.FieldByName(payload) + return unmarshalAny(value.FieldByName(payload), data, field.Tag) + } + + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + if field.PkgPath != "" { + continue // ignore unexported fields + } + + // figure out what this field is called + name := field.Name + if locName := field.Tag.Get("locationName"); locName != "" { + name = locName + } + + member := value.FieldByIndex(field.Index) + err := unmarshalAny(member, mapData[name], field.Tag) + if err != nil { + return err + } + } + return nil +} + +func unmarshalList(value reflect.Value, data interface{}, tag reflect.StructTag) error { + if data == nil { + return nil + } + listData, ok := data.([]interface{}) + if !ok { + return fmt.Errorf("JSON value is not a list (%#v)", data) + } + + if value.IsNil() { + l := len(listData) + value.Set(reflect.MakeSlice(value.Type(), l, l)) + } + + for i, c := range listData { + err := unmarshalAny(value.Index(i), c, "") + if err != nil { + return err + } + } + + return nil +} + +func unmarshalMap(value reflect.Value, data interface{}, tag reflect.StructTag) error { + if data == nil { + return nil + } + mapData, ok := data.(map[string]interface{}) + if !ok { + return fmt.Errorf("JSON value is not a map (%#v)", data) + } + + if value.IsNil() { + value.Set(reflect.MakeMap(value.Type())) + } + + for k, v := range mapData { + kvalue := reflect.ValueOf(k) + vvalue := reflect.New(value.Type().Elem()).Elem() + + unmarshalAny(vvalue, v, "") + value.SetMapIndex(kvalue, vvalue) + } + + return nil +} + +func unmarshalScalar(value reflect.Value, data interface{}, tag reflect.StructTag) error { + errf := func() error { + return fmt.Errorf("unsupported value: %v (%s)", value.Interface(), value.Type()) + } + + switch d := data.(type) { + case nil: + return nil // nothing to do here + case string: + switch value.Interface().(type) { + case *string: + value.Set(reflect.ValueOf(&d)) + case []byte: + b, err := base64.StdEncoding.DecodeString(d) + if err != nil { + return err + } + value.Set(reflect.ValueOf(b)) + default: + return errf() + } + case float64: + switch value.Interface().(type) { + case *int64: + di := int64(d) + value.Set(reflect.ValueOf(&di)) + case *float64: + value.Set(reflect.ValueOf(&d)) + case *time.Time: + t := time.Unix(int64(d), 0).UTC() + value.Set(reflect.ValueOf(&t)) + default: + return errf() + } + case bool: + switch value.Interface().(type) { + case *bool: + value.Set(reflect.ValueOf(&d)) + default: + return errf() + } + default: + return fmt.Errorf("unsupported JSON value (%v)", data) + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/jsonrpc/jsonrpc.go b/Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/jsonrpc/jsonrpc.go new file mode 100644 index 00000000000..c4e71cf4875 --- /dev/null +++ b/Godeps/_workspace/src/github.com/aws/aws-sdk-go/private/protocol/jsonrpc/jsonrpc.go @@ -0,0 +1,99 @@ +// Package jsonrpc provides JSON RPC utilities for serialisation of AWS +// 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 + +import ( + "encoding/json" + "io/ioutil" + "strings" + + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil" + "github.com/aws/aws-sdk-go/private/protocol/rest" +) + +var emptyJSON = []byte("{}") + +// Build builds a JSON payload for a JSON RPC request. +func Build(req *request.Request) { + var buf []byte + var err error + if req.ParamsFilled() { + buf, err = jsonutil.BuildJSON(req.Params) + if err != nil { + req.Error = awserr.New("SerializationError", "failed encoding JSON RPC request", err) + return + } + } else { + buf = emptyJSON + } + + if req.ClientInfo.TargetPrefix != "" || string(buf) != "{}" { + req.SetBufferBody(buf) + } + + if req.ClientInfo.TargetPrefix != "" { + target := req.ClientInfo.TargetPrefix + "." + req.Operation.Name + req.HTTPRequest.Header.Add("X-Amz-Target", target) + } + if req.ClientInfo.JSONVersion != "" { + jsonVersion := req.ClientInfo.JSONVersion + req.HTTPRequest.Header.Add("Content-Type", "application/x-amz-json-"+jsonVersion) + } +} + +// Unmarshal unmarshals a response for a JSON RPC service. +func Unmarshal(req *request.Request) { + defer req.HTTPResponse.Body.Close() + if req.DataFilled() { + err := jsonutil.UnmarshalJSON(req.Data, req.HTTPResponse.Body) + if err != nil { + req.Error = awserr.New("SerializationError", "failed decoding JSON RPC response", err) + } + } + return +} + +// UnmarshalMeta unmarshals headers from a response for a JSON RPC service. +func UnmarshalMeta(req *request.Request) { + rest.UnmarshalMeta(req) +} + +// UnmarshalError unmarshals an error response for a JSON RPC service. +func UnmarshalError(req *request.Request) { + defer req.HTTPResponse.Body.Close() + bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body) + if err != nil { + req.Error = awserr.New("SerializationError", "failed reading JSON RPC error response", err) + return + } + if len(bodyBytes) == 0 { + req.Error = awserr.NewRequestFailure( + awserr.New("SerializationError", req.HTTPResponse.Status, nil), + req.HTTPResponse.StatusCode, + "", + ) + return + } + var jsonErr jsonErrorResponse + if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil { + req.Error = awserr.New("SerializationError", "failed decoding JSON RPC error response", err) + return + } + + codes := strings.SplitN(jsonErr.Code, "#", 2) + req.Error = awserr.NewRequestFailure( + awserr.New(codes[len(codes)-1], jsonErr.Message, nil), + req.HTTPResponse.StatusCode, + req.RequestID, + ) +} + +type jsonErrorResponse struct { + Code string `json:"__type"` + Message string `json:"message"` +} diff --git a/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/ecr/api.go b/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/ecr/api.go new file mode 100644 index 00000000000..73bd81f8dd3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/ecr/api.go @@ -0,0 +1,1433 @@ +// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. + +// Package ecr provides a client for Amazon EC2 Container Registry. +package ecr + +import ( + "time" + + "github.com/aws/aws-sdk-go/aws/awsutil" + "github.com/aws/aws-sdk-go/aws/request" +) + +const opBatchCheckLayerAvailability = "BatchCheckLayerAvailability" + +// BatchCheckLayerAvailabilityRequest generates a request for the BatchCheckLayerAvailability operation. +func (c *ECR) BatchCheckLayerAvailabilityRequest(input *BatchCheckLayerAvailabilityInput) (req *request.Request, output *BatchCheckLayerAvailabilityOutput) { + op := &request.Operation{ + Name: opBatchCheckLayerAvailability, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &BatchCheckLayerAvailabilityInput{} + } + + req = c.newRequest(op, input, output) + output = &BatchCheckLayerAvailabilityOutput{} + req.Data = output + return +} + +// Check the availability of multiple image layers in a specified registry and +// repository. +// +// This operation is used by the Amazon ECR proxy, and it is not intended +// for general use by customers. Use the docker CLI to pull, tag, and push images. +func (c *ECR) BatchCheckLayerAvailability(input *BatchCheckLayerAvailabilityInput) (*BatchCheckLayerAvailabilityOutput, error) { + req, out := c.BatchCheckLayerAvailabilityRequest(input) + err := req.Send() + return out, err +} + +const opBatchDeleteImage = "BatchDeleteImage" + +// BatchDeleteImageRequest generates a request for the BatchDeleteImage operation. +func (c *ECR) BatchDeleteImageRequest(input *BatchDeleteImageInput) (req *request.Request, output *BatchDeleteImageOutput) { + op := &request.Operation{ + Name: opBatchDeleteImage, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &BatchDeleteImageInput{} + } + + req = c.newRequest(op, input, output) + output = &BatchDeleteImageOutput{} + req.Data = output + return +} + +// Deletes a list of specified images within a specified repository. Images +// are specified with either imageTag or imageDigest. +func (c *ECR) BatchDeleteImage(input *BatchDeleteImageInput) (*BatchDeleteImageOutput, error) { + req, out := c.BatchDeleteImageRequest(input) + err := req.Send() + return out, err +} + +const opBatchGetImage = "BatchGetImage" + +// BatchGetImageRequest generates a request for the BatchGetImage operation. +func (c *ECR) BatchGetImageRequest(input *BatchGetImageInput) (req *request.Request, output *BatchGetImageOutput) { + op := &request.Operation{ + Name: opBatchGetImage, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &BatchGetImageInput{} + } + + req = c.newRequest(op, input, output) + output = &BatchGetImageOutput{} + req.Data = output + return +} + +// Gets detailed information for specified images within a specified repository. +// Images are specified with either imageTag or imageDigest. +func (c *ECR) BatchGetImage(input *BatchGetImageInput) (*BatchGetImageOutput, error) { + req, out := c.BatchGetImageRequest(input) + err := req.Send() + return out, err +} + +const opCompleteLayerUpload = "CompleteLayerUpload" + +// CompleteLayerUploadRequest generates a request for the CompleteLayerUpload operation. +func (c *ECR) CompleteLayerUploadRequest(input *CompleteLayerUploadInput) (req *request.Request, output *CompleteLayerUploadOutput) { + op := &request.Operation{ + Name: opCompleteLayerUpload, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &CompleteLayerUploadInput{} + } + + req = c.newRequest(op, input, output) + output = &CompleteLayerUploadOutput{} + req.Data = output + return +} + +// Inform Amazon ECR that the image layer upload for a specified registry, repository +// name, and upload ID, has completed. You can optionally provide a sha256 digest +// of the image layer for data validation purposes. +// +// This operation is used by the Amazon ECR proxy, and it is not intended +// for general use by customers. Use the docker CLI to pull, tag, and push images. +func (c *ECR) CompleteLayerUpload(input *CompleteLayerUploadInput) (*CompleteLayerUploadOutput, error) { + req, out := c.CompleteLayerUploadRequest(input) + err := req.Send() + return out, err +} + +const opCreateRepository = "CreateRepository" + +// CreateRepositoryRequest generates a request for the CreateRepository operation. +func (c *ECR) CreateRepositoryRequest(input *CreateRepositoryInput) (req *request.Request, output *CreateRepositoryOutput) { + op := &request.Operation{ + Name: opCreateRepository, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &CreateRepositoryInput{} + } + + req = c.newRequest(op, input, output) + output = &CreateRepositoryOutput{} + req.Data = output + return +} + +// Creates an image repository. +func (c *ECR) CreateRepository(input *CreateRepositoryInput) (*CreateRepositoryOutput, error) { + req, out := c.CreateRepositoryRequest(input) + err := req.Send() + return out, err +} + +const opDeleteRepository = "DeleteRepository" + +// DeleteRepositoryRequest generates a request for the DeleteRepository operation. +func (c *ECR) DeleteRepositoryRequest(input *DeleteRepositoryInput) (req *request.Request, output *DeleteRepositoryOutput) { + op := &request.Operation{ + Name: opDeleteRepository, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DeleteRepositoryInput{} + } + + req = c.newRequest(op, input, output) + output = &DeleteRepositoryOutput{} + req.Data = output + return +} + +// Deletes an existing image repository. If a repository contains images, you +// must use the force option to delete it. +func (c *ECR) DeleteRepository(input *DeleteRepositoryInput) (*DeleteRepositoryOutput, error) { + req, out := c.DeleteRepositoryRequest(input) + err := req.Send() + return out, err +} + +const opDeleteRepositoryPolicy = "DeleteRepositoryPolicy" + +// DeleteRepositoryPolicyRequest generates a request for the DeleteRepositoryPolicy operation. +func (c *ECR) DeleteRepositoryPolicyRequest(input *DeleteRepositoryPolicyInput) (req *request.Request, output *DeleteRepositoryPolicyOutput) { + op := &request.Operation{ + Name: opDeleteRepositoryPolicy, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DeleteRepositoryPolicyInput{} + } + + req = c.newRequest(op, input, output) + output = &DeleteRepositoryPolicyOutput{} + req.Data = output + return +} + +// Deletes the repository policy from a specified repository. +func (c *ECR) DeleteRepositoryPolicy(input *DeleteRepositoryPolicyInput) (*DeleteRepositoryPolicyOutput, error) { + req, out := c.DeleteRepositoryPolicyRequest(input) + err := req.Send() + return out, err +} + +const opDescribeRepositories = "DescribeRepositories" + +// DescribeRepositoriesRequest generates a request for the DescribeRepositories operation. +func (c *ECR) DescribeRepositoriesRequest(input *DescribeRepositoriesInput) (req *request.Request, output *DescribeRepositoriesOutput) { + op := &request.Operation{ + Name: opDescribeRepositories, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DescribeRepositoriesInput{} + } + + req = c.newRequest(op, input, output) + output = &DescribeRepositoriesOutput{} + req.Data = output + return +} + +// Describes image repositories in a registry. +func (c *ECR) DescribeRepositories(input *DescribeRepositoriesInput) (*DescribeRepositoriesOutput, error) { + req, out := c.DescribeRepositoriesRequest(input) + err := req.Send() + return out, err +} + +const opGetAuthorizationToken = "GetAuthorizationToken" + +// GetAuthorizationTokenRequest generates a request for the GetAuthorizationToken operation. +func (c *ECR) GetAuthorizationTokenRequest(input *GetAuthorizationTokenInput) (req *request.Request, output *GetAuthorizationTokenOutput) { + op := &request.Operation{ + Name: opGetAuthorizationToken, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &GetAuthorizationTokenInput{} + } + + req = c.newRequest(op, input, output) + output = &GetAuthorizationTokenOutput{} + req.Data = output + return +} + +// Retrieves a token that is valid for a specified registry for 12 hours. This +// command allows you to use the docker CLI to push and pull images with Amazon +// ECR. If you do not specify a registry, the default registry is assumed. +// +// The authorizationToken returned for each registry specified is a base64 +// encoded string that can be decoded and used in a docker login command to +// authenticate to a registry. The AWS CLI offers an aws ecr get-login command +// that simplifies the login process. +func (c *ECR) GetAuthorizationToken(input *GetAuthorizationTokenInput) (*GetAuthorizationTokenOutput, error) { + req, out := c.GetAuthorizationTokenRequest(input) + err := req.Send() + return out, err +} + +const opGetDownloadUrlForLayer = "GetDownloadUrlForLayer" + +// GetDownloadUrlForLayerRequest generates a request for the GetDownloadUrlForLayer operation. +func (c *ECR) GetDownloadUrlForLayerRequest(input *GetDownloadUrlForLayerInput) (req *request.Request, output *GetDownloadUrlForLayerOutput) { + op := &request.Operation{ + Name: opGetDownloadUrlForLayer, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &GetDownloadUrlForLayerInput{} + } + + req = c.newRequest(op, input, output) + output = &GetDownloadUrlForLayerOutput{} + req.Data = output + return +} + +// Retrieves the pre-signed Amazon S3 download URL corresponding to an image +// layer. You can only get URLs for image layers that are referenced in an image. +// +// This operation is used by the Amazon ECR proxy, and it is not intended +// for general use by customers. Use the docker CLI to pull, tag, and push images. +func (c *ECR) GetDownloadUrlForLayer(input *GetDownloadUrlForLayerInput) (*GetDownloadUrlForLayerOutput, error) { + req, out := c.GetDownloadUrlForLayerRequest(input) + err := req.Send() + return out, err +} + +const opGetRepositoryPolicy = "GetRepositoryPolicy" + +// GetRepositoryPolicyRequest generates a request for the GetRepositoryPolicy operation. +func (c *ECR) GetRepositoryPolicyRequest(input *GetRepositoryPolicyInput) (req *request.Request, output *GetRepositoryPolicyOutput) { + op := &request.Operation{ + Name: opGetRepositoryPolicy, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &GetRepositoryPolicyInput{} + } + + req = c.newRequest(op, input, output) + output = &GetRepositoryPolicyOutput{} + req.Data = output + return +} + +// Retrieves the repository policy for a specified repository. +func (c *ECR) GetRepositoryPolicy(input *GetRepositoryPolicyInput) (*GetRepositoryPolicyOutput, error) { + req, out := c.GetRepositoryPolicyRequest(input) + err := req.Send() + return out, err +} + +const opInitiateLayerUpload = "InitiateLayerUpload" + +// InitiateLayerUploadRequest generates a request for the InitiateLayerUpload operation. +func (c *ECR) InitiateLayerUploadRequest(input *InitiateLayerUploadInput) (req *request.Request, output *InitiateLayerUploadOutput) { + op := &request.Operation{ + Name: opInitiateLayerUpload, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &InitiateLayerUploadInput{} + } + + req = c.newRequest(op, input, output) + output = &InitiateLayerUploadOutput{} + req.Data = output + return +} + +// Notify Amazon ECR that you intend to upload an image layer. +// +// This operation is used by the Amazon ECR proxy, and it is not intended +// for general use by customers. Use the docker CLI to pull, tag, and push images. +func (c *ECR) InitiateLayerUpload(input *InitiateLayerUploadInput) (*InitiateLayerUploadOutput, error) { + req, out := c.InitiateLayerUploadRequest(input) + err := req.Send() + return out, err +} + +const opListImages = "ListImages" + +// ListImagesRequest generates a request for the ListImages operation. +func (c *ECR) ListImagesRequest(input *ListImagesInput) (req *request.Request, output *ListImagesOutput) { + op := &request.Operation{ + Name: opListImages, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &ListImagesInput{} + } + + req = c.newRequest(op, input, output) + output = &ListImagesOutput{} + req.Data = output + return +} + +// Lists all the image IDs for a given repository. +func (c *ECR) ListImages(input *ListImagesInput) (*ListImagesOutput, error) { + req, out := c.ListImagesRequest(input) + err := req.Send() + return out, err +} + +const opPutImage = "PutImage" + +// PutImageRequest generates a request for the PutImage operation. +func (c *ECR) PutImageRequest(input *PutImageInput) (req *request.Request, output *PutImageOutput) { + op := &request.Operation{ + Name: opPutImage, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &PutImageInput{} + } + + req = c.newRequest(op, input, output) + output = &PutImageOutput{} + req.Data = output + return +} + +// Creates or updates the image manifest associated with an image. +// +// This operation is used by the Amazon ECR proxy, and it is not intended +// for general use by customers. Use the docker CLI to pull, tag, and push images. +func (c *ECR) PutImage(input *PutImageInput) (*PutImageOutput, error) { + req, out := c.PutImageRequest(input) + err := req.Send() + return out, err +} + +const opSetRepositoryPolicy = "SetRepositoryPolicy" + +// SetRepositoryPolicyRequest generates a request for the SetRepositoryPolicy operation. +func (c *ECR) SetRepositoryPolicyRequest(input *SetRepositoryPolicyInput) (req *request.Request, output *SetRepositoryPolicyOutput) { + op := &request.Operation{ + Name: opSetRepositoryPolicy, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &SetRepositoryPolicyInput{} + } + + req = c.newRequest(op, input, output) + output = &SetRepositoryPolicyOutput{} + req.Data = output + return +} + +// Applies a repository policy on a specified repository to control access permissions. +func (c *ECR) SetRepositoryPolicy(input *SetRepositoryPolicyInput) (*SetRepositoryPolicyOutput, error) { + req, out := c.SetRepositoryPolicyRequest(input) + err := req.Send() + return out, err +} + +const opUploadLayerPart = "UploadLayerPart" + +// UploadLayerPartRequest generates a request for the UploadLayerPart operation. +func (c *ECR) UploadLayerPartRequest(input *UploadLayerPartInput) (req *request.Request, output *UploadLayerPartOutput) { + op := &request.Operation{ + Name: opUploadLayerPart, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &UploadLayerPartInput{} + } + + req = c.newRequest(op, input, output) + output = &UploadLayerPartOutput{} + req.Data = output + return +} + +// Uploads an image layer part to Amazon ECR. +// +// This operation is used by the Amazon ECR proxy, and it is not intended +// for general use by customers. Use the docker CLI to pull, tag, and push images. +func (c *ECR) UploadLayerPart(input *UploadLayerPartInput) (*UploadLayerPartOutput, error) { + req, out := c.UploadLayerPartRequest(input) + err := req.Send() + return out, err +} + +// An object representing authorization data for an Amazon ECR registry. +type AuthorizationData struct { + _ struct{} `type:"structure"` + + // A base64-encoded string that contains authorization data for the specified + // Amazon ECR registry. When the string is decoded, it is presented in the format + // user:password for private registry authentication using docker login. + AuthorizationToken *string `locationName:"authorizationToken" type:"string"` + + // The Unix time in seconds and milliseconds when the authorization token expires. + // Authorization tokens are valid for 12 hours. + ExpiresAt *time.Time `locationName:"expiresAt" type:"timestamp" timestampFormat:"unix"` + + // The registry URL to use for this authorization token in a docker login command. + // The Amazon ECR registry URL format is https://aws_account_id.dkr.ecr.region.amazonaws.com. + // For example, https://012345678910.dkr.ecr.us-east-1.amazonaws.com. + ProxyEndpoint *string `locationName:"proxyEndpoint" type:"string"` +} + +// String returns the string representation +func (s AuthorizationData) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s AuthorizationData) GoString() string { + return s.String() +} + +type BatchCheckLayerAvailabilityInput struct { + _ struct{} `type:"structure"` + + // The digests of the image layers to check. + LayerDigests []*string `locationName:"layerDigests" min:"1" type:"list" required:"true"` + + // The AWS account ID associated with the registry that contains the image layers + // to check. If you do not specify a registry, the default registry is assumed. + RegistryId *string `locationName:"registryId" type:"string"` + + // The name of the repository that is associated with the image layers to check. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string" required:"true"` +} + +// String returns the string representation +func (s BatchCheckLayerAvailabilityInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s BatchCheckLayerAvailabilityInput) GoString() string { + return s.String() +} + +type BatchCheckLayerAvailabilityOutput struct { + _ struct{} `type:"structure"` + + // Any failures associated with the call. + Failures []*LayerFailure `locationName:"failures" type:"list"` + + // A list of image layer objects corresponding to the image layer references + // in the request. + Layers []*Layer `locationName:"layers" type:"list"` +} + +// String returns the string representation +func (s BatchCheckLayerAvailabilityOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s BatchCheckLayerAvailabilityOutput) GoString() string { + return s.String() +} + +// Deletes specified images within a specified repository. Images are specified +// with either the imageTag or imageDigest. +type BatchDeleteImageInput struct { + _ struct{} `type:"structure"` + + // A list of image ID references that correspond to images to delete. The format + // of the imageIds reference is imageTag=tag or imageDigest=digest. + ImageIds []*ImageIdentifier `locationName:"imageIds" min:"1" type:"list" required:"true"` + + // The AWS account ID associated with the registry that contains the image to + // delete. If you do not specify a registry, the default registry is assumed. + RegistryId *string `locationName:"registryId" type:"string"` + + // The repository that contains the image to delete. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string" required:"true"` +} + +// String returns the string representation +func (s BatchDeleteImageInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s BatchDeleteImageInput) GoString() string { + return s.String() +} + +type BatchDeleteImageOutput struct { + _ struct{} `type:"structure"` + + // Any failures associated with the call. + Failures []*ImageFailure `locationName:"failures" type:"list"` + + // The image IDs of the deleted images. + ImageIds []*ImageIdentifier `locationName:"imageIds" min:"1" type:"list"` +} + +// String returns the string representation +func (s BatchDeleteImageOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s BatchDeleteImageOutput) GoString() string { + return s.String() +} + +type BatchGetImageInput struct { + _ struct{} `type:"structure"` + + // A list of image ID references that correspond to images to describe. The + // format of the imageIds reference is imageTag=tag or imageDigest=digest. + ImageIds []*ImageIdentifier `locationName:"imageIds" min:"1" type:"list" required:"true"` + + // The AWS account ID associated with the registry that contains the images + // to describe. If you do not specify a registry, the default registry is assumed. + RegistryId *string `locationName:"registryId" type:"string"` + + // The repository that contains the images to describe. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string" required:"true"` +} + +// String returns the string representation +func (s BatchGetImageInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s BatchGetImageInput) GoString() string { + return s.String() +} + +type BatchGetImageOutput struct { + _ struct{} `type:"structure"` + + // Any failures associated with the call. + Failures []*ImageFailure `locationName:"failures" type:"list"` + + // A list of image objects corresponding to the image references in the request. + Images []*Image `locationName:"images" type:"list"` +} + +// String returns the string representation +func (s BatchGetImageOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s BatchGetImageOutput) GoString() string { + return s.String() +} + +type CompleteLayerUploadInput struct { + _ struct{} `type:"structure"` + + // The sha256 digest of the image layer. + LayerDigests []*string `locationName:"layerDigests" min:"1" type:"list" required:"true"` + + // The AWS account ID associated with the registry to which to upload layers. + // If you do not specify a registry, the default registry is assumed. + RegistryId *string `locationName:"registryId" type:"string"` + + // The name of the repository to associate with the image layer. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string" required:"true"` + + // The upload ID from a previous InitiateLayerUpload operation to associate + // with the image layer. + UploadId *string `locationName:"uploadId" type:"string" required:"true"` +} + +// String returns the string representation +func (s CompleteLayerUploadInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CompleteLayerUploadInput) GoString() string { + return s.String() +} + +type CompleteLayerUploadOutput struct { + _ struct{} `type:"structure"` + + // The sha256 digest of the image layer. + LayerDigest *string `locationName:"layerDigest" type:"string"` + + // The registry ID associated with the request. + RegistryId *string `locationName:"registryId" type:"string"` + + // The repository name associated with the request. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string"` + + // The upload ID associated with the layer. + UploadId *string `locationName:"uploadId" type:"string"` +} + +// String returns the string representation +func (s CompleteLayerUploadOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CompleteLayerUploadOutput) GoString() string { + return s.String() +} + +type CreateRepositoryInput struct { + _ struct{} `type:"structure"` + + // The name to use for the repository. The repository name may be specified + // on its own (such as nginx-web-app) or it can be prepended with a namespace + // to group the repository into a category (such as project-a/nginx-web-app). + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string" required:"true"` +} + +// String returns the string representation +func (s CreateRepositoryInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CreateRepositoryInput) GoString() string { + return s.String() +} + +type CreateRepositoryOutput struct { + _ struct{} `type:"structure"` + + // Object representing a repository. + Repository *Repository `locationName:"repository" type:"structure"` +} + +// String returns the string representation +func (s CreateRepositoryOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CreateRepositoryOutput) GoString() string { + return s.String() +} + +type DeleteRepositoryInput struct { + _ struct{} `type:"structure"` + + // Force the deletion of the repository if it contains images. + Force *bool `locationName:"force" type:"boolean"` + + // The AWS account ID associated with the registry that contains the repository + // to delete. If you do not specify a registry, the default registry is assumed. + RegistryId *string `locationName:"registryId" type:"string"` + + // The name of the repository to delete. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string" required:"true"` +} + +// String returns the string representation +func (s DeleteRepositoryInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteRepositoryInput) GoString() string { + return s.String() +} + +type DeleteRepositoryOutput struct { + _ struct{} `type:"structure"` + + // Object representing a repository. + Repository *Repository `locationName:"repository" type:"structure"` +} + +// String returns the string representation +func (s DeleteRepositoryOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteRepositoryOutput) GoString() string { + return s.String() +} + +type DeleteRepositoryPolicyInput struct { + _ struct{} `type:"structure"` + + // The AWS account ID associated with the registry that contains the repository + // policy to delete. If you do not specify a registry, the default registry + // is assumed. + RegistryId *string `locationName:"registryId" type:"string"` + + // The name of the repository that is associated with the repository policy + // to delete. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string" required:"true"` +} + +// String returns the string representation +func (s DeleteRepositoryPolicyInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteRepositoryPolicyInput) GoString() string { + return s.String() +} + +type DeleteRepositoryPolicyOutput struct { + _ struct{} `type:"structure"` + + // The JSON repository policy that was deleted from the repository. + PolicyText *string `locationName:"policyText" type:"string"` + + // The registry ID associated with the request. + RegistryId *string `locationName:"registryId" type:"string"` + + // The repository name associated with the request. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string"` +} + +// String returns the string representation +func (s DeleteRepositoryPolicyOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteRepositoryPolicyOutput) GoString() string { + return s.String() +} + +type DescribeRepositoriesInput struct { + _ struct{} `type:"structure"` + + // The maximum number of repository results returned by DescribeRepositories + // in paginated output. When this parameter is used, DescribeRepositories only + // returns maxResults results in a single page along with a nextToken response + // element. The remaining results of the initial request can be seen by sending + // another DescribeRepositories request with the returned nextToken value. This + // value can be between 1 and 100. If this parameter is not used, then DescribeRepositories + // returns up to 100 results and a nextToken value, if applicable. + MaxResults *int64 `locationName:"maxResults" min:"1" type:"integer"` + + // The nextToken value returned from a previous paginated DescribeRepositories + // request where maxResults was used and the results exceeded the value of that + // parameter. Pagination continues from the end of the previous results that + // returned the nextToken value. This value is null when there are no more results + // to return. + NextToken *string `locationName:"nextToken" type:"string"` + + // The AWS account ID associated with the registry that contains the repositories + // to be described. If you do not specify a registry, the default registry is + // assumed. + RegistryId *string `locationName:"registryId" type:"string"` + + // A list of repositories to describe. If this parameter is omitted, then all + // repositories in a registry are described. + RepositoryNames []*string `locationName:"repositoryNames" min:"1" type:"list"` +} + +// String returns the string representation +func (s DescribeRepositoriesInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeRepositoriesInput) GoString() string { + return s.String() +} + +type DescribeRepositoriesOutput struct { + _ struct{} `type:"structure"` + + // The nextToken value to include in a future DescribeRepositories request. + // When the results of a DescribeRepositories request exceed maxResults, this + // value can be used to retrieve the next page of results. This value is null + // when there are no more results to return. + NextToken *string `locationName:"nextToken" type:"string"` + + // A list of repository objects corresponding to valid repositories. + Repositories []*Repository `locationName:"repositories" type:"list"` +} + +// String returns the string representation +func (s DescribeRepositoriesOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeRepositoriesOutput) GoString() string { + return s.String() +} + +type GetAuthorizationTokenInput struct { + _ struct{} `type:"structure"` + + // A list of AWS account IDs that are associated with the registries for which + // to get authorization tokens. If you do not specify a registry, the default + // registry is assumed. + RegistryIds []*string `locationName:"registryIds" min:"1" type:"list"` +} + +// String returns the string representation +func (s GetAuthorizationTokenInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s GetAuthorizationTokenInput) GoString() string { + return s.String() +} + +type GetAuthorizationTokenOutput struct { + _ struct{} `type:"structure"` + + // A list of authorization token data objects that correspond to the registryIds + // values in the request. + AuthorizationData []*AuthorizationData `locationName:"authorizationData" type:"list"` +} + +// String returns the string representation +func (s GetAuthorizationTokenOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s GetAuthorizationTokenOutput) GoString() string { + return s.String() +} + +type GetDownloadUrlForLayerInput struct { + _ struct{} `type:"structure"` + + // The digest of the image layer to download. + LayerDigest *string `locationName:"layerDigest" type:"string" required:"true"` + + // The AWS account ID associated with the registry that contains the image layer + // to download. If you do not specify a registry, the default registry is assumed. + RegistryId *string `locationName:"registryId" type:"string"` + + // The name of the repository that is associated with the image layer to download. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string" required:"true"` +} + +// String returns the string representation +func (s GetDownloadUrlForLayerInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s GetDownloadUrlForLayerInput) GoString() string { + return s.String() +} + +type GetDownloadUrlForLayerOutput struct { + _ struct{} `type:"structure"` + + // The pre-signed Amazon S3 download URL for the requested layer. + DownloadUrl *string `locationName:"downloadUrl" type:"string"` + + // The digest of the image layer to download. + LayerDigest *string `locationName:"layerDigest" type:"string"` +} + +// String returns the string representation +func (s GetDownloadUrlForLayerOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s GetDownloadUrlForLayerOutput) GoString() string { + return s.String() +} + +type GetRepositoryPolicyInput struct { + _ struct{} `type:"structure"` + + // The AWS account ID associated with the registry that contains the repository. + // If you do not specify a registry, the default registry is assumed. + RegistryId *string `locationName:"registryId" type:"string"` + + // The name of the repository whose policy you want to retrieve. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string" required:"true"` +} + +// String returns the string representation +func (s GetRepositoryPolicyInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s GetRepositoryPolicyInput) GoString() string { + return s.String() +} + +type GetRepositoryPolicyOutput struct { + _ struct{} `type:"structure"` + + // The JSON repository policy text associated with the repository. + PolicyText *string `locationName:"policyText" type:"string"` + + // The registry ID associated with the request. + RegistryId *string `locationName:"registryId" type:"string"` + + // The repository name associated with the request. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string"` +} + +// String returns the string representation +func (s GetRepositoryPolicyOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s GetRepositoryPolicyOutput) GoString() string { + return s.String() +} + +// Object representing an image. +type Image struct { + _ struct{} `type:"structure"` + + // An object containing the image tag and image digest associated with an image. + ImageId *ImageIdentifier `locationName:"imageId" type:"structure"` + + // The image manifest associated with the image. + ImageManifest *string `locationName:"imageManifest" type:"string"` + + // The AWS account ID associated with the registry containing the image. + RegistryId *string `locationName:"registryId" type:"string"` + + // The name of the repository associated with the image. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string"` +} + +// String returns the string representation +func (s Image) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s Image) GoString() string { + return s.String() +} + +type ImageFailure struct { + _ struct{} `type:"structure"` + + // The code associated with the failure. + FailureCode *string `locationName:"failureCode" type:"string" enum:"ImageFailureCode"` + + // The reason for the failure. + FailureReason *string `locationName:"failureReason" type:"string"` + + // The image ID associated with the failure. + ImageId *ImageIdentifier `locationName:"imageId" type:"structure"` +} + +// String returns the string representation +func (s ImageFailure) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ImageFailure) GoString() string { + return s.String() +} + +type ImageIdentifier struct { + _ struct{} `type:"structure"` + + // The sha256 digest of the image manifest. + ImageDigest *string `locationName:"imageDigest" type:"string"` + + // The tag used for the image. + ImageTag *string `locationName:"imageTag" type:"string"` +} + +// String returns the string representation +func (s ImageIdentifier) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ImageIdentifier) GoString() string { + return s.String() +} + +type InitiateLayerUploadInput struct { + _ struct{} `type:"structure"` + + // The AWS account ID associated with the registry that you intend to upload + // layers to. If you do not specify a registry, the default registry is assumed. + RegistryId *string `locationName:"registryId" type:"string"` + + // The name of the repository that you intend to upload layers to. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string" required:"true"` +} + +// String returns the string representation +func (s InitiateLayerUploadInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s InitiateLayerUploadInput) GoString() string { + return s.String() +} + +type InitiateLayerUploadOutput struct { + _ struct{} `type:"structure"` + + // The size, in bytes, that Amazon ECR expects future layer part uploads to + // be. + PartSize *int64 `locationName:"partSize" type:"long"` + + // The upload ID for the layer upload. This parameter is passed to further UploadLayerPart + // and CompleteLayerUpload operations. + UploadId *string `locationName:"uploadId" type:"string"` +} + +// String returns the string representation +func (s InitiateLayerUploadOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s InitiateLayerUploadOutput) GoString() string { + return s.String() +} + +type Layer struct { + _ struct{} `type:"structure"` + + // The availability status of the image layer. Valid values are AVAILABLE and + // UNAVAILABLE. + LayerAvailability *string `locationName:"layerAvailability" type:"string" enum:"LayerAvailability"` + + // The sha256 digest of the image layer. + LayerDigest *string `locationName:"layerDigest" type:"string"` + + // The size, in bytes, of the image layer. + LayerSize *int64 `locationName:"layerSize" type:"long"` +} + +// String returns the string representation +func (s Layer) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s Layer) GoString() string { + return s.String() +} + +type LayerFailure struct { + _ struct{} `type:"structure"` + + // The failure code associated with the failure. + FailureCode *string `locationName:"failureCode" type:"string" enum:"LayerFailureCode"` + + // The reason for the failure. + FailureReason *string `locationName:"failureReason" type:"string"` + + // The layer digest associated with the failure. + LayerDigest *string `locationName:"layerDigest" type:"string"` +} + +// String returns the string representation +func (s LayerFailure) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LayerFailure) GoString() string { + return s.String() +} + +type ListImagesInput struct { + _ struct{} `type:"structure"` + + // The maximum number of image results returned by ListImages in paginated output. + // When this parameter is used, ListImages only returns maxResults results in + // a single page along with a nextToken response element. The remaining results + // of the initial request can be seen by sending another ListImages request + // with the returned nextToken value. This value can be between 1 and 100. If + // this parameter is not used, then ListImages returns up to 100 results and + // a nextToken value, if applicable. + MaxResults *int64 `locationName:"maxResults" min:"1" type:"integer"` + + // The nextToken value returned from a previous paginated ListImages request + // where maxResults was used and the results exceeded the value of that parameter. + // Pagination continues from the end of the previous results that returned the + // nextToken value. This value is null when there are no more results to return. + NextToken *string `locationName:"nextToken" type:"string"` + + // The AWS account ID associated with the registry that contains the repository + // to list images in. If you do not specify a registry, the default registry + // is assumed. + RegistryId *string `locationName:"registryId" type:"string"` + + // The repository whose image IDs are to be listed. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string" required:"true"` +} + +// String returns the string representation +func (s ListImagesInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ListImagesInput) GoString() string { + return s.String() +} + +type ListImagesOutput struct { + _ struct{} `type:"structure"` + + // The list of image IDs for the requested repository. + ImageIds []*ImageIdentifier `locationName:"imageIds" min:"1" type:"list"` + + // The nextToken value to include in a future ListImages request. When the results + // of a ListImages request exceed maxResults, this value can be used to retrieve + // the next page of results. This value is null when there are no more results + // to return. + NextToken *string `locationName:"nextToken" type:"string"` +} + +// String returns the string representation +func (s ListImagesOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ListImagesOutput) GoString() string { + return s.String() +} + +type PutImageInput struct { + _ struct{} `type:"structure"` + + // The image manifest corresponding to the image to be uploaded. + ImageManifest *string `locationName:"imageManifest" type:"string" required:"true"` + + // The AWS account ID associated with the registry that contains the repository + // in which to put the image. If you do not specify a registry, the default + // registry is assumed. + RegistryId *string `locationName:"registryId" type:"string"` + + // The name of the repository in which to put the image. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string" required:"true"` +} + +// String returns the string representation +func (s PutImageInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s PutImageInput) GoString() string { + return s.String() +} + +type PutImageOutput struct { + _ struct{} `type:"structure"` + + // Details of the image uploaded. + Image *Image `locationName:"image" type:"structure"` +} + +// String returns the string representation +func (s PutImageOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s PutImageOutput) GoString() string { + return s.String() +} + +// Object representing a repository. +type Repository struct { + _ struct{} `type:"structure"` + + // The AWS account ID associated with the registry that contains the repository. + RegistryId *string `locationName:"registryId" type:"string"` + + // The Amazon Resource Name (ARN) that identifies the repository. The ARN contains + // the arn:aws:ecr namespace, followed by the region of the repository, the + // AWS account ID of the repository owner, the repository namespace, and then + // the repository name. For example, arn:aws:ecr:region:012345678910:repository/test. + RepositoryArn *string `locationName:"repositoryArn" type:"string"` + + // The name of the repository. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string"` +} + +// String returns the string representation +func (s Repository) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s Repository) GoString() string { + return s.String() +} + +type SetRepositoryPolicyInput struct { + _ struct{} `type:"structure"` + + // If the policy you are attempting to set on a repository policy would prevent + // you from setting another policy in the future, you must force the SetRepositoryPolicy + // operation. This is intended to prevent accidental repository lock outs. + Force *bool `locationName:"force" type:"boolean"` + + // The JSON repository policy text to apply to the repository. + PolicyText *string `locationName:"policyText" type:"string" required:"true"` + + // The AWS account ID associated with the registry that contains the repository. + // If you do not specify a registry, the default registry is assumed. + RegistryId *string `locationName:"registryId" type:"string"` + + // The name of the repository to receive the policy. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string" required:"true"` +} + +// String returns the string representation +func (s SetRepositoryPolicyInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s SetRepositoryPolicyInput) GoString() string { + return s.String() +} + +type SetRepositoryPolicyOutput struct { + _ struct{} `type:"structure"` + + // The JSON repository policy text applied to the repository. + PolicyText *string `locationName:"policyText" type:"string"` + + // The registry ID associated with the request. + RegistryId *string `locationName:"registryId" type:"string"` + + // The repository name associated with the request. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string"` +} + +// String returns the string representation +func (s SetRepositoryPolicyOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s SetRepositoryPolicyOutput) GoString() string { + return s.String() +} + +type UploadLayerPartInput struct { + _ struct{} `type:"structure"` + + // The base64-encoded layer part payload. + LayerPartBlob []byte `locationName:"layerPartBlob" type:"blob" required:"true"` + + // The integer value of the first byte of the layer part. + PartFirstByte *int64 `locationName:"partFirstByte" type:"long" required:"true"` + + // The integer value of the last byte of the layer part. + PartLastByte *int64 `locationName:"partLastByte" type:"long" required:"true"` + + // The AWS account ID associated with the registry that you are uploading layer + // parts to. If you do not specify a registry, the default registry is assumed. + RegistryId *string `locationName:"registryId" type:"string"` + + // The name of the repository that you are uploading layer parts to. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string" required:"true"` + + // The upload ID from a previous InitiateLayerUpload operation to associate + // with the layer part upload. + UploadId *string `locationName:"uploadId" type:"string" required:"true"` +} + +// String returns the string representation +func (s UploadLayerPartInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s UploadLayerPartInput) GoString() string { + return s.String() +} + +type UploadLayerPartOutput struct { + _ struct{} `type:"structure"` + + // The integer value of the last byte received in the request. + LastByteReceived *int64 `locationName:"lastByteReceived" type:"long"` + + // The registry ID associated with the request. + RegistryId *string `locationName:"registryId" type:"string"` + + // The repository name associated with the request. + RepositoryName *string `locationName:"repositoryName" min:"2" type:"string"` + + // The upload ID associated with the request. + UploadId *string `locationName:"uploadId" type:"string"` +} + +// String returns the string representation +func (s UploadLayerPartOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s UploadLayerPartOutput) GoString() string { + return s.String() +} + +const ( + // @enum ImageFailureCode + ImageFailureCodeInvalidImageDigest = "InvalidImageDigest" + // @enum ImageFailureCode + ImageFailureCodeInvalidImageTag = "InvalidImageTag" + // @enum ImageFailureCode + ImageFailureCodeImageTagDoesNotMatchDigest = "ImageTagDoesNotMatchDigest" + // @enum ImageFailureCode + ImageFailureCodeImageNotFound = "ImageNotFound" + // @enum ImageFailureCode + ImageFailureCodeMissingDigestAndTag = "MissingDigestAndTag" +) + +const ( + // @enum LayerAvailability + LayerAvailabilityAvailable = "AVAILABLE" + // @enum LayerAvailability + LayerAvailabilityUnavailable = "UNAVAILABLE" +) + +const ( + // @enum LayerFailureCode + LayerFailureCodeInvalidLayerDigest = "InvalidLayerDigest" + // @enum LayerFailureCode + LayerFailureCodeMissingLayerDigest = "MissingLayerDigest" +) diff --git a/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/ecr/ecriface/interface.go b/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/ecr/ecriface/interface.go new file mode 100644 index 00000000000..f98fda64751 --- /dev/null +++ b/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/ecr/ecriface/interface.go @@ -0,0 +1,78 @@ +// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. + +// Package ecriface provides an interface for the Amazon EC2 Container Registry. +package ecriface + +import ( + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/service/ecr" +) + +// ECRAPI is the interface type for ecr.ECR. +type ECRAPI interface { + BatchCheckLayerAvailabilityRequest(*ecr.BatchCheckLayerAvailabilityInput) (*request.Request, *ecr.BatchCheckLayerAvailabilityOutput) + + BatchCheckLayerAvailability(*ecr.BatchCheckLayerAvailabilityInput) (*ecr.BatchCheckLayerAvailabilityOutput, error) + + BatchDeleteImageRequest(*ecr.BatchDeleteImageInput) (*request.Request, *ecr.BatchDeleteImageOutput) + + BatchDeleteImage(*ecr.BatchDeleteImageInput) (*ecr.BatchDeleteImageOutput, error) + + BatchGetImageRequest(*ecr.BatchGetImageInput) (*request.Request, *ecr.BatchGetImageOutput) + + BatchGetImage(*ecr.BatchGetImageInput) (*ecr.BatchGetImageOutput, error) + + CompleteLayerUploadRequest(*ecr.CompleteLayerUploadInput) (*request.Request, *ecr.CompleteLayerUploadOutput) + + CompleteLayerUpload(*ecr.CompleteLayerUploadInput) (*ecr.CompleteLayerUploadOutput, error) + + CreateRepositoryRequest(*ecr.CreateRepositoryInput) (*request.Request, *ecr.CreateRepositoryOutput) + + CreateRepository(*ecr.CreateRepositoryInput) (*ecr.CreateRepositoryOutput, error) + + DeleteRepositoryRequest(*ecr.DeleteRepositoryInput) (*request.Request, *ecr.DeleteRepositoryOutput) + + DeleteRepository(*ecr.DeleteRepositoryInput) (*ecr.DeleteRepositoryOutput, error) + + DeleteRepositoryPolicyRequest(*ecr.DeleteRepositoryPolicyInput) (*request.Request, *ecr.DeleteRepositoryPolicyOutput) + + DeleteRepositoryPolicy(*ecr.DeleteRepositoryPolicyInput) (*ecr.DeleteRepositoryPolicyOutput, error) + + DescribeRepositoriesRequest(*ecr.DescribeRepositoriesInput) (*request.Request, *ecr.DescribeRepositoriesOutput) + + DescribeRepositories(*ecr.DescribeRepositoriesInput) (*ecr.DescribeRepositoriesOutput, error) + + GetAuthorizationTokenRequest(*ecr.GetAuthorizationTokenInput) (*request.Request, *ecr.GetAuthorizationTokenOutput) + + GetAuthorizationToken(*ecr.GetAuthorizationTokenInput) (*ecr.GetAuthorizationTokenOutput, error) + + GetDownloadUrlForLayerRequest(*ecr.GetDownloadUrlForLayerInput) (*request.Request, *ecr.GetDownloadUrlForLayerOutput) + + GetDownloadUrlForLayer(*ecr.GetDownloadUrlForLayerInput) (*ecr.GetDownloadUrlForLayerOutput, error) + + GetRepositoryPolicyRequest(*ecr.GetRepositoryPolicyInput) (*request.Request, *ecr.GetRepositoryPolicyOutput) + + GetRepositoryPolicy(*ecr.GetRepositoryPolicyInput) (*ecr.GetRepositoryPolicyOutput, error) + + InitiateLayerUploadRequest(*ecr.InitiateLayerUploadInput) (*request.Request, *ecr.InitiateLayerUploadOutput) + + InitiateLayerUpload(*ecr.InitiateLayerUploadInput) (*ecr.InitiateLayerUploadOutput, error) + + ListImagesRequest(*ecr.ListImagesInput) (*request.Request, *ecr.ListImagesOutput) + + ListImages(*ecr.ListImagesInput) (*ecr.ListImagesOutput, error) + + PutImageRequest(*ecr.PutImageInput) (*request.Request, *ecr.PutImageOutput) + + PutImage(*ecr.PutImageInput) (*ecr.PutImageOutput, error) + + SetRepositoryPolicyRequest(*ecr.SetRepositoryPolicyInput) (*request.Request, *ecr.SetRepositoryPolicyOutput) + + SetRepositoryPolicy(*ecr.SetRepositoryPolicyInput) (*ecr.SetRepositoryPolicyOutput, error) + + UploadLayerPartRequest(*ecr.UploadLayerPartInput) (*request.Request, *ecr.UploadLayerPartOutput) + + UploadLayerPart(*ecr.UploadLayerPartInput) (*ecr.UploadLayerPartOutput, error) +} + +var _ ECRAPI = (*ecr.ECR)(nil) diff --git a/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/ecr/service.go b/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/ecr/service.go new file mode 100644 index 00000000000..a0c6aa02e39 --- /dev/null +++ b/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/ecr/service.go @@ -0,0 +1,95 @@ +// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. + +package ecr + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/aws/client/metadata" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/private/protocol/jsonrpc" + "github.com/aws/aws-sdk-go/private/signer/v4" +) + +// The Amazon EC2 Container Registry makes it easier to manage public and private +// Docker images for AWS or on-premises environments. Amazon ECR supports resource-level +// permissions to control who can create, update, use, or delete images. Users +// and groups can be created individually in AWS Identity and Access Management +// (IAM) or federated with enterprise directories such as Microsoft Active Directory. +// Images are stored on highly durable AWS infrastructure and include built-in +// caching so that starting hundreds of containers is as fast as starting a +// single container. +//The service client's operations are safe to be used concurrently. +// It is not safe to mutate any of the client's properties though. +type ECR struct { + *client.Client +} + +// Used for custom client initialization logic +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" + +// New creates a new instance of the ECR client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a ECR client from just a session. +// svc := ecr.New(mySession) +// +// // 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) +} + +// newClient creates, initializes and returns a new service client instance. +func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *ECR { + svc := &ECR{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: ServiceName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2015-09-21", + JSONVersion: "1.1", + TargetPrefix: "AmazonEC2ContainerRegistry_V20150921", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBack(v4.Sign) + svc.Handlers.Build.PushBack(jsonrpc.Build) + svc.Handlers.Unmarshal.PushBack(jsonrpc.Unmarshal) + svc.Handlers.UnmarshalMeta.PushBack(jsonrpc.UnmarshalMeta) + svc.Handlers.UnmarshalError.PushBack(jsonrpc.UnmarshalError) + + // Run custom client initialization if present + if initClient != nil { + initClient(svc.Client) + } + + return svc +} + +// newRequest creates a new request for a ECR operation and runs any +// custom request initialization. +func (c *ECR) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + // Run custom request initialization if present + if initRequest != nil { + initRequest(req) + } + + return req +} diff --git a/cluster/aws/templates/iam/kubernetes-minion-policy.json b/cluster/aws/templates/iam/kubernetes-minion-policy.json index 32453443a40..0a7ba67849e 100644 --- a/cluster/aws/templates/iam/kubernetes-minion-policy.json +++ b/cluster/aws/templates/iam/kubernetes-minion-policy.json @@ -22,6 +22,19 @@ "Effect": "Allow", "Action": "ec2:DetachVolume", "Resource": "*" + }, + { + "Effect": "Allow", + "Action": [ + "ecr:GetAuthorizationToken", + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer", + "ecr:GetRepositoryPolicy", + "ecr:DescribeRepositories", + "ecr:ListImages", + "ecr:BatchGetImage" + ], + "Resource": "*" } ] } diff --git a/cmd/kubelet/app/plugins.go b/cmd/kubelet/app/plugins.go index 3343da0a781..9dc450a5843 100644 --- a/cmd/kubelet/app/plugins.go +++ b/cmd/kubelet/app/plugins.go @@ -19,6 +19,7 @@ package app // This file exists to force the desired plugin implementations to be linked. import ( // Credential providers + _ "k8s.io/kubernetes/pkg/credentialprovider/aws" _ "k8s.io/kubernetes/pkg/credentialprovider/gcp" // Network plugins "k8s.io/kubernetes/pkg/kubelet/network" diff --git a/docs/design/aws_under_the_hood.md b/docs/design/aws_under_the_hood.md index a551c07c3f5..019b07d6213 100644 --- a/docs/design/aws_under_the_hood.md +++ b/docs/design/aws_under_the_hood.md @@ -171,7 +171,11 @@ The nodes do not need a lot of access to the AWS APIs. They need to download a distribution file, and then are responsible for attaching and detaching EBS volumes from itself. -The node policy is relatively minimal. The master policy is probably overly +The node policy is relatively minimal. In 1.2 and later, nodes can retrieve ECR +authorization tokens, refresh them every 12 hours if needed, and fetch Docker +images from it, as long as the appropriate permissions are enabled. Those in +[AmazonEC2ContainerRegistryReadOnly](http://docs.aws.amazon.com/AmazonECR/latest/userguide/ecr_managed_policies.html#AmazonEC2ContainerRegistryReadOnly), +without write access, should suffice. The master policy is probably overly permissive. The security conscious may want to lock-down the IAM policies further ([#11936](http://issues.k8s.io/11936)). @@ -180,7 +184,7 @@ are correctly configured ([#14226](http://issues.k8s.io/14226)). ### Tagging -All AWS resources are tagged with a tag named "KuberentesCluster", with a value +All AWS resources are tagged with a tag named "KubernetesCluster", with a value that is the unique cluster-id. This tag is used to identify a particular 'instance' of Kubernetes, even if two clusters are deployed into the same VPC. Resources are considered to belong to the same cluster if and only if they have diff --git a/docs/user-guide/images.md b/docs/user-guide/images.md index a4ce92bf136..7c2db77c2cd 100644 --- a/docs/user-guide/images.md +++ b/docs/user-guide/images.md @@ -47,6 +47,7 @@ The `image` property of a container supports the same syntax as the `docker` com - [Updating Images](#updating-images) - [Using a Private Registry](#using-a-private-registry) - [Using Google Container Registry](#using-google-container-registry) + - [Using AWS EC2 Container Registry](#using-aws-ec2-container-registry) - [Configuring Nodes to Authenticate to a Private Repository](#configuring-nodes-to-authenticate-to-a-private-repository) - [Pre-pulling Images](#pre-pulling-images) - [Specifying ImagePullSecrets on a Pod](#specifying-imagepullsecrets-on-a-pod) @@ -97,6 +98,21 @@ Google service account. The service account on the instance will have a `https://www.googleapis.com/auth/devstorage.read_only`, so it can pull from the project's GCR, but not push. +### Using AWS EC2 Container Registry + +Kubernetes has native support for the [AWS EC2 Container +Registry](https://aws.amazon.com/ecr/), when nodes are AWS instances. + +Simply use the full image name (e.g. `ACCOUNT.dkr.ecr.REGION.amazonaws.com/imagename:tag`) +in the Pod definition. + +All users of the cluster who can create pods will be able to run pods that use any of the +images in the ECR registry. + +The kubelet will fetch and periodically refresh ECR credentials. It needs the +`ecr:GetAuthorizationToken` permission to do this. + + ### Configuring Nodes to Authenticate to a Private Repository **Note:** if you are running on Google Container Engine (GKE), there will already be a `.dockercfg` on each node diff --git a/pkg/credentialprovider/aws/aws_credentials.go b/pkg/credentialprovider/aws/aws_credentials.go new file mode 100644 index 00000000000..dd349a58f44 --- /dev/null +++ b/pkg/credentialprovider/aws/aws_credentials.go @@ -0,0 +1,163 @@ +/* +Copyright 2014 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package aws_credentials + +import ( + "encoding/base64" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ecr" + "github.com/golang/glog" + "k8s.io/kubernetes/pkg/cloudprovider" + aws_cloud "k8s.io/kubernetes/pkg/cloudprovider/providers/aws" + "k8s.io/kubernetes/pkg/credentialprovider" +) + +var registryUrls = []string{"*.dkr.ecr.*.amazonaws.com"} + +// awsHandlerLogger is a handler that logs all AWS SDK requests +// Copied from cloudprovider/aws/log_handler.go +func awsHandlerLogger(req *request.Request) { + service := req.ClientInfo.ServiceName + + name := "?" + if req.Operation != nil { + name = req.Operation.Name + } + + glog.V(4).Infof("AWS request: %s %s", service, name) +} + +// An interface for testing purposes. +type tokenGetter interface { + GetAuthorizationToken(input *ecr.GetAuthorizationTokenInput) (*ecr.GetAuthorizationTokenOutput, error) +} + +// The canonical implementation +type ecrTokenGetter struct { + svc *ecr.ECR +} + +func (p *ecrTokenGetter) GetAuthorizationToken(input *ecr.GetAuthorizationTokenInput) (*ecr.GetAuthorizationTokenOutput, error) { + return p.svc.GetAuthorizationToken(input) +} + +// ecrProvider is a DockerConfigProvider that gets and refreshes 12-hour tokens +// from AWS to access ECR. +type ecrProvider struct { + getter tokenGetter +} + +// init registers the various means by which ECR credentials may +// be resolved. +func init() { + credentialprovider.RegisterCredentialProvider("aws-ecr-key", + &credentialprovider.CachingDockerConfigProvider{ + Provider: &ecrProvider{}, + // Refresh credentials a little earlier before they expire + Lifetime: 11*time.Hour + 55*time.Minute, + }) +} + +// Enabled implements DockerConfigProvider.Enabled for the AWS token-based implementation. +// For now, it gets activated only if AWS was chosen as the cloud provider. +// TODO: figure how to enable it manually for deployments that are not on AWS but still +// use ECR somehow? +func (p *ecrProvider) Enabled() bool { + provider, err := cloudprovider.GetCloudProvider(aws_cloud.ProviderName, nil) + if err != nil { + glog.Errorf("while initializing AWS cloud provider %v", err) + return false + } + if provider == nil { + return false + } + + zones, ok := provider.Zones() + if !ok { + glog.Errorf("couldn't get Zones() interface") + return false + } + zone, err := zones.GetZone() + if err != nil { + glog.Errorf("while getting zone %v", err) + return false + } + if zone.Region == "" { + glog.Errorf("Region information is empty") + return false + } + + getter := &ecrTokenGetter{svc: ecr.New(session.New(&aws.Config{ + Credentials: nil, + Region: &zone.Region, + }))} + getter.svc.Handlers.Sign.PushFrontNamed(request.NamedHandler{ + Name: "k8s/logger", + Fn: awsHandlerLogger, + }) + p.getter = getter + + return true +} + +// Provide implements DockerConfigProvider.Provide, refreshing ECR tokens on demand +func (p *ecrProvider) Provide() credentialprovider.DockerConfig { + cfg := credentialprovider.DockerConfig{} + + // TODO: fill in RegistryIds? + params := &ecr.GetAuthorizationTokenInput{} + output, err := p.getter.GetAuthorizationToken(params) + if err != nil { + glog.Errorf("while requesting ECR authorization token %v", err) + return cfg + } + if output == nil { + glog.Errorf("Got back no ECR token") + return cfg + } + + for _, data := range output.AuthorizationData { + if data.ProxyEndpoint != nil && + data.AuthorizationToken != nil { + decodedToken, err := base64.StdEncoding.DecodeString(aws.StringValue(data.AuthorizationToken)) + if err != nil { + glog.Errorf("while decoding token for endpoint %s %v", data.ProxyEndpoint, err) + return cfg + } + parts := strings.SplitN(string(decodedToken), ":", 2) + user := parts[0] + password := parts[1] + entry := credentialprovider.DockerConfigEntry{ + Username: user, + Password: password, + // ECR doesn't care and Docker is about to obsolete it + Email: "not@val.id", + } + + // Add our entry for each of the supported container registry URLs + for _, k := range registryUrls { + cfg[k] = entry + } + } + } + return cfg +} diff --git a/pkg/credentialprovider/aws/aws_credentials_test.go b/pkg/credentialprovider/aws/aws_credentials_test.go new file mode 100644 index 00000000000..a07493993f1 --- /dev/null +++ b/pkg/credentialprovider/aws/aws_credentials_test.go @@ -0,0 +1,108 @@ +/* +Copyright 2014 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package aws_credentials + +import ( + "encoding/base64" + "fmt" + "path" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ecr" + + "k8s.io/kubernetes/pkg/credentialprovider" +) + +const user = "foo" +const password = "1234567890abcdef" +const email = "not@val.id" + +// Mock implementation +type testTokenGetter struct { + user string + password string + endpoint string +} + +func (p *testTokenGetter) GetAuthorizationToken(input *ecr.GetAuthorizationTokenInput) (*ecr.GetAuthorizationTokenOutput, error) { + + expiration := time.Now().Add(1 * time.Hour) + creds := []byte(fmt.Sprintf("%s:%s", p.user, p.password)) + data := &ecr.AuthorizationData{ + AuthorizationToken: aws.String(base64.StdEncoding.EncodeToString(creds)), + ExpiresAt: &expiration, + ProxyEndpoint: aws.String(p.endpoint), + } + output := &ecr.GetAuthorizationTokenOutput{ + AuthorizationData: []*ecr.AuthorizationData{data}, + } + + return output, nil //p.svc.GetAuthorizationToken(input) +} + +func TestEcrProvide(t *testing.T) { + registry := "123456789012.dkr.ecr.lala-land-1.amazonaws.com" + otherRegistries := []string{"private.registry.com", + "gcr.io", + } + image := "foo/bar" + + provider := &ecrProvider{ + getter: &testTokenGetter{ + user: user, + password: password, + endpoint: registry}, + } + + keyring := &credentialprovider.BasicDockerKeyring{} + keyring.Add(provider.Provide()) + + // Verify that we get the expected username/password combo for + // an ECR image name. + fullImage := path.Join(registry, image) + creds, ok := keyring.Lookup(fullImage) + if !ok { + t.Errorf("Didn't find expected URL: %s", fullImage) + return + } + if len(creds) > 1 { + t.Errorf("Got more hits than expected: %s", creds) + } + val := creds[0] + + if user != val.Username { + t.Errorf("Unexpected username value, want: _token, got: %s", val.Username) + } + if password != val.Password { + t.Errorf("Unexpected password value, want: %s, got: %s", password, val.Password) + } + if email != val.Email { + t.Errorf("Unexpected email value, want: %s, got: %s", email, val.Email) + } + + // Verify that we get an error for other images. + for _, otherRegistry := range otherRegistries { + fullImage = path.Join(otherRegistry, image) + creds, ok = keyring.Lookup(fullImage) + if ok { + t.Errorf("Unexpectedly found image: %s", fullImage) + return + } + } +}