├── .gitignore ├── LICENCE ├── README.md ├── buffer.go ├── circle.yml ├── client.go ├── flusher.go ├── flusher_test.go ├── kinesis.go ├── stream.go ├── stream_test.go ├── template.go ├── vendor ├── github.com │ ├── aws │ │ └── aws-sdk-go │ │ │ ├── aws │ │ │ ├── awserr │ │ │ │ ├── error.go │ │ │ │ └── types.go │ │ │ ├── awsutil │ │ │ │ ├── copy.go │ │ │ │ ├── equal.go │ │ │ │ ├── path_value.go │ │ │ │ ├── prettify.go │ │ │ │ └── string_value.go │ │ │ ├── client │ │ │ │ ├── client.go │ │ │ │ ├── default_retryer.go │ │ │ │ └── metadata │ │ │ │ │ └── client_info.go │ │ │ ├── config.go │ │ │ ├── convert_types.go │ │ │ ├── corehandlers │ │ │ │ ├── handlers.go │ │ │ │ └── param_validator.go │ │ │ ├── credentials │ │ │ │ ├── chain_provider.go │ │ │ │ ├── credentials.go │ │ │ │ ├── ec2rolecreds │ │ │ │ │ └── ec2_role_provider.go │ │ │ │ ├── env_provider.go │ │ │ │ ├── example.ini │ │ │ │ ├── shared_credentials_provider.go │ │ │ │ └── static_provider.go │ │ │ ├── defaults │ │ │ │ └── defaults.go │ │ │ ├── ec2metadata │ │ │ │ ├── api.go │ │ │ │ └── service.go │ │ │ ├── errors.go │ │ │ ├── logger.go │ │ │ ├── request │ │ │ │ ├── handlers.go │ │ │ │ ├── request.go │ │ │ │ ├── request_pagination.go │ │ │ │ └── retryer.go │ │ │ ├── session │ │ │ │ └── session.go │ │ │ ├── types.go │ │ │ └── version.go │ │ │ ├── private │ │ │ ├── endpoints │ │ │ │ ├── endpoints.go │ │ │ │ ├── endpoints.json │ │ │ │ └── endpoints_map.go │ │ │ ├── protocol │ │ │ │ ├── json │ │ │ │ │ └── jsonutil │ │ │ │ │ │ ├── build.go │ │ │ │ │ │ └── unmarshal.go │ │ │ │ ├── jsonrpc │ │ │ │ │ └── jsonrpc.go │ │ │ │ └── rest │ │ │ │ │ ├── build.go │ │ │ │ │ ├── payload.go │ │ │ │ │ └── unmarshal.go │ │ │ ├── signer │ │ │ │ └── v4 │ │ │ │ │ └── v4.go │ │ │ └── waiter │ │ │ │ └── waiter.go │ │ │ └── service │ │ │ └── kinesis │ │ │ ├── api.go │ │ │ ├── service.go │ │ │ └── waiters.go │ ├── fsouza │ │ └── go-dockerclient │ │ │ ├── AUTHORS │ │ │ ├── DOCKER-LICENSE │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README.markdown │ │ │ ├── auth.go │ │ │ ├── change.go │ │ │ ├── client.go │ │ │ ├── container.go │ │ │ ├── env.go │ │ │ ├── event.go │ │ │ ├── exec.go │ │ │ ├── external │ │ │ └── github.com │ │ │ │ ├── Sirupsen │ │ │ │ └── logrus │ │ │ │ │ ├── CHANGELOG.md │ │ │ │ │ ├── LICENSE │ │ │ │ │ ├── README.md │ │ │ │ │ ├── entry.go │ │ │ │ │ ├── exported.go │ │ │ │ │ ├── formatter.go │ │ │ │ │ ├── hooks.go │ │ │ │ │ ├── json_formatter.go │ │ │ │ │ ├── logger.go │ │ │ │ │ ├── logrus.go │ │ │ │ │ ├── terminal_bsd.go │ │ │ │ │ ├── terminal_freebsd.go │ │ │ │ │ ├── terminal_linux.go │ │ │ │ │ ├── terminal_notwindows.go │ │ │ │ │ ├── terminal_openbsd.go │ │ │ │ │ ├── terminal_windows.go │ │ │ │ │ ├── text_formatter.go │ │ │ │ │ └── writer.go │ │ │ │ ├── docker │ │ │ │ └── docker │ │ │ │ │ ├── opts │ │ │ │ │ ├── envfile.go │ │ │ │ │ ├── hosts_unix.go │ │ │ │ │ ├── hosts_windows.go │ │ │ │ │ ├── ip.go │ │ │ │ │ ├── opts.go │ │ │ │ │ └── ulimit.go │ │ │ │ │ ├── pkg │ │ │ │ │ ├── archive │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ ├── archive.go │ │ │ │ │ │ ├── archive_unix.go │ │ │ │ │ │ ├── archive_windows.go │ │ │ │ │ │ ├── changes.go │ │ │ │ │ │ ├── changes_linux.go │ │ │ │ │ │ ├── changes_other.go │ │ │ │ │ │ ├── changes_unix.go │ │ │ │ │ │ ├── changes_windows.go │ │ │ │ │ │ ├── copy.go │ │ │ │ │ │ ├── copy_unix.go │ │ │ │ │ │ ├── copy_windows.go │ │ │ │ │ │ ├── diff.go │ │ │ │ │ │ ├── example_changes.go │ │ │ │ │ │ ├── time_linux.go │ │ │ │ │ │ ├── time_unsupported.go │ │ │ │ │ │ └── wrap.go │ │ │ │ │ ├── fileutils │ │ │ │ │ │ └── fileutils.go │ │ │ │ │ ├── homedir │ │ │ │ │ │ └── homedir.go │ │ │ │ │ ├── ioutils │ │ │ │ │ │ ├── fmt.go │ │ │ │ │ │ ├── multireader.go │ │ │ │ │ │ ├── readers.go │ │ │ │ │ │ ├── scheduler.go │ │ │ │ │ │ ├── scheduler_gccgo.go │ │ │ │ │ │ ├── writeflusher.go │ │ │ │ │ │ └── writers.go │ │ │ │ │ ├── parsers │ │ │ │ │ │ └── parsers.go │ │ │ │ │ ├── pools │ │ │ │ │ │ └── pools.go │ │ │ │ │ ├── promise │ │ │ │ │ │ └── promise.go │ │ │ │ │ ├── stdcopy │ │ │ │ │ │ └── stdcopy.go │ │ │ │ │ ├── system │ │ │ │ │ │ ├── errors.go │ │ │ │ │ │ ├── events_windows.go │ │ │ │ │ │ ├── filesys.go │ │ │ │ │ │ ├── filesys_windows.go │ │ │ │ │ │ ├── lstat.go │ │ │ │ │ │ ├── lstat_windows.go │ │ │ │ │ │ ├── meminfo.go │ │ │ │ │ │ ├── meminfo_linux.go │ │ │ │ │ │ ├── meminfo_unsupported.go │ │ │ │ │ │ ├── meminfo_windows.go │ │ │ │ │ │ ├── mknod.go │ │ │ │ │ │ ├── mknod_windows.go │ │ │ │ │ │ ├── stat.go │ │ │ │ │ │ ├── stat_freebsd.go │ │ │ │ │ │ ├── stat_linux.go │ │ │ │ │ │ ├── stat_unsupported.go │ │ │ │ │ │ ├── stat_windows.go │ │ │ │ │ │ ├── umask.go │ │ │ │ │ │ ├── umask_windows.go │ │ │ │ │ │ ├── utimes_darwin.go │ │ │ │ │ │ ├── utimes_freebsd.go │ │ │ │ │ │ ├── utimes_linux.go │ │ │ │ │ │ ├── utimes_unsupported.go │ │ │ │ │ │ ├── xattrs_linux.go │ │ │ │ │ │ └── xattrs_unsupported.go │ │ │ │ │ ├── ulimit │ │ │ │ │ │ └── ulimit.go │ │ │ │ │ └── units │ │ │ │ │ │ ├── duration.go │ │ │ │ │ │ └── size.go │ │ │ │ │ └── volume │ │ │ │ │ └── volume.go │ │ │ │ └── opencontainers │ │ │ │ └── runc │ │ │ │ └── libcontainer │ │ │ │ └── user │ │ │ │ ├── MAINTAINERS │ │ │ │ ├── lookup.go │ │ │ │ ├── lookup_unix.go │ │ │ │ ├── lookup_unsupported.go │ │ │ │ └── user.go │ │ │ ├── image.go │ │ │ ├── misc.go │ │ │ ├── network.go │ │ │ ├── signal.go │ │ │ ├── tar.go │ │ │ ├── tls.go │ │ │ └── volume.go │ ├── gliderlabs │ │ └── logspout │ │ │ └── router │ │ │ ├── extpoints.go │ │ │ ├── http.go │ │ │ ├── persist.go │ │ │ ├── pump.go │ │ │ ├── routes.go │ │ │ └── types.go │ ├── go-ini │ │ └── ini │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── README_ZH.md │ │ │ ├── ini.go │ │ │ └── struct.go │ ├── jmespath │ │ └── go-jmespath │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── api.go │ │ │ ├── astnodetype_string.go │ │ │ ├── functions.go │ │ │ ├── interpreter.go │ │ │ ├── lexer.go │ │ │ ├── parser.go │ │ │ ├── toktype_string.go │ │ │ └── util.go │ ├── pborman │ │ └── uuid │ │ │ ├── CONTRIBUTORS │ │ │ ├── LICENSE │ │ │ ├── dce.go │ │ │ ├── doc.go │ │ │ ├── hash.go │ │ │ ├── json.go │ │ │ ├── node.go │ │ │ ├── sql.go │ │ │ ├── time.go │ │ │ ├── util.go │ │ │ ├── uuid.go │ │ │ ├── version1.go │ │ │ └── version4.go │ └── stretchr │ │ └── testify │ │ └── assert │ │ ├── assertions.go │ │ ├── doc.go │ │ ├── errors.go │ │ ├── forward_assertions.go │ │ └── http_assertions.go └── vendor.json ├── writer.go └── writer_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.sublime-project 2 | *.sublime-workspace 3 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Remind101, Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /buffer.go: -------------------------------------------------------------------------------- 1 | package kinesis 2 | 3 | import ( 4 | "errors" 5 | "text/template" 6 | 7 | "github.com/aws/aws-sdk-go/aws" 8 | "github.com/aws/aws-sdk-go/service/kinesis" 9 | "github.com/gliderlabs/logspout/router" 10 | "github.com/pborman/uuid" 11 | ) 12 | 13 | // ErrRecordTooBig is raised when a record is too big to be sent. 14 | var ErrRecordTooBig = errors.New("data byte size is over the limit") 15 | 16 | type limits struct { 17 | putRecords int 18 | putRecordsSize int 19 | recordSize int 20 | } 21 | 22 | const ( 23 | // PutRecordsLimit is the maximum number of records allowed for a PutRecords request. 24 | PutRecordsLimit int = 500 25 | 26 | // PutRecordsSizeLimit is the maximum allowed size per PutRecords request. 27 | PutRecordsSizeLimit int = 5 * 1024 * 1024 // 5MB 28 | 29 | // RecordSizeLimit is the maximum allowed size per record. 30 | RecordSizeLimit int = 1 * 1024 * 1024 // 1MB 31 | ) 32 | 33 | type buffer struct { 34 | count int 35 | byteSize int 36 | pKeyTmpl *template.Template 37 | input *kinesis.PutRecordsInput 38 | limits *limits 39 | } 40 | 41 | func newBuffer(tmpl *template.Template, sn string) *buffer { 42 | return &buffer{ 43 | pKeyTmpl: tmpl, 44 | input: &kinesis.PutRecordsInput{ 45 | StreamName: aws.String(sn), 46 | Records: make([]*kinesis.PutRecordsRequestEntry, 0), 47 | }, 48 | limits: &limits{ 49 | putRecords: PutRecordsLimit, 50 | putRecordsSize: PutRecordsSizeLimit, 51 | recordSize: RecordSizeLimit, 52 | }, 53 | } 54 | } 55 | 56 | func (b *buffer) add(m *router.Message) error { 57 | dataLen := len(m.Data) 58 | 59 | // This record is too large, we can't submit it to kinesis. 60 | if dataLen > b.limits.recordSize { 61 | return ErrRecordTooBig 62 | } 63 | 64 | pKey, err := executeTmpl(b.pKeyTmpl, m) 65 | if err != nil { 66 | return err 67 | } 68 | 69 | // We default to a uuid if the template didn't match. 70 | if pKey == "" { 71 | pKey = uuid.New() 72 | debug("the partition key is an empty string, defaulting to a uuid %s", pKey) 73 | } 74 | 75 | // Add to count 76 | b.count++ 77 | 78 | // Add data and partition key size to byteSize 79 | b.byteSize += dataLen + len(pKey) 80 | 81 | // Add record 82 | b.input.Records = append(b.input.Records, &kinesis.PutRecordsRequestEntry{ 83 | Data: []byte(m.Data), 84 | PartitionKey: aws.String(pKey), 85 | }) 86 | 87 | debug("record added, stream: %s, partition key: %s, length: %d", 88 | *b.input.StreamName, pKey, len(b.input.Records)) 89 | 90 | return nil 91 | } 92 | 93 | func (b *buffer) full(m *router.Message) bool { 94 | // Adding this event would make our request have too many records. 95 | if b.count+1 > b.limits.putRecords { 96 | return true 97 | } 98 | 99 | // Adding this event would make our request too large. 100 | if b.byteSize+len(m.Data) > b.limits.putRecordsSize { 101 | return true 102 | } 103 | 104 | return false 105 | } 106 | 107 | func (b *buffer) empty() bool { 108 | return b.count == 0 109 | } 110 | 111 | func (b *buffer) reset() { 112 | b.count = 0 113 | b.byteSize = 0 114 | b.input.Records = make([]*kinesis.PutRecordsRequestEntry, 0) 115 | 116 | debug("buffer reset, stream: %s", *b.input.StreamName) 117 | } 118 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | environment: 3 | GO15VENDOREXPERIMENT: 1 4 | 5 | checkout: 6 | post: 7 | - rm -rf ~/.go_workspace/src/github.com/remind101 8 | - mkdir -p ~/.go_workspace/src/github.com/remind101 9 | - cp -R ~/logspout-kinesis ~/.go_workspace/src/github.com/remind101/logspout-kinesis 10 | 11 | dependencies: 12 | override: 13 | - go install -a -race std 14 | - go version 15 | - echo $GO15VENDOREXPERIMENT 16 | 17 | test: 18 | override: 19 | - cd ~/.go_workspace/src/github.com/remind101/logspout-kinesis && go test -race -short $(go list ./... | grep -v /vendor/) 20 | - cd ~/.go_workspace/src/github.com/remind101/logspout-kinesis && go vet $(go list ./... | grep -v /vendor/) 21 | -------------------------------------------------------------------------------- /client.go: -------------------------------------------------------------------------------- 1 | package kinesis 2 | 3 | import ( 4 | "github.com/aws/aws-sdk-go/aws/awserr" 5 | "github.com/aws/aws-sdk-go/service/kinesis" 6 | ) 7 | 8 | // Client is a wrapper for the AWS Kinesis client. 9 | type Client interface { 10 | Create(*kinesis.CreateStreamInput) (bool, error) 11 | Status(*kinesis.DescribeStreamInput) string 12 | Tag(*kinesis.AddTagsToStreamInput) error 13 | PutRecords(inp *kinesis.PutRecordsInput) (*kinesis.PutRecordsOutput, error) 14 | } 15 | 16 | type client struct { 17 | kinesis *kinesis.Kinesis 18 | } 19 | 20 | func (c *client) Create(input *kinesis.CreateStreamInput) (bool, error) { 21 | _, err := c.kinesis.CreateStream(input) 22 | 23 | if err != nil { 24 | if reqErr, ok := err.(awserr.RequestFailure); ok { 25 | if reqErr.Code() == "ResourceInUseException" { 26 | return true, nil 27 | } 28 | return false, err 29 | } 30 | return false, err 31 | } 32 | 33 | return false, nil 34 | } 35 | 36 | func (c *client) Status(input *kinesis.DescribeStreamInput) string { 37 | resp, _ := c.kinesis.DescribeStream(input) 38 | return *resp.StreamDescription.StreamStatus 39 | } 40 | 41 | func (c *client) Tag(input *kinesis.AddTagsToStreamInput) error { 42 | _, err := c.kinesis.AddTagsToStream(input) 43 | if err != nil { 44 | return err 45 | } 46 | 47 | return nil 48 | } 49 | 50 | func (c *client) PutRecords(inp *kinesis.PutRecordsInput) (*kinesis.PutRecordsOutput, error) { 51 | return c.kinesis.PutRecords(inp) 52 | } 53 | -------------------------------------------------------------------------------- /flusher.go: -------------------------------------------------------------------------------- 1 | package kinesis 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/aws/aws-sdk-go/service/kinesis" 7 | ) 8 | 9 | // DroppedInputError is returned when an input is dropped. 10 | type DroppedInputError struct { 11 | Stream string 12 | Count int 13 | } 14 | 15 | func (e *DroppedInputError) Error() string { 16 | return fmt.Sprintf("input dropped! stream: %s, # items: %d", e.Stream, e.Count) 17 | } 18 | 19 | // Flusher flushes the inputs to Amazon Kinesis. 20 | type Flusher interface { 21 | start() 22 | flush(input kinesis.PutRecordsInput) 23 | flushInputs() 24 | } 25 | 26 | type flusher struct { 27 | client Client 28 | inputs chan kinesis.PutRecordsInput 29 | dropInputFunc func(kinesis.PutRecordsInput) 30 | } 31 | 32 | func newFlusher(client Client) Flusher { 33 | return &flusher{ 34 | client: client, 35 | inputs: make(chan kinesis.PutRecordsInput, 10), 36 | dropInputFunc: dropInput, 37 | } 38 | } 39 | 40 | func (f *flusher) start() { 41 | f.flushInputs() 42 | } 43 | 44 | func (f *flusher) flush(input kinesis.PutRecordsInput) { 45 | select { 46 | case f.inputs <- input: 47 | default: 48 | f.dropInputFunc(input) 49 | } 50 | } 51 | 52 | func (f *flusher) flushInputs() { 53 | for inp := range f.inputs { 54 | _, err := f.client.PutRecords(&inp) 55 | if err != nil { 56 | ErrorHandler(err) 57 | } 58 | 59 | debug("buffer flushed, stream: %s, length: %d", 60 | *inp.StreamName, len(inp.Records)) 61 | } 62 | } 63 | 64 | func dropInput(input kinesis.PutRecordsInput) { 65 | ErrorHandler(&DroppedInputError{ 66 | Stream: *input.StreamName, 67 | Count: len(input.Records), 68 | }) 69 | } 70 | -------------------------------------------------------------------------------- /flusher_test.go: -------------------------------------------------------------------------------- 1 | package kinesis 2 | 3 | import ( 4 | "testing" 5 | "text/template" 6 | "time" 7 | 8 | "github.com/aws/aws-sdk-go/aws" 9 | "github.com/aws/aws-sdk-go/service/kinesis" 10 | "github.com/fsouza/go-dockerclient" 11 | "github.com/gliderlabs/logspout/router" 12 | ) 13 | 14 | func TestFlusher_FlushFull(t *testing.T) { 15 | drop := make(chan struct{}) 16 | f := &flusher{ 17 | inputs: make(chan kinesis.PutRecordsInput, 0), 18 | dropInputFunc: func(input kinesis.PutRecordsInput) { 19 | close(drop) 20 | }, 21 | } 22 | 23 | go func() { 24 | f.inputs <- kinesis.PutRecordsInput{} 25 | }() 26 | 27 | f.flush(kinesis.PutRecordsInput{}) 28 | 29 | select { 30 | case <-drop: 31 | case <-time.After(1 * time.Second): 32 | t.Fatal("Expected input to be dropped") 33 | } 34 | } 35 | 36 | func TestFlusher_IntegrationInputsChannelFull(t *testing.T) { 37 | drop := make(chan struct{}) 38 | f := &fakeFlusher{ 39 | inputs: make(chan kinesis.PutRecordsInput, 0), 40 | dropInputFunc: func(input kinesis.PutRecordsInput) { 41 | close(drop) 42 | }, 43 | flushFunc: func() { 44 | <-time.After(time.Minute) 45 | }, 46 | } 47 | 48 | streamName := "abc" 49 | tmpl, _ := template.New("").Parse(streamName) 50 | tags := make(map[string]*string) 51 | tags["name"] = aws.String("kinesis-test") 52 | 53 | m := &router.Message{ 54 | Data: "hello", 55 | Container: &docker.Container{ 56 | ID: "123", 57 | }, 58 | } 59 | 60 | s := NewStream(streamName, &tags, tmpl) 61 | 62 | w := newWriter( 63 | newBuffer(tmpl, streamName), 64 | f, 65 | ) 66 | w.ticker = nil 67 | w.buffer.limits = &testLimits 68 | 69 | s.writers[m.Container.ID] = w 70 | s.client = &fakeClient{ 71 | created: true, 72 | err: nil, 73 | } 74 | 75 | s.writers[m.Container.ID].start() 76 | s.ready = true 77 | s.Start() 78 | 79 | go func() { 80 | for { 81 | f.inputs <- kinesis.PutRecordsInput{} 82 | } 83 | }() 84 | s.Write(m) 85 | s.Write(m) 86 | s.Write(m) 87 | 88 | select { 89 | case <-drop: 90 | case <-time.After(1 * time.Second): 91 | t.Fatal("Expected input to be dropped") 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /kinesis.go: -------------------------------------------------------------------------------- 1 | package kinesis 2 | 3 | import ( 4 | "errors" 5 | "log" 6 | "os" 7 | "text/template" 8 | 9 | "github.com/aws/aws-sdk-go/aws" 10 | "github.com/gliderlabs/logspout/router" 11 | ) 12 | 13 | func init() { 14 | router.AdapterFactories.Register(NewAdapter, "kinesis") 15 | } 16 | 17 | var ( 18 | // ErrorHandler handles the reporting of an error. 19 | ErrorHandler = logErr 20 | 21 | // ErrMissingTagKey is returned when the tag key environment variable doesn't match. 22 | ErrMissingTagKey = errors.New("the tag key is empty, check your template KINESIS_STREAM_TAG_KEY") 23 | 24 | // ErrMissingTagValue is returned when the tag value environment variable doesn't match. 25 | ErrMissingTagValue = errors.New("the tag value is empty, check your template KINESIS_STREAM_TAG_VALUE") 26 | ) 27 | 28 | // Adapter represents the logspout adapter for Kinesis. 29 | type Adapter struct { 30 | Streams map[string]*Stream 31 | StreamTmpl *template.Template 32 | TagTmpl *template.Template 33 | PKeyTmpl *template.Template 34 | } 35 | 36 | // NewAdapter creates a kinesis adapter. Called during init. 37 | func NewAdapter(route *router.Route) (router.LogAdapter, error) { 38 | sTmpl, err := compileTmpl("KINESIS_STREAM_TEMPLATE") 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | tagTmpl, err := compileTmpl("KINESIS_STREAM_TAG_VALUE") 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | pKeyTmpl, err := compileTmpl("KINESIS_PARTITION_KEY_TEMPLATE") 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | streams := make(map[string]*Stream) 54 | 55 | return &Adapter{ 56 | Streams: streams, 57 | StreamTmpl: sTmpl, 58 | TagTmpl: tagTmpl, 59 | PKeyTmpl: pKeyTmpl, 60 | }, nil 61 | } 62 | 63 | // Stream handles the routing of a message to Kinesis. 64 | func (a *Adapter) Stream(logstream chan *router.Message) { 65 | for m := range logstream { 66 | sn, err := executeTmpl(a.StreamTmpl, m) 67 | if err != nil { 68 | ErrorHandler(err) 69 | break 70 | } 71 | 72 | if sn == "" { 73 | debug("the stream name is empty, couldn't match the template. Skipping the log.") 74 | continue 75 | } 76 | 77 | if s, ok := a.Streams[sn]; ok { 78 | ErrorHandler(s.Write(m)) 79 | } else { 80 | tags, err := tags(a.TagTmpl, m) 81 | if err != nil { 82 | ErrorHandler(err) 83 | break 84 | } 85 | 86 | s := NewStream(sn, tags, a.PKeyTmpl) 87 | s.Start() 88 | a.Streams[sn] = s 89 | } 90 | } 91 | } 92 | 93 | func tags(tmpl *template.Template, m *router.Message) (*map[string]*string, error) { 94 | tagKey := os.Getenv("KINESIS_STREAM_TAG_KEY") 95 | if tagKey == "" { 96 | return nil, ErrMissingTagKey 97 | } 98 | 99 | tagValue, err := executeTmpl(tmpl, m) 100 | if err != nil { 101 | return nil, err 102 | } 103 | 104 | if tagValue == "" { 105 | return nil, ErrMissingTagValue 106 | } 107 | 108 | return &map[string]*string{ 109 | tagKey: aws.String(tagValue), 110 | }, nil 111 | } 112 | 113 | func logErr(err error) { 114 | if err != nil { 115 | log.Println("kinesis:", err.Error()) 116 | } 117 | } 118 | 119 | func debug(format string, p ...interface{}) { 120 | if os.Getenv("KINESIS_DEBUG") == "true" { 121 | log.Printf("kinesis: "+format, p...) 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /stream.go: -------------------------------------------------------------------------------- 1 | package kinesis 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "text/template" 7 | "time" 8 | 9 | "github.com/aws/aws-sdk-go/aws" 10 | "github.com/aws/aws-sdk-go/aws/session" 11 | "github.com/aws/aws-sdk-go/service/kinesis" 12 | "github.com/gliderlabs/logspout/router" 13 | ) 14 | 15 | // StreamNotReadyError is returned while the stream is being created. 16 | type StreamNotReadyError struct { 17 | Stream string 18 | } 19 | 20 | func (e *StreamNotReadyError) Error() string { 21 | return fmt.Sprintf("not ready, stream: %s", e.Stream) 22 | } 23 | 24 | // Stream represents a stream that will send messages to its writer. 25 | type Stream struct { 26 | client Client 27 | name string 28 | tags *map[string]*string 29 | writers map[string]*writer 30 | pKeyTmpl *template.Template 31 | ready bool 32 | readyWrite chan bool 33 | err error 34 | errChan chan error 35 | } 36 | 37 | // NewStream instantiates a new stream. 38 | func NewStream(name string, tags *map[string]*string, pKeyTmpl *template.Template) *Stream { 39 | session := session.New(&aws.Config{}) 40 | client := &client{ 41 | kinesis: kinesis.New(session), 42 | } 43 | 44 | s := &Stream{ 45 | client: client, 46 | name: name, 47 | tags: tags, 48 | writers: make(map[string]*writer), 49 | pKeyTmpl: pKeyTmpl, 50 | readyWrite: make(chan bool), 51 | errChan: make(chan error), 52 | } 53 | 54 | return s 55 | } 56 | 57 | // Start runs the goroutines making calls to create and tag the stream on 58 | // AWS. 59 | func (s *Stream) Start() { 60 | go s.start() 61 | } 62 | 63 | func (s *Stream) start() { 64 | if err := s.create(); err != nil { 65 | s.errChan <- err 66 | ErrorHandler(err) 67 | return 68 | } 69 | 70 | if err := s.tag(); err != nil { 71 | s.errChan <- err 72 | ErrorHandler(err) 73 | return 74 | } 75 | 76 | s.readyWrite <- true 77 | log.Printf("ready! stream: %s", s.name) 78 | } 79 | 80 | // Write sends the message to the writer if the stream is ready 81 | // i.e created and tagged. 82 | func (s *Stream) Write(m *router.Message) error { 83 | select { 84 | case s.ready = <-s.readyWrite: 85 | case s.err = <-s.errChan: 86 | default: 87 | } 88 | 89 | switch { 90 | case s.err != nil: 91 | return s.err 92 | case s.ready: 93 | return s.write(m) 94 | default: 95 | return &StreamNotReadyError{Stream: s.name} 96 | } 97 | } 98 | 99 | func (s *Stream) write(m *router.Message) error { 100 | if w, ok := s.writers[m.Container.ID]; ok { 101 | w.write(m) 102 | return nil 103 | } 104 | 105 | w := newWriter( 106 | newBuffer(s.pKeyTmpl, s.name), 107 | newFlusher(s.client), 108 | ) 109 | w.start() 110 | s.writers[m.Container.ID] = w 111 | w.write(m) 112 | return nil 113 | } 114 | 115 | func (s *Stream) create() error { 116 | created, err := s.client.Create(&kinesis.CreateStreamInput{ 117 | ShardCount: aws.Int64(1), 118 | StreamName: aws.String(s.name), 119 | }) 120 | 121 | if err != nil { 122 | return err 123 | } 124 | 125 | if created { 126 | return nil 127 | } 128 | 129 | debug("need to create stream: %s", s.name) 130 | for { 131 | status := s.client.Status(&kinesis.DescribeStreamInput{ 132 | StreamName: aws.String(s.name), 133 | }) 134 | if status == "ACTIVE" { 135 | return nil 136 | } 137 | time.Sleep(4 * time.Second) // wait a bit 138 | debug("stream %s status: %s", s.name, status) 139 | } 140 | } 141 | 142 | func (s *Stream) tag() error { 143 | err := s.client.Tag(&kinesis.AddTagsToStreamInput{ 144 | StreamName: aws.String(s.name), 145 | Tags: *s.tags, 146 | }) 147 | 148 | if err != nil { 149 | return err 150 | } 151 | 152 | return nil 153 | } 154 | -------------------------------------------------------------------------------- /stream_test.go: -------------------------------------------------------------------------------- 1 | package kinesis 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | "text/template" 7 | "time" 8 | 9 | "github.com/aws/aws-sdk-go/aws" 10 | "github.com/aws/aws-sdk-go/aws/awserr" 11 | "github.com/aws/aws-sdk-go/service/kinesis" 12 | "github.com/fsouza/go-dockerclient" 13 | "github.com/gliderlabs/logspout/router" 14 | "github.com/stretchr/testify/assert" 15 | ) 16 | 17 | type fakeClient struct { 18 | created bool 19 | status string 20 | err error 21 | mutex sync.Mutex 22 | } 23 | 24 | func (f *fakeClient) Create(input *kinesis.CreateStreamInput) (bool, error) { 25 | f.mutex.Lock() 26 | defer f.mutex.Unlock() 27 | 28 | return f.created, f.err 29 | } 30 | 31 | func (f *fakeClient) Status(input *kinesis.DescribeStreamInput) string { 32 | f.mutex.Lock() 33 | defer f.mutex.Unlock() 34 | 35 | return f.status 36 | } 37 | 38 | func (f *fakeClient) Tag(input *kinesis.AddTagsToStreamInput) error { 39 | f.mutex.Lock() 40 | defer f.mutex.Unlock() 41 | 42 | return f.err 43 | } 44 | 45 | func (f *fakeClient) PutRecords(inp *kinesis.PutRecordsInput) (*kinesis.PutRecordsOutput, error) { 46 | return nil, nil 47 | } 48 | 49 | // TODO: implement optional stream creation 50 | // func TestStream_CreationDeactivated(t *testing.T) { 51 | 52 | // } 53 | 54 | // TODO: implement optional stream tagging 55 | // func TestStream_TaggingDeactivated(t *testing.T) { 56 | 57 | // } 58 | 59 | func TestStream_CreateAlreadyExists(t *testing.T) { 60 | s := NewStream("abc", nil, nil) 61 | s.client = &fakeClient{ 62 | created: true, 63 | } 64 | 65 | err := s.create() 66 | assert.Nil(t, err) 67 | } 68 | 69 | func TestStream_CreateStatusActive(t *testing.T) { 70 | s := NewStream("abc", nil, nil) 71 | s.client = &fakeClient{ 72 | created: false, 73 | status: "ACTIVE", 74 | } 75 | 76 | err := s.create() 77 | assert.Nil(t, err) 78 | } 79 | 80 | func TestStream_CreateError(t *testing.T) { 81 | s := NewStream("abc", nil, nil) 82 | s.client = &fakeClient{ 83 | created: false, 84 | err: awserr.New("RequestError", "500", nil), 85 | } 86 | 87 | err := s.create() 88 | assert.NotNil(t, err) 89 | } 90 | 91 | func TestStream_WriteStreamNotReady(t *testing.T) { 92 | m := &router.Message{ 93 | Data: "hello", 94 | Container: &docker.Container{ 95 | ID: "123", 96 | }, 97 | } 98 | 99 | s := NewStream("abc", nil, nil) 100 | s.client = &fakeClient{ 101 | created: false, 102 | } 103 | s.Start() 104 | err := s.Write(m) 105 | 106 | if assert.Error(t, err, "A stream not ready error was expected") { 107 | assert.Equal(t, err, &StreamNotReadyError{Stream: "abc"}) 108 | } 109 | } 110 | 111 | func TestStream_WriteStreamBecomesReady(t *testing.T) { 112 | tmpl, _ := template.New("").Parse("abc") 113 | tags := make(map[string]*string) 114 | tags["name"] = aws.String("kinesis-test") 115 | 116 | m := &router.Message{ 117 | Data: "hello", 118 | Container: &docker.Container{ 119 | ID: "123", 120 | }, 121 | } 122 | 123 | s := NewStream("abc", &tags, tmpl) 124 | fk := &fakeClient{ 125 | created: false, 126 | status: "CREATING", 127 | mutex: sync.Mutex{}, 128 | } 129 | s.client = fk 130 | s.Start() 131 | 132 | err := s.Write(m) 133 | if assert.Error(t, err, "A stream not ready error was expected") { 134 | assert.Equal(t, err, &StreamNotReadyError{Stream: "abc"}) 135 | } 136 | 137 | fk.mutex.Lock() 138 | fk.status = "ACTIVE" 139 | fk.mutex.Unlock() 140 | 141 | timeout := make(chan bool) 142 | go func() { 143 | time.Sleep(1 * time.Second) 144 | timeout <- true 145 | }() 146 | 147 | // trying to write until we succeed or timeout 148 | for { 149 | err = s.Write(m) 150 | if err == nil { 151 | break 152 | } 153 | 154 | select { 155 | case <-timeout: 156 | break 157 | default: 158 | } 159 | } 160 | 161 | assert.Nil(t, err) 162 | } 163 | -------------------------------------------------------------------------------- /template.go: -------------------------------------------------------------------------------- 1 | package kinesis 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "os" 8 | "strings" 9 | "text/template" 10 | 11 | "github.com/gliderlabs/logspout/router" 12 | ) 13 | 14 | var funcMap = template.FuncMap{ 15 | "lookUp": lookUp, 16 | } 17 | 18 | // ErrEmptyTmpl is returned when the template is empty. 19 | var ErrEmptyTmpl = errors.New("the template is empty") 20 | 21 | // MissingEnvVarError is return when an environment variable is missing. 22 | type MissingEnvVarError struct { 23 | EnvVar string 24 | } 25 | 26 | func (e *MissingEnvVarError) Error() string { 27 | return fmt.Sprintf("missing required %s environment variable", e.EnvVar) 28 | } 29 | 30 | func compileTmpl(envVar string) (*template.Template, error) { 31 | tmplString := os.Getenv(envVar) 32 | if tmplString == "" { 33 | return nil, &MissingEnvVarError{EnvVar: envVar} 34 | } 35 | 36 | tmpl, err := template.New("").Funcs(funcMap).Parse(tmplString) 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | return tmpl, nil 42 | } 43 | 44 | func executeTmpl(tmpl *template.Template, m *router.Message) (string, error) { 45 | if tmpl == nil { 46 | return "", ErrEmptyTmpl 47 | } 48 | 49 | var res bytes.Buffer 50 | err := tmpl.Execute(&res, m) 51 | if err != nil { 52 | return "", err 53 | } 54 | 55 | return res.String(), nil 56 | } 57 | 58 | // lookUp searches into an array of environment variable by key, 59 | // and returns the value. 60 | func lookUp(arr []string, key string) string { 61 | for _, v := range arr { 62 | parts := strings.Split(v, "=") 63 | if key == parts[0] { 64 | return parts[1] 65 | } 66 | } 67 | return "" 68 | } 69 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy.go: -------------------------------------------------------------------------------- 1 | package awsutil 2 | 3 | import ( 4 | "io" 5 | "reflect" 6 | ) 7 | 8 | // Copy deeply copies a src structure to dst. Useful for copying request and 9 | // response structures. 10 | // 11 | // Can copy between structs of different type, but will only copy fields which 12 | // are assignable, and exist in both structs. Fields which are not assignable, 13 | // or do not exist in both structs are ignored. 14 | func Copy(dst, src interface{}) { 15 | dstval := reflect.ValueOf(dst) 16 | if !dstval.IsValid() { 17 | panic("Copy dst cannot be nil") 18 | } 19 | 20 | rcopy(dstval, reflect.ValueOf(src), true) 21 | } 22 | 23 | // CopyOf returns a copy of src while also allocating the memory for dst. 24 | // src must be a pointer type or this operation will fail. 25 | func CopyOf(src interface{}) (dst interface{}) { 26 | dsti := reflect.New(reflect.TypeOf(src).Elem()) 27 | dst = dsti.Interface() 28 | rcopy(dsti, reflect.ValueOf(src), true) 29 | return 30 | } 31 | 32 | // rcopy performs a recursive copy of values from the source to destination. 33 | // 34 | // root is used to skip certain aspects of the copy which are not valid 35 | // for the root node of a object. 36 | func rcopy(dst, src reflect.Value, root bool) { 37 | if !src.IsValid() { 38 | return 39 | } 40 | 41 | switch src.Kind() { 42 | case reflect.Ptr: 43 | if _, ok := src.Interface().(io.Reader); ok { 44 | if dst.Kind() == reflect.Ptr && dst.Elem().CanSet() { 45 | dst.Elem().Set(src) 46 | } else if dst.CanSet() { 47 | dst.Set(src) 48 | } 49 | } else { 50 | e := src.Type().Elem() 51 | if dst.CanSet() && !src.IsNil() { 52 | dst.Set(reflect.New(e)) 53 | } 54 | if src.Elem().IsValid() { 55 | // Keep the current root state since the depth hasn't changed 56 | rcopy(dst.Elem(), src.Elem(), root) 57 | } 58 | } 59 | case reflect.Struct: 60 | t := dst.Type() 61 | for i := 0; i < t.NumField(); i++ { 62 | name := t.Field(i).Name 63 | srcVal := src.FieldByName(name) 64 | dstVal := dst.FieldByName(name) 65 | if srcVal.IsValid() && dstVal.CanSet() { 66 | rcopy(dstVal, srcVal, false) 67 | } 68 | } 69 | case reflect.Slice: 70 | if src.IsNil() { 71 | break 72 | } 73 | 74 | s := reflect.MakeSlice(src.Type(), src.Len(), src.Cap()) 75 | dst.Set(s) 76 | for i := 0; i < src.Len(); i++ { 77 | rcopy(dst.Index(i), src.Index(i), false) 78 | } 79 | case reflect.Map: 80 | if src.IsNil() { 81 | break 82 | } 83 | 84 | s := reflect.MakeMap(src.Type()) 85 | dst.Set(s) 86 | for _, k := range src.MapKeys() { 87 | v := src.MapIndex(k) 88 | v2 := reflect.New(v.Type()).Elem() 89 | rcopy(v2, v, false) 90 | dst.SetMapIndex(k, v2) 91 | } 92 | default: 93 | // Assign the value if possible. If its not assignable, the value would 94 | // need to be converted and the impact of that may be unexpected, or is 95 | // not compatible with the dst type. 96 | if src.Type().AssignableTo(dst.Type()) { 97 | dst.Set(src) 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal.go: -------------------------------------------------------------------------------- 1 | package awsutil 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | // DeepEqual returns if the two values are deeply equal like reflect.DeepEqual. 8 | // In addition to this, this method will also dereference the input values if 9 | // possible so the DeepEqual performed will not fail if one parameter is a 10 | // pointer and the other is not. 11 | // 12 | // DeepEqual will not perform indirection of nested values of the input parameters. 13 | func DeepEqual(a, b interface{}) bool { 14 | ra := reflect.Indirect(reflect.ValueOf(a)) 15 | rb := reflect.Indirect(reflect.ValueOf(b)) 16 | 17 | if raValid, rbValid := ra.IsValid(), rb.IsValid(); !raValid && !rbValid { 18 | // If the elements are both nil, and of the same type the are equal 19 | // If they are of different types they are not equal 20 | return reflect.TypeOf(a) == reflect.TypeOf(b) 21 | } else if raValid != rbValid { 22 | // Both values must be valid to be equal 23 | return false 24 | } 25 | 26 | return reflect.DeepEqual(ra.Interface(), rb.Interface()) 27 | } 28 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/awsutil/prettify.go: -------------------------------------------------------------------------------- 1 | package awsutil 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "reflect" 8 | "strings" 9 | ) 10 | 11 | // Prettify returns the string representation of a value. 12 | func Prettify(i interface{}) string { 13 | var buf bytes.Buffer 14 | prettify(reflect.ValueOf(i), 0, &buf) 15 | return buf.String() 16 | } 17 | 18 | // prettify will recursively walk value v to build a textual 19 | // representation of the value. 20 | func prettify(v reflect.Value, indent int, buf *bytes.Buffer) { 21 | for v.Kind() == reflect.Ptr { 22 | v = v.Elem() 23 | } 24 | 25 | switch v.Kind() { 26 | case reflect.Struct: 27 | strtype := v.Type().String() 28 | if strtype == "time.Time" { 29 | fmt.Fprintf(buf, "%s", v.Interface()) 30 | break 31 | } else if strings.HasPrefix(strtype, "io.") { 32 | buf.WriteString("") 33 | break 34 | } 35 | 36 | buf.WriteString("{\n") 37 | 38 | names := []string{} 39 | for i := 0; i < v.Type().NumField(); i++ { 40 | name := v.Type().Field(i).Name 41 | f := v.Field(i) 42 | if name[0:1] == strings.ToLower(name[0:1]) { 43 | continue // ignore unexported fields 44 | } 45 | if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice || f.Kind() == reflect.Map) && f.IsNil() { 46 | continue // ignore unset fields 47 | } 48 | names = append(names, name) 49 | } 50 | 51 | for i, n := range names { 52 | val := v.FieldByName(n) 53 | buf.WriteString(strings.Repeat(" ", indent+2)) 54 | buf.WriteString(n + ": ") 55 | prettify(val, indent+2, buf) 56 | 57 | if i < len(names)-1 { 58 | buf.WriteString(",\n") 59 | } 60 | } 61 | 62 | buf.WriteString("\n" + strings.Repeat(" ", indent) + "}") 63 | case reflect.Slice: 64 | nl, id, id2 := "", "", "" 65 | if v.Len() > 3 { 66 | nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2) 67 | } 68 | buf.WriteString("[" + nl) 69 | for i := 0; i < v.Len(); i++ { 70 | buf.WriteString(id2) 71 | prettify(v.Index(i), indent+2, buf) 72 | 73 | if i < v.Len()-1 { 74 | buf.WriteString("," + nl) 75 | } 76 | } 77 | 78 | buf.WriteString(nl + id + "]") 79 | case reflect.Map: 80 | buf.WriteString("{\n") 81 | 82 | for i, k := range v.MapKeys() { 83 | buf.WriteString(strings.Repeat(" ", indent+2)) 84 | buf.WriteString(k.String() + ": ") 85 | prettify(v.MapIndex(k), indent+2, buf) 86 | 87 | if i < v.Len()-1 { 88 | buf.WriteString(",\n") 89 | } 90 | } 91 | 92 | buf.WriteString("\n" + strings.Repeat(" ", indent) + "}") 93 | default: 94 | format := "%v" 95 | switch v.Interface().(type) { 96 | case string: 97 | format = "%q" 98 | case io.ReadSeeker, io.Reader: 99 | format = "buffer(%p)" 100 | } 101 | fmt.Fprintf(buf, format, v.Interface()) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/awsutil/string_value.go: -------------------------------------------------------------------------------- 1 | package awsutil 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "reflect" 7 | "strings" 8 | ) 9 | 10 | // StringValue returns the string representation of a value. 11 | func StringValue(i interface{}) string { 12 | var buf bytes.Buffer 13 | stringValue(reflect.ValueOf(i), 0, &buf) 14 | return buf.String() 15 | } 16 | 17 | func stringValue(v reflect.Value, indent int, buf *bytes.Buffer) { 18 | for v.Kind() == reflect.Ptr { 19 | v = v.Elem() 20 | } 21 | 22 | switch v.Kind() { 23 | case reflect.Struct: 24 | buf.WriteString("{\n") 25 | 26 | names := []string{} 27 | for i := 0; i < v.Type().NumField(); i++ { 28 | name := v.Type().Field(i).Name 29 | f := v.Field(i) 30 | if name[0:1] == strings.ToLower(name[0:1]) { 31 | continue // ignore unexported fields 32 | } 33 | if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice) && f.IsNil() { 34 | continue // ignore unset fields 35 | } 36 | names = append(names, name) 37 | } 38 | 39 | for i, n := range names { 40 | val := v.FieldByName(n) 41 | buf.WriteString(strings.Repeat(" ", indent+2)) 42 | buf.WriteString(n + ": ") 43 | stringValue(val, indent+2, buf) 44 | 45 | if i < len(names)-1 { 46 | buf.WriteString(",\n") 47 | } 48 | } 49 | 50 | buf.WriteString("\n" + strings.Repeat(" ", indent) + "}") 51 | case reflect.Slice: 52 | nl, id, id2 := "", "", "" 53 | if v.Len() > 3 { 54 | nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2) 55 | } 56 | buf.WriteString("[" + nl) 57 | for i := 0; i < v.Len(); i++ { 58 | buf.WriteString(id2) 59 | stringValue(v.Index(i), indent+2, buf) 60 | 61 | if i < v.Len()-1 { 62 | buf.WriteString("," + nl) 63 | } 64 | } 65 | 66 | buf.WriteString(nl + id + "]") 67 | case reflect.Map: 68 | buf.WriteString("{\n") 69 | 70 | for i, k := range v.MapKeys() { 71 | buf.WriteString(strings.Repeat(" ", indent+2)) 72 | buf.WriteString(k.String() + ": ") 73 | stringValue(v.MapIndex(k), indent+2, buf) 74 | 75 | if i < v.Len()-1 { 76 | buf.WriteString(",\n") 77 | } 78 | } 79 | 80 | buf.WriteString("\n" + strings.Repeat(" ", indent) + "}") 81 | default: 82 | format := "%v" 83 | switch v.Interface().(type) { 84 | case string: 85 | format = "%q" 86 | } 87 | fmt.Fprintf(buf, format, v.Interface()) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "math" 5 | "math/rand" 6 | "time" 7 | 8 | "github.com/aws/aws-sdk-go/aws/request" 9 | ) 10 | 11 | // DefaultRetryer implements basic retry logic using exponential backoff for 12 | // most services. If you want to implement custom retry logic, implement the 13 | // request.Retryer interface or create a structure type that composes this 14 | // struct and override the specific methods. For example, to override only 15 | // the MaxRetries method: 16 | // 17 | // type retryer struct { 18 | // service.DefaultRetryer 19 | // } 20 | // 21 | // // This implementation always has 100 max retries 22 | // func (d retryer) MaxRetries() uint { return 100 } 23 | type DefaultRetryer struct { 24 | NumMaxRetries int 25 | } 26 | 27 | // MaxRetries returns the number of maximum returns the service will use to make 28 | // an individual API request. 29 | func (d DefaultRetryer) MaxRetries() int { 30 | return d.NumMaxRetries 31 | } 32 | 33 | // RetryRules returns the delay duration before retrying this request again 34 | func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration { 35 | delay := int(math.Pow(2, float64(r.RetryCount))) * (rand.Intn(30) + 30) 36 | return time.Duration(delay) * time.Millisecond 37 | } 38 | 39 | // ShouldRetry returns if the request should be retried. 40 | func (d DefaultRetryer) ShouldRetry(r *request.Request) bool { 41 | if r.HTTPResponse.StatusCode >= 500 { 42 | return true 43 | } 44 | return r.IsErrorRetryable() 45 | } 46 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | // ClientInfo wraps immutable data from the client.Client structure. 4 | type ClientInfo struct { 5 | ServiceName string 6 | APIVersion string 7 | Endpoint string 8 | SigningName string 9 | SigningRegion string 10 | JSONVersion string 11 | TargetPrefix string 12 | } 13 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider.go: -------------------------------------------------------------------------------- 1 | package credentials 2 | 3 | import ( 4 | "github.com/aws/aws-sdk-go/aws/awserr" 5 | ) 6 | 7 | var ( 8 | // ErrNoValidProvidersFoundInChain Is returned when there are no valid 9 | // providers in the ChainProvider. 10 | // 11 | // @readonly 12 | ErrNoValidProvidersFoundInChain = awserr.New("NoCredentialProviders", "no valid providers in chain", nil) 13 | ) 14 | 15 | // A ChainProvider will search for a provider which returns credentials 16 | // and cache that provider until Retrieve is called again. 17 | // 18 | // The ChainProvider provides a way of chaining multiple providers together 19 | // which will pick the first available using priority order of the Providers 20 | // in the list. 21 | // 22 | // If none of the Providers retrieve valid credentials Value, ChainProvider's 23 | // Retrieve() will return the error ErrNoValidProvidersFoundInChain. 24 | // 25 | // If a Provider is found which returns valid credentials Value ChainProvider 26 | // will cache that Provider for all calls to IsExpired(), until Retrieve is 27 | // called again. 28 | // 29 | // Example of ChainProvider to be used with an EnvProvider and EC2RoleProvider. 30 | // In this example EnvProvider will first check if any credentials are available 31 | // vai the environment variables. If there are none ChainProvider will check 32 | // the next Provider in the list, EC2RoleProvider in this case. If EC2RoleProvider 33 | // does not return any credentials ChainProvider will return the error 34 | // ErrNoValidProvidersFoundInChain 35 | // 36 | // creds := NewChainCredentials( 37 | // []Provider{ 38 | // &EnvProvider{}, 39 | // &EC2RoleProvider{ 40 | // Client: ec2metadata.New(sess), 41 | // }, 42 | // }) 43 | // 44 | // // Usage of ChainCredentials with aws.Config 45 | // svc := ec2.New(&aws.Config{Credentials: creds}) 46 | // 47 | type ChainProvider struct { 48 | Providers []Provider 49 | curr Provider 50 | } 51 | 52 | // NewChainCredentials returns a pointer to a new Credentials object 53 | // wrapping a chain of providers. 54 | func NewChainCredentials(providers []Provider) *Credentials { 55 | return NewCredentials(&ChainProvider{ 56 | Providers: append([]Provider{}, providers...), 57 | }) 58 | } 59 | 60 | // Retrieve returns the credentials value or error if no provider returned 61 | // without error. 62 | // 63 | // If a provider is found it will be cached and any calls to IsExpired() 64 | // will return the expired state of the cached provider. 65 | func (c *ChainProvider) Retrieve() (Value, error) { 66 | for _, p := range c.Providers { 67 | if creds, err := p.Retrieve(); err == nil { 68 | c.curr = p 69 | return creds, nil 70 | } 71 | } 72 | c.curr = nil 73 | 74 | // TODO better error reporting. maybe report error for each failed retrieve? 75 | 76 | return Value{}, ErrNoValidProvidersFoundInChain 77 | } 78 | 79 | // IsExpired will returned the expired state of the currently cached provider 80 | // if there is one. If there is no current provider, true will be returned. 81 | func (c *ChainProvider) IsExpired() bool { 82 | if c.curr != nil { 83 | return c.curr.IsExpired() 84 | } 85 | 86 | return true 87 | } 88 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/credentials/env_provider.go: -------------------------------------------------------------------------------- 1 | package credentials 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/aws/aws-sdk-go/aws/awserr" 7 | ) 8 | 9 | var ( 10 | // ErrAccessKeyIDNotFound is returned when the AWS Access Key ID can't be 11 | // found in the process's environment. 12 | // 13 | // @readonly 14 | ErrAccessKeyIDNotFound = awserr.New("EnvAccessKeyNotFound", "AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment", nil) 15 | 16 | // ErrSecretAccessKeyNotFound is returned when the AWS Secret Access Key 17 | // can't be found in the process's environment. 18 | // 19 | // @readonly 20 | ErrSecretAccessKeyNotFound = awserr.New("EnvSecretNotFound", "AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment", nil) 21 | ) 22 | 23 | // A EnvProvider retrieves credentials from the environment variables of the 24 | // running process. Environment credentials never expire. 25 | // 26 | // Environment variables used: 27 | // 28 | // * Access Key ID: AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY 29 | // * Secret Access Key: AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY 30 | type EnvProvider struct { 31 | retrieved bool 32 | } 33 | 34 | // NewEnvCredentials returns a pointer to a new Credentials object 35 | // wrapping the environment variable provider. 36 | func NewEnvCredentials() *Credentials { 37 | return NewCredentials(&EnvProvider{}) 38 | } 39 | 40 | // Retrieve retrieves the keys from the environment. 41 | func (e *EnvProvider) Retrieve() (Value, error) { 42 | e.retrieved = false 43 | 44 | id := os.Getenv("AWS_ACCESS_KEY_ID") 45 | if id == "" { 46 | id = os.Getenv("AWS_ACCESS_KEY") 47 | } 48 | 49 | secret := os.Getenv("AWS_SECRET_ACCESS_KEY") 50 | if secret == "" { 51 | secret = os.Getenv("AWS_SECRET_KEY") 52 | } 53 | 54 | if id == "" { 55 | return Value{}, ErrAccessKeyIDNotFound 56 | } 57 | 58 | if secret == "" { 59 | return Value{}, ErrSecretAccessKeyNotFound 60 | } 61 | 62 | e.retrieved = true 63 | return Value{ 64 | AccessKeyID: id, 65 | SecretAccessKey: secret, 66 | SessionToken: os.Getenv("AWS_SESSION_TOKEN"), 67 | }, nil 68 | } 69 | 70 | // IsExpired returns if the credentials have been retrieved. 71 | func (e *EnvProvider) IsExpired() bool { 72 | return !e.retrieved 73 | } 74 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini: -------------------------------------------------------------------------------- 1 | [default] 2 | aws_access_key_id = accessKey 3 | aws_secret_access_key = secret 4 | aws_session_token = token 5 | 6 | [no_token] 7 | aws_access_key_id = accessKey 8 | aws_secret_access_key = secret 9 | 10 | [with_colon] 11 | aws_access_key_id: accessKey 12 | aws_secret_access_key: secret 13 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/credentials/static_provider.go: -------------------------------------------------------------------------------- 1 | package credentials 2 | 3 | import ( 4 | "github.com/aws/aws-sdk-go/aws/awserr" 5 | ) 6 | 7 | var ( 8 | // ErrStaticCredentialsEmpty is emitted when static credentials are empty. 9 | // 10 | // @readonly 11 | ErrStaticCredentialsEmpty = awserr.New("EmptyStaticCreds", "static credentials are empty", nil) 12 | ) 13 | 14 | // A StaticProvider is a set of credentials which are set pragmatically, 15 | // and will never expire. 16 | type StaticProvider struct { 17 | Value 18 | } 19 | 20 | // NewStaticCredentials returns a pointer to a new Credentials object 21 | // wrapping a static credentials value provider. 22 | func NewStaticCredentials(id, secret, token string) *Credentials { 23 | return NewCredentials(&StaticProvider{Value: Value{ 24 | AccessKeyID: id, 25 | SecretAccessKey: secret, 26 | SessionToken: token, 27 | }}) 28 | } 29 | 30 | // Retrieve returns the credentials or error if the credentials are invalid. 31 | func (s *StaticProvider) Retrieve() (Value, error) { 32 | if s.AccessKeyID == "" || s.SecretAccessKey == "" { 33 | return Value{}, ErrStaticCredentialsEmpty 34 | } 35 | 36 | return s.Value, nil 37 | } 38 | 39 | // IsExpired returns if the credentials are expired. 40 | // 41 | // For StaticProvider, the credentials never expired. 42 | func (s *StaticProvider) IsExpired() bool { 43 | return false 44 | } 45 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults.go: -------------------------------------------------------------------------------- 1 | // Package defaults is a collection of helpers to retrieve the SDK's default 2 | // configuration and handlers. 3 | // 4 | // Generally this package shouldn't be used directly, but session.Session 5 | // instead. This package is useful when you need to reset the defaults 6 | // of a session or service client to the SDK defaults before setting 7 | // additional parameters. 8 | package defaults 9 | 10 | import ( 11 | "net/http" 12 | "os" 13 | "time" 14 | 15 | "github.com/aws/aws-sdk-go/aws" 16 | "github.com/aws/aws-sdk-go/aws/corehandlers" 17 | "github.com/aws/aws-sdk-go/aws/credentials" 18 | "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" 19 | "github.com/aws/aws-sdk-go/aws/ec2metadata" 20 | "github.com/aws/aws-sdk-go/aws/request" 21 | "github.com/aws/aws-sdk-go/private/endpoints" 22 | ) 23 | 24 | // A Defaults provides a collection of default values for SDK clients. 25 | type Defaults struct { 26 | Config *aws.Config 27 | Handlers request.Handlers 28 | } 29 | 30 | // Get returns the SDK's default values with Config and handlers pre-configured. 31 | func Get() Defaults { 32 | cfg := Config() 33 | handlers := Handlers() 34 | cfg.Credentials = CredChain(cfg, handlers) 35 | 36 | return Defaults{ 37 | Config: cfg, 38 | Handlers: handlers, 39 | } 40 | } 41 | 42 | // Config returns the default configuration without credentials. 43 | // To retrieve a config with credentials also included use 44 | // `defaults.Get().Config` instead. 45 | // 46 | // Generally you shouldn't need to use this method directly, but 47 | // is available if you need to reset the configuration of an 48 | // existing service client or session. 49 | func Config() *aws.Config { 50 | return aws.NewConfig(). 51 | WithCredentials(credentials.AnonymousCredentials). 52 | WithRegion(os.Getenv("AWS_REGION")). 53 | WithHTTPClient(http.DefaultClient). 54 | WithMaxRetries(aws.UseServiceDefaultRetries). 55 | WithLogger(aws.NewDefaultLogger()). 56 | WithLogLevel(aws.LogOff). 57 | WithSleepDelay(time.Sleep) 58 | } 59 | 60 | // Handlers returns the default request handlers. 61 | // 62 | // Generally you shouldn't need to use this method directly, but 63 | // is available if you need to reset the request handlers of an 64 | // existing service client or session. 65 | func Handlers() request.Handlers { 66 | var handlers request.Handlers 67 | 68 | handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler) 69 | handlers.Build.PushBackNamed(corehandlers.SDKVersionUserAgentHandler) 70 | handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler) 71 | handlers.Send.PushBackNamed(corehandlers.SendHandler) 72 | handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler) 73 | handlers.ValidateResponse.PushBackNamed(corehandlers.ValidateResponseHandler) 74 | 75 | return handlers 76 | } 77 | 78 | // CredChain returns the default credential chain. 79 | // 80 | // Generally you shouldn't need to use this method directly, but 81 | // is available if you need to reset the credentials of an 82 | // existing service client or session's Config. 83 | func CredChain(cfg *aws.Config, handlers request.Handlers) *credentials.Credentials { 84 | endpoint, signingRegion := endpoints.EndpointForRegion(ec2metadata.ServiceName, *cfg.Region, true) 85 | 86 | return credentials.NewChainCredentials( 87 | []credentials.Provider{ 88 | &credentials.EnvProvider{}, 89 | &credentials.SharedCredentialsProvider{Filename: "", Profile: ""}, 90 | &ec2rolecreds.EC2RoleProvider{ 91 | Client: ec2metadata.NewClient(*cfg, handlers, endpoint, signingRegion), 92 | ExpiryWindow: 5 * time.Minute, 93 | }, 94 | }) 95 | } 96 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/api.go: -------------------------------------------------------------------------------- 1 | package ec2metadata 2 | 3 | import ( 4 | "path" 5 | 6 | "github.com/aws/aws-sdk-go/aws/request" 7 | ) 8 | 9 | // GetMetadata uses the path provided to request 10 | func (c *EC2Metadata) GetMetadata(p string) (string, error) { 11 | op := &request.Operation{ 12 | Name: "GetMetadata", 13 | HTTPMethod: "GET", 14 | HTTPPath: path.Join("/", "meta-data", p), 15 | } 16 | 17 | output := &metadataOutput{} 18 | req := c.NewRequest(op, nil, output) 19 | 20 | return output.Content, req.Send() 21 | } 22 | 23 | // Region returns the region the instance is running in. 24 | func (c *EC2Metadata) Region() (string, error) { 25 | resp, err := c.GetMetadata("placement/availability-zone") 26 | if err != nil { 27 | return "", err 28 | } 29 | 30 | // returns region without the suffix. Eg: us-west-2a becomes us-west-2 31 | return resp[:len(resp)-1], nil 32 | } 33 | 34 | // Available returns if the application has access to the EC2 Metadata service. 35 | // Can be used to determine if application is running within an EC2 Instance and 36 | // the metadata service is available. 37 | func (c *EC2Metadata) Available() bool { 38 | if _, err := c.GetMetadata("instance-id"); err != nil { 39 | return false 40 | } 41 | 42 | return true 43 | } 44 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go: -------------------------------------------------------------------------------- 1 | // Package ec2metadata provides the client for making API calls to the 2 | // EC2 Metadata service. 3 | package ec2metadata 4 | 5 | import ( 6 | "io/ioutil" 7 | "net" 8 | "net/http" 9 | "time" 10 | 11 | "github.com/aws/aws-sdk-go/aws" 12 | "github.com/aws/aws-sdk-go/aws/awserr" 13 | "github.com/aws/aws-sdk-go/aws/client" 14 | "github.com/aws/aws-sdk-go/aws/client/metadata" 15 | "github.com/aws/aws-sdk-go/aws/request" 16 | ) 17 | 18 | // ServiceName is the name of the service. 19 | const ServiceName = "ec2metadata" 20 | 21 | // A EC2Metadata is an EC2 Metadata service Client. 22 | type EC2Metadata struct { 23 | *client.Client 24 | } 25 | 26 | // New creates a new instance of the EC2Metadata client with a session. 27 | // This client is safe to use across multiple goroutines. 28 | // 29 | // Example: 30 | // // Create a EC2Metadata client from just a session. 31 | // svc := ec2metadata.New(mySession) 32 | // 33 | // // Create a EC2Metadata client with additional configuration 34 | // svc := ec2metadata.New(mySession, aws.NewConfig().WithLogLevel(aws.LogDebugHTTPBody)) 35 | func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2Metadata { 36 | c := p.ClientConfig(ServiceName, cfgs...) 37 | return NewClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion) 38 | } 39 | 40 | // NewClient returns a new EC2Metadata client. Should be used to create 41 | // a client when not using a session. Generally using just New with a session 42 | // is preferred. 43 | func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string, opts ...func(*client.Client)) *EC2Metadata { 44 | // If the default http client is provided, replace it with a custom 45 | // client using default timeouts. 46 | if cfg.HTTPClient == http.DefaultClient { 47 | cfg.HTTPClient = &http.Client{ 48 | Transport: &http.Transport{ 49 | Proxy: http.ProxyFromEnvironment, 50 | Dial: (&net.Dialer{ 51 | // use a shorter timeout than default because the metadata 52 | // service is local if it is running, and to fail faster 53 | // if not running on an ec2 instance. 54 | Timeout: 5 * time.Second, 55 | KeepAlive: 30 * time.Second, 56 | }).Dial, 57 | TLSHandshakeTimeout: 10 * time.Second, 58 | }, 59 | } 60 | } 61 | 62 | svc := &EC2Metadata{ 63 | Client: client.New( 64 | cfg, 65 | metadata.ClientInfo{ 66 | ServiceName: ServiceName, 67 | Endpoint: endpoint, 68 | APIVersion: "latest", 69 | }, 70 | handlers, 71 | ), 72 | } 73 | 74 | svc.Handlers.Unmarshal.PushBack(unmarshalHandler) 75 | svc.Handlers.UnmarshalError.PushBack(unmarshalError) 76 | svc.Handlers.Validate.Clear() 77 | svc.Handlers.Validate.PushBack(validateEndpointHandler) 78 | 79 | // Add additional options to the service config 80 | for _, option := range opts { 81 | option(svc.Client) 82 | } 83 | 84 | return svc 85 | } 86 | 87 | type metadataOutput struct { 88 | Content string 89 | } 90 | 91 | func unmarshalHandler(r *request.Request) { 92 | defer r.HTTPResponse.Body.Close() 93 | b, err := ioutil.ReadAll(r.HTTPResponse.Body) 94 | if err != nil { 95 | r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata respose", err) 96 | } 97 | 98 | data := r.Data.(*metadataOutput) 99 | data.Content = string(b) 100 | } 101 | 102 | func unmarshalError(r *request.Request) { 103 | defer r.HTTPResponse.Body.Close() 104 | _, err := ioutil.ReadAll(r.HTTPResponse.Body) 105 | if err != nil { 106 | r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata error respose", err) 107 | } 108 | 109 | // TODO extract the error... 110 | } 111 | 112 | func validateEndpointHandler(r *request.Request) { 113 | if r.ClientInfo.Endpoint == "" { 114 | r.Error = aws.ErrMissingEndpoint 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/errors.go: -------------------------------------------------------------------------------- 1 | package aws 2 | 3 | import "github.com/aws/aws-sdk-go/aws/awserr" 4 | 5 | var ( 6 | // ErrMissingRegion is an error that is returned if region configuration is 7 | // not found. 8 | // 9 | // @readonly 10 | ErrMissingRegion = awserr.New("MissingRegion", "could not find region configuration", nil) 11 | 12 | // ErrMissingEndpoint is an error that is returned if an endpoint cannot be 13 | // resolved for a service. 14 | // 15 | // @readonly 16 | ErrMissingEndpoint = awserr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil) 17 | ) 18 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/logger.go: -------------------------------------------------------------------------------- 1 | package aws 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | // A LogLevelType defines the level logging should be performed at. Used to instruct 9 | // the SDK which statements should be logged. 10 | type LogLevelType uint 11 | 12 | // LogLevel returns the pointer to a LogLevel. Should be used to workaround 13 | // not being able to take the address of a non-composite literal. 14 | func LogLevel(l LogLevelType) *LogLevelType { 15 | return &l 16 | } 17 | 18 | // Value returns the LogLevel value or the default value LogOff if the LogLevel 19 | // is nil. Safe to use on nil value LogLevelTypes. 20 | func (l *LogLevelType) Value() LogLevelType { 21 | if l != nil { 22 | return *l 23 | } 24 | return LogOff 25 | } 26 | 27 | // Matches returns true if the v LogLevel is enabled by this LogLevel. Should be 28 | // used with logging sub levels. Is safe to use on nil value LogLevelTypes. If 29 | // LogLevel is nill, will default to LogOff comparison. 30 | func (l *LogLevelType) Matches(v LogLevelType) bool { 31 | c := l.Value() 32 | return c&v == v 33 | } 34 | 35 | // AtLeast returns true if this LogLevel is at least high enough to satisfies v. 36 | // Is safe to use on nil value LogLevelTypes. If LogLevel is nill, will default 37 | // to LogOff comparison. 38 | func (l *LogLevelType) AtLeast(v LogLevelType) bool { 39 | c := l.Value() 40 | return c >= v 41 | } 42 | 43 | const ( 44 | // LogOff states that no logging should be performed by the SDK. This is the 45 | // default state of the SDK, and should be use to disable all logging. 46 | LogOff LogLevelType = iota * 0x1000 47 | 48 | // LogDebug state that debug output should be logged by the SDK. This should 49 | // be used to inspect request made and responses received. 50 | LogDebug 51 | ) 52 | 53 | // Debug Logging Sub Levels 54 | const ( 55 | // LogDebugWithSigning states that the SDK should log request signing and 56 | // presigning events. This should be used to log the signing details of 57 | // requests for debugging. Will also enable LogDebug. 58 | LogDebugWithSigning LogLevelType = LogDebug | (1 << iota) 59 | 60 | // LogDebugWithHTTPBody states the SDK should log HTTP request and response 61 | // HTTP bodys in addition to the headers and path. This should be used to 62 | // see the body content of requests and responses made while using the SDK 63 | // Will also enable LogDebug. 64 | LogDebugWithHTTPBody 65 | 66 | // LogDebugWithRequestRetries states the SDK should log when service requests will 67 | // be retried. This should be used to log when you want to log when service 68 | // requests are being retried. Will also enable LogDebug. 69 | LogDebugWithRequestRetries 70 | 71 | // LogDebugWithRequestErrors states the SDK should log when service requests fail 72 | // to build, send, validate, or unmarshal. 73 | LogDebugWithRequestErrors 74 | ) 75 | 76 | // A Logger is a minimalistic interface for the SDK to log messages to. Should 77 | // be used to provide custom logging writers for the SDK to use. 78 | type Logger interface { 79 | Log(...interface{}) 80 | } 81 | 82 | // NewDefaultLogger returns a Logger which will write log messages to stdout, and 83 | // use same formatting runes as the stdlib log.Logger 84 | func NewDefaultLogger() Logger { 85 | return &defaultLogger{ 86 | logger: log.New(os.Stdout, "", log.LstdFlags), 87 | } 88 | } 89 | 90 | // A defaultLogger provides a minimalistic logger satisfying the Logger interface. 91 | type defaultLogger struct { 92 | logger *log.Logger 93 | } 94 | 95 | // Log logs the parameters to the stdlib logger. See log.Println. 96 | func (l defaultLogger) Log(args ...interface{}) { 97 | l.logger.Println(args...) 98 | } 99 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/request/request_pagination.go: -------------------------------------------------------------------------------- 1 | package request 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/aws/awsutil" 8 | ) 9 | 10 | //type Paginater interface { 11 | // HasNextPage() bool 12 | // NextPage() *Request 13 | // EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error 14 | //} 15 | 16 | // HasNextPage returns true if this request has more pages of data available. 17 | func (r *Request) HasNextPage() bool { 18 | return len(r.nextPageTokens()) > 0 19 | } 20 | 21 | // nextPageTokens returns the tokens to use when asking for the next page of 22 | // data. 23 | func (r *Request) nextPageTokens() []interface{} { 24 | if r.Operation.Paginator == nil { 25 | return nil 26 | } 27 | 28 | if r.Operation.TruncationToken != "" { 29 | tr, _ := awsutil.ValuesAtPath(r.Data, r.Operation.TruncationToken) 30 | if len(tr) == 0 { 31 | return nil 32 | } 33 | 34 | switch v := tr[0].(type) { 35 | case *bool: 36 | if !aws.BoolValue(v) { 37 | return nil 38 | } 39 | case bool: 40 | if v == false { 41 | return nil 42 | } 43 | } 44 | } 45 | 46 | tokens := []interface{}{} 47 | tokenAdded := false 48 | for _, outToken := range r.Operation.OutputTokens { 49 | v, _ := awsutil.ValuesAtPath(r.Data, outToken) 50 | if len(v) > 0 { 51 | tokens = append(tokens, v[0]) 52 | tokenAdded = true 53 | } else { 54 | tokens = append(tokens, nil) 55 | } 56 | } 57 | if !tokenAdded { 58 | return nil 59 | } 60 | 61 | return tokens 62 | } 63 | 64 | // NextPage returns a new Request that can be executed to return the next 65 | // page of result data. Call .Send() on this request to execute it. 66 | func (r *Request) NextPage() *Request { 67 | tokens := r.nextPageTokens() 68 | if len(tokens) == 0 { 69 | return nil 70 | } 71 | 72 | data := reflect.New(reflect.TypeOf(r.Data).Elem()).Interface() 73 | nr := New(r.Config, r.ClientInfo, r.Handlers, r.Retryer, r.Operation, awsutil.CopyOf(r.Params), data) 74 | for i, intok := range nr.Operation.InputTokens { 75 | awsutil.SetValueAtPath(nr.Params, intok, tokens[i]) 76 | } 77 | return nr 78 | } 79 | 80 | // EachPage iterates over each page of a paginated request object. The fn 81 | // parameter should be a function with the following sample signature: 82 | // 83 | // func(page *T, lastPage bool) bool { 84 | // return true // return false to stop iterating 85 | // } 86 | // 87 | // Where "T" is the structure type matching the output structure of the given 88 | // operation. For example, a request object generated by 89 | // DynamoDB.ListTablesRequest() would expect to see dynamodb.ListTablesOutput 90 | // as the structure "T". The lastPage value represents whether the page is 91 | // the last page of data or not. The return value of this function should 92 | // return true to keep iterating or false to stop. 93 | func (r *Request) EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error { 94 | for page := r; page != nil; page = page.NextPage() { 95 | if err := page.Send(); err != nil { 96 | return err 97 | } 98 | if getNextPage := fn(page.Data, !page.HasNextPage()); !getNextPage { 99 | return page.Error 100 | } 101 | } 102 | 103 | return nil 104 | } 105 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/request/retryer.go: -------------------------------------------------------------------------------- 1 | package request 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/aws/awserr" 8 | ) 9 | 10 | // Retryer is an interface to control retry logic for a given service. 11 | // The default implementation used by most services is the service.DefaultRetryer 12 | // structure, which contains basic retry logic using exponential backoff. 13 | type Retryer interface { 14 | RetryRules(*Request) time.Duration 15 | ShouldRetry(*Request) bool 16 | MaxRetries() int 17 | } 18 | 19 | // WithRetryer sets a config Retryer value to the given Config returning it 20 | // for chaining. 21 | func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config { 22 | cfg.Retryer = retryer 23 | return cfg 24 | } 25 | 26 | // retryableCodes is a collection of service response codes which are retry-able 27 | // without any further action. 28 | var retryableCodes = map[string]struct{}{ 29 | "RequestError": {}, 30 | "RequestTimeout": {}, 31 | "ProvisionedThroughputExceededException": {}, 32 | "Throttling": {}, 33 | "ThrottlingException": {}, 34 | "RequestLimitExceeded": {}, 35 | "RequestThrottled": {}, 36 | "LimitExceededException": {}, // Deleting 10+ DynamoDb tables at once 37 | "TooManyRequestsException": {}, // Lambda functions 38 | } 39 | 40 | // credsExpiredCodes is a collection of error codes which signify the credentials 41 | // need to be refreshed. Expired tokens require refreshing of credentials, and 42 | // resigning before the request can be retried. 43 | var credsExpiredCodes = map[string]struct{}{ 44 | "ExpiredToken": {}, 45 | "ExpiredTokenException": {}, 46 | "RequestExpired": {}, // EC2 Only 47 | } 48 | 49 | func isCodeRetryable(code string) bool { 50 | if _, ok := retryableCodes[code]; ok { 51 | return true 52 | } 53 | 54 | return isCodeExpiredCreds(code) 55 | } 56 | 57 | func isCodeExpiredCreds(code string) bool { 58 | _, ok := credsExpiredCodes[code] 59 | return ok 60 | } 61 | 62 | // IsErrorRetryable returns whether the error is retryable, based on its Code. 63 | // Returns false if the request has no Error set. 64 | func (r *Request) IsErrorRetryable() bool { 65 | if r.Error != nil { 66 | if err, ok := r.Error.(awserr.Error); ok { 67 | return isCodeRetryable(err.Code()) 68 | } 69 | } 70 | return false 71 | } 72 | 73 | // IsErrorExpired returns whether the error code is a credential expiry error. 74 | // Returns false if the request has no Error set. 75 | func (r *Request) IsErrorExpired() bool { 76 | if r.Error != nil { 77 | if err, ok := r.Error.(awserr.Error); ok { 78 | return isCodeExpiredCreds(err.Code()) 79 | } 80 | } 81 | return false 82 | } 83 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/types.go: -------------------------------------------------------------------------------- 1 | package aws 2 | 3 | import ( 4 | "io" 5 | "sync" 6 | ) 7 | 8 | // ReadSeekCloser wraps a io.Reader returning a ReaderSeekerCloser 9 | func ReadSeekCloser(r io.Reader) ReaderSeekerCloser { 10 | return ReaderSeekerCloser{r} 11 | } 12 | 13 | // ReaderSeekerCloser represents a reader that can also delegate io.Seeker and 14 | // io.Closer interfaces to the underlying object if they are available. 15 | type ReaderSeekerCloser struct { 16 | r io.Reader 17 | } 18 | 19 | // Read reads from the reader up to size of p. The number of bytes read, and 20 | // error if it occurred will be returned. 21 | // 22 | // If the reader is not an io.Reader zero bytes read, and nil error will be returned. 23 | // 24 | // Performs the same functionality as io.Reader Read 25 | func (r ReaderSeekerCloser) Read(p []byte) (int, error) { 26 | switch t := r.r.(type) { 27 | case io.Reader: 28 | return t.Read(p) 29 | } 30 | return 0, nil 31 | } 32 | 33 | // Seek sets the offset for the next Read to offset, interpreted according to 34 | // whence: 0 means relative to the origin of the file, 1 means relative to the 35 | // current offset, and 2 means relative to the end. Seek returns the new offset 36 | // and an error, if any. 37 | // 38 | // If the ReaderSeekerCloser is not an io.Seeker nothing will be done. 39 | func (r ReaderSeekerCloser) Seek(offset int64, whence int) (int64, error) { 40 | switch t := r.r.(type) { 41 | case io.Seeker: 42 | return t.Seek(offset, whence) 43 | } 44 | return int64(0), nil 45 | } 46 | 47 | // Close closes the ReaderSeekerCloser. 48 | // 49 | // If the ReaderSeekerCloser is not an io.Closer nothing will be done. 50 | func (r ReaderSeekerCloser) Close() error { 51 | switch t := r.r.(type) { 52 | case io.Closer: 53 | return t.Close() 54 | } 55 | return nil 56 | } 57 | 58 | // A WriteAtBuffer provides a in memory buffer supporting the io.WriterAt interface 59 | // Can be used with the s3manager.Downloader to download content to a buffer 60 | // in memory. Safe to use concurrently. 61 | type WriteAtBuffer struct { 62 | buf []byte 63 | m sync.Mutex 64 | } 65 | 66 | // WriteAt writes a slice of bytes to a buffer starting at the position provided 67 | // The number of bytes written will be returned, or error. Can overwrite previous 68 | // written slices if the write ats overlap. 69 | func (b *WriteAtBuffer) WriteAt(p []byte, pos int64) (n int, err error) { 70 | b.m.Lock() 71 | defer b.m.Unlock() 72 | 73 | expLen := pos + int64(len(p)) 74 | if int64(len(b.buf)) < expLen { 75 | newBuf := make([]byte, expLen) 76 | copy(newBuf, b.buf) 77 | b.buf = newBuf 78 | } 79 | copy(b.buf[pos:], p) 80 | return len(p), nil 81 | } 82 | 83 | // Bytes returns a slice of bytes written to the buffer. 84 | func (b *WriteAtBuffer) Bytes() []byte { 85 | b.m.Lock() 86 | defer b.m.Unlock() 87 | return b.buf[:len(b.buf):len(b.buf)] 88 | } 89 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/aws/version.go: -------------------------------------------------------------------------------- 1 | // Package aws provides core functionality for making requests to AWS services. 2 | package aws 3 | 4 | // SDKName is the name of this AWS SDK 5 | const SDKName = "aws-sdk-go" 6 | 7 | // SDKVersion is the version of this SDK 8 | const SDKVersion = "1.0.7" 9 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/private/endpoints/endpoints.go: -------------------------------------------------------------------------------- 1 | // Package endpoints validates regional endpoints for services. 2 | package endpoints 3 | 4 | //go:generate go run ../model/cli/gen-endpoints/main.go endpoints.json endpoints_map.go 5 | //go:generate gofmt -s -w endpoints_map.go 6 | 7 | import ( 8 | "fmt" 9 | "regexp" 10 | "strings" 11 | ) 12 | 13 | // NormalizeEndpoint takes and endpoint and service API information to return a 14 | // normalized endpoint and signing region. If the endpoint is not an empty string 15 | // the service name and region will be used to look up the service's API endpoint. 16 | // If the endpoint is provided the scheme will be added if it is not present. 17 | func NormalizeEndpoint(endpoint, serviceName, region string, disableSSL bool) (normEndpoint, signingRegion string) { 18 | if endpoint == "" { 19 | return EndpointForRegion(serviceName, region, disableSSL) 20 | } 21 | 22 | return AddScheme(endpoint, disableSSL), "" 23 | } 24 | 25 | // EndpointForRegion returns an endpoint and its signing region for a service and region. 26 | // if the service and region pair are not found endpoint and signingRegion will be empty. 27 | func EndpointForRegion(svcName, region string, disableSSL bool) (endpoint, signingRegion string) { 28 | derivedKeys := []string{ 29 | region + "/" + svcName, 30 | region + "/*", 31 | "*/" + svcName, 32 | "*/*", 33 | } 34 | 35 | for _, key := range derivedKeys { 36 | if val, ok := endpointsMap.Endpoints[key]; ok { 37 | ep := val.Endpoint 38 | ep = strings.Replace(ep, "{region}", region, -1) 39 | ep = strings.Replace(ep, "{service}", svcName, -1) 40 | 41 | endpoint = ep 42 | signingRegion = val.SigningRegion 43 | break 44 | } 45 | } 46 | 47 | return AddScheme(endpoint, disableSSL), signingRegion 48 | } 49 | 50 | // Regular expression to determine if the endpoint string is prefixed with a scheme. 51 | var schemeRE = regexp.MustCompile("^([^:]+)://") 52 | 53 | // AddScheme adds the HTTP or HTTPS schemes to a endpoint URL if there is no 54 | // scheme. If disableSSL is true HTTP will be added instead of the default HTTPS. 55 | func AddScheme(endpoint string, disableSSL bool) string { 56 | if endpoint != "" && !schemeRE.MatchString(endpoint) { 57 | scheme := "https" 58 | if disableSSL { 59 | scheme = "http" 60 | } 61 | endpoint = fmt.Sprintf("%s://%s", scheme, endpoint) 62 | } 63 | 64 | return endpoint 65 | } 66 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/private/endpoints/endpoints.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "endpoints": { 4 | "*/*": { 5 | "endpoint": "{service}.{region}.amazonaws.com" 6 | }, 7 | "cn-north-1/*": { 8 | "endpoint": "{service}.{region}.amazonaws.com.cn", 9 | "signatureVersion": "v4" 10 | }, 11 | "us-gov-west-1/iam": { 12 | "endpoint": "iam.us-gov.amazonaws.com" 13 | }, 14 | "us-gov-west-1/sts": { 15 | "endpoint": "sts.us-gov-west-1.amazonaws.com" 16 | }, 17 | "us-gov-west-1/s3": { 18 | "endpoint": "s3-{region}.amazonaws.com" 19 | }, 20 | "*/cloudfront": { 21 | "endpoint": "cloudfront.amazonaws.com", 22 | "signingRegion": "us-east-1" 23 | }, 24 | "*/cloudsearchdomain": { 25 | "endpoint": "", 26 | "signingRegion": "us-east-1" 27 | }, 28 | "*/data.iot": { 29 | "endpoint": "", 30 | "signingRegion": "us-east-1" 31 | }, 32 | "*/ec2metadata": { 33 | "endpoint": "http://169.254.169.254/latest", 34 | "signingRegion": "us-east-1" 35 | }, 36 | "*/iam": { 37 | "endpoint": "iam.amazonaws.com", 38 | "signingRegion": "us-east-1" 39 | }, 40 | "*/importexport": { 41 | "endpoint": "importexport.amazonaws.com", 42 | "signingRegion": "us-east-1" 43 | }, 44 | "*/route53": { 45 | "endpoint": "route53.amazonaws.com", 46 | "signingRegion": "us-east-1" 47 | }, 48 | "*/sts": { 49 | "endpoint": "sts.amazonaws.com", 50 | "signingRegion": "us-east-1" 51 | }, 52 | "*/waf": { 53 | "endpoint": "waf.amazonaws.com", 54 | "signingRegion": "us-east-1" 55 | }, 56 | "us-east-1/sdb": { 57 | "endpoint": "sdb.amazonaws.com", 58 | "signingRegion": "us-east-1" 59 | }, 60 | "us-east-1/s3": { 61 | "endpoint": "s3.amazonaws.com" 62 | }, 63 | "us-west-1/s3": { 64 | "endpoint": "s3-{region}.amazonaws.com" 65 | }, 66 | "us-west-2/s3": { 67 | "endpoint": "s3-{region}.amazonaws.com" 68 | }, 69 | "eu-west-1/s3": { 70 | "endpoint": "s3-{region}.amazonaws.com" 71 | }, 72 | "ap-southeast-1/s3": { 73 | "endpoint": "s3-{region}.amazonaws.com" 74 | }, 75 | "ap-southeast-2/s3": { 76 | "endpoint": "s3-{region}.amazonaws.com" 77 | }, 78 | "ap-northeast-1/s3": { 79 | "endpoint": "s3-{region}.amazonaws.com" 80 | }, 81 | "sa-east-1/s3": { 82 | "endpoint": "s3-{region}.amazonaws.com" 83 | }, 84 | "eu-central-1/s3": { 85 | "endpoint": "{service}.{region}.amazonaws.com", 86 | "signatureVersion": "v4" 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/private/endpoints/endpoints_map.go: -------------------------------------------------------------------------------- 1 | package endpoints 2 | 3 | // THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. 4 | 5 | type endpointStruct struct { 6 | Version int 7 | Endpoints map[string]endpointEntry 8 | } 9 | 10 | type endpointEntry struct { 11 | Endpoint string 12 | SigningRegion string 13 | } 14 | 15 | var endpointsMap = endpointStruct{ 16 | Version: 2, 17 | Endpoints: map[string]endpointEntry{ 18 | "*/*": { 19 | Endpoint: "{service}.{region}.amazonaws.com", 20 | }, 21 | "*/cloudfront": { 22 | Endpoint: "cloudfront.amazonaws.com", 23 | SigningRegion: "us-east-1", 24 | }, 25 | "*/cloudsearchdomain": { 26 | Endpoint: "", 27 | SigningRegion: "us-east-1", 28 | }, 29 | "*/data.iot": { 30 | Endpoint: "", 31 | SigningRegion: "us-east-1", 32 | }, 33 | "*/ec2metadata": { 34 | Endpoint: "http://169.254.169.254/latest", 35 | SigningRegion: "us-east-1", 36 | }, 37 | "*/iam": { 38 | Endpoint: "iam.amazonaws.com", 39 | SigningRegion: "us-east-1", 40 | }, 41 | "*/importexport": { 42 | Endpoint: "importexport.amazonaws.com", 43 | SigningRegion: "us-east-1", 44 | }, 45 | "*/route53": { 46 | Endpoint: "route53.amazonaws.com", 47 | SigningRegion: "us-east-1", 48 | }, 49 | "*/sts": { 50 | Endpoint: "sts.amazonaws.com", 51 | SigningRegion: "us-east-1", 52 | }, 53 | "*/waf": { 54 | Endpoint: "waf.amazonaws.com", 55 | SigningRegion: "us-east-1", 56 | }, 57 | "ap-northeast-1/s3": { 58 | Endpoint: "s3-{region}.amazonaws.com", 59 | }, 60 | "ap-southeast-1/s3": { 61 | Endpoint: "s3-{region}.amazonaws.com", 62 | }, 63 | "ap-southeast-2/s3": { 64 | Endpoint: "s3-{region}.amazonaws.com", 65 | }, 66 | "cn-north-1/*": { 67 | Endpoint: "{service}.{region}.amazonaws.com.cn", 68 | }, 69 | "eu-central-1/s3": { 70 | Endpoint: "{service}.{region}.amazonaws.com", 71 | }, 72 | "eu-west-1/s3": { 73 | Endpoint: "s3-{region}.amazonaws.com", 74 | }, 75 | "sa-east-1/s3": { 76 | Endpoint: "s3-{region}.amazonaws.com", 77 | }, 78 | "us-east-1/s3": { 79 | Endpoint: "s3.amazonaws.com", 80 | }, 81 | "us-east-1/sdb": { 82 | Endpoint: "sdb.amazonaws.com", 83 | SigningRegion: "us-east-1", 84 | }, 85 | "us-gov-west-1/iam": { 86 | Endpoint: "iam.us-gov.amazonaws.com", 87 | }, 88 | "us-gov-west-1/s3": { 89 | Endpoint: "s3-{region}.amazonaws.com", 90 | }, 91 | "us-gov-west-1/sts": { 92 | Endpoint: "sts.us-gov-west-1.amazonaws.com", 93 | }, 94 | "us-west-1/s3": { 95 | Endpoint: "s3-{region}.amazonaws.com", 96 | }, 97 | "us-west-2/s3": { 98 | Endpoint: "s3-{region}.amazonaws.com", 99 | }, 100 | }, 101 | } 102 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/private/protocol/jsonrpc/jsonrpc.go: -------------------------------------------------------------------------------- 1 | // Package jsonrpc provides JSON RPC utilities for serialisation of AWS 2 | // requests and responses. 3 | package jsonrpc 4 | 5 | //go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/json.json build_test.go 6 | //go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/json.json unmarshal_test.go 7 | 8 | import ( 9 | "encoding/json" 10 | "io/ioutil" 11 | "strings" 12 | 13 | "github.com/aws/aws-sdk-go/aws/awserr" 14 | "github.com/aws/aws-sdk-go/aws/request" 15 | "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil" 16 | "github.com/aws/aws-sdk-go/private/protocol/rest" 17 | ) 18 | 19 | var emptyJSON = []byte("{}") 20 | 21 | // Build builds a JSON payload for a JSON RPC request. 22 | func Build(req *request.Request) { 23 | var buf []byte 24 | var err error 25 | if req.ParamsFilled() { 26 | buf, err = jsonutil.BuildJSON(req.Params) 27 | if err != nil { 28 | req.Error = awserr.New("SerializationError", "failed encoding JSON RPC request", err) 29 | return 30 | } 31 | } else { 32 | buf = emptyJSON 33 | } 34 | 35 | if req.ClientInfo.TargetPrefix != "" || string(buf) != "{}" { 36 | req.SetBufferBody(buf) 37 | } 38 | 39 | if req.ClientInfo.TargetPrefix != "" { 40 | target := req.ClientInfo.TargetPrefix + "." + req.Operation.Name 41 | req.HTTPRequest.Header.Add("X-Amz-Target", target) 42 | } 43 | if req.ClientInfo.JSONVersion != "" { 44 | jsonVersion := req.ClientInfo.JSONVersion 45 | req.HTTPRequest.Header.Add("Content-Type", "application/x-amz-json-"+jsonVersion) 46 | } 47 | } 48 | 49 | // Unmarshal unmarshals a response for a JSON RPC service. 50 | func Unmarshal(req *request.Request) { 51 | defer req.HTTPResponse.Body.Close() 52 | if req.DataFilled() { 53 | err := jsonutil.UnmarshalJSON(req.Data, req.HTTPResponse.Body) 54 | if err != nil { 55 | req.Error = awserr.New("SerializationError", "failed decoding JSON RPC response", err) 56 | } 57 | } 58 | return 59 | } 60 | 61 | // UnmarshalMeta unmarshals headers from a response for a JSON RPC service. 62 | func UnmarshalMeta(req *request.Request) { 63 | rest.UnmarshalMeta(req) 64 | } 65 | 66 | // UnmarshalError unmarshals an error response for a JSON RPC service. 67 | func UnmarshalError(req *request.Request) { 68 | defer req.HTTPResponse.Body.Close() 69 | bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body) 70 | if err != nil { 71 | req.Error = awserr.New("SerializationError", "failed reading JSON RPC error response", err) 72 | return 73 | } 74 | if len(bodyBytes) == 0 { 75 | req.Error = awserr.NewRequestFailure( 76 | awserr.New("SerializationError", req.HTTPResponse.Status, nil), 77 | req.HTTPResponse.StatusCode, 78 | "", 79 | ) 80 | return 81 | } 82 | var jsonErr jsonErrorResponse 83 | if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil { 84 | req.Error = awserr.New("SerializationError", "failed decoding JSON RPC error response", err) 85 | return 86 | } 87 | 88 | codes := strings.SplitN(jsonErr.Code, "#", 2) 89 | req.Error = awserr.NewRequestFailure( 90 | awserr.New(codes[len(codes)-1], jsonErr.Message, nil), 91 | req.HTTPResponse.StatusCode, 92 | req.RequestID, 93 | ) 94 | } 95 | 96 | type jsonErrorResponse struct { 97 | Code string `json:"__type"` 98 | Message string `json:"message"` 99 | } 100 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/private/protocol/rest/payload.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import "reflect" 4 | 5 | // PayloadMember returns the payload field member of i if there is one, or nil. 6 | func PayloadMember(i interface{}) interface{} { 7 | if i == nil { 8 | return nil 9 | } 10 | 11 | v := reflect.ValueOf(i).Elem() 12 | if !v.IsValid() { 13 | return nil 14 | } 15 | if field, ok := v.Type().FieldByName("_"); ok { 16 | if payloadName := field.Tag.Get("payload"); payloadName != "" { 17 | field, _ := v.Type().FieldByName(payloadName) 18 | if field.Tag.Get("type") != "structure" { 19 | return nil 20 | } 21 | 22 | payload := v.FieldByName(payloadName) 23 | if payload.IsValid() || (payload.Kind() == reflect.Ptr && !payload.IsNil()) { 24 | return payload.Interface() 25 | } 26 | } 27 | } 28 | return nil 29 | } 30 | 31 | // PayloadType returns the type of a payload field member of i if there is one, or "". 32 | func PayloadType(i interface{}) string { 33 | v := reflect.Indirect(reflect.ValueOf(i)) 34 | if !v.IsValid() { 35 | return "" 36 | } 37 | if field, ok := v.Type().FieldByName("_"); ok { 38 | if payloadName := field.Tag.Get("payload"); payloadName != "" { 39 | if member, ok := v.Type().FieldByName(payloadName); ok { 40 | return member.Tag.Get("type") 41 | } 42 | } 43 | } 44 | return "" 45 | } 46 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/service/kinesis/service.go: -------------------------------------------------------------------------------- 1 | // THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. 2 | 3 | package kinesis 4 | 5 | import ( 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/aws/client" 8 | "github.com/aws/aws-sdk-go/aws/client/metadata" 9 | "github.com/aws/aws-sdk-go/aws/request" 10 | "github.com/aws/aws-sdk-go/private/protocol/jsonrpc" 11 | "github.com/aws/aws-sdk-go/private/signer/v4" 12 | ) 13 | 14 | // Amazon Kinesis is a managed service that scales elastically for real time 15 | // processing of streaming big data. 16 | //The service client's operations are safe to be used concurrently. 17 | // It is not safe to mutate any of the client's properties though. 18 | type Kinesis struct { 19 | *client.Client 20 | } 21 | 22 | // Used for custom client initialization logic 23 | var initClient func(*client.Client) 24 | 25 | // Used for custom request initialization logic 26 | var initRequest func(*request.Request) 27 | 28 | // A ServiceName is the name of the service the client will make API calls to. 29 | const ServiceName = "kinesis" 30 | 31 | // New creates a new instance of the Kinesis client with a session. 32 | // If additional configuration is needed for the client instance use the optional 33 | // aws.Config parameter to add your extra config. 34 | // 35 | // Example: 36 | // // Create a Kinesis client from just a session. 37 | // svc := kinesis.New(mySession) 38 | // 39 | // // Create a Kinesis client with additional configuration 40 | // svc := kinesis.New(mySession, aws.NewConfig().WithRegion("us-west-2")) 41 | func New(p client.ConfigProvider, cfgs ...*aws.Config) *Kinesis { 42 | c := p.ClientConfig(ServiceName, cfgs...) 43 | return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion) 44 | } 45 | 46 | // newClient creates, initializes and returns a new service client instance. 47 | func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *Kinesis { 48 | svc := &Kinesis{ 49 | Client: client.New( 50 | cfg, 51 | metadata.ClientInfo{ 52 | ServiceName: ServiceName, 53 | SigningRegion: signingRegion, 54 | Endpoint: endpoint, 55 | APIVersion: "2013-12-02", 56 | JSONVersion: "1.1", 57 | TargetPrefix: "Kinesis_20131202", 58 | }, 59 | handlers, 60 | ), 61 | } 62 | 63 | // Handlers 64 | svc.Handlers.Sign.PushBack(v4.Sign) 65 | svc.Handlers.Build.PushBack(jsonrpc.Build) 66 | svc.Handlers.Unmarshal.PushBack(jsonrpc.Unmarshal) 67 | svc.Handlers.UnmarshalMeta.PushBack(jsonrpc.UnmarshalMeta) 68 | svc.Handlers.UnmarshalError.PushBack(jsonrpc.UnmarshalError) 69 | 70 | // Run custom client initialization if present 71 | if initClient != nil { 72 | initClient(svc.Client) 73 | } 74 | 75 | return svc 76 | } 77 | 78 | // newRequest creates a new request for a Kinesis operation and runs any 79 | // custom request initialization. 80 | func (c *Kinesis) newRequest(op *request.Operation, params, data interface{}) *request.Request { 81 | req := c.NewRequest(op, params, data) 82 | 83 | // Run custom request initialization if present 84 | if initRequest != nil { 85 | initRequest(req) 86 | } 87 | 88 | return req 89 | } 90 | -------------------------------------------------------------------------------- /vendor/github.com/aws/aws-sdk-go/service/kinesis/waiters.go: -------------------------------------------------------------------------------- 1 | // THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. 2 | 3 | package kinesis 4 | 5 | import ( 6 | "github.com/aws/aws-sdk-go/private/waiter" 7 | ) 8 | 9 | func (c *Kinesis) WaitUntilStreamExists(input *DescribeStreamInput) error { 10 | waiterCfg := waiter.Config{ 11 | Operation: "DescribeStream", 12 | Delay: 10, 13 | MaxAttempts: 18, 14 | Acceptors: []waiter.WaitAcceptor{ 15 | { 16 | State: "success", 17 | Matcher: "path", 18 | Argument: "StreamDescription.StreamStatus", 19 | Expected: "ACTIVE", 20 | }, 21 | }, 22 | } 23 | 24 | w := waiter.Waiter{ 25 | Client: c, 26 | Input: input, 27 | Config: waiterCfg, 28 | } 29 | return w.Wait() 30 | } 31 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/AUTHORS: -------------------------------------------------------------------------------- 1 | # This is the official list of go-dockerclient authors for copyright purposes. 2 | 3 | Adam Bell-Hanssen 4 | Aldrin Leal 5 | Andreas Jaekle 6 | Andrews Medina 7 | Artem Sidorenko 8 | Andy Goldstein 9 | Ben Marini 10 | Ben McCann 11 | Brendan Fosberry 12 | Brian Lalor 13 | Brian Palmer 14 | Bryan Boreham 15 | Burke Libbey 16 | Carlos Diaz-Padron 17 | Cesar Wong 18 | Cezar Sa Espinola 19 | Cheah Chu Yeow 20 | cheneydeng 21 | CMGS 22 | Craig Jellick 23 | Dan Williams 24 | Daniel, Dao Quang Minh 25 | Daniel Garcia 26 | Darren Shepherd 27 | Dave Choi 28 | David Huie 29 | Dawn Chen 30 | Dinesh Subhraveti 31 | Ed 32 | Erez Horev 33 | Eric Anderson 34 | Ewout Prangsma 35 | Fabio Rehm 36 | Fatih Arslan 37 | Flavia Missi 38 | Francisco Souza 39 | Grégoire Delattre 40 | Guillermo Álvarez Fernández 41 | He Simei 42 | Ivan Mikushin 43 | James Bardin 44 | Jari Kolehmainen 45 | Jason Wilder 46 | Jawher Moussa 47 | Jean-Baptiste Dalido 48 | Jeff Mitchell 49 | Jeffrey Hulten 50 | Jen Andre 51 | Johan Euphrosine 52 | Kamil Domanski 53 | Karan Misra 54 | Kim, Hirokuni 55 | Kyle Allan 56 | Liron Levin 57 | Liu Peng 58 | Lorenz Leutgeb 59 | Lucas Clemente 60 | Lucas Weiblen 61 | Mantas Matelis 62 | Martin Sweeney 63 | Máximo Cuadros Ortiz 64 | Michal Fojtik 65 | Mike Dillon 66 | Mrunal Patel 67 | Nick Ethier 68 | Omeid Matten 69 | Orivej Desh 70 | Paul Bellamy 71 | Paul Morie 72 | Paul Weil 73 | Peter Edge 74 | Peter Jihoon Kim 75 | Phil Lu 76 | Philippe Lafoucrière 77 | Rafe Colton 78 | Rob Miller 79 | Robert Williamson 80 | Salvador Gironès 81 | Sam Rijs 82 | Samuel Karp 83 | Simon Eskildsen 84 | Simon Menke 85 | Skolos 86 | Soulou 87 | Sridhar Ratnakumar 88 | Summer Mousa 89 | Sunjin Lee 90 | Tarsis Azevedo 91 | Tim Schindler 92 | Tobi Knaup 93 | Tonic 94 | ttyh061 95 | Victor Marmol 96 | Vincenzo Prignano 97 | Wiliam Souza 98 | Ye Yin 99 | Yuriy Bogdanov 100 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/DOCKER-LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | You can find the Docker license at the following link: 6 | https://raw.githubusercontent.com/docker/docker/master/LICENSE 7 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, go-dockerclient authors 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: \ 2 | all \ 3 | vendor \ 4 | lint \ 5 | vet \ 6 | fmt \ 7 | fmtcheck \ 8 | pretest \ 9 | test \ 10 | cov \ 11 | clean 12 | 13 | SRCS = $(shell git ls-files '*.go' | grep -v '^external/') 14 | PKGS = ./. ./testing 15 | 16 | all: test 17 | 18 | vendor: 19 | @ go get -v github.com/mjibson/party 20 | party -d external -c -u 21 | 22 | lint: 23 | @ go get -v github.com/golang/lint/golint 24 | $(foreach file,$(SRCS),golint $(file) || exit;) 25 | 26 | vet: 27 | @-go get -v golang.org/x/tools/cmd/vet 28 | $(foreach pkg,$(PKGS),go vet $(pkg);) 29 | 30 | fmt: 31 | gofmt -w $(SRCS) 32 | 33 | fmtcheck: 34 | $(foreach file,$(SRCS),gofmt $(file) | diff -u $(file) - || exit;) 35 | 36 | pretest: lint vet fmtcheck 37 | 38 | test: pretest 39 | $(foreach pkg,$(PKGS),go test $(pkg) || exit;) 40 | 41 | cov: 42 | @ go get -v github.com/axw/gocov/gocov 43 | @ go get golang.org/x/tools/cmd/cover 44 | gocov test | gocov report 45 | 46 | clean: 47 | $(foreach pkg,$(PKGS),go clean $(pkg) || exit;) 48 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/README.markdown: -------------------------------------------------------------------------------- 1 | # go-dockerclient 2 | 3 | [![Drone](https://drone.io/github.com/fsouza/go-dockerclient/status.png)](https://drone.io/github.com/fsouza/go-dockerclient/latest) 4 | [![Travis](https://img.shields.io/travis/fsouza/go-dockerclient.svg?style=flat-square)](https://travis-ci.org/fsouza/go-dockerclient) 5 | [![GoDoc](https://img.shields.io/badge/api-Godoc-blue.svg?style=flat-square)](https://godoc.org/github.com/fsouza/go-dockerclient) 6 | 7 | This package presents a client for the Docker remote API. It also provides 8 | support for the extensions in the [Swarm API](https://docs.docker.com/swarm/API/). 9 | 10 | This package also provides support for docker's network API, which is a simple 11 | passthrough to the libnetwork remote API. Note that docker's network API is 12 | only available in docker 1.8 and above, and only enabled in docker if 13 | DOCKER_EXPERIMENTAL is defined during the docker build process. 14 | 15 | For more details, check the [remote API documentation](http://docs.docker.com/en/latest/reference/api/docker_remote_api/). 16 | 17 | ## Vendoring 18 | 19 | If you are having issues with Go 1.5 and have `GO15VENDOREXPERIMENT` set with an application that has go-dockerclient vendored, 20 | please update your vendoring of go-dockerclient :) We recently moved the `vendor` directory to `external` so that go-dockerclient 21 | is compatible with this configuration. See [338](https://github.com/fsouza/go-dockerclient/issues/338) and [339](https://github.com/fsouza/go-dockerclient/pull/339) 22 | for details. 23 | 24 | ## Example 25 | 26 | ```go 27 | package main 28 | 29 | import ( 30 | "fmt" 31 | 32 | "github.com/fsouza/go-dockerclient" 33 | ) 34 | 35 | func main() { 36 | endpoint := "unix:///var/run/docker.sock" 37 | client, _ := docker.NewClient(endpoint) 38 | imgs, _ := client.ListImages(docker.ListImagesOptions{All: false}) 39 | for _, img := range imgs { 40 | fmt.Println("ID: ", img.ID) 41 | fmt.Println("RepoTags: ", img.RepoTags) 42 | fmt.Println("Created: ", img.Created) 43 | fmt.Println("Size: ", img.Size) 44 | fmt.Println("VirtualSize: ", img.VirtualSize) 45 | fmt.Println("ParentId: ", img.ParentID) 46 | } 47 | } 48 | ``` 49 | 50 | ## Using with TLS 51 | 52 | In order to instantiate the client for a TLS-enabled daemon, you should use NewTLSClient, passing the endpoint and path for key and certificates as parameters. 53 | 54 | ```go 55 | package main 56 | 57 | import ( 58 | "fmt" 59 | 60 | "github.com/fsouza/go-dockerclient" 61 | ) 62 | 63 | func main() { 64 | endpoint := "tcp://[ip]:[port]" 65 | path := os.Getenv("DOCKER_CERT_PATH") 66 | ca := fmt.Sprintf("%s/ca.pem", path) 67 | cert := fmt.Sprintf("%s/cert.pem", path) 68 | key := fmt.Sprintf("%s/key.pem", path) 69 | client, _ := docker.NewTLSClient(endpoint, cert, key, ca) 70 | // use client 71 | } 72 | ``` 73 | 74 | If using [docker-machine](https://docs.docker.com/machine/), or another application that exports environment variables 75 | `DOCKER_HOST, DOCKER_TLS_VERIFY, DOCKER_CERT_PATH`, you can use NewClientFromEnv. 76 | 77 | 78 | ```go 79 | package main 80 | 81 | import ( 82 | "fmt" 83 | 84 | "github.com/fsouza/go-dockerclient" 85 | ) 86 | 87 | func main() { 88 | client, _ := docker.NewClientFromEnv() 89 | // use client 90 | } 91 | ``` 92 | 93 | See the documentation for more details. 94 | 95 | ## Developing 96 | 97 | All development commands can be seen in the [Makefile](Makefile). 98 | 99 | Commited code must pass: 100 | 101 | * [golint](https://github.com/golang/lint) 102 | * [go vet](https://godoc.org/golang.org/x/tools/cmd/vet) 103 | * [gofmt](https://golang.org/cmd/gofmt) 104 | * [go test](https://golang.org/cmd/go/#hdr-Test_packages) 105 | 106 | Running `make test` will check all of these. If your editor does not automatically call gofmt, `make fmt` will format all go files in this repository. 107 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/change.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 go-dockerclient authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package docker 6 | 7 | import "fmt" 8 | 9 | // ChangeType is a type for constants indicating the type of change 10 | // in a container 11 | type ChangeType int 12 | 13 | const ( 14 | // ChangeModify is the ChangeType for container modifications 15 | ChangeModify ChangeType = iota 16 | 17 | // ChangeAdd is the ChangeType for additions to a container 18 | ChangeAdd 19 | 20 | // ChangeDelete is the ChangeType for deletions from a container 21 | ChangeDelete 22 | ) 23 | 24 | // Change represents a change in a container. 25 | // 26 | // See https://goo.gl/9GsTIF for more details. 27 | type Change struct { 28 | Path string 29 | Kind ChangeType 30 | } 31 | 32 | func (change *Change) String() string { 33 | var kind string 34 | switch change.Kind { 35 | case ChangeModify: 36 | kind = "C" 37 | case ChangeAdd: 38 | kind = "A" 39 | case ChangeDelete: 40 | kind = "D" 41 | } 42 | return fmt.Sprintf("%s %s", kind, change.Path) 43 | } 44 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/Sirupsen/logrus/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # (Unreleased) 2 | 3 | logrus/core: improve performance of text formatter by 40% 4 | logrus/core: expose `LevelHooks` type 5 | 6 | # 0.8.2 7 | 8 | logrus: fix more Fatal family functions 9 | 10 | # 0.8.1 11 | 12 | logrus: fix not exiting on `Fatalf` and `Fatalln` 13 | 14 | # 0.8.0 15 | 16 | logrus: defaults to stderr instead of stdout 17 | hooks/sentry: add special field for `*http.Request` 18 | formatter/text: ignore Windows for colors 19 | 20 | # 0.7.3 21 | 22 | formatter/\*: allow configuration of timestamp layout 23 | 24 | # 0.7.2 25 | 26 | formatter/text: Add configuration option for time format (#158) 27 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/Sirupsen/logrus/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Simon Eskildsen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/Sirupsen/logrus/formatter.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import "time" 4 | 5 | const DefaultTimestampFormat = time.RFC3339 6 | 7 | // The Formatter interface is used to implement a custom Formatter. It takes an 8 | // `Entry`. It exposes all the fields, including the default ones: 9 | // 10 | // * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. 11 | // * `entry.Data["time"]`. The timestamp. 12 | // * `entry.Data["level"]. The level the entry was logged at. 13 | // 14 | // Any additional fields added with `WithField` or `WithFields` are also in 15 | // `entry.Data`. Format is expected to return an array of bytes which are then 16 | // logged to `logger.Out`. 17 | type Formatter interface { 18 | Format(*Entry) ([]byte, error) 19 | } 20 | 21 | // This is to not silently overwrite `time`, `msg` and `level` fields when 22 | // dumping it. If this code wasn't there doing: 23 | // 24 | // logrus.WithField("level", 1).Info("hello") 25 | // 26 | // Would just silently drop the user provided level. Instead with this code 27 | // it'll logged as: 28 | // 29 | // {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} 30 | // 31 | // It's not exported because it's still using Data in an opinionated way. It's to 32 | // avoid code duplication between the two default formatters. 33 | func prefixFieldClashes(data Fields) { 34 | _, ok := data["time"] 35 | if ok { 36 | data["fields.time"] = data["time"] 37 | } 38 | 39 | _, ok = data["msg"] 40 | if ok { 41 | data["fields.msg"] = data["msg"] 42 | } 43 | 44 | _, ok = data["level"] 45 | if ok { 46 | data["fields.level"] = data["level"] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/Sirupsen/logrus/hooks.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | // A hook to be fired when logging on the logging levels returned from 4 | // `Levels()` on your implementation of the interface. Note that this is not 5 | // fired in a goroutine or a channel with workers, you should handle such 6 | // functionality yourself if your call is non-blocking and you don't wish for 7 | // the logging calls for levels returned from `Levels()` to block. 8 | type Hook interface { 9 | Levels() []Level 10 | Fire(*Entry) error 11 | } 12 | 13 | // Internal type for storing the hooks on a logger instance. 14 | type LevelHooks map[Level][]Hook 15 | 16 | // Add a hook to an instance of logger. This is called with 17 | // `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface. 18 | func (hooks LevelHooks) Add(hook Hook) { 19 | for _, level := range hook.Levels() { 20 | hooks[level] = append(hooks[level], hook) 21 | } 22 | } 23 | 24 | // Fire all the hooks for the passed level. Used by `entry.log` to fire 25 | // appropriate hooks for a log entry. 26 | func (hooks LevelHooks) Fire(level Level, entry *Entry) error { 27 | for _, hook := range hooks[level] { 28 | if err := hook.Fire(entry); err != nil { 29 | return err 30 | } 31 | } 32 | 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/Sirupsen/logrus/json_formatter.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | type JSONFormatter struct { 9 | // TimestampFormat sets the format used for marshaling timestamps. 10 | TimestampFormat string 11 | } 12 | 13 | func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { 14 | data := make(Fields, len(entry.Data)+3) 15 | for k, v := range entry.Data { 16 | switch v := v.(type) { 17 | case error: 18 | // Otherwise errors are ignored by `encoding/json` 19 | // https://github.com/Sirupsen/logrus/issues/137 20 | data[k] = v.Error() 21 | default: 22 | data[k] = v 23 | } 24 | } 25 | prefixFieldClashes(data) 26 | 27 | timestampFormat := f.TimestampFormat 28 | if timestampFormat == "" { 29 | timestampFormat = DefaultTimestampFormat 30 | } 31 | 32 | data["time"] = entry.Time.Format(timestampFormat) 33 | data["msg"] = entry.Message 34 | data["level"] = entry.Level.String() 35 | 36 | serialized, err := json.Marshal(data) 37 | if err != nil { 38 | return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) 39 | } 40 | return append(serialized, '\n'), nil 41 | } 42 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/Sirupsen/logrus/logrus.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | ) 7 | 8 | // Fields type, used to pass to `WithFields`. 9 | type Fields map[string]interface{} 10 | 11 | // Level type 12 | type Level uint8 13 | 14 | // Convert the Level to a string. E.g. PanicLevel becomes "panic". 15 | func (level Level) String() string { 16 | switch level { 17 | case DebugLevel: 18 | return "debug" 19 | case InfoLevel: 20 | return "info" 21 | case WarnLevel: 22 | return "warning" 23 | case ErrorLevel: 24 | return "error" 25 | case FatalLevel: 26 | return "fatal" 27 | case PanicLevel: 28 | return "panic" 29 | } 30 | 31 | return "unknown" 32 | } 33 | 34 | // ParseLevel takes a string level and returns the Logrus log level constant. 35 | func ParseLevel(lvl string) (Level, error) { 36 | switch lvl { 37 | case "panic": 38 | return PanicLevel, nil 39 | case "fatal": 40 | return FatalLevel, nil 41 | case "error": 42 | return ErrorLevel, nil 43 | case "warn", "warning": 44 | return WarnLevel, nil 45 | case "info": 46 | return InfoLevel, nil 47 | case "debug": 48 | return DebugLevel, nil 49 | } 50 | 51 | var l Level 52 | return l, fmt.Errorf("not a valid logrus Level: %q", lvl) 53 | } 54 | 55 | // These are the different logging levels. You can set the logging level to log 56 | // on your instance of logger, obtained with `logrus.New()`. 57 | const ( 58 | // PanicLevel level, highest level of severity. Logs and then calls panic with the 59 | // message passed to Debug, Info, ... 60 | PanicLevel Level = iota 61 | // FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the 62 | // logging level is set to Panic. 63 | FatalLevel 64 | // ErrorLevel level. Logs. Used for errors that should definitely be noted. 65 | // Commonly used for hooks to send errors to an error tracking service. 66 | ErrorLevel 67 | // WarnLevel level. Non-critical entries that deserve eyes. 68 | WarnLevel 69 | // InfoLevel level. General operational entries about what's going on inside the 70 | // application. 71 | InfoLevel 72 | // DebugLevel level. Usually only enabled when debugging. Very verbose logging. 73 | DebugLevel 74 | ) 75 | 76 | // Won't compile if StdLogger can't be realized by a log.Logger 77 | var _ StdLogger = &log.Logger{} 78 | 79 | // StdLogger is what your logrus-enabled library should take, that way 80 | // it'll accept a stdlib logger and a logrus logger. There's no standard 81 | // interface, this is the closest we get, unfortunately. 82 | type StdLogger interface { 83 | Print(...interface{}) 84 | Printf(string, ...interface{}) 85 | Println(...interface{}) 86 | 87 | Fatal(...interface{}) 88 | Fatalf(string, ...interface{}) 89 | Fatalln(...interface{}) 90 | 91 | Panic(...interface{}) 92 | Panicf(string, ...interface{}) 93 | Panicln(...interface{}) 94 | } 95 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/Sirupsen/logrus/terminal_bsd.go: -------------------------------------------------------------------------------- 1 | // +build darwin freebsd openbsd netbsd dragonfly 2 | 3 | package logrus 4 | 5 | import "syscall" 6 | 7 | const ioctlReadTermios = syscall.TIOCGETA 8 | 9 | type Termios syscall.Termios 10 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/Sirupsen/logrus/terminal_freebsd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Go 1.2 doesn't include Termios for FreeBSD. This should be added in 1.3 and this could be merged with terminal_darwin. 3 | */ 4 | package logrus 5 | 6 | import ( 7 | "syscall" 8 | ) 9 | 10 | const ioctlReadTermios = syscall.TIOCGETA 11 | 12 | type Termios struct { 13 | Iflag uint32 14 | Oflag uint32 15 | Cflag uint32 16 | Lflag uint32 17 | Cc [20]uint8 18 | Ispeed uint32 19 | Ospeed uint32 20 | } 21 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/Sirupsen/logrus/terminal_linux.go: -------------------------------------------------------------------------------- 1 | // Based on ssh/terminal: 2 | // Copyright 2013 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package logrus 7 | 8 | import "syscall" 9 | 10 | const ioctlReadTermios = syscall.TCGETS 11 | 12 | type Termios syscall.Termios 13 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/Sirupsen/logrus/terminal_notwindows.go: -------------------------------------------------------------------------------- 1 | // Based on ssh/terminal: 2 | // Copyright 2011 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // +build linux darwin freebsd openbsd 7 | 8 | package logrus 9 | 10 | import ( 11 | "syscall" 12 | "unsafe" 13 | ) 14 | 15 | // IsTerminal returns true if the given file descriptor is a terminal. 16 | func IsTerminal() bool { 17 | fd := syscall.Stdout 18 | var termios Termios 19 | _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) 20 | return err == 0 21 | } 22 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/Sirupsen/logrus/terminal_openbsd.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import "syscall" 4 | 5 | const ioctlReadTermios = syscall.TIOCGETA 6 | 7 | type Termios syscall.Termios 8 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/Sirupsen/logrus/terminal_windows.go: -------------------------------------------------------------------------------- 1 | // Based on ssh/terminal: 2 | // Copyright 2011 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // +build windows 7 | 8 | package logrus 9 | 10 | import ( 11 | "syscall" 12 | "unsafe" 13 | ) 14 | 15 | var kernel32 = syscall.NewLazyDLL("kernel32.dll") 16 | 17 | var ( 18 | procGetConsoleMode = kernel32.NewProc("GetConsoleMode") 19 | ) 20 | 21 | // IsTerminal returns true if the given file descriptor is a terminal. 22 | func IsTerminal() bool { 23 | fd := syscall.Stdout 24 | var st uint32 25 | r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) 26 | return r != 0 && e == 0 27 | } 28 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/Sirupsen/logrus/writer.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bufio" 5 | "io" 6 | "runtime" 7 | ) 8 | 9 | func (logger *Logger) Writer() *io.PipeWriter { 10 | reader, writer := io.Pipe() 11 | 12 | go logger.writerScanner(reader) 13 | runtime.SetFinalizer(writer, writerFinalizer) 14 | 15 | return writer 16 | } 17 | 18 | func (logger *Logger) writerScanner(reader *io.PipeReader) { 19 | scanner := bufio.NewScanner(reader) 20 | for scanner.Scan() { 21 | logger.Print(scanner.Text()) 22 | } 23 | if err := scanner.Err(); err != nil { 24 | logger.Errorf("Error while reading from Writer: %s", err) 25 | } 26 | reader.Close() 27 | } 28 | 29 | func writerFinalizer(writer *io.PipeWriter) { 30 | writer.Close() 31 | } 32 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/opts/envfile.go: -------------------------------------------------------------------------------- 1 | package opts 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "regexp" 8 | "strings" 9 | ) 10 | 11 | var ( 12 | // EnvironmentVariableRegexp A regexp to validate correct environment variables 13 | // Environment variables set by the user must have a name consisting solely of 14 | // alphabetics, numerics, and underscores - the first of which must not be numeric. 15 | EnvironmentVariableRegexp = regexp.MustCompile("^[[:alpha:]_][[:alpha:][:digit:]_]*$") 16 | ) 17 | 18 | // ParseEnvFile Read in a line delimited file with environment variables enumerated 19 | func ParseEnvFile(filename string) ([]string, error) { 20 | fh, err := os.Open(filename) 21 | if err != nil { 22 | return []string{}, err 23 | } 24 | defer fh.Close() 25 | 26 | lines := []string{} 27 | scanner := bufio.NewScanner(fh) 28 | for scanner.Scan() { 29 | line := scanner.Text() 30 | // line is not empty, and not starting with '#' 31 | if len(line) > 0 && !strings.HasPrefix(line, "#") { 32 | data := strings.SplitN(line, "=", 2) 33 | 34 | // trim the front of a variable, but nothing else 35 | variable := strings.TrimLeft(data[0], whiteSpaces) 36 | 37 | if !EnvironmentVariableRegexp.MatchString(variable) { 38 | return []string{}, ErrBadEnvVariable{fmt.Sprintf("variable '%s' is not a valid environment variable", variable)} 39 | } 40 | if len(data) > 1 { 41 | 42 | // pass the value through, no trimming 43 | lines = append(lines, fmt.Sprintf("%s=%s", variable, data[1])) 44 | } else { 45 | // if only a pass-through variable is given, clean it up. 46 | lines = append(lines, fmt.Sprintf("%s=%s", strings.TrimSpace(line), os.Getenv(line))) 47 | } 48 | } 49 | } 50 | return lines, scanner.Err() 51 | } 52 | 53 | var whiteSpaces = " \t" 54 | 55 | // ErrBadEnvVariable typed error for bad environment variable 56 | type ErrBadEnvVariable struct { 57 | msg string 58 | } 59 | 60 | func (e ErrBadEnvVariable) Error() string { 61 | return fmt.Sprintf("poorly formatted environment: %s", e.msg) 62 | } 63 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/opts/hosts_unix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package opts 4 | 5 | import "fmt" 6 | 7 | var DefaultHost = fmt.Sprintf("unix://%s", DefaultUnixSocket) 8 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/opts/hosts_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package opts 4 | 5 | import "fmt" 6 | 7 | var DefaultHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultHTTPPort) 8 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/opts/ip.go: -------------------------------------------------------------------------------- 1 | package opts 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | ) 7 | 8 | // IpOpt type that hold an IP 9 | type IpOpt struct { 10 | *net.IP 11 | } 12 | 13 | func NewIpOpt(ref *net.IP, defaultVal string) *IpOpt { 14 | o := &IpOpt{ 15 | IP: ref, 16 | } 17 | o.Set(defaultVal) 18 | return o 19 | } 20 | 21 | func (o *IpOpt) Set(val string) error { 22 | ip := net.ParseIP(val) 23 | if ip == nil { 24 | return fmt.Errorf("%s is not an ip address", val) 25 | } 26 | *o.IP = ip 27 | return nil 28 | } 29 | 30 | func (o *IpOpt) String() string { 31 | if *o.IP == nil { 32 | return "" 33 | } 34 | return o.IP.String() 35 | } 36 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/opts/ulimit.go: -------------------------------------------------------------------------------- 1 | package opts 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/ulimit" 7 | ) 8 | 9 | type UlimitOpt struct { 10 | values *map[string]*ulimit.Ulimit 11 | } 12 | 13 | func NewUlimitOpt(ref *map[string]*ulimit.Ulimit) *UlimitOpt { 14 | if ref == nil { 15 | ref = &map[string]*ulimit.Ulimit{} 16 | } 17 | return &UlimitOpt{ref} 18 | } 19 | 20 | func (o *UlimitOpt) Set(val string) error { 21 | l, err := ulimit.Parse(val) 22 | if err != nil { 23 | return err 24 | } 25 | 26 | (*o.values)[l.Name] = l 27 | 28 | return nil 29 | } 30 | 31 | func (o *UlimitOpt) String() string { 32 | var out []string 33 | for _, v := range *o.values { 34 | out = append(out, v.String()) 35 | } 36 | 37 | return fmt.Sprintf("%v", out) 38 | } 39 | 40 | func (o *UlimitOpt) GetList() []*ulimit.Ulimit { 41 | var ulimits []*ulimit.Ulimit 42 | for _, v := range *o.values { 43 | ulimits = append(ulimits, v) 44 | } 45 | 46 | return ulimits 47 | } 48 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/README.md: -------------------------------------------------------------------------------- 1 | This code provides helper functions for dealing with archive files. 2 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/archive_unix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package archive 4 | 5 | import ( 6 | "archive/tar" 7 | "errors" 8 | "os" 9 | "syscall" 10 | 11 | "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system" 12 | ) 13 | 14 | // CanonicalTarNameForPath returns platform-specific filepath 15 | // to canonical posix-style path for tar archival. p is relative 16 | // path. 17 | func CanonicalTarNameForPath(p string) (string, error) { 18 | return p, nil // already unix-style 19 | } 20 | 21 | // chmodTarEntry is used to adjust the file permissions used in tar header based 22 | // on the platform the archival is done. 23 | 24 | func chmodTarEntry(perm os.FileMode) os.FileMode { 25 | return perm // noop for unix as golang APIs provide perm bits correctly 26 | } 27 | 28 | func setHeaderForSpecialDevice(hdr *tar.Header, ta *tarAppender, name string, stat interface{}) (nlink uint32, inode uint64, err error) { 29 | s, ok := stat.(*syscall.Stat_t) 30 | 31 | if !ok { 32 | err = errors.New("cannot convert stat value to syscall.Stat_t") 33 | return 34 | } 35 | 36 | nlink = uint32(s.Nlink) 37 | inode = uint64(s.Ino) 38 | 39 | // Currently go does not fil in the major/minors 40 | if s.Mode&syscall.S_IFBLK != 0 || 41 | s.Mode&syscall.S_IFCHR != 0 { 42 | hdr.Devmajor = int64(major(uint64(s.Rdev))) 43 | hdr.Devminor = int64(minor(uint64(s.Rdev))) 44 | } 45 | 46 | return 47 | } 48 | 49 | func major(device uint64) uint64 { 50 | return (device >> 8) & 0xfff 51 | } 52 | 53 | func minor(device uint64) uint64 { 54 | return (device & 0xff) | ((device >> 12) & 0xfff00) 55 | } 56 | 57 | // handleTarTypeBlockCharFifo is an OS-specific helper function used by 58 | // createTarFile to handle the following types of header: Block; Char; Fifo 59 | func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error { 60 | mode := uint32(hdr.Mode & 07777) 61 | switch hdr.Typeflag { 62 | case tar.TypeBlock: 63 | mode |= syscall.S_IFBLK 64 | case tar.TypeChar: 65 | mode |= syscall.S_IFCHR 66 | case tar.TypeFifo: 67 | mode |= syscall.S_IFIFO 68 | } 69 | 70 | if err := system.Mknod(path, mode, int(system.Mkdev(hdr.Devmajor, hdr.Devminor))); err != nil { 71 | return err 72 | } 73 | return nil 74 | } 75 | 76 | func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error { 77 | if hdr.Typeflag == tar.TypeLink { 78 | if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) { 79 | if err := os.Chmod(path, hdrInfo.Mode()); err != nil { 80 | return err 81 | } 82 | } 83 | } else if hdr.Typeflag != tar.TypeSymlink { 84 | if err := os.Chmod(path, hdrInfo.Mode()); err != nil { 85 | return err 86 | } 87 | } 88 | return nil 89 | } 90 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/archive_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package archive 4 | 5 | import ( 6 | "archive/tar" 7 | "fmt" 8 | "os" 9 | "strings" 10 | ) 11 | 12 | // canonicalTarNameForPath returns platform-specific filepath 13 | // to canonical posix-style path for tar archival. p is relative 14 | // path. 15 | func CanonicalTarNameForPath(p string) (string, error) { 16 | // windows: convert windows style relative path with backslashes 17 | // into forward slashes. Since windows does not allow '/' or '\' 18 | // in file names, it is mostly safe to replace however we must 19 | // check just in case 20 | if strings.Contains(p, "/") { 21 | return "", fmt.Errorf("Windows path contains forward slash: %s", p) 22 | } 23 | return strings.Replace(p, string(os.PathSeparator), "/", -1), nil 24 | 25 | } 26 | 27 | // chmodTarEntry is used to adjust the file permissions used in tar header based 28 | // on the platform the archival is done. 29 | func chmodTarEntry(perm os.FileMode) os.FileMode { 30 | perm &= 0755 31 | // Add the x bit: make everything +x from windows 32 | perm |= 0111 33 | 34 | return perm 35 | } 36 | 37 | func setHeaderForSpecialDevice(hdr *tar.Header, ta *tarAppender, name string, stat interface{}) (nlink uint32, inode uint64, err error) { 38 | // do nothing. no notion of Rdev, Inode, Nlink in stat on Windows 39 | return 40 | } 41 | 42 | // handleTarTypeBlockCharFifo is an OS-specific helper function used by 43 | // createTarFile to handle the following types of header: Block; Char; Fifo 44 | func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error { 45 | return nil 46 | } 47 | 48 | func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error { 49 | return nil 50 | } 51 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/changes_other.go: -------------------------------------------------------------------------------- 1 | // +build !linux 2 | 3 | package archive 4 | 5 | import ( 6 | "fmt" 7 | "os" 8 | "path/filepath" 9 | "runtime" 10 | "strings" 11 | 12 | "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system" 13 | ) 14 | 15 | func collectFileInfoForChanges(oldDir, newDir string) (*FileInfo, *FileInfo, error) { 16 | var ( 17 | oldRoot, newRoot *FileInfo 18 | err1, err2 error 19 | errs = make(chan error, 2) 20 | ) 21 | go func() { 22 | oldRoot, err1 = collectFileInfo(oldDir) 23 | errs <- err1 24 | }() 25 | go func() { 26 | newRoot, err2 = collectFileInfo(newDir) 27 | errs <- err2 28 | }() 29 | 30 | // block until both routines have returned 31 | for i := 0; i < 2; i++ { 32 | if err := <-errs; err != nil { 33 | return nil, nil, err 34 | } 35 | } 36 | 37 | return oldRoot, newRoot, nil 38 | } 39 | 40 | func collectFileInfo(sourceDir string) (*FileInfo, error) { 41 | root := newRootFileInfo() 42 | 43 | err := filepath.Walk(sourceDir, func(path string, f os.FileInfo, err error) error { 44 | if err != nil { 45 | return err 46 | } 47 | 48 | // Rebase path 49 | relPath, err := filepath.Rel(sourceDir, path) 50 | if err != nil { 51 | return err 52 | } 53 | 54 | // As this runs on the daemon side, file paths are OS specific. 55 | relPath = filepath.Join(string(os.PathSeparator), relPath) 56 | 57 | // See https://github.com/golang/go/issues/9168 - bug in filepath.Join. 58 | // Temporary workaround. If the returned path starts with two backslashes, 59 | // trim it down to a single backslash. Only relevant on Windows. 60 | if runtime.GOOS == "windows" { 61 | if strings.HasPrefix(relPath, `\\`) { 62 | relPath = relPath[1:] 63 | } 64 | } 65 | 66 | if relPath == string(os.PathSeparator) { 67 | return nil 68 | } 69 | 70 | parent := root.LookUp(filepath.Dir(relPath)) 71 | if parent == nil { 72 | return fmt.Errorf("collectFileInfo: Unexpectedly no parent for %s", relPath) 73 | } 74 | 75 | info := &FileInfo{ 76 | name: filepath.Base(relPath), 77 | children: make(map[string]*FileInfo), 78 | parent: parent, 79 | } 80 | 81 | s, err := system.Lstat(path) 82 | if err != nil { 83 | return err 84 | } 85 | info.stat = s 86 | 87 | info.capability, _ = system.Lgetxattr(path, "security.capability") 88 | 89 | parent.children[info.name] = info 90 | 91 | return nil 92 | }) 93 | if err != nil { 94 | return nil, err 95 | } 96 | return root, nil 97 | } 98 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/changes_unix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package archive 4 | 5 | import ( 6 | "syscall" 7 | 8 | "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system" 9 | ) 10 | 11 | func statDifferent(oldStat *system.Stat_t, newStat *system.Stat_t) bool { 12 | // Don't look at size for dirs, its not a good measure of change 13 | if oldStat.Mode() != newStat.Mode() || 14 | oldStat.Uid() != newStat.Uid() || 15 | oldStat.Gid() != newStat.Gid() || 16 | oldStat.Rdev() != newStat.Rdev() || 17 | // Don't look at size for dirs, its not a good measure of change 18 | (oldStat.Mode()&syscall.S_IFDIR != syscall.S_IFDIR && 19 | (!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) || (oldStat.Size() != newStat.Size()))) { 20 | return true 21 | } 22 | return false 23 | } 24 | 25 | func (info *FileInfo) isDir() bool { 26 | return info.parent == nil || info.stat.Mode()&syscall.S_IFDIR != 0 27 | } 28 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/changes_windows.go: -------------------------------------------------------------------------------- 1 | package archive 2 | 3 | import ( 4 | "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system" 5 | ) 6 | 7 | func statDifferent(oldStat *system.Stat_t, newStat *system.Stat_t) bool { 8 | 9 | // Don't look at size for dirs, its not a good measure of change 10 | if oldStat.ModTime() != newStat.ModTime() || 11 | oldStat.Mode() != newStat.Mode() || 12 | oldStat.Size() != newStat.Size() && !oldStat.IsDir() { 13 | return true 14 | } 15 | return false 16 | } 17 | 18 | func (info *FileInfo) isDir() bool { 19 | return info.parent == nil || info.stat.IsDir() 20 | } 21 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/copy_unix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package archive 4 | 5 | import ( 6 | "path/filepath" 7 | ) 8 | 9 | func normalizePath(path string) string { 10 | return filepath.ToSlash(path) 11 | } 12 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/copy_windows.go: -------------------------------------------------------------------------------- 1 | package archive 2 | 3 | import ( 4 | "path/filepath" 5 | ) 6 | 7 | func normalizePath(path string) string { 8 | return filepath.FromSlash(path) 9 | } 10 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/example_changes.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | // Simple tool to create an archive stream from an old and new directory 4 | // 5 | // By default it will stream the comparison of two temporary directories with junk files 6 | package main 7 | 8 | import ( 9 | "flag" 10 | "fmt" 11 | "io" 12 | "io/ioutil" 13 | "os" 14 | "path" 15 | 16 | "github.com/fsouza/go-dockerclient/external/github.com/Sirupsen/logrus" 17 | "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive" 18 | ) 19 | 20 | var ( 21 | flDebug = flag.Bool("D", false, "debugging output") 22 | flNewDir = flag.String("newdir", "", "") 23 | flOldDir = flag.String("olddir", "", "") 24 | log = logrus.New() 25 | ) 26 | 27 | func main() { 28 | flag.Usage = func() { 29 | fmt.Println("Produce a tar from comparing two directory paths. By default a demo tar is created of around 200 files (including hardlinks)") 30 | fmt.Printf("%s [OPTIONS]\n", os.Args[0]) 31 | flag.PrintDefaults() 32 | } 33 | flag.Parse() 34 | log.Out = os.Stderr 35 | if (len(os.Getenv("DEBUG")) > 0) || *flDebug { 36 | logrus.SetLevel(logrus.DebugLevel) 37 | } 38 | var newDir, oldDir string 39 | 40 | if len(*flNewDir) == 0 { 41 | var err error 42 | newDir, err = ioutil.TempDir("", "docker-test-newDir") 43 | if err != nil { 44 | log.Fatal(err) 45 | } 46 | defer os.RemoveAll(newDir) 47 | if _, err := prepareUntarSourceDirectory(100, newDir, true); err != nil { 48 | log.Fatal(err) 49 | } 50 | } else { 51 | newDir = *flNewDir 52 | } 53 | 54 | if len(*flOldDir) == 0 { 55 | oldDir, err := ioutil.TempDir("", "docker-test-oldDir") 56 | if err != nil { 57 | log.Fatal(err) 58 | } 59 | defer os.RemoveAll(oldDir) 60 | } else { 61 | oldDir = *flOldDir 62 | } 63 | 64 | changes, err := archive.ChangesDirs(newDir, oldDir) 65 | if err != nil { 66 | log.Fatal(err) 67 | } 68 | 69 | a, err := archive.ExportChanges(newDir, changes) 70 | if err != nil { 71 | log.Fatal(err) 72 | } 73 | defer a.Close() 74 | 75 | i, err := io.Copy(os.Stdout, a) 76 | if err != nil && err != io.EOF { 77 | log.Fatal(err) 78 | } 79 | fmt.Fprintf(os.Stderr, "wrote archive of %d bytes", i) 80 | } 81 | 82 | func prepareUntarSourceDirectory(numberOfFiles int, targetPath string, makeLinks bool) (int, error) { 83 | fileData := []byte("fooo") 84 | for n := 0; n < numberOfFiles; n++ { 85 | fileName := fmt.Sprintf("file-%d", n) 86 | if err := ioutil.WriteFile(path.Join(targetPath, fileName), fileData, 0700); err != nil { 87 | return 0, err 88 | } 89 | if makeLinks { 90 | if err := os.Link(path.Join(targetPath, fileName), path.Join(targetPath, fileName+"-link")); err != nil { 91 | return 0, err 92 | } 93 | } 94 | } 95 | totalSize := numberOfFiles * len(fileData) 96 | return totalSize, nil 97 | } 98 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/time_linux.go: -------------------------------------------------------------------------------- 1 | package archive 2 | 3 | import ( 4 | "syscall" 5 | "time" 6 | ) 7 | 8 | func timeToTimespec(time time.Time) (ts syscall.Timespec) { 9 | if time.IsZero() { 10 | // Return UTIME_OMIT special value 11 | ts.Sec = 0 12 | ts.Nsec = ((1 << 30) - 2) 13 | return 14 | } 15 | return syscall.NsecToTimespec(time.UnixNano()) 16 | } 17 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/time_unsupported.go: -------------------------------------------------------------------------------- 1 | // +build !linux 2 | 3 | package archive 4 | 5 | import ( 6 | "syscall" 7 | "time" 8 | ) 9 | 10 | func timeToTimespec(time time.Time) (ts syscall.Timespec) { 11 | nsec := int64(0) 12 | if !time.IsZero() { 13 | nsec = time.UnixNano() 14 | } 15 | return syscall.NsecToTimespec(nsec) 16 | } 17 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive/wrap.go: -------------------------------------------------------------------------------- 1 | package archive 2 | 3 | import ( 4 | "archive/tar" 5 | "bytes" 6 | "io/ioutil" 7 | ) 8 | 9 | // Generate generates a new archive from the content provided 10 | // as input. 11 | // 12 | // `files` is a sequence of path/content pairs. A new file is 13 | // added to the archive for each pair. 14 | // If the last pair is incomplete, the file is created with an 15 | // empty content. For example: 16 | // 17 | // Generate("foo.txt", "hello world", "emptyfile") 18 | // 19 | // The above call will return an archive with 2 files: 20 | // * ./foo.txt with content "hello world" 21 | // * ./empty with empty content 22 | // 23 | // FIXME: stream content instead of buffering 24 | // FIXME: specify permissions and other archive metadata 25 | func Generate(input ...string) (Archive, error) { 26 | files := parseStringPairs(input...) 27 | buf := new(bytes.Buffer) 28 | tw := tar.NewWriter(buf) 29 | for _, file := range files { 30 | name, content := file[0], file[1] 31 | hdr := &tar.Header{ 32 | Name: name, 33 | Size: int64(len(content)), 34 | } 35 | if err := tw.WriteHeader(hdr); err != nil { 36 | return nil, err 37 | } 38 | if _, err := tw.Write([]byte(content)); err != nil { 39 | return nil, err 40 | } 41 | } 42 | if err := tw.Close(); err != nil { 43 | return nil, err 44 | } 45 | return ioutil.NopCloser(buf), nil 46 | } 47 | 48 | func parseStringPairs(input ...string) (output [][2]string) { 49 | output = make([][2]string, 0, len(input)/2+1) 50 | for i := 0; i < len(input); i += 2 { 51 | var pair [2]string 52 | pair[0] = input[i] 53 | if i+1 < len(input) { 54 | pair[1] = input[i+1] 55 | } 56 | output = append(output, pair) 57 | } 58 | return 59 | } 60 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/homedir/homedir.go: -------------------------------------------------------------------------------- 1 | package homedir 2 | 3 | import ( 4 | "os" 5 | "runtime" 6 | 7 | "github.com/fsouza/go-dockerclient/external/github.com/opencontainers/runc/libcontainer/user" 8 | ) 9 | 10 | // Key returns the env var name for the user's home dir based on 11 | // the platform being run on 12 | func Key() string { 13 | if runtime.GOOS == "windows" { 14 | return "USERPROFILE" 15 | } 16 | return "HOME" 17 | } 18 | 19 | // Get returns the home directory of the current user with the help of 20 | // environment variables depending on the target operating system. 21 | // Returned path should be used with "path/filepath" to form new paths. 22 | func Get() string { 23 | home := os.Getenv(Key()) 24 | if home == "" && runtime.GOOS != "windows" { 25 | if u, err := user.CurrentUser(); err == nil { 26 | return u.Home 27 | } 28 | } 29 | return home 30 | } 31 | 32 | // GetShortcutString returns the string that is shortcut to user's home directory 33 | // in the native shell of the platform running on. 34 | func GetShortcutString() string { 35 | if runtime.GOOS == "windows" { 36 | return "%USERPROFILE%" // be careful while using in format functions 37 | } 38 | return "~" 39 | } 40 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/ioutils/fmt.go: -------------------------------------------------------------------------------- 1 | package ioutils 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | ) 7 | 8 | // FprintfIfNotEmpty prints the string value if it's not empty 9 | func FprintfIfNotEmpty(w io.Writer, format, value string) (int, error) { 10 | if value != "" { 11 | return fmt.Fprintf(w, format, value) 12 | } 13 | return 0, nil 14 | } 15 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/ioutils/scheduler.go: -------------------------------------------------------------------------------- 1 | // +build !gccgo 2 | 3 | package ioutils 4 | 5 | func callSchedulerIfNecessary() { 6 | } 7 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/ioutils/scheduler_gccgo.go: -------------------------------------------------------------------------------- 1 | // +build gccgo 2 | 3 | package ioutils 4 | 5 | import ( 6 | "runtime" 7 | ) 8 | 9 | func callSchedulerIfNecessary() { 10 | //allow or force Go scheduler to switch context, without explicitly 11 | //forcing this will make it hang when using gccgo implementation 12 | runtime.Gosched() 13 | } 14 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/ioutils/writeflusher.go: -------------------------------------------------------------------------------- 1 | package ioutils 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | "sync" 7 | ) 8 | 9 | type WriteFlusher struct { 10 | sync.Mutex 11 | w io.Writer 12 | flusher http.Flusher 13 | flushed bool 14 | } 15 | 16 | func (wf *WriteFlusher) Write(b []byte) (n int, err error) { 17 | wf.Lock() 18 | defer wf.Unlock() 19 | n, err = wf.w.Write(b) 20 | wf.flushed = true 21 | wf.flusher.Flush() 22 | return n, err 23 | } 24 | 25 | // Flush the stream immediately. 26 | func (wf *WriteFlusher) Flush() { 27 | wf.Lock() 28 | defer wf.Unlock() 29 | wf.flushed = true 30 | wf.flusher.Flush() 31 | } 32 | 33 | func (wf *WriteFlusher) Flushed() bool { 34 | wf.Lock() 35 | defer wf.Unlock() 36 | return wf.flushed 37 | } 38 | 39 | func NewWriteFlusher(w io.Writer) *WriteFlusher { 40 | var flusher http.Flusher 41 | if f, ok := w.(http.Flusher); ok { 42 | flusher = f 43 | } else { 44 | flusher = &NopFlusher{} 45 | } 46 | return &WriteFlusher{w: w, flusher: flusher} 47 | } 48 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/ioutils/writers.go: -------------------------------------------------------------------------------- 1 | package ioutils 2 | 3 | import "io" 4 | 5 | type NopWriter struct{} 6 | 7 | func (*NopWriter) Write(buf []byte) (int, error) { 8 | return len(buf), nil 9 | } 10 | 11 | type nopWriteCloser struct { 12 | io.Writer 13 | } 14 | 15 | func (w *nopWriteCloser) Close() error { return nil } 16 | 17 | func NopWriteCloser(w io.Writer) io.WriteCloser { 18 | return &nopWriteCloser{w} 19 | } 20 | 21 | type NopFlusher struct{} 22 | 23 | func (f *NopFlusher) Flush() {} 24 | 25 | type writeCloserWrapper struct { 26 | io.Writer 27 | closer func() error 28 | } 29 | 30 | func (r *writeCloserWrapper) Close() error { 31 | return r.closer() 32 | } 33 | 34 | func NewWriteCloserWrapper(r io.Writer, closer func() error) io.WriteCloser { 35 | return &writeCloserWrapper{ 36 | Writer: r, 37 | closer: closer, 38 | } 39 | } 40 | 41 | // Wrap a concrete io.Writer and hold a count of the number 42 | // of bytes written to the writer during a "session". 43 | // This can be convenient when write return is masked 44 | // (e.g., json.Encoder.Encode()) 45 | type WriteCounter struct { 46 | Count int64 47 | Writer io.Writer 48 | } 49 | 50 | func NewWriteCounter(w io.Writer) *WriteCounter { 51 | return &WriteCounter{ 52 | Writer: w, 53 | } 54 | } 55 | 56 | func (wc *WriteCounter) Write(p []byte) (count int, err error) { 57 | count, err = wc.Writer.Write(p) 58 | wc.Count += int64(count) 59 | return 60 | } 61 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/promise/promise.go: -------------------------------------------------------------------------------- 1 | package promise 2 | 3 | // Go is a basic promise implementation: it wraps calls a function in a goroutine, 4 | // and returns a channel which will later return the function's return value. 5 | func Go(f func() error) chan error { 6 | ch := make(chan error, 1) 7 | go func() { 8 | ch <- f() 9 | }() 10 | return ch 11 | } 12 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/errors.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | var ( 8 | ErrNotSupportedPlatform = errors.New("platform and architecture is not supported") 9 | ) 10 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/events_windows.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | // This file implements syscalls for Win32 events which are not implemented 4 | // in golang. 5 | 6 | import ( 7 | "syscall" 8 | "unsafe" 9 | ) 10 | 11 | const ( 12 | EVENT_ALL_ACCESS = 0x1F0003 13 | EVENT_MODIFY_STATUS = 0x0002 14 | ) 15 | 16 | var ( 17 | procCreateEvent = modkernel32.NewProc("CreateEventW") 18 | procOpenEvent = modkernel32.NewProc("OpenEventW") 19 | procSetEvent = modkernel32.NewProc("SetEvent") 20 | procResetEvent = modkernel32.NewProc("ResetEvent") 21 | procPulseEvent = modkernel32.NewProc("PulseEvent") 22 | ) 23 | 24 | func CreateEvent(eventAttributes *syscall.SecurityAttributes, manualReset bool, initialState bool, name string) (handle syscall.Handle, err error) { 25 | namep, _ := syscall.UTF16PtrFromString(name) 26 | var _p1 uint32 = 0 27 | if manualReset { 28 | _p1 = 1 29 | } 30 | var _p2 uint32 = 0 31 | if initialState { 32 | _p2 = 1 33 | } 34 | r0, _, e1 := procCreateEvent.Call(uintptr(unsafe.Pointer(eventAttributes)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(namep))) 35 | use(unsafe.Pointer(namep)) 36 | handle = syscall.Handle(r0) 37 | if handle == syscall.InvalidHandle { 38 | err = e1 39 | } 40 | return 41 | } 42 | 43 | func OpenEvent(desiredAccess uint32, inheritHandle bool, name string) (handle syscall.Handle, err error) { 44 | namep, _ := syscall.UTF16PtrFromString(name) 45 | var _p1 uint32 = 0 46 | if inheritHandle { 47 | _p1 = 1 48 | } 49 | r0, _, e1 := procOpenEvent.Call(uintptr(desiredAccess), uintptr(_p1), uintptr(unsafe.Pointer(namep))) 50 | use(unsafe.Pointer(namep)) 51 | handle = syscall.Handle(r0) 52 | if handle == syscall.InvalidHandle { 53 | err = e1 54 | } 55 | return 56 | } 57 | 58 | func SetEvent(handle syscall.Handle) (err error) { 59 | return setResetPulse(handle, procSetEvent) 60 | } 61 | 62 | func ResetEvent(handle syscall.Handle) (err error) { 63 | return setResetPulse(handle, procResetEvent) 64 | } 65 | 66 | func PulseEvent(handle syscall.Handle) (err error) { 67 | return setResetPulse(handle, procPulseEvent) 68 | } 69 | 70 | func setResetPulse(handle syscall.Handle, proc *syscall.LazyProc) (err error) { 71 | r0, _, _ := proc.Call(uintptr(handle)) 72 | if r0 != 0 { 73 | err = syscall.Errno(r0) 74 | } 75 | return 76 | } 77 | 78 | var temp unsafe.Pointer 79 | 80 | // use ensures a variable is kept alive without the GC freeing while still needed 81 | func use(p unsafe.Pointer) { 82 | temp = p 83 | } 84 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/filesys.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package system 4 | 5 | import ( 6 | "os" 7 | ) 8 | 9 | func MkdirAll(path string, perm os.FileMode) error { 10 | return os.MkdirAll(path, perm) 11 | } 12 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/filesys_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package system 4 | 5 | import ( 6 | "os" 7 | "regexp" 8 | "syscall" 9 | ) 10 | 11 | // MkdirAll implementation that is volume path aware for Windows. 12 | func MkdirAll(path string, perm os.FileMode) error { 13 | if re := regexp.MustCompile(`^\\\\\?\\Volume{[a-z0-9-]+}$`); re.MatchString(path) { 14 | return nil 15 | } 16 | 17 | // The rest of this method is copied from os.MkdirAll and should be kept 18 | // as-is to ensure compatibility. 19 | 20 | // Fast path: if we can tell whether path is a directory or file, stop with success or error. 21 | dir, err := os.Stat(path) 22 | if err == nil { 23 | if dir.IsDir() { 24 | return nil 25 | } 26 | return &os.PathError{ 27 | Op: "mkdir", 28 | Path: path, 29 | Err: syscall.ENOTDIR, 30 | } 31 | } 32 | 33 | // Slow path: make sure parent exists and then call Mkdir for path. 34 | i := len(path) 35 | for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator. 36 | i-- 37 | } 38 | 39 | j := i 40 | for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element. 41 | j-- 42 | } 43 | 44 | if j > 1 { 45 | // Create parent 46 | err = MkdirAll(path[0:j-1], perm) 47 | if err != nil { 48 | return err 49 | } 50 | } 51 | 52 | // Parent now exists; invoke Mkdir and use its result. 53 | err = os.Mkdir(path, perm) 54 | if err != nil { 55 | // Handle arguments like "foo/." by 56 | // double-checking that directory doesn't exist. 57 | dir, err1 := os.Lstat(path) 58 | if err1 == nil && dir.IsDir() { 59 | return nil 60 | } 61 | return err 62 | } 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/lstat.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package system 4 | 5 | import ( 6 | "syscall" 7 | ) 8 | 9 | // Lstat takes a path to a file and returns 10 | // a system.Stat_t type pertaining to that file. 11 | // 12 | // Throws an error if the file does not exist 13 | func Lstat(path string) (*Stat_t, error) { 14 | s := &syscall.Stat_t{} 15 | if err := syscall.Lstat(path, s); err != nil { 16 | return nil, err 17 | } 18 | return fromStatT(s) 19 | } 20 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/lstat_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package system 4 | 5 | import ( 6 | "os" 7 | ) 8 | 9 | // Some explanation for my own sanity, and hopefully maintainers in the 10 | // future. 11 | // 12 | // Lstat calls os.Lstat to get a fileinfo interface back. 13 | // This is then copied into our own locally defined structure. 14 | // Note the Linux version uses fromStatT to do the copy back, 15 | // but that not strictly necessary when already in an OS specific module. 16 | 17 | func Lstat(path string) (*Stat_t, error) { 18 | fi, err := os.Lstat(path) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | return &Stat_t{ 24 | name: fi.Name(), 25 | size: fi.Size(), 26 | mode: fi.Mode(), 27 | modTime: fi.ModTime(), 28 | isDir: fi.IsDir()}, nil 29 | } 30 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/meminfo.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | // MemInfo contains memory statistics of the host system. 4 | type MemInfo struct { 5 | // Total usable RAM (i.e. physical RAM minus a few reserved bits and the 6 | // kernel binary code). 7 | MemTotal int64 8 | 9 | // Amount of free memory. 10 | MemFree int64 11 | 12 | // Total amount of swap space available. 13 | SwapTotal int64 14 | 15 | // Amount of swap space that is currently unused. 16 | SwapFree int64 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/meminfo_linux.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "io" 7 | "os" 8 | "strconv" 9 | "strings" 10 | 11 | "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/units" 12 | ) 13 | 14 | var ( 15 | ErrMalformed = errors.New("malformed file") 16 | ) 17 | 18 | // ReadMemInfo retrieves memory statistics of the host system and returns a 19 | // MemInfo type. 20 | func ReadMemInfo() (*MemInfo, error) { 21 | file, err := os.Open("/proc/meminfo") 22 | if err != nil { 23 | return nil, err 24 | } 25 | defer file.Close() 26 | return parseMemInfo(file) 27 | } 28 | 29 | // parseMemInfo parses the /proc/meminfo file into 30 | // a MemInfo object given a io.Reader to the file. 31 | // 32 | // Throws error if there are problems reading from the file 33 | func parseMemInfo(reader io.Reader) (*MemInfo, error) { 34 | meminfo := &MemInfo{} 35 | scanner := bufio.NewScanner(reader) 36 | for scanner.Scan() { 37 | // Expected format: ["MemTotal:", "1234", "kB"] 38 | parts := strings.Fields(scanner.Text()) 39 | 40 | // Sanity checks: Skip malformed entries. 41 | if len(parts) < 3 || parts[2] != "kB" { 42 | continue 43 | } 44 | 45 | // Convert to bytes. 46 | size, err := strconv.Atoi(parts[1]) 47 | if err != nil { 48 | continue 49 | } 50 | bytes := int64(size) * units.KiB 51 | 52 | switch parts[0] { 53 | case "MemTotal:": 54 | meminfo.MemTotal = bytes 55 | case "MemFree:": 56 | meminfo.MemFree = bytes 57 | case "SwapTotal:": 58 | meminfo.SwapTotal = bytes 59 | case "SwapFree:": 60 | meminfo.SwapFree = bytes 61 | } 62 | 63 | } 64 | 65 | // Handle errors that may have occurred during the reading of the file. 66 | if err := scanner.Err(); err != nil { 67 | return nil, err 68 | } 69 | 70 | return meminfo, nil 71 | } 72 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/meminfo_unsupported.go: -------------------------------------------------------------------------------- 1 | // +build !linux,!windows 2 | 3 | package system 4 | 5 | func ReadMemInfo() (*MemInfo, error) { 6 | return nil, ErrNotSupportedPlatform 7 | } 8 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/meminfo_windows.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "syscall" 5 | "unsafe" 6 | ) 7 | 8 | var ( 9 | modkernel32 = syscall.NewLazyDLL("kernel32.dll") 10 | 11 | procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx") 12 | ) 13 | 14 | // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366589(v=vs.85).aspx 15 | // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366770(v=vs.85).aspx 16 | type memorystatusex struct { 17 | dwLength uint32 18 | dwMemoryLoad uint32 19 | ullTotalPhys uint64 20 | ullAvailPhys uint64 21 | ullTotalPageFile uint64 22 | ullAvailPageFile uint64 23 | ullTotalVirtual uint64 24 | ullAvailVirtual uint64 25 | ullAvailExtendedVirtual uint64 26 | } 27 | 28 | // ReadMemInfo retrieves memory statistics of the host system and returns a 29 | // MemInfo type. 30 | func ReadMemInfo() (*MemInfo, error) { 31 | msi := &memorystatusex{ 32 | dwLength: 64, 33 | } 34 | r1, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(msi))) 35 | if r1 == 0 { 36 | return &MemInfo{}, nil 37 | } 38 | return &MemInfo{ 39 | MemTotal: int64(msi.ullTotalPhys), 40 | MemFree: int64(msi.ullAvailPhys), 41 | SwapTotal: int64(msi.ullTotalPageFile), 42 | SwapFree: int64(msi.ullAvailPageFile), 43 | }, nil 44 | } 45 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/mknod.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package system 4 | 5 | import ( 6 | "syscall" 7 | ) 8 | 9 | // Mknod creates a filesystem node (file, device special file or named pipe) named path 10 | // with attributes specified by mode and dev 11 | func Mknod(path string, mode uint32, dev int) error { 12 | return syscall.Mknod(path, mode, dev) 13 | } 14 | 15 | // Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes. 16 | // They are, from low to high: the lower 8 bits of the minor, then 12 bits of the major, 17 | // then the top 12 bits of the minor 18 | func Mkdev(major int64, minor int64) uint32 { 19 | return uint32(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff)) 20 | } 21 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/mknod_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package system 4 | 5 | func Mknod(path string, mode uint32, dev int) error { 6 | return ErrNotSupportedPlatform 7 | } 8 | 9 | func Mkdev(major int64, minor int64) uint32 { 10 | panic("Mkdev not implemented on Windows.") 11 | } 12 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/stat.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package system 4 | 5 | import ( 6 | "syscall" 7 | ) 8 | 9 | // Stat_t type contains status of a file. It contains metadata 10 | // like permission, owner, group, size, etc about a file 11 | type Stat_t struct { 12 | mode uint32 13 | uid uint32 14 | gid uint32 15 | rdev uint64 16 | size int64 17 | mtim syscall.Timespec 18 | } 19 | 20 | func (s Stat_t) Mode() uint32 { 21 | return s.mode 22 | } 23 | 24 | func (s Stat_t) Uid() uint32 { 25 | return s.uid 26 | } 27 | 28 | func (s Stat_t) Gid() uint32 { 29 | return s.gid 30 | } 31 | 32 | func (s Stat_t) Rdev() uint64 { 33 | return s.rdev 34 | } 35 | 36 | func (s Stat_t) Size() int64 { 37 | return s.size 38 | } 39 | 40 | func (s Stat_t) Mtim() syscall.Timespec { 41 | return s.mtim 42 | } 43 | 44 | func (s Stat_t) GetLastModification() syscall.Timespec { 45 | return s.Mtim() 46 | } 47 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/stat_freebsd.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "syscall" 5 | ) 6 | 7 | // fromStatT converts a syscall.Stat_t type to a system.Stat_t type 8 | func fromStatT(s *syscall.Stat_t) (*Stat_t, error) { 9 | return &Stat_t{size: s.Size, 10 | mode: uint32(s.Mode), 11 | uid: s.Uid, 12 | gid: s.Gid, 13 | rdev: uint64(s.Rdev), 14 | mtim: s.Mtimespec}, nil 15 | } 16 | 17 | // Stat takes a path to a file and returns 18 | // a system.Stat_t type pertaining to that file. 19 | // 20 | // Throws an error if the file does not exist 21 | func Stat(path string) (*Stat_t, error) { 22 | s := &syscall.Stat_t{} 23 | if err := syscall.Stat(path, s); err != nil { 24 | return nil, err 25 | } 26 | return fromStatT(s) 27 | } 28 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/stat_linux.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "syscall" 5 | ) 6 | 7 | // fromStatT converts a syscall.Stat_t type to a system.Stat_t type 8 | func fromStatT(s *syscall.Stat_t) (*Stat_t, error) { 9 | return &Stat_t{size: s.Size, 10 | mode: s.Mode, 11 | uid: s.Uid, 12 | gid: s.Gid, 13 | rdev: s.Rdev, 14 | mtim: s.Mtim}, nil 15 | } 16 | 17 | // FromStatT exists only on linux, and loads a system.Stat_t from a 18 | // syscal.Stat_t. 19 | func FromStatT(s *syscall.Stat_t) (*Stat_t, error) { 20 | return fromStatT(s) 21 | } 22 | 23 | // Stat takes a path to a file and returns 24 | // a system.Stat_t type pertaining to that file. 25 | // 26 | // Throws an error if the file does not exist 27 | func Stat(path string) (*Stat_t, error) { 28 | s := &syscall.Stat_t{} 29 | if err := syscall.Stat(path, s); err != nil { 30 | return nil, err 31 | } 32 | return fromStatT(s) 33 | } 34 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/stat_unsupported.go: -------------------------------------------------------------------------------- 1 | // +build !linux,!windows,!freebsd 2 | 3 | package system 4 | 5 | import ( 6 | "syscall" 7 | ) 8 | 9 | // fromStatT creates a system.Stat_t type from a syscall.Stat_t type 10 | func fromStatT(s *syscall.Stat_t) (*Stat_t, error) { 11 | return &Stat_t{size: s.Size, 12 | mode: uint32(s.Mode), 13 | uid: s.Uid, 14 | gid: s.Gid, 15 | rdev: uint64(s.Rdev), 16 | mtim: s.Mtimespec}, nil 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/stat_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package system 4 | 5 | import ( 6 | "os" 7 | "time" 8 | ) 9 | 10 | type Stat_t struct { 11 | name string 12 | size int64 13 | mode os.FileMode 14 | modTime time.Time 15 | isDir bool 16 | } 17 | 18 | func (s Stat_t) Name() string { 19 | return s.name 20 | } 21 | 22 | func (s Stat_t) Size() int64 { 23 | return s.size 24 | } 25 | 26 | func (s Stat_t) Mode() os.FileMode { 27 | return s.mode 28 | } 29 | 30 | func (s Stat_t) ModTime() time.Time { 31 | return s.modTime 32 | } 33 | 34 | func (s Stat_t) IsDir() bool { 35 | return s.isDir 36 | } 37 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/umask.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package system 4 | 5 | import ( 6 | "syscall" 7 | ) 8 | 9 | func Umask(newmask int) (oldmask int, err error) { 10 | return syscall.Umask(newmask), nil 11 | } 12 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/umask_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package system 4 | 5 | func Umask(newmask int) (oldmask int, err error) { 6 | // should not be called on cli code path 7 | return 0, ErrNotSupportedPlatform 8 | } 9 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/utimes_darwin.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import "syscall" 4 | 5 | func LUtimesNano(path string, ts []syscall.Timespec) error { 6 | return ErrNotSupportedPlatform 7 | } 8 | 9 | func UtimesNano(path string, ts []syscall.Timespec) error { 10 | return syscall.UtimesNano(path, ts) 11 | } 12 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/utimes_freebsd.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "syscall" 5 | "unsafe" 6 | ) 7 | 8 | func LUtimesNano(path string, ts []syscall.Timespec) error { 9 | var _path *byte 10 | _path, err := syscall.BytePtrFromString(path) 11 | if err != nil { 12 | return err 13 | } 14 | 15 | if _, _, err := syscall.Syscall(syscall.SYS_LUTIMES, uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), 0); err != 0 && err != syscall.ENOSYS { 16 | return err 17 | } 18 | 19 | return nil 20 | } 21 | 22 | func UtimesNano(path string, ts []syscall.Timespec) error { 23 | return syscall.UtimesNano(path, ts) 24 | } 25 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/utimes_linux.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "syscall" 5 | "unsafe" 6 | ) 7 | 8 | func LUtimesNano(path string, ts []syscall.Timespec) error { 9 | // These are not currently available in syscall 10 | AT_FDCWD := -100 11 | AT_SYMLINK_NOFOLLOW := 0x100 12 | 13 | var _path *byte 14 | _path, err := syscall.BytePtrFromString(path) 15 | if err != nil { 16 | return err 17 | } 18 | 19 | if _, _, err := syscall.Syscall6(syscall.SYS_UTIMENSAT, uintptr(AT_FDCWD), uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), uintptr(AT_SYMLINK_NOFOLLOW), 0, 0); err != 0 && err != syscall.ENOSYS { 20 | return err 21 | } 22 | 23 | return nil 24 | } 25 | 26 | func UtimesNano(path string, ts []syscall.Timespec) error { 27 | return syscall.UtimesNano(path, ts) 28 | } 29 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/utimes_unsupported.go: -------------------------------------------------------------------------------- 1 | // +build !linux,!freebsd,!darwin 2 | 3 | package system 4 | 5 | import "syscall" 6 | 7 | func LUtimesNano(path string, ts []syscall.Timespec) error { 8 | return ErrNotSupportedPlatform 9 | } 10 | 11 | func UtimesNano(path string, ts []syscall.Timespec) error { 12 | return ErrNotSupportedPlatform 13 | } 14 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/xattrs_linux.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "syscall" 5 | "unsafe" 6 | ) 7 | 8 | // Returns a nil slice and nil error if the xattr is not set 9 | func Lgetxattr(path string, attr string) ([]byte, error) { 10 | pathBytes, err := syscall.BytePtrFromString(path) 11 | if err != nil { 12 | return nil, err 13 | } 14 | attrBytes, err := syscall.BytePtrFromString(attr) 15 | if err != nil { 16 | return nil, err 17 | } 18 | 19 | dest := make([]byte, 128) 20 | destBytes := unsafe.Pointer(&dest[0]) 21 | sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) 22 | if errno == syscall.ENODATA { 23 | return nil, nil 24 | } 25 | if errno == syscall.ERANGE { 26 | dest = make([]byte, sz) 27 | destBytes := unsafe.Pointer(&dest[0]) 28 | sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) 29 | } 30 | if errno != 0 { 31 | return nil, errno 32 | } 33 | 34 | return dest[:sz], nil 35 | } 36 | 37 | var _zero uintptr 38 | 39 | func Lsetxattr(path string, attr string, data []byte, flags int) error { 40 | pathBytes, err := syscall.BytePtrFromString(path) 41 | if err != nil { 42 | return err 43 | } 44 | attrBytes, err := syscall.BytePtrFromString(attr) 45 | if err != nil { 46 | return err 47 | } 48 | var dataBytes unsafe.Pointer 49 | if len(data) > 0 { 50 | dataBytes = unsafe.Pointer(&data[0]) 51 | } else { 52 | dataBytes = unsafe.Pointer(&_zero) 53 | } 54 | _, _, errno := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(dataBytes), uintptr(len(data)), uintptr(flags), 0) 55 | if errno != 0 { 56 | return errno 57 | } 58 | return nil 59 | } 60 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/system/xattrs_unsupported.go: -------------------------------------------------------------------------------- 1 | // +build !linux 2 | 3 | package system 4 | 5 | func Lgetxattr(path string, attr string) ([]byte, error) { 6 | return nil, ErrNotSupportedPlatform 7 | } 8 | 9 | func Lsetxattr(path string, attr string, data []byte, flags int) error { 10 | return ErrNotSupportedPlatform 11 | } 12 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/ulimit/ulimit.go: -------------------------------------------------------------------------------- 1 | // Package ulimit provides structure and helper function to parse and represent 2 | // resource limits (Rlimit and Ulimit, its human friendly version). 3 | package ulimit 4 | 5 | import ( 6 | "fmt" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | // Ulimit is a human friendly version of Rlimit. 12 | type Ulimit struct { 13 | Name string 14 | Hard int64 15 | Soft int64 16 | } 17 | 18 | // Rlimit specifies the resource limits, such as max open files. 19 | type Rlimit struct { 20 | Type int `json:"type,omitempty"` 21 | Hard uint64 `json:"hard,omitempty"` 22 | Soft uint64 `json:"soft,omitempty"` 23 | } 24 | 25 | const ( 26 | // magic numbers for making the syscall 27 | // some of these are defined in the syscall package, but not all. 28 | // Also since Windows client doesn't get access to the syscall package, need to 29 | // define these here 30 | rlimitAs = 9 31 | rlimitCore = 4 32 | rlimitCPU = 0 33 | rlimitData = 2 34 | rlimitFsize = 1 35 | rlimitLocks = 10 36 | rlimitMemlock = 8 37 | rlimitMsgqueue = 12 38 | rlimitNice = 13 39 | rlimitNofile = 7 40 | rlimitNproc = 6 41 | rlimitRss = 5 42 | rlimitRtprio = 14 43 | rlimitRttime = 15 44 | rlimitSigpending = 11 45 | rlimitStack = 3 46 | ) 47 | 48 | var ulimitNameMapping = map[string]int{ 49 | //"as": rlimitAs, // Disabled since this doesn't seem usable with the way Docker inits a container. 50 | "core": rlimitCore, 51 | "cpu": rlimitCPU, 52 | "data": rlimitData, 53 | "fsize": rlimitFsize, 54 | "locks": rlimitLocks, 55 | "memlock": rlimitMemlock, 56 | "msgqueue": rlimitMsgqueue, 57 | "nice": rlimitNice, 58 | "nofile": rlimitNofile, 59 | "nproc": rlimitNproc, 60 | "rss": rlimitRss, 61 | "rtprio": rlimitRtprio, 62 | "rttime": rlimitRttime, 63 | "sigpending": rlimitSigpending, 64 | "stack": rlimitStack, 65 | } 66 | 67 | // Parse parses and returns a Ulimit from the specified string. 68 | func Parse(val string) (*Ulimit, error) { 69 | parts := strings.SplitN(val, "=", 2) 70 | if len(parts) != 2 { 71 | return nil, fmt.Errorf("invalid ulimit argument: %s", val) 72 | } 73 | 74 | if _, exists := ulimitNameMapping[parts[0]]; !exists { 75 | return nil, fmt.Errorf("invalid ulimit type: %s", parts[0]) 76 | } 77 | 78 | limitVals := strings.SplitN(parts[1], ":", 2) 79 | if len(limitVals) > 2 { 80 | return nil, fmt.Errorf("too many limit value arguments - %s, can only have up to two, `soft[:hard]`", parts[1]) 81 | } 82 | 83 | soft, err := strconv.ParseInt(limitVals[0], 10, 64) 84 | if err != nil { 85 | return nil, err 86 | } 87 | 88 | hard := soft // in case no hard was set 89 | if len(limitVals) == 2 { 90 | hard, err = strconv.ParseInt(limitVals[1], 10, 64) 91 | } 92 | if soft > hard { 93 | return nil, fmt.Errorf("ulimit soft limit must be less than or equal to hard limit: %d > %d", soft, hard) 94 | } 95 | 96 | return &Ulimit{Name: parts[0], Soft: soft, Hard: hard}, nil 97 | } 98 | 99 | // GetRlimit returns the RLimit corresponding to Ulimit. 100 | func (u *Ulimit) GetRlimit() (*Rlimit, error) { 101 | t, exists := ulimitNameMapping[u.Name] 102 | if !exists { 103 | return nil, fmt.Errorf("invalid ulimit name %s", u.Name) 104 | } 105 | 106 | return &Rlimit{Type: t, Soft: uint64(u.Soft), Hard: uint64(u.Hard)}, nil 107 | } 108 | 109 | func (u *Ulimit) String() string { 110 | return fmt.Sprintf("%s=%d:%d", u.Name, u.Soft, u.Hard) 111 | } 112 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/units/duration.go: -------------------------------------------------------------------------------- 1 | // Package units provides helper function to parse and print size and time units 2 | // in human-readable format. 3 | package units 4 | 5 | import ( 6 | "fmt" 7 | "time" 8 | ) 9 | 10 | // HumanDuration returns a human-readable approximation of a duration 11 | // (eg. "About a minute", "4 hours ago", etc.). 12 | func HumanDuration(d time.Duration) string { 13 | if seconds := int(d.Seconds()); seconds < 1 { 14 | return "Less than a second" 15 | } else if seconds < 60 { 16 | return fmt.Sprintf("%d seconds", seconds) 17 | } else if minutes := int(d.Minutes()); minutes == 1 { 18 | return "About a minute" 19 | } else if minutes < 60 { 20 | return fmt.Sprintf("%d minutes", minutes) 21 | } else if hours := int(d.Hours()); hours == 1 { 22 | return "About an hour" 23 | } else if hours < 48 { 24 | return fmt.Sprintf("%d hours", hours) 25 | } else if hours < 24*7*2 { 26 | return fmt.Sprintf("%d days", hours/24) 27 | } else if hours < 24*30*3 { 28 | return fmt.Sprintf("%d weeks", hours/24/7) 29 | } else if hours < 24*365*2 { 30 | return fmt.Sprintf("%d months", hours/24/30) 31 | } 32 | return fmt.Sprintf("%d years", int(d.Hours())/24/365) 33 | } 34 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/units/size.go: -------------------------------------------------------------------------------- 1 | package units 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | // See: http://en.wikipedia.org/wiki/Binary_prefix 11 | const ( 12 | // Decimal 13 | 14 | KB = 1000 15 | MB = 1000 * KB 16 | GB = 1000 * MB 17 | TB = 1000 * GB 18 | PB = 1000 * TB 19 | 20 | // Binary 21 | 22 | KiB = 1024 23 | MiB = 1024 * KiB 24 | GiB = 1024 * MiB 25 | TiB = 1024 * GiB 26 | PiB = 1024 * TiB 27 | ) 28 | 29 | type unitMap map[string]int64 30 | 31 | var ( 32 | decimalMap = unitMap{"k": KB, "m": MB, "g": GB, "t": TB, "p": PB} 33 | binaryMap = unitMap{"k": KiB, "m": MiB, "g": GiB, "t": TiB, "p": PiB} 34 | sizeRegex = regexp.MustCompile(`^(\d+)([kKmMgGtTpP])?[bB]?$`) 35 | ) 36 | 37 | var decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"} 38 | var binaryAbbrs = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"} 39 | 40 | // CustomSize returns a human-readable approximation of a size 41 | // using custom format. 42 | func CustomSize(format string, size float64, base float64, _map []string) string { 43 | i := 0 44 | for size >= base { 45 | size = size / base 46 | i++ 47 | } 48 | return fmt.Sprintf(format, size, _map[i]) 49 | } 50 | 51 | // HumanSize returns a human-readable approximation of a size 52 | // using SI standard (eg. "44kB", "17MB"). 53 | func HumanSize(size float64) string { 54 | return CustomSize("%.4g %s", size, 1000.0, decimapAbbrs) 55 | } 56 | 57 | // BytesSize returns a human-readable size in bytes, kibibytes, 58 | // mebibytes, gibibytes, or tebibytes (eg. "44kiB", "17MiB"). 59 | func BytesSize(size float64) string { 60 | return CustomSize("%.4g %s", size, 1024.0, binaryAbbrs) 61 | } 62 | 63 | // FromHumanSize returns an integer from a human-readable specification of a 64 | // size using SI standard (eg. "44kB", "17MB"). 65 | func FromHumanSize(size string) (int64, error) { 66 | return parseSize(size, decimalMap) 67 | } 68 | 69 | // RAMInBytes parses a human-readable string representing an amount of RAM 70 | // in bytes, kibibytes, mebibytes, gibibytes, or tebibytes and 71 | // returns the number of bytes, or -1 if the string is unparseable. 72 | // Units are case-insensitive, and the 'b' suffix is optional. 73 | func RAMInBytes(size string) (int64, error) { 74 | return parseSize(size, binaryMap) 75 | } 76 | 77 | // Parses the human-readable size string into the amount it represents. 78 | func parseSize(sizeStr string, uMap unitMap) (int64, error) { 79 | matches := sizeRegex.FindStringSubmatch(sizeStr) 80 | if len(matches) != 3 { 81 | return -1, fmt.Errorf("invalid size: '%s'", sizeStr) 82 | } 83 | 84 | size, err := strconv.ParseInt(matches[1], 10, 0) 85 | if err != nil { 86 | return -1, err 87 | } 88 | 89 | unitPrefix := strings.ToLower(matches[2]) 90 | if mul, ok := uMap[unitPrefix]; ok { 91 | size *= mul 92 | } 93 | 94 | return size, nil 95 | } 96 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/docker/volume/volume.go: -------------------------------------------------------------------------------- 1 | package volume 2 | 3 | // DefaultDriverName is the driver name used for the driver 4 | // implemented in the local package. 5 | const DefaultDriverName string = "local" 6 | 7 | // Driver is for creating and removing volumes. 8 | type Driver interface { 9 | // Name returns the name of the volume driver. 10 | Name() string 11 | // Create makes a new volume with the given id. 12 | Create(string) (Volume, error) 13 | // Remove deletes the volume. 14 | Remove(Volume) error 15 | } 16 | 17 | // Volume is a place to store data. It is backed by a specific driver, and can be mounted. 18 | type Volume interface { 19 | // Name returns the name of the volume 20 | Name() string 21 | // DriverName returns the name of the driver which owns this volume. 22 | DriverName() string 23 | // Path returns the absolute path to the volume. 24 | Path() string 25 | // Mount mounts the volume and returns the absolute path to 26 | // where it can be consumed. 27 | Mount() (string, error) 28 | // Unmount unmounts the volume when it is no longer in use. 29 | Unmount() error 30 | } 31 | 32 | // read-write modes 33 | var rwModes = map[string]bool{ 34 | "rw": true, 35 | "rw,Z": true, 36 | "rw,z": true, 37 | "z,rw": true, 38 | "Z,rw": true, 39 | "Z": true, 40 | "z": true, 41 | } 42 | 43 | // read-only modes 44 | var roModes = map[string]bool{ 45 | "ro": true, 46 | "ro,Z": true, 47 | "ro,z": true, 48 | "z,ro": true, 49 | "Z,ro": true, 50 | } 51 | 52 | // ValidateMountMode will make sure the mount mode is valid. 53 | // returns if it's a valid mount mode and if it's read-write or not. 54 | func ValidateMountMode(mode string) (bool, bool) { 55 | return roModes[mode] || rwModes[mode], rwModes[mode] 56 | } 57 | 58 | // ReadWrite tells you if a mode string is a valid read-only mode or not. 59 | func ReadWrite(mode string) bool { 60 | return rwModes[mode] 61 | } 62 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/opencontainers/runc/libcontainer/user/MAINTAINERS: -------------------------------------------------------------------------------- 1 | Tianon Gravi (@tianon) 2 | Aleksa Sarai (@cyphar) 3 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/opencontainers/runc/libcontainer/user/lookup.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "syscall" 7 | ) 8 | 9 | var ( 10 | // The current operating system does not provide the required data for user lookups. 11 | ErrUnsupported = errors.New("user lookup: operating system does not provide passwd-formatted data") 12 | ) 13 | 14 | func lookupUser(filter func(u User) bool) (User, error) { 15 | // Get operating system-specific passwd reader-closer. 16 | passwd, err := GetPasswd() 17 | if err != nil { 18 | return User{}, err 19 | } 20 | defer passwd.Close() 21 | 22 | // Get the users. 23 | users, err := ParsePasswdFilter(passwd, filter) 24 | if err != nil { 25 | return User{}, err 26 | } 27 | 28 | // No user entries found. 29 | if len(users) == 0 { 30 | return User{}, fmt.Errorf("no matching entries in passwd file") 31 | } 32 | 33 | // Assume the first entry is the "correct" one. 34 | return users[0], nil 35 | } 36 | 37 | // CurrentUser looks up the current user by their user id in /etc/passwd. If the 38 | // user cannot be found (or there is no /etc/passwd file on the filesystem), 39 | // then CurrentUser returns an error. 40 | func CurrentUser() (User, error) { 41 | return LookupUid(syscall.Getuid()) 42 | } 43 | 44 | // LookupUser looks up a user by their username in /etc/passwd. If the user 45 | // cannot be found (or there is no /etc/passwd file on the filesystem), then 46 | // LookupUser returns an error. 47 | func LookupUser(username string) (User, error) { 48 | return lookupUser(func(u User) bool { 49 | return u.Name == username 50 | }) 51 | } 52 | 53 | // LookupUid looks up a user by their user id in /etc/passwd. If the user cannot 54 | // be found (or there is no /etc/passwd file on the filesystem), then LookupId 55 | // returns an error. 56 | func LookupUid(uid int) (User, error) { 57 | return lookupUser(func(u User) bool { 58 | return u.Uid == uid 59 | }) 60 | } 61 | 62 | func lookupGroup(filter func(g Group) bool) (Group, error) { 63 | // Get operating system-specific group reader-closer. 64 | group, err := GetGroup() 65 | if err != nil { 66 | return Group{}, err 67 | } 68 | defer group.Close() 69 | 70 | // Get the users. 71 | groups, err := ParseGroupFilter(group, filter) 72 | if err != nil { 73 | return Group{}, err 74 | } 75 | 76 | // No user entries found. 77 | if len(groups) == 0 { 78 | return Group{}, fmt.Errorf("no matching entries in group file") 79 | } 80 | 81 | // Assume the first entry is the "correct" one. 82 | return groups[0], nil 83 | } 84 | 85 | // CurrentGroup looks up the current user's group by their primary group id's 86 | // entry in /etc/passwd. If the group cannot be found (or there is no 87 | // /etc/group file on the filesystem), then CurrentGroup returns an error. 88 | func CurrentGroup() (Group, error) { 89 | return LookupGid(syscall.Getgid()) 90 | } 91 | 92 | // LookupGroup looks up a group by its name in /etc/group. If the group cannot 93 | // be found (or there is no /etc/group file on the filesystem), then LookupGroup 94 | // returns an error. 95 | func LookupGroup(groupname string) (Group, error) { 96 | return lookupGroup(func(g Group) bool { 97 | return g.Name == groupname 98 | }) 99 | } 100 | 101 | // LookupGid looks up a group by its group id in /etc/group. If the group cannot 102 | // be found (or there is no /etc/group file on the filesystem), then LookupGid 103 | // returns an error. 104 | func LookupGid(gid int) (Group, error) { 105 | return lookupGroup(func(g Group) bool { 106 | return g.Gid == gid 107 | }) 108 | } 109 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go: -------------------------------------------------------------------------------- 1 | // +build darwin dragonfly freebsd linux netbsd openbsd solaris 2 | 3 | package user 4 | 5 | import ( 6 | "io" 7 | "os" 8 | ) 9 | 10 | // Unix-specific path to the passwd and group formatted files. 11 | const ( 12 | unixPasswdPath = "/etc/passwd" 13 | unixGroupPath = "/etc/group" 14 | ) 15 | 16 | func GetPasswdPath() (string, error) { 17 | return unixPasswdPath, nil 18 | } 19 | 20 | func GetPasswd() (io.ReadCloser, error) { 21 | return os.Open(unixPasswdPath) 22 | } 23 | 24 | func GetGroupPath() (string, error) { 25 | return unixGroupPath, nil 26 | } 27 | 28 | func GetGroup() (io.ReadCloser, error) { 29 | return os.Open(unixGroupPath) 30 | } 31 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/external/github.com/opencontainers/runc/libcontainer/user/lookup_unsupported.go: -------------------------------------------------------------------------------- 1 | // +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris 2 | 3 | package user 4 | 5 | import "io" 6 | 7 | func GetPasswdPath() (string, error) { 8 | return "", ErrUnsupported 9 | } 10 | 11 | func GetPasswd() (io.ReadCloser, error) { 12 | return nil, ErrUnsupported 13 | } 14 | 15 | func GetGroupPath() (string, error) { 16 | return "", ErrUnsupported 17 | } 18 | 19 | func GetGroup() (io.ReadCloser, error) { 20 | return nil, ErrUnsupported 21 | } 22 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/misc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 go-dockerclient authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package docker 6 | 7 | import ( 8 | "bytes" 9 | "strings" 10 | ) 11 | 12 | // Version returns version information about the docker server. 13 | // 14 | // See https://goo.gl/ND9R8L for more details. 15 | func (c *Client) Version() (*Env, error) { 16 | body, _, err := c.do("GET", "/version", doOptions{}) 17 | if err != nil { 18 | return nil, err 19 | } 20 | var env Env 21 | if err := env.Decode(bytes.NewReader(body)); err != nil { 22 | return nil, err 23 | } 24 | return &env, nil 25 | } 26 | 27 | // Info returns system-wide information about the Docker server. 28 | // 29 | // See https://goo.gl/ElTHi2 for more details. 30 | func (c *Client) Info() (*Env, error) { 31 | body, _, err := c.do("GET", "/info", doOptions{}) 32 | if err != nil { 33 | return nil, err 34 | } 35 | var info Env 36 | err = info.Decode(bytes.NewReader(body)) 37 | if err != nil { 38 | return nil, err 39 | } 40 | return &info, nil 41 | } 42 | 43 | // ParseRepositoryTag gets the name of the repository and returns it splitted 44 | // in two parts: the repository and the tag. 45 | // 46 | // Some examples: 47 | // 48 | // localhost.localdomain:5000/samalba/hipache:latest -> localhost.localdomain:5000/samalba/hipache, latest 49 | // localhost.localdomain:5000/samalba/hipache -> localhost.localdomain:5000/samalba/hipache, "" 50 | func ParseRepositoryTag(repoTag string) (repository string, tag string) { 51 | n := strings.LastIndex(repoTag, ":") 52 | if n < 0 { 53 | return repoTag, "" 54 | } 55 | if tag := repoTag[n+1:]; !strings.Contains(tag, "/") { 56 | return repoTag[:n], tag 57 | } 58 | return repoTag, "" 59 | } 60 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/network.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 go-dockerclient authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package docker 6 | 7 | import ( 8 | "encoding/json" 9 | "errors" 10 | "fmt" 11 | "net/http" 12 | ) 13 | 14 | // ErrNetworkAlreadyExists is the error returned by CreateNetwork when the 15 | // network already exists. 16 | var ErrNetworkAlreadyExists = errors.New("network already exists") 17 | 18 | // Network represents a network. 19 | // 20 | // See https://goo.gl/FDkCdQ for more details. 21 | type Network struct { 22 | Name string `json:"name"` 23 | ID string `json:"id"` 24 | Type string `json:"type"` 25 | Endpoints []*Endpoint `json:"endpoints"` 26 | } 27 | 28 | // Endpoint represents an endpoint. 29 | // 30 | // See https://goo.gl/FDkCdQ for more details. 31 | type Endpoint struct { 32 | Name string `json:"name"` 33 | ID string `json:"id"` 34 | Network string `json:"network"` 35 | } 36 | 37 | // ListNetworks returns all networks. 38 | // 39 | // See https://goo.gl/4hCNtZ for more details. 40 | func (c *Client) ListNetworks() ([]Network, error) { 41 | body, _, err := c.do("GET", "/networks", doOptions{}) 42 | if err != nil { 43 | return nil, err 44 | } 45 | var networks []Network 46 | if err := json.Unmarshal(body, &networks); err != nil { 47 | return nil, err 48 | } 49 | return networks, nil 50 | } 51 | 52 | // NetworkInfo returns information about a network by its ID. 53 | // 54 | // See https://goo.gl/4hCNtZ for more details. 55 | func (c *Client) NetworkInfo(id string) (*Network, error) { 56 | path := "/networks/" + id 57 | body, status, err := c.do("GET", path, doOptions{}) 58 | if status == http.StatusNotFound { 59 | return nil, &NoSuchNetwork{ID: id} 60 | } 61 | if err != nil { 62 | return nil, err 63 | } 64 | var network Network 65 | if err := json.Unmarshal(body, &network); err != nil { 66 | return nil, err 67 | } 68 | return &network, nil 69 | } 70 | 71 | // CreateNetworkOptions specify parameters to the CreateNetwork function and 72 | // (for now) is the expected body of the "create network" http request message 73 | // 74 | // See https://goo.gl/FDkCdQ for more details. 75 | type CreateNetworkOptions struct { 76 | Name string `json:"name"` 77 | NetworkType string `json:"network_type"` 78 | Options map[string]interface{} `json:"options"` 79 | } 80 | 81 | // CreateNetwork creates a new network, returning the network instance, 82 | // or an error in case of failure. 83 | // 84 | // See http://goo.gl/mErxNp for more details. 85 | func (c *Client) CreateNetwork(opts CreateNetworkOptions) (*Network, error) { 86 | body, status, err := c.do( 87 | "POST", 88 | "/networks", 89 | doOptions{ 90 | data: opts, 91 | }, 92 | ) 93 | 94 | if status == http.StatusConflict { 95 | return nil, ErrNetworkAlreadyExists 96 | } 97 | if err != nil { 98 | return nil, err 99 | } 100 | 101 | type createNetworkResponse struct { 102 | ID string 103 | } 104 | var ( 105 | network Network 106 | resp createNetworkResponse 107 | ) 108 | err = json.Unmarshal(body, &resp) 109 | if err != nil { 110 | return nil, err 111 | } 112 | 113 | network.Name = opts.Name 114 | network.ID = resp.ID 115 | network.Type = opts.NetworkType 116 | 117 | return &network, nil 118 | } 119 | 120 | // NoSuchNetwork is the error returned when a given network does not exist. 121 | type NoSuchNetwork struct { 122 | ID string 123 | } 124 | 125 | func (err *NoSuchNetwork) Error() string { 126 | return fmt.Sprintf("No such network: %s", err.ID) 127 | } 128 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/signal.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 go-dockerclient authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package docker 6 | 7 | // Signal represents a signal that can be send to the container on 8 | // KillContainer call. 9 | type Signal int 10 | 11 | // These values represent all signals available on Linux, where containers will 12 | // be running. 13 | const ( 14 | SIGABRT = Signal(0x6) 15 | SIGALRM = Signal(0xe) 16 | SIGBUS = Signal(0x7) 17 | SIGCHLD = Signal(0x11) 18 | SIGCLD = Signal(0x11) 19 | SIGCONT = Signal(0x12) 20 | SIGFPE = Signal(0x8) 21 | SIGHUP = Signal(0x1) 22 | SIGILL = Signal(0x4) 23 | SIGINT = Signal(0x2) 24 | SIGIO = Signal(0x1d) 25 | SIGIOT = Signal(0x6) 26 | SIGKILL = Signal(0x9) 27 | SIGPIPE = Signal(0xd) 28 | SIGPOLL = Signal(0x1d) 29 | SIGPROF = Signal(0x1b) 30 | SIGPWR = Signal(0x1e) 31 | SIGQUIT = Signal(0x3) 32 | SIGSEGV = Signal(0xb) 33 | SIGSTKFLT = Signal(0x10) 34 | SIGSTOP = Signal(0x13) 35 | SIGSYS = Signal(0x1f) 36 | SIGTERM = Signal(0xf) 37 | SIGTRAP = Signal(0x5) 38 | SIGTSTP = Signal(0x14) 39 | SIGTTIN = Signal(0x15) 40 | SIGTTOU = Signal(0x16) 41 | SIGUNUSED = Signal(0x1f) 42 | SIGURG = Signal(0x17) 43 | SIGUSR1 = Signal(0xa) 44 | SIGUSR2 = Signal(0xc) 45 | SIGVTALRM = Signal(0x1a) 46 | SIGWINCH = Signal(0x1c) 47 | SIGXCPU = Signal(0x18) 48 | SIGXFSZ = Signal(0x19) 49 | ) 50 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/tar.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 go-dockerclient authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package docker 6 | 7 | import ( 8 | "fmt" 9 | "io" 10 | "io/ioutil" 11 | "os" 12 | "path" 13 | "path/filepath" 14 | "strings" 15 | 16 | "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive" 17 | "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/fileutils" 18 | ) 19 | 20 | func createTarStream(srcPath, dockerfilePath string) (io.ReadCloser, error) { 21 | excludes, err := parseDockerignore(srcPath) 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | includes := []string{"."} 27 | 28 | // If .dockerignore mentions .dockerignore or the Dockerfile 29 | // then make sure we send both files over to the daemon 30 | // because Dockerfile is, obviously, needed no matter what, and 31 | // .dockerignore is needed to know if either one needs to be 32 | // removed. The deamon will remove them for us, if needed, after it 33 | // parses the Dockerfile. 34 | // 35 | // https://github.com/docker/docker/issues/8330 36 | // 37 | forceIncludeFiles := []string{".dockerignore", dockerfilePath} 38 | 39 | for _, includeFile := range forceIncludeFiles { 40 | if includeFile == "" { 41 | continue 42 | } 43 | keepThem, err := fileutils.Matches(includeFile, excludes) 44 | if err != nil { 45 | return nil, fmt.Errorf("cannot match .dockerfile: '%s', error: %s", includeFile, err) 46 | } 47 | if keepThem { 48 | includes = append(includes, includeFile) 49 | } 50 | } 51 | 52 | if err := validateContextDirectory(srcPath, excludes); err != nil { 53 | return nil, err 54 | } 55 | tarOpts := &archive.TarOptions{ 56 | ExcludePatterns: excludes, 57 | IncludeFiles: includes, 58 | Compression: archive.Uncompressed, 59 | NoLchown: true, 60 | } 61 | return archive.TarWithOptions(srcPath, tarOpts) 62 | } 63 | 64 | // validateContextDirectory checks if all the contents of the directory 65 | // can be read and returns an error if some files can't be read. 66 | // Symlinks which point to non-existing files don't trigger an error 67 | func validateContextDirectory(srcPath string, excludes []string) error { 68 | return filepath.Walk(filepath.Join(srcPath, "."), func(filePath string, f os.FileInfo, err error) error { 69 | // skip this directory/file if it's not in the path, it won't get added to the context 70 | if relFilePath, err := filepath.Rel(srcPath, filePath); err != nil { 71 | return err 72 | } else if skip, err := fileutils.Matches(relFilePath, excludes); err != nil { 73 | return err 74 | } else if skip { 75 | if f.IsDir() { 76 | return filepath.SkipDir 77 | } 78 | return nil 79 | } 80 | 81 | if err != nil { 82 | if os.IsPermission(err) { 83 | return fmt.Errorf("can't stat '%s'", filePath) 84 | } 85 | if os.IsNotExist(err) { 86 | return nil 87 | } 88 | return err 89 | } 90 | 91 | // skip checking if symlinks point to non-existing files, such symlinks can be useful 92 | // also skip named pipes, because they hanging on open 93 | if f.Mode()&(os.ModeSymlink|os.ModeNamedPipe) != 0 { 94 | return nil 95 | } 96 | 97 | if !f.IsDir() { 98 | currentFile, err := os.Open(filePath) 99 | if err != nil && os.IsPermission(err) { 100 | return fmt.Errorf("no permission to read from '%s'", filePath) 101 | } 102 | currentFile.Close() 103 | } 104 | return nil 105 | }) 106 | } 107 | 108 | func parseDockerignore(root string) ([]string, error) { 109 | var excludes []string 110 | ignore, err := ioutil.ReadFile(path.Join(root, ".dockerignore")) 111 | if err != nil && !os.IsNotExist(err) { 112 | return excludes, fmt.Errorf("error reading .dockerignore: '%s'", err) 113 | } 114 | excludes = strings.Split(string(ignore), "\n") 115 | 116 | return excludes, nil 117 | } 118 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/tls.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 go-dockerclient authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | // 5 | // The content is borrowed from Docker's own source code to provide a simple 6 | // tls based dialer 7 | 8 | package docker 9 | 10 | import ( 11 | "crypto/tls" 12 | "errors" 13 | "net" 14 | "strings" 15 | "time" 16 | ) 17 | 18 | type tlsClientCon struct { 19 | *tls.Conn 20 | rawConn net.Conn 21 | } 22 | 23 | func (c *tlsClientCon) CloseWrite() error { 24 | // Go standard tls.Conn doesn't provide the CloseWrite() method so we do it 25 | // on its underlying connection. 26 | if cwc, ok := c.rawConn.(interface { 27 | CloseWrite() error 28 | }); ok { 29 | return cwc.CloseWrite() 30 | } 31 | return nil 32 | } 33 | 34 | func tlsDialWithDialer(dialer *net.Dialer, network, addr string, config *tls.Config) (net.Conn, error) { 35 | // We want the Timeout and Deadline values from dialer to cover the 36 | // whole process: TCP connection and TLS handshake. This means that we 37 | // also need to start our own timers now. 38 | timeout := dialer.Timeout 39 | 40 | if !dialer.Deadline.IsZero() { 41 | deadlineTimeout := dialer.Deadline.Sub(time.Now()) 42 | if timeout == 0 || deadlineTimeout < timeout { 43 | timeout = deadlineTimeout 44 | } 45 | } 46 | 47 | var errChannel chan error 48 | 49 | if timeout != 0 { 50 | errChannel = make(chan error, 2) 51 | time.AfterFunc(timeout, func() { 52 | errChannel <- errors.New("") 53 | }) 54 | } 55 | 56 | rawConn, err := dialer.Dial(network, addr) 57 | if err != nil { 58 | return nil, err 59 | } 60 | 61 | colonPos := strings.LastIndex(addr, ":") 62 | if colonPos == -1 { 63 | colonPos = len(addr) 64 | } 65 | hostname := addr[:colonPos] 66 | 67 | // If no ServerName is set, infer the ServerName 68 | // from the hostname we're connecting to. 69 | if config.ServerName == "" { 70 | // Make a copy to avoid polluting argument or default. 71 | c := *config 72 | c.ServerName = hostname 73 | config = &c 74 | } 75 | 76 | conn := tls.Client(rawConn, config) 77 | 78 | if timeout == 0 { 79 | err = conn.Handshake() 80 | } else { 81 | go func() { 82 | errChannel <- conn.Handshake() 83 | }() 84 | 85 | err = <-errChannel 86 | } 87 | 88 | if err != nil { 89 | rawConn.Close() 90 | return nil, err 91 | } 92 | 93 | // This is Docker difference with standard's crypto/tls package: returned a 94 | // wrapper which holds both the TLS and raw connections. 95 | return &tlsClientCon{conn, rawConn}, nil 96 | } 97 | -------------------------------------------------------------------------------- /vendor/github.com/fsouza/go-dockerclient/volume.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 go-dockerclient authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package docker 6 | 7 | import ( 8 | "encoding/json" 9 | "errors" 10 | "net/http" 11 | ) 12 | 13 | var ( 14 | // ErrNoSuchVolume is the error returned when the volume does not exist. 15 | ErrNoSuchVolume = errors.New("no such volume") 16 | 17 | // ErrVolumeInUse is the error returned when the volume requested to be removed is still in use. 18 | ErrVolumeInUse = errors.New("volume in use and cannot be removed") 19 | ) 20 | 21 | // Volume represents a volume. 22 | // 23 | // See https://goo.gl/FZA4BK for more details. 24 | type Volume struct { 25 | Name string `json:"Name" yaml:"Name"` 26 | Driver string `json:"Driver,omitempty" yaml:"Driver,omitempty"` 27 | Mountpoint string `json:"Mountpoint,omitempty" yaml:"Mountpoint,omitempty"` 28 | } 29 | 30 | // ListVolumesOptions specify parameters to the ListVolumes function. 31 | // 32 | // See https://goo.gl/FZA4BK for more details. 33 | type ListVolumesOptions struct { 34 | Filters map[string][]string 35 | } 36 | 37 | // ListVolumes returns a list of available volumes in the server. 38 | // 39 | // See https://goo.gl/FZA4BK for more details. 40 | func (c *Client) ListVolumes(opts ListVolumesOptions) ([]Volume, error) { 41 | body, _, err := c.do("GET", "/volumes?"+queryString(opts), doOptions{}) 42 | if err != nil { 43 | return nil, err 44 | } 45 | m := make(map[string]interface{}) 46 | if err := json.Unmarshal(body, &m); err != nil { 47 | return nil, err 48 | } 49 | var volumes []Volume 50 | volumesJSON, ok := m["Volumes"] 51 | if !ok { 52 | return volumes, nil 53 | } 54 | data, err := json.Marshal(volumesJSON) 55 | if err != nil { 56 | return nil, err 57 | } 58 | if err := json.Unmarshal(data, &volumes); err != nil { 59 | return nil, err 60 | } 61 | return volumes, nil 62 | } 63 | 64 | // CreateVolumeOptions specify parameters to the CreateVolume function. 65 | // 66 | // See https://goo.gl/pBUbZ9 for more details. 67 | type CreateVolumeOptions struct { 68 | Name string 69 | Driver string 70 | DriverOpts map[string]string 71 | } 72 | 73 | // CreateVolume creates a volume on the server. 74 | // 75 | // See https://goo.gl/pBUbZ9 for more details. 76 | func (c *Client) CreateVolume(opts CreateVolumeOptions) (*Volume, error) { 77 | body, _, err := c.do("POST", "/volumes", doOptions{data: opts}) 78 | if err != nil { 79 | return nil, err 80 | } 81 | var volume Volume 82 | if err := json.Unmarshal(body, &volume); err != nil { 83 | return nil, err 84 | } 85 | return &volume, nil 86 | } 87 | 88 | // InspectVolume returns a volume by its name. 89 | // 90 | // See https://goo.gl/0g9A6i for more details. 91 | func (c *Client) InspectVolume(name string) (*Volume, error) { 92 | body, status, err := c.do("GET", "/volumes/"+name, doOptions{}) 93 | if status == http.StatusNotFound { 94 | return nil, ErrNoSuchVolume 95 | } 96 | if err != nil { 97 | return nil, err 98 | } 99 | var volume Volume 100 | if err := json.Unmarshal(body, &volume); err != nil { 101 | return nil, err 102 | } 103 | return &volume, nil 104 | } 105 | 106 | // RemoveVolume removes a volume by its name. 107 | // 108 | // See https://goo.gl/79GNQz for more details. 109 | func (c *Client) RemoveVolume(name string) error { 110 | _, status, err := c.do("DELETE", "/volumes/"+name, doOptions{}) 111 | if status == http.StatusNotFound { 112 | return ErrNoSuchVolume 113 | } 114 | if status == http.StatusConflict { 115 | return ErrVolumeInUse 116 | } 117 | return err 118 | } 119 | -------------------------------------------------------------------------------- /vendor/github.com/gliderlabs/logspout/router/http.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "strings" 7 | ) 8 | 9 | func init() { 10 | port := getopt("PORT", getopt("HTTP_PORT", "80")) 11 | Jobs.Register(&httpService{port}, "http") 12 | } 13 | 14 | type httpService struct { 15 | port string 16 | } 17 | 18 | func (s *httpService) Name() string { 19 | return fmt.Sprintf("http[%s]:%s", 20 | strings.Join(HttpHandlers.Names(), ","), s.port) 21 | } 22 | 23 | func (s *httpService) Setup() error { 24 | for name, handler := range HttpHandlers.All() { 25 | h := handler() 26 | http.Handle("/"+name, h) 27 | http.Handle("/"+name+"/", h) 28 | } 29 | return nil 30 | } 31 | 32 | func (s *httpService) Run() error { 33 | return http.ListenAndServe(":"+s.port, nil) 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/gliderlabs/logspout/router/persist.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "encoding/json" 5 | "io" 6 | "io/ioutil" 7 | "log" 8 | "os" 9 | "strings" 10 | ) 11 | 12 | type RouteFileStore string 13 | 14 | func (fs RouteFileStore) Filename(id string) string { 15 | return string(fs) + "/" + id + ".json" 16 | } 17 | 18 | func (fs RouteFileStore) Get(id string) (*Route, error) { 19 | file, err := os.Open(fs.Filename(id)) 20 | if err != nil { 21 | return nil, err 22 | } 23 | route := new(Route) 24 | if err = unmarshal(file, route); err != nil { 25 | return nil, err 26 | } 27 | return route, nil 28 | } 29 | 30 | func (fs RouteFileStore) GetAll() ([]*Route, error) { 31 | files, err := ioutil.ReadDir(string(fs)) 32 | if err != nil { 33 | return nil, err 34 | } 35 | var routes []*Route 36 | for _, file := range files { 37 | fileparts := strings.Split(file.Name(), ".") 38 | if len(fileparts) > 1 && fileparts[1] == "json" { 39 | route, err := fs.Get(fileparts[0]) 40 | if err == nil { 41 | routes = append(routes, route) 42 | } 43 | } 44 | } 45 | return routes, nil 46 | } 47 | 48 | func (fs RouteFileStore) Add(route *Route) error { 49 | return ioutil.WriteFile(fs.Filename(route.ID), marshal(route), 0644) 50 | } 51 | 52 | func (fs RouteFileStore) Remove(id string) bool { 53 | if _, err := os.Stat(fs.Filename(id)); err == nil { 54 | if err := os.Remove(fs.Filename(id)); err != nil { 55 | return true 56 | } 57 | } 58 | return false 59 | } 60 | 61 | func marshal(obj interface{}) []byte { 62 | bytes, err := json.MarshalIndent(obj, "", " ") 63 | if err != nil { 64 | log.Println("marshal:", err) 65 | } 66 | return bytes 67 | } 68 | 69 | func unmarshal(input io.Reader, obj interface{}) error { 70 | dec := json.NewDecoder(input) 71 | if err := dec.Decode(obj); err != nil { 72 | return err 73 | } 74 | return nil 75 | } 76 | -------------------------------------------------------------------------------- /vendor/github.com/gliderlabs/logspout/router/types.go: -------------------------------------------------------------------------------- 1 | //go:generate go-extpoints . AdapterFactory HttpHandler AdapterTransport LogRouter Job 2 | package router 3 | 4 | import ( 5 | "net" 6 | "net/http" 7 | "path" 8 | "strings" 9 | "time" 10 | 11 | "github.com/fsouza/go-dockerclient" 12 | ) 13 | 14 | // Extension type for adding HTTP endpoints 15 | type HttpHandler func() http.Handler 16 | 17 | // Extension type for adding new log adapters 18 | type AdapterFactory func(route *Route) (LogAdapter, error) 19 | 20 | // Extension type for connection transports used by adapters 21 | type AdapterTransport interface { 22 | Dial(addr string, options map[string]string) (net.Conn, error) 23 | } 24 | 25 | // LogAdapters are streamed logs 26 | type LogAdapter interface { 27 | Stream(logstream chan *Message) 28 | } 29 | 30 | type Job interface { 31 | Run() error 32 | Setup() error 33 | Name() string 34 | } 35 | 36 | // LogRouters send logs to LogAdapters via Routes 37 | type LogRouter interface { 38 | RoutingFrom(containerID string) bool 39 | Route(route *Route, logstream chan *Message) 40 | } 41 | 42 | // RouteStores are collections of Routes 43 | type RouteStore interface { 44 | Get(id string) (*Route, error) 45 | GetAll() ([]*Route, error) 46 | Add(route *Route) error 47 | Remove(id string) bool 48 | } 49 | 50 | // Messages are log messages 51 | type Message struct { 52 | Container *docker.Container 53 | Source string 54 | Data string 55 | Time time.Time 56 | } 57 | 58 | // Routes represent what subset of logs should go where 59 | type Route struct { 60 | ID string `json:"id"` 61 | FilterID string `json:"filter_id,omitempty"` 62 | FilterName string `json:"filter_name,omitempty"` 63 | FilterSources []string `json:"filter_sources,omitempty"` 64 | Adapter string `json:"adapter"` 65 | Address string `json:"address"` 66 | Options map[string]string `json:"options,omitempty"` 67 | adapter LogAdapter 68 | closer chan bool 69 | closerRcv <-chan bool // used instead of closer when set 70 | } 71 | 72 | func (r *Route) AdapterType() string { 73 | return strings.Split(r.Adapter, "+")[0] 74 | } 75 | 76 | func (r *Route) AdapterTransport(dfault string) string { 77 | parts := strings.Split(r.Adapter, "+") 78 | if len(parts) > 1 { 79 | return parts[1] 80 | } 81 | return dfault 82 | } 83 | 84 | func (r *Route) Closer() <-chan bool { 85 | if r.closerRcv != nil { 86 | return r.closerRcv 87 | } 88 | return r.closer 89 | } 90 | 91 | func (r *Route) OverrideCloser(closer <-chan bool) { 92 | r.closerRcv = closer 93 | } 94 | 95 | func (r *Route) Close() { 96 | r.closer <- true 97 | } 98 | 99 | func (r *Route) matchAll() bool { 100 | if r.FilterID == "" && r.FilterName == "" && len(r.FilterSources) == 0 { 101 | return true 102 | } 103 | return false 104 | } 105 | 106 | func (r *Route) MultiContainer() bool { 107 | return r.matchAll() || strings.Contains(r.FilterName, "*") 108 | } 109 | 110 | func (r *Route) MatchContainer(id, name string) bool { 111 | if r.matchAll() { 112 | return true 113 | } 114 | if r.FilterID != "" && !strings.HasPrefix(id, r.FilterID) { 115 | return false 116 | } 117 | match, err := path.Match(r.FilterName, name) 118 | if err != nil || (r.FilterName != "" && !match) { 119 | return false 120 | } 121 | return true 122 | } 123 | 124 | func (r *Route) MatchMessage(message *Message) bool { 125 | if r.matchAll() { 126 | return true 127 | } 128 | if len(r.FilterSources) > 0 && !contains(r.FilterSources, message.Source) { 129 | return false 130 | } 131 | return true 132 | } 133 | 134 | func contains(strs []string, str string) bool { 135 | for _, s := range strs { 136 | if s == str { 137 | return true 138 | } 139 | } 140 | return false 141 | } 142 | -------------------------------------------------------------------------------- /vendor/github.com/jmespath/go-jmespath/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015 James Saryerwinnie 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /vendor/github.com/jmespath/go-jmespath/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CMD = jpgo 3 | 4 | help: 5 | @echo "Please use \`make ' where is one of" 6 | @echo " test to run all the tests" 7 | @echo " build to build the library and jp executable" 8 | @echo " generate to run codegen" 9 | 10 | 11 | generate: 12 | go generate ./... 13 | 14 | build: 15 | rm -f $(CMD) 16 | go build ./... 17 | rm -f cmd/$(CMD)/$(CMD) && cd cmd/$(CMD)/ && go build ./... 18 | mv cmd/$(CMD)/$(CMD) . 19 | 20 | test: 21 | go test -v ./... 22 | 23 | check: 24 | go vet ./... 25 | @echo "golint ./..." 26 | @lint=`golint ./...`; \ 27 | lint=`echo "$$lint" | grep -v "astnodetype_string.go" | grep -v "toktype_string.go"`; \ 28 | echo "$$lint"; \ 29 | if [ "$$lint" != "" ]; then exit 1; fi 30 | 31 | htmlc: 32 | go test -coverprofile="/tmp/jpcov" && go tool cover -html="/tmp/jpcov" && unlink /tmp/jpcov 33 | 34 | buildfuzz: 35 | go-fuzz-build github.com/jmespath/go-jmespath/fuzz 36 | 37 | fuzz: buildfuzz 38 | go-fuzz -bin=./jmespath-fuzz.zip -workdir=fuzz/corpus 39 | 40 | bench: 41 | go test -bench . -cpuprofile cpu.out 42 | 43 | pprof-cpu: 44 | go tool pprof ./go-jmespath.test ./cpu.out 45 | -------------------------------------------------------------------------------- /vendor/github.com/jmespath/go-jmespath/README.md: -------------------------------------------------------------------------------- 1 | # go-jmespath - A JMESPath implementation in Go 2 | 3 | [![Build Status](https://img.shields.io/travis/jmespath/go-jmespath.svg)](https://travis-ci.org/jmespath/go-jmespath) 4 | 5 | 6 | 7 | See http://jmespath.org for more info. 8 | -------------------------------------------------------------------------------- /vendor/github.com/jmespath/go-jmespath/api.go: -------------------------------------------------------------------------------- 1 | package jmespath 2 | 3 | // Search evaluates a JMESPath expression against input data and returns the result. 4 | func Search(expression string, data interface{}) (interface{}, error) { 5 | intr := newInterpreter() 6 | parser := NewParser() 7 | ast, err := parser.Parse(expression) 8 | if err != nil { 9 | return nil, err 10 | } 11 | return intr.Execute(ast, data) 12 | } 13 | -------------------------------------------------------------------------------- /vendor/github.com/jmespath/go-jmespath/astnodetype_string.go: -------------------------------------------------------------------------------- 1 | // generated by stringer -type astNodeType; DO NOT EDIT 2 | 3 | package jmespath 4 | 5 | import "fmt" 6 | 7 | const _astNodeType_name = "ASTEmptyASTComparatorASTCurrentNodeASTExpRefASTFunctionExpressionASTFieldASTFilterProjectionASTFlattenASTIdentityASTIndexASTIndexExpressionASTKeyValPairASTLiteralASTMultiSelectHashASTMultiSelectListASTOrExpressionASTAndExpressionASTNotExpressionASTPipeASTProjectionASTSubexpressionASTSliceASTValueProjection" 8 | 9 | var _astNodeType_index = [...]uint16{0, 8, 21, 35, 44, 65, 73, 92, 102, 113, 121, 139, 152, 162, 180, 198, 213, 229, 245, 252, 265, 281, 289, 307} 10 | 11 | func (i astNodeType) String() string { 12 | if i < 0 || i >= astNodeType(len(_astNodeType_index)-1) { 13 | return fmt.Sprintf("astNodeType(%d)", i) 14 | } 15 | return _astNodeType_name[_astNodeType_index[i]:_astNodeType_index[i+1]] 16 | } 17 | -------------------------------------------------------------------------------- /vendor/github.com/jmespath/go-jmespath/toktype_string.go: -------------------------------------------------------------------------------- 1 | // generated by stringer -type=tokType; DO NOT EDIT 2 | 3 | package jmespath 4 | 5 | import "fmt" 6 | 7 | const _tokType_name = "tUnknowntStartDottFiltertFlattentLparentRparentLbrackettRbrackettLbracetRbracetOrtPipetNumbertUnquotedIdentifiertQuotedIdentifiertCommatColontLTtLTEtGTtGTEtEQtNEtJSONLiteraltStringLiteraltCurrenttExpreftAndtNottEOF" 8 | 9 | var _tokType_index = [...]uint8{0, 8, 13, 17, 24, 32, 39, 46, 55, 64, 71, 78, 81, 86, 93, 112, 129, 135, 141, 144, 148, 151, 155, 158, 161, 173, 187, 195, 202, 206, 210, 214} 10 | 11 | func (i tokType) String() string { 12 | if i < 0 || i >= tokType(len(_tokType_index)-1) { 13 | return fmt.Sprintf("tokType(%d)", i) 14 | } 15 | return _tokType_name[_tokType_index[i]:_tokType_index[i+1]] 16 | } 17 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | Paul Borman 2 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009,2014 Google Inc. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/dce.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "encoding/binary" 9 | "fmt" 10 | "os" 11 | ) 12 | 13 | // A Domain represents a Version 2 domain 14 | type Domain byte 15 | 16 | // Domain constants for DCE Security (Version 2) UUIDs. 17 | const ( 18 | Person = Domain(0) 19 | Group = Domain(1) 20 | Org = Domain(2) 21 | ) 22 | 23 | // NewDCESecurity returns a DCE Security (Version 2) UUID. 24 | // 25 | // The domain should be one of Person, Group or Org. 26 | // On a POSIX system the id should be the users UID for the Person 27 | // domain and the users GID for the Group. The meaning of id for 28 | // the domain Org or on non-POSIX systems is site defined. 29 | // 30 | // For a given domain/id pair the same token may be returned for up to 31 | // 7 minutes and 10 seconds. 32 | func NewDCESecurity(domain Domain, id uint32) UUID { 33 | uuid := NewUUID() 34 | if uuid != nil { 35 | uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2 36 | uuid[9] = byte(domain) 37 | binary.BigEndian.PutUint32(uuid[0:], id) 38 | } 39 | return uuid 40 | } 41 | 42 | // NewDCEPerson returns a DCE Security (Version 2) UUID in the person 43 | // domain with the id returned by os.Getuid. 44 | // 45 | // NewDCEPerson(Person, uint32(os.Getuid())) 46 | func NewDCEPerson() UUID { 47 | return NewDCESecurity(Person, uint32(os.Getuid())) 48 | } 49 | 50 | // NewDCEGroup returns a DCE Security (Version 2) UUID in the group 51 | // domain with the id returned by os.Getgid. 52 | // 53 | // NewDCEGroup(Group, uint32(os.Getgid())) 54 | func NewDCEGroup() UUID { 55 | return NewDCESecurity(Group, uint32(os.Getgid())) 56 | } 57 | 58 | // Domain returns the domain for a Version 2 UUID or false. 59 | func (uuid UUID) Domain() (Domain, bool) { 60 | if v, _ := uuid.Version(); v != 2 { 61 | return 0, false 62 | } 63 | return Domain(uuid[9]), true 64 | } 65 | 66 | // Id returns the id for a Version 2 UUID or false. 67 | func (uuid UUID) Id() (uint32, bool) { 68 | if v, _ := uuid.Version(); v != 2 { 69 | return 0, false 70 | } 71 | return binary.BigEndian.Uint32(uuid[0:4]), true 72 | } 73 | 74 | func (d Domain) String() string { 75 | switch d { 76 | case Person: 77 | return "Person" 78 | case Group: 79 | return "Group" 80 | case Org: 81 | return "Org" 82 | } 83 | return fmt.Sprintf("Domain%d", int(d)) 84 | } 85 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // The uuid package generates and inspects UUIDs. 6 | // 7 | // UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security Services. 8 | package uuid 9 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/hash.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "crypto/md5" 9 | "crypto/sha1" 10 | "hash" 11 | ) 12 | 13 | // Well known Name Space IDs and UUIDs 14 | var ( 15 | NameSpace_DNS = Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") 16 | NameSpace_URL = Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8") 17 | NameSpace_OID = Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8") 18 | NameSpace_X500 = Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8") 19 | NIL = Parse("00000000-0000-0000-0000-000000000000") 20 | ) 21 | 22 | // NewHash returns a new UUID dervied from the hash of space concatenated with 23 | // data generated by h. The hash should be at least 16 byte in length. The 24 | // first 16 bytes of the hash are used to form the UUID. The version of the 25 | // UUID will be the lower 4 bits of version. NewHash is used to implement 26 | // NewMD5 and NewSHA1. 27 | func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { 28 | h.Reset() 29 | h.Write(space) 30 | h.Write([]byte(data)) 31 | s := h.Sum(nil) 32 | uuid := make([]byte, 16) 33 | copy(uuid, s) 34 | uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) 35 | uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant 36 | return uuid 37 | } 38 | 39 | // NewMD5 returns a new MD5 (Version 3) UUID based on the 40 | // supplied name space and data. 41 | // 42 | // NewHash(md5.New(), space, data, 3) 43 | func NewMD5(space UUID, data []byte) UUID { 44 | return NewHash(md5.New(), space, data, 3) 45 | } 46 | 47 | // NewSHA1 returns a new SHA1 (Version 5) UUID based on the 48 | // supplied name space and data. 49 | // 50 | // NewHash(sha1.New(), space, data, 5) 51 | func NewSHA1(space UUID, data []byte) UUID { 52 | return NewHash(sha1.New(), space, data, 5) 53 | } 54 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/json.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import "errors" 8 | 9 | func (u UUID) MarshalJSON() ([]byte, error) { 10 | if len(u) == 0 { 11 | return []byte(`""`), nil 12 | } 13 | return []byte(`"` + u.String() + `"`), nil 14 | } 15 | 16 | func (u *UUID) UnmarshalJSON(data []byte) error { 17 | if len(data) == 0 || string(data) == `""` { 18 | return nil 19 | } 20 | if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' { 21 | return errors.New("invalid UUID format") 22 | } 23 | data = data[1 : len(data)-1] 24 | uu := Parse(string(data)) 25 | if uu == nil { 26 | return errors.New("invalid UUID format") 27 | } 28 | *u = uu 29 | return nil 30 | } 31 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/node.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import "net" 8 | 9 | var ( 10 | interfaces []net.Interface // cached list of interfaces 11 | ifname string // name of interface being used 12 | nodeID []byte // hardware for version 1 UUIDs 13 | ) 14 | 15 | // NodeInterface returns the name of the interface from which the NodeID was 16 | // derived. The interface "user" is returned if the NodeID was set by 17 | // SetNodeID. 18 | func NodeInterface() string { 19 | return ifname 20 | } 21 | 22 | // SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. 23 | // If name is "" then the first usable interface found will be used or a random 24 | // Node ID will be generated. If a named interface cannot be found then false 25 | // is returned. 26 | // 27 | // SetNodeInterface never fails when name is "". 28 | func SetNodeInterface(name string) bool { 29 | if interfaces == nil { 30 | var err error 31 | interfaces, err = net.Interfaces() 32 | if err != nil && name != "" { 33 | return false 34 | } 35 | } 36 | 37 | for _, ifs := range interfaces { 38 | if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { 39 | if setNodeID(ifs.HardwareAddr) { 40 | ifname = ifs.Name 41 | return true 42 | } 43 | } 44 | } 45 | 46 | // We found no interfaces with a valid hardware address. If name 47 | // does not specify a specific interface generate a random Node ID 48 | // (section 4.1.6) 49 | if name == "" { 50 | if nodeID == nil { 51 | nodeID = make([]byte, 6) 52 | } 53 | randomBits(nodeID) 54 | return true 55 | } 56 | return false 57 | } 58 | 59 | // NodeID returns a slice of a copy of the current Node ID, setting the Node ID 60 | // if not already set. 61 | func NodeID() []byte { 62 | if nodeID == nil { 63 | SetNodeInterface("") 64 | } 65 | nid := make([]byte, 6) 66 | copy(nid, nodeID) 67 | return nid 68 | } 69 | 70 | // SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes 71 | // of id are used. If id is less than 6 bytes then false is returned and the 72 | // Node ID is not set. 73 | func SetNodeID(id []byte) bool { 74 | if setNodeID(id) { 75 | ifname = "user" 76 | return true 77 | } 78 | return false 79 | } 80 | 81 | func setNodeID(id []byte) bool { 82 | if len(id) < 6 { 83 | return false 84 | } 85 | if nodeID == nil { 86 | nodeID = make([]byte, 6) 87 | } 88 | copy(nodeID, id) 89 | return true 90 | } 91 | 92 | // NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is 93 | // not valid. The NodeID is only well defined for version 1 and 2 UUIDs. 94 | func (uuid UUID) NodeID() []byte { 95 | if len(uuid) != 16 { 96 | return nil 97 | } 98 | node := make([]byte, 6) 99 | copy(node, uuid[10:]) 100 | return node 101 | } 102 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/sql.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | ) 11 | 12 | // Scan implements sql.Scanner so UUIDs can be read from databases transparently 13 | // Currently, database types that map to string and []byte are supported. Please 14 | // consult database-specific driver documentation for matching types. 15 | func (uuid *UUID) Scan(src interface{}) error { 16 | switch src.(type) { 17 | case string: 18 | // see uuid.Parse for required string format 19 | parsed := Parse(src.(string)) 20 | 21 | if parsed == nil { 22 | return errors.New("Scan: invalid UUID format") 23 | } 24 | 25 | *uuid = parsed 26 | case []byte: 27 | // assumes a simple slice of bytes, just check validity and store 28 | u := UUID(src.([]byte)) 29 | 30 | if u.Variant() == Invalid { 31 | return errors.New("Scan: invalid UUID format") 32 | } 33 | 34 | *uuid = u 35 | default: 36 | return fmt.Errorf("Scan: unable to scan type %T into UUID", src) 37 | } 38 | 39 | return nil 40 | } 41 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "io" 9 | ) 10 | 11 | // randomBits completely fills slice b with random data. 12 | func randomBits(b []byte) { 13 | if _, err := io.ReadFull(rander, b); err != nil { 14 | panic(err.Error()) // rand should never fail 15 | } 16 | } 17 | 18 | // xvalues returns the value of a byte as a hexadecimal digit or 255. 19 | var xvalues = []byte{ 20 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 21 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 22 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 23 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, 24 | 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, 25 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 26 | 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, 27 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 28 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 29 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 30 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 31 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 32 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 33 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 34 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 35 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 36 | } 37 | 38 | // xtob converts the the first two hex bytes of x into a byte. 39 | func xtob(x string) (byte, bool) { 40 | b1 := xvalues[x[0]] 41 | b2 := xvalues[x[1]] 42 | return (b1 << 4) | b2, b1 != 255 && b2 != 255 43 | } 44 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/version1.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | import ( 8 | "encoding/binary" 9 | ) 10 | 11 | // NewUUID returns a Version 1 UUID based on the current NodeID and clock 12 | // sequence, and the current time. If the NodeID has not been set by SetNodeID 13 | // or SetNodeInterface then it will be set automatically. If the NodeID cannot 14 | // be set NewUUID returns nil. If clock sequence has not been set by 15 | // SetClockSequence then it will be set automatically. If GetTime fails to 16 | // return the current NewUUID returns nil. 17 | func NewUUID() UUID { 18 | if nodeID == nil { 19 | SetNodeInterface("") 20 | } 21 | 22 | now, seq, err := GetTime() 23 | if err != nil { 24 | return nil 25 | } 26 | 27 | uuid := make([]byte, 16) 28 | 29 | time_low := uint32(now & 0xffffffff) 30 | time_mid := uint16((now >> 32) & 0xffff) 31 | time_hi := uint16((now >> 48) & 0x0fff) 32 | time_hi |= 0x1000 // Version 1 33 | 34 | binary.BigEndian.PutUint32(uuid[0:], time_low) 35 | binary.BigEndian.PutUint16(uuid[4:], time_mid) 36 | binary.BigEndian.PutUint16(uuid[6:], time_hi) 37 | binary.BigEndian.PutUint16(uuid[8:], seq) 38 | copy(uuid[10:], nodeID) 39 | 40 | return uuid 41 | } 42 | -------------------------------------------------------------------------------- /vendor/github.com/pborman/uuid/version4.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package uuid 6 | 7 | // Random returns a Random (Version 4) UUID or panics. 8 | // 9 | // The strength of the UUIDs is based on the strength of the crypto/rand 10 | // package. 11 | // 12 | // A note about uniqueness derived from from the UUID Wikipedia entry: 13 | // 14 | // Randomly generated UUIDs have 122 random bits. One's annual risk of being 15 | // hit by a meteorite is estimated to be one chance in 17 billion, that 16 | // means the probability is about 0.00000000006 (6 × 10−11), 17 | // equivalent to the odds of creating a few tens of trillions of UUIDs in a 18 | // year and having one duplicate. 19 | func NewRandom() UUID { 20 | uuid := make([]byte, 16) 21 | randomBits([]byte(uuid)) 22 | uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 23 | uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 24 | return uuid 25 | } 26 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/errors.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // AnError is an error instance useful for testing. If the code does not care 8 | // about error specifics, and only needs to return the error for example, this 9 | // error should be used to make the test code more readable. 10 | var AnError = errors.New("assert.AnError general error for testing") 11 | -------------------------------------------------------------------------------- /writer.go: -------------------------------------------------------------------------------- 1 | package kinesis 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/gliderlabs/logspout/router" 7 | ) 8 | 9 | type writer struct { 10 | buffer *buffer 11 | flusher Flusher 12 | messages chan *router.Message 13 | ticker <-chan time.Time 14 | } 15 | 16 | func newWriter(b *buffer, f Flusher) *writer { 17 | w := &writer{ 18 | messages: make(chan *router.Message), 19 | ticker: time.NewTicker(time.Second).C, 20 | flusher: f, 21 | buffer: b, 22 | } 23 | 24 | return w 25 | } 26 | 27 | func (w *writer) start() { 28 | go w.flusher.start() 29 | go w.bufferMessages() 30 | } 31 | 32 | func (w *writer) write(m *router.Message) { 33 | w.messages <- m 34 | } 35 | 36 | func (w *writer) bufferMessages() { 37 | flush := func() { 38 | w.flusher.flush(*w.buffer.input) 39 | w.buffer.reset() 40 | } 41 | 42 | for { 43 | select { 44 | case m := <-w.messages: 45 | if w.buffer.full(m) { 46 | flush() 47 | } 48 | 49 | ErrorHandler(w.buffer.add(m)) 50 | case <-w.ticker: 51 | if !w.buffer.empty() { 52 | flush() 53 | } else { 54 | debug("buffer is empty, stream: %s", *w.buffer.input.StreamName) 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /writer_test.go: -------------------------------------------------------------------------------- 1 | package kinesis 2 | 3 | import ( 4 | "testing" 5 | "text/template" 6 | "time" 7 | 8 | "github.com/aws/aws-sdk-go/service/kinesis" 9 | "github.com/fsouza/go-dockerclient" 10 | "github.com/gliderlabs/logspout/router" 11 | ) 12 | 13 | type fakeFlusher struct { 14 | inputs chan kinesis.PutRecordsInput 15 | dropInputFunc func(kinesis.PutRecordsInput) 16 | flushFunc func() 17 | flushed chan struct{} 18 | } 19 | 20 | func (f *fakeFlusher) start() { 21 | f.flushInputs() 22 | } 23 | 24 | func (f *fakeFlusher) flush(input kinesis.PutRecordsInput) { 25 | select { 26 | case f.inputs <- input: 27 | f.flushInputs() 28 | default: 29 | f.dropInputFunc(input) 30 | } 31 | } 32 | 33 | func (f *fakeFlusher) flushInputs() { 34 | if f.flushFunc == nil { 35 | close(f.flushed) 36 | } else { 37 | f.flushFunc() 38 | } 39 | } 40 | 41 | var testLimits = limits{ 42 | putRecords: 2, 43 | putRecordsSize: PutRecordsSizeLimit, 44 | recordSize: RecordSizeLimit, 45 | } 46 | 47 | func TestWriter_Flush(t *testing.T) { 48 | tmpl, _ := template.New("").Parse("abc") 49 | b := newBuffer(tmpl, "abc") 50 | b.limits = &testLimits 51 | 52 | f := &fakeFlusher{ 53 | inputs: make(chan kinesis.PutRecordsInput, 10), 54 | flushed: make(chan struct{}), 55 | } 56 | 57 | w := newWriter(b, f) 58 | w.ticker = nil 59 | 60 | go w.bufferMessages() 61 | 62 | m := &router.Message{ 63 | Data: "hello", 64 | Container: &docker.Container{ 65 | ID: "123", 66 | }, 67 | } 68 | 69 | w.write(m) 70 | w.write(m) 71 | w.write(m) 72 | 73 | select { 74 | case <-f.flushed: 75 | case <-time.After(1 * time.Second): 76 | t.Fatal("Expected flush to be called") 77 | } 78 | } 79 | 80 | func TestWriter_PeriodicFlush(t *testing.T) { 81 | tmpl, _ := template.New("").Parse("abc") 82 | b := newBuffer(tmpl, "abc") 83 | b.limits = &testLimits 84 | 85 | f := &fakeFlusher{ 86 | inputs: make(chan kinesis.PutRecordsInput, 10), 87 | flushed: make(chan struct{}), 88 | } 89 | 90 | w := newWriter(b, f) 91 | 92 | ticker := make(chan time.Time, 1) 93 | w.ticker = ticker 94 | 95 | go w.bufferMessages() 96 | 97 | m := &router.Message{ 98 | Data: "hello", 99 | Container: &docker.Container{ 100 | ID: "123", 101 | }, 102 | } 103 | w.write(m) 104 | 105 | select { 106 | case ticker <- time.Now(): 107 | default: 108 | t.Fatal("Couldn't send on stream.ticker channel") 109 | } 110 | 111 | select { 112 | case <-f.flushed: 113 | case <-time.After(time.Second): 114 | t.Fatal("Expected flush to be called") 115 | } 116 | } 117 | --------------------------------------------------------------------------------