diff --git a/cmd/up.go b/cmd/up.go
index b24032b34..822d2b2e7 100644
--- a/cmd/up.go
+++ b/cmd/up.go
@@ -1,14 +1,14 @@
package cmd
import (
- "github.com/docker/libcompose/project"
- rancherApp "github.com/rancher/rancher-compose/app"
+ "github.com/rancher/rancher-compose-executor/app"
+ "github.com/rancher/rancher-compose-executor/project"
"github.com/urfave/cli"
)
func UpCommand() cli.Command {
factory := &projectFactory{}
- cmd := rancherApp.UpCommand(factory)
+ cmd := app.UpCommand(factory)
cmd.Flags = append(cmd.Flags, []cli.Flag{
cli.StringFlag{
Name: "rancher-file",
@@ -35,7 +35,7 @@ func UpCommand() cli.Command {
type projectFactory struct {
}
-func (p *projectFactory) Create(c *cli.Context) (project.APIProject, error) {
+func (p *projectFactory) Create(c *cli.Context) (*project.Project, error) {
config, err := lookupConfig(c)
if err != nil {
return nil, err
@@ -59,6 +59,6 @@ func (p *projectFactory) Create(c *cli.Context) (project.APIProject, error) {
c.GlobalSet("file", f)
}
- factory := &rancherApp.ProjectFactory{}
+ factory := &app.RancherProjectFactory{}
return factory.Create(c)
}
diff --git a/generate.go b/generate.go
deleted file mode 100644
index 8458a69ab..000000000
--- a/generate.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package main
-
-//go:generate go run scripts/inline_schema.go
diff --git a/scripts/inline_schema.go b/scripts/inline_schema.go
deleted file mode 100644
index 510f1fee3..000000000
--- a/scripts/inline_schema.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package main
-
-import (
- "io/ioutil"
- "os"
- "text/template"
-)
-
-func main() {
- t, err := template.New("schema_template").ParseFiles("./scripts/schema_template")
- if err != nil {
- panic(err)
- }
-
- schemaV1, err := ioutil.ReadFile("./scripts/config_schema_v1.json")
- if err != nil {
- panic(err)
- }
- schemaV2, err := ioutil.ReadFile("./scripts/config_schema_v2.0.json")
- if err != nil {
- panic(err)
- }
-
- inlinedFile, err := os.Create("vendor/github.com/docker/libcompose/config/schema.go")
- if err != nil {
- panic(err)
- }
-
- err = t.Execute(inlinedFile, map[string]string{
- "schemaV1": string(schemaV1),
- "schemaV2": string(schemaV2),
- })
-
- if err != nil {
- panic(err)
- }
-}
diff --git a/trash.conf b/trash.conf
index 69f3dcac9..7ff179bb6 100644
--- a/trash.conf
+++ b/trash.conf
@@ -17,7 +17,7 @@ github.com/patrickmn/go-cache 1881a9bccb818787f68c52bfba648c6cf34c34fa
github.com/pkg/errors 1d2e60385a13aaa66134984235061c2f9302520e
github.com/rancher/go-rancher f4560b58215d7eefc74f867a450ded571b731609
github.com/rancher/rancher-catalog-service a3a8b500adceb82b3a0387b2c7b06a60e7eeee9a
-github.com/rancher/rancher-compose 1a5c2725c1ce1761d8869be5288a797b619fa0bb
+github.com/rancher/rancher-compose-executor 65ba458226af2fe23f8ebbf2f2bab50c9b3e5948
github.com/rancher/rancher-docker-api-proxy 461b5e7022698283030495cf5693680699ce9c28
github.com/Sirupsen/logrus 26709e2714106fb8ad40b773b711ebce25b78914
github.com/spf13/pflag cb88ea77998c3f024757528e3305022ab50b43be
@@ -33,3 +33,6 @@ golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46
golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
gopkg.in/yaml.v2 e4d366fc3c7938e2958e662b4258c7a89e1f0e3e
github.com/fatih/structs dc3312cb1a4513a366c4c9e622ad55c32df12ed3
+github.com/Masterminds/sprig c974324bb59b465f00b128a055656d44f60e4ffc
+github.com/aokoli/goutils 9c37978a95bd5c709a15883b6242714ea6709e64
+github.com/satori/go.uuid b061729afc07e77a8aa4fad0a2fd840958f1942a
diff --git a/vendor/github.com/Masterminds/sprig/.gitignore b/vendor/github.com/Masterminds/sprig/.gitignore
new file mode 100644
index 000000000..5e3002f88
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/.gitignore
@@ -0,0 +1,2 @@
+vendor/
+/.glide
diff --git a/vendor/github.com/Masterminds/sprig/.travis.yml b/vendor/github.com/Masterminds/sprig/.travis.yml
new file mode 100644
index 000000000..092b27d19
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/.travis.yml
@@ -0,0 +1,20 @@
+language: go
+
+go:
+ - 1.6
+ - 1.7
+ - tip
+
+# Setting sudo access to false will let Travis CI use containers rather than
+# VMs to run the tests. For more details see:
+# - http://docs.travis-ci.com/user/workers/container-based-infrastructure/
+# - http://docs.travis-ci.com/user/workers/standard-infrastructure/
+sudo: false
+
+notifications:
+ webhooks:
+ urls:
+ - https://webhooks.gitter.im/e/06e3328629952dabe3e0
+ on_success: change # options: [always|never|change] default: always
+ on_failure: always # options: [always|never|change] default: always
+ on_start: never # options: [always|never|change] default: always
diff --git a/vendor/github.com/Masterminds/sprig/CHANGELOG.md b/vendor/github.com/Masterminds/sprig/CHANGELOG.md
new file mode 100644
index 000000000..1caedc980
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/CHANGELOG.md
@@ -0,0 +1,16 @@
+# Release 1.2.0 (2016-02-01)
+
+- Added quote and squote
+- Added b32enc and b32dec
+- add now takes varargs
+- biggest now takes varargs
+
+# Release 1.1.0 (2015-12-29)
+
+- Added #4: Added contains function. strings.Contains, but with the arguments
+ switched to simplify common pipelines. (thanks krancour)
+- Added Travis-CI testing support
+
+# Release 1.0.0 (2015-12-23)
+
+- Initial release
diff --git a/vendor/github.com/Masterminds/sprig/LICENSE.txt b/vendor/github.com/Masterminds/sprig/LICENSE.txt
new file mode 100644
index 000000000..5c95accc2
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/LICENSE.txt
@@ -0,0 +1,20 @@
+Sprig
+Copyright (C) 2013 Masterminds
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/Masterminds/sprig/README.md b/vendor/github.com/Masterminds/sprig/README.md
new file mode 100644
index 000000000..674a5e2c1
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/README.md
@@ -0,0 +1,246 @@
+# Sprig: Template functions for Go templates
+
+The Go language comes with a [built-in template
+language](http://golang.org/pkg/text/template/), but not
+very many template functions. This library provides a group of commonly
+used template functions.
+
+It is inspired by the template functions found in
+[Twig](http://twig.sensiolabs.org/documentation).
+
+[](https://travis-ci.org/Masterminds/sprig)
+
+## Usage
+
+API documentation is available [at GoDoc.org](http://godoc.org/github.com/Masterminds/sprig), but
+read on for standard usage.
+
+### Load the Sprig library
+
+To load the Sprig `FuncMap`:
+
+```go
+
+import (
+ "github.com/Masterminds/sprig"
+ "html/template"
+)
+
+// This example illustrates that the FuncMap *must* be set before the
+// templates themselves are loaded.
+tpl := template.Must(
+ template.New("base").Funcs(sprig.FuncMap()).ParseGlob("*.html")
+)
+
+
+```
+
+### Call the functions inside of templates
+
+By convention, all functions are lowercase. This seems to follow the Go
+idiom for template functions (as opposed to template methods, which are
+TitleCase).
+
+
+Example:
+
+```
+{{ "hello!" | upper | repeat 5 }}
+```
+
+Produces:
+
+```
+HELLO!HELLO!HELLO!HELLO!HELLO!
+```
+
+## Functions
+
+### Date Functions
+
+- date: Format a date, where a date is an integer type or a time.Time type, and
+ format is a time.Format formatting string.
+- dateModify: Given a date, modify it with a duration: `date_modify "-1.5h" now`. If the duration doesn't
+parse, it returns the time unaltered. See `time.ParseDuration` for info on duration strings.
+- now: Current time.Time, for feeding into date-related functions.
+- htmlDate: Format a date for use in the value field of an HTML "date" form element.
+- dateInZone: Like date, but takes three arguments: format, timestamp,
+ timezone.
+- htmlDateInZone: Like htmlDate, but takes two arguments: timestamp,
+ timezone.
+
+### String Functions
+
+- trim: strings.TrimSpace
+- trimAll: strings.Trim, but with the argument order reversed `trimAll "$" "$5.00"` or `"$5.00 | trimAll "$"`
+- trimSuffix: strings.TrimSuffix, but with the argument order reversed `trimSuffix "-" "5-"`
+- trimPrefix: strings.TrimPrefix, but with the argument order reversed `trimPrefix "$" "$5"`
+- upper: strings.ToUpper
+- lower: strings.ToLower
+- title: strings.Title
+- repeat: strings.Repeat, but with the arguments switched: `repeat count str`. (This simplifies common pipelines)
+- substr: Given string, start, and length, return a substr.
+- nospace: Remove all spaces from a string. `h e l l o` becomes
+ `hello`.
+- abbrev: Truncate a string with ellipses
+- trunc: Truncate a string (no suffix). `trunc 5 "Hello World"` yields "hello".
+- abbrevboth: Truncate both sides of a string with ellipses
+- untitle: Remove title case
+- intials: Given multiple words, return the first letter of each
+ word
+- randAlphaNum: Generate a random alpha-numeric string
+- randAlpha: Generate a random alphabetic string
+- randAscii: Generate a random ASCII string, including symbols
+- randNumeric: Generate a random numeric string
+- wrap: Wrap text at the given column count
+- wrapWith: Wrap text at the given column count, and with the given
+ string for a line terminator: `wrap 50 "\n\t" $string`
+- contains: strings.Contains, but with the arguments switched: `contains "cat" "uncatch"`. (This simplifies common pipelines)
+- hasPrefix: strings.hasPrefix, but with the arguments switched: `hasPrefix "cat" "catch"`.
+- hasSuffix: strings.hasSuffix, but with the arguments switched: `hasSuffix "cat" "ducat"`.
+- quote: Wrap strings in double quotes. `quote "a" "b"` returns `"a"
+ "b"`
+- squote: Wrap strings in single quotes.
+- cat: Concatenate strings, separating them by spaces. `cat $a $b $c`.
+- indent: Indent a string using space characters. `indent 4 "foo\nbar"` produces " foo\n bar"
+- replace: Replace an old with a new in a string: `$name | replace " " "-"`
+- plural: Choose singular or plural based on length: `len $fish | plural
+ "one anchovy" "many anchovies"`
+- uuidv4: Generate a UUID v4 string
+- sha256sum: Generate a hex encoded sha256 hash of the input
+
+### String Slice Functions:
+
+- join: strings.Join, but as `join SEP SLICE`
+- split: strings.Split, but as `split SEP STRING`. The results are returned
+ as a map with the indexes set to _N, where N is an integer starting from 0.
+ Use it like this: `{{$v := "foo/bar/baz" | split "/"}}{{$v._0}}` (Prints `foo`)
+
+### Integer Slice Functions:
+
+- until: Given an integer, returns a slice of counting integers from 0 to one
+ less than the given integer: `range $i, $e := until 5`
+- untilStep: Given start, stop, and step, return an integer slice starting at
+ 'start', stopping at `stop`, and incrementing by 'step'. This is the same
+ as Python's long-form of 'range'.
+
+### Conversions:
+
+- atoi: Convert a string to an integer. 0 if the integer could not be parsed.
+- int: Convert a string or numeric to an int
+- int64: Convert a string or numeric to an int64
+- float64: Convert a string or numeric to a float64
+
+### Defaults:
+
+- default: Give a default value. Used like this: {{trim " "| default "empty"}}.
+ Since trim produces an empty string, the default value is returned. For
+ things with a length (strings, slices, maps), len(0) will trigger the default.
+ For numbers, the value 0 will trigger the default. For booleans, false will
+ trigger the default. For structs, the default is never returned (there is
+ no clear empty condition). For everything else, nil value triggers a default.
+- empty: Returns true if the given value is the zero value for that
+ type. Structs are always non-empty.
+
+### OS:
+
+- env: Read an environment variable.
+- expandenv: Expand all environment variables in a string.
+
+### File Paths:
+- base: Return the last element of a path. https://golang.org/pkg/path#Base
+- dir: Remove the last element of a path. https://golang.org/pkg/path#Dir
+- clean: Clean a path to the shortest equivalent name. (e.g. remove "foo/.."
+ from "foo/../bar.html") https://golang.org/pkg/path#Clean
+- ext: Get the extension for a file path: https://golang.org/pkg/path#Ext
+- isAbs: Returns true if a path is absolute: https://golang.org/pkg/path#IsAbs
+
+### Encoding:
+
+- b32enc: Encode a string into a Base32 string
+- b32dec: Decode a string from a Base32 string
+- b64enc: Encode a string into a Base64 string
+- b64dec: Decode a string from a Base64 string
+
+### Data Structures:
+
+- tuple: A sequence of related objects. It is implemented as a
+ `[]interface{}`, where each item can be accessed using `index`.
+- dict: Takes a list of name/values and returns a map[string]interface{}.
+ The first parameter is converted to a string and stored as a key, the
+ second parameter is treated as the value. And so on, with odds as keys and
+ evens as values. If the function call ends with an odd, the last key will
+ be assigned the empty string. Non-string keys are converted to strings as
+ follows: []byte are converted, fmt.Stringers will have String() called.
+ errors will have Error() called. All others will be passed through
+ fmt.Sprtinf("%v").
+- set: Takes a dict, a key, and a value, and sets that key/value pair in
+ the dict. `set $dict $key $value`. For convenience, it returns the dict,
+ even though the dict was modified in place.
+- unset: Takes a dict and a key, and deletes that key/value pair from the
+ dict. `unset $dict $key`. This returns the dict for convenience.
+- hasKey: Takes a dict and a key, and returns boolean true if the key is in
+ the dict.
+
+```
+{{$t := tuple 1 "a" "foo"}}
+{{index $t 2}}{{index $t 0 }}{{index $t 1}}
+{{/* Prints foo1a *}}
+```
+
+### Reflection:
+
+- typeOf: Takes an interface and returns a string representation of the type.
+ For pointers, this will return a type prefixed with an asterisk(`*`). So
+ a pointer to type `Foo` will be `*Foo`.
+- typeIs: Compares an interface with a string name, and returns true if they match.
+ Note that a pointer will not match a reference. For example `*Foo` will not
+ match `Foo`.
+- typeIsLike: returns true if the interface is of the given type, or
+ is a pointer to the given type.
+- kindOf: Takes an interface and returns a string representation of its kind.
+- kindIs: Returns true if the given string matches the kind of the given interface.
+
+ Note: None of these can test whether or not something implements a given
+ interface, since doing so would require compiling the interface in ahead of
+ time.
+
+
+### Math Functions:
+
+Integer functions will convert integers of any width to `int64`. If a
+string is passed in, functions will attempt to conver with
+`strconv.ParseInt(s, 1064)`. If this fails, the value will be treated as 0.
+
+- add1: Increment an integer by 1
+- add: Sum integers. `add 1 2 3` renders `6`
+- sub: Subtract the second integer from the first
+- div: Divide the first integer by the second
+- mod: Module of first integer divided by second
+- mul: Multiply integers integers
+- max (biggest): Return the biggest of a series of integers. `max 1 2 3`
+ returns `3`.
+- min: Return the smallest of a series of integers. `min 1 2 3` returns
+ `1`.
+
+
+## Principles:
+
+The following principles were used in deciding on which functions to add, and
+determining how to implement them.
+
+- Template functions should be used to build layout. Therefore, the following
+ types of operations are within the domain of template functions:
+ - Formatting
+ - Layout
+ - Simple type conversions
+ - Utilities that assist in handling common formatting and layout needs (e.g. arithmetic)
+- Template functions should not return errors unless there is no way to print
+ a sensible value. For example, converting a string to an integer should not
+ produce an error if conversion fails. Instead, it should display a default
+ value that can be displayed.
+- Simple math is necessary for grid layouts, pagers, and so on. Complex math
+ (anything other than arithmetic) should be done outside of templates.
+- Template functions only deal with the data passed into them. They never retrieve
+ data from a source.
+- Finally, do not override core Go template functions.
diff --git a/vendor/github.com/Masterminds/sprig/functions.go b/vendor/github.com/Masterminds/sprig/functions.go
new file mode 100644
index 000000000..601f3b580
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/functions.go
@@ -0,0 +1,895 @@
+/*
+Sprig: Template functions for Go.
+
+This package contains a number of utility functions for working with data
+inside of Go `html/template` and `text/template` files.
+
+To add these functions, use the `template.Funcs()` method:
+
+ t := templates.New("foo").Funcs(sprig.FuncMap())
+
+Note that you should add the function map before you parse any template files.
+
+ In several cases, Sprig reverses the order of arguments from the way they
+ appear in the standard library. This is to make it easier to pipe
+ arguments into functions.
+
+Date Functions
+
+ - date FORMAT TIME: Format a date, where a date is an integer type or a time.Time type, and
+ format is a time.Format formatting string.
+ - dateModify: Given a date, modify it with a duration: `date_modify "-1.5h" now`. If the duration doesn't
+ parse, it returns the time unaltered. See `time.ParseDuration` for info on duration strings.
+ - now: Current time.Time, for feeding into date-related functions.
+ - htmlDate TIME: Format a date for use in the value field of an HTML "date" form element.
+ - dateInZone FORMAT TIME TZ: Like date, but takes three arguments: format, timestamp,
+ timezone.
+ - htmlDateInZone TIME TZ: Like htmlDate, but takes two arguments: timestamp,
+ timezone.
+
+String Functions
+
+ - abbrev: Truncate a string with ellipses. `abbrev 5 "hello world"` yields "he..."
+ - abbrevboth: Abbreviate from both sides, yielding "...lo wo..."
+ - trunc: Truncate a string (no suffix). `trunc 5 "Hello World"` yields "hello".
+ - trim: strings.TrimSpace
+ - trimAll: strings.Trim, but with the argument order reversed `trimAll "$" "$5.00"` or `"$5.00 | trimAll "$"`
+ - trimSuffix: strings.TrimSuffix, but with the argument order reversed: `trimSuffix "-" "ends-with-"`
+ - trimPrefix: strings.TrimPrefix, but with the argument order reversed `trimPrefix "$" "$5"`
+ - upper: strings.ToUpper
+ - lower: strings.ToLower
+ - nospace: Remove all space characters from a string. `nospace "h e l l o"` becomes "hello"
+ - title: strings.Title
+ - untitle: Remove title casing
+ - repeat: strings.Repeat, but with the arguments switched: `repeat count str`. (This simplifies common pipelines)
+ - substr: Given string, start, and length, return a substr.
+ - initials: Given a multi-word string, return the initials. `initials "Matt Butcher"` returns "MB"
+ - randAlphaNum: Given a length, generate a random alphanumeric sequence
+ - randAlpha: Given a length, generate an alphabetic string
+ - randAscii: Given a length, generate a random ASCII string (symbols included)
+ - randNumeric: Given a length, generate a string of digits.
+ - wrap: Force a line wrap at the given width. `wrap 80 "imagine a longer string"`
+ - wrapWith: Wrap a line at the given length, but using 'sep' instead of a newline. `wrapWith 50, "
", $html`
+ - contains: strings.Contains, but with the arguments switched: `contains substr str`. (This simplifies common pipelines)
+ - hasPrefix: strings.hasPrefix, but with the arguments switched
+ - hasSuffix: strings.hasSuffix, but with the arguments switched
+ - quote: Wrap string(s) in double quotation marks, escape the contents by adding '\' before '"'.
+ - squote: Wrap string(s) in double quotation marks, does not escape content.
+ - cat: Concatenate strings, separating them by spaces. `cat $a $b $c`.
+ - indent: Indent a string using space characters. `indent 4 "foo\nbar"` produces " foo\n bar"
+ - replace: Replace an old with a new in a string: `$name | replace " " "-"`
+ - plural: Choose singular or plural based on length: `len $fish | plural "one anchovy" "many anchovies"`
+ - sha256sum: Generate a hex encoded sha256 hash of the input
+
+String Slice Functions:
+
+ - join: strings.Join, but as `join SEP SLICE`
+ - split: strings.Split, but as `split SEP STRING`. The results are returned
+ as a map with the indexes set to _N, where N is an integer starting from 0.
+ Use it like this: `{{$v := "foo/bar/baz" | split "/"}}{{$v._0}}` (Prints `foo`)
+
+Integer Slice Functions:
+
+ - until: Given an integer, returns a slice of counting integers from 0 to one
+ less than the given integer: `range $i, $e := until 5`
+ - untilStep: Given start, stop, and step, return an integer slice starting at
+ 'start', stopping at `stop`, and incrementing by 'step. This is the same
+ as Python's long-form of 'range'.
+
+Conversions:
+
+ - atoi: Convert a string to an integer. 0 if the integer could not be parsed.
+ - in64: Convert a string or another numeric type to an int64.
+ - int: Convert a string or another numeric type to an int.
+ - float64: Convert a string or another numeric type to a float64.
+
+Defaults:
+
+ - default: Give a default value. Used like this: trim " "| default "empty".
+ Since trim produces an empty string, the default value is returned. For
+ things with a length (strings, slices, maps), len(0) will trigger the default.
+ For numbers, the value 0 will trigger the default. For booleans, false will
+ trigger the default. For structs, the default is never returned (there is
+ no clear empty condition). For everything else, nil value triggers a default.
+ - empty: Return true if the given value is the zero value for its type.
+ Caveats: structs are always non-empty. This should match the behavior of
+ {{if pipeline}}, but can be used inside of a pipeline.
+
+OS:
+ - env: Resolve an environment variable
+ - expandenv: Expand a string through the environment
+
+File Paths:
+ - base: Return the last element of a path. https://golang.org/pkg/path#Base
+ - dir: Remove the last element of a path. https://golang.org/pkg/path#Dir
+ - clean: Clean a path to the shortest equivalent name. (e.g. remove "foo/.."
+ from "foo/../bar.html") https://golang.org/pkg/path#Clean
+ - ext: https://golang.org/pkg/path#Ext
+ - isAbs: https://golang.org/pkg/path#IsAbs
+
+Encoding:
+ - b64enc: Base 64 encode a string.
+ - b64dec: Base 64 decode a string.
+
+Reflection:
+
+ - typeOf: Takes an interface and returns a string representation of the type.
+ For pointers, this will return a type prefixed with an asterisk(`*`). So
+ a pointer to type `Foo` will be `*Foo`.
+ - typeIs: Compares an interface with a string name, and returns true if they match.
+ Note that a pointer will not match a reference. For example `*Foo` will not
+ match `Foo`.
+ - typeIsLike: Compares an interface with a string name and returns true if
+ the interface is that `name` or that `*name`. In other words, if the given
+ value matches the given type or is a pointer to the given type, this returns
+ true.
+ - kindOf: Takes an interface and returns a string representation of its kind.
+ - kindIs: Returns true if the given string matches the kind of the given interface.
+
+ Note: None of these can test whether or not something implements a given
+ interface, since doing so would require compiling the interface in ahead of
+ time.
+
+Data Structures:
+
+ - tuple: Takes an arbitrary list of items and returns a slice of items. Its
+ tuple-ish properties are mainly gained through the template idiom, and not
+ through an API provided here.
+ - dict: Takes a list of name/values and returns a map[string]interface{}.
+ The first parameter is converted to a string and stored as a key, the
+ second parameter is treated as the value. And so on, with odds as keys and
+ evens as values. If the function call ends with an odd, the last key will
+ be assigned the empty string. Non-string keys are converted to strings as
+ follows: []byte are converted, fmt.Stringers will have String() called.
+ errors will have Error() called. All others will be passed through
+ fmt.Sprtinf("%v").
+ - set: Takes a dict, a key, and a value, and sets that key/value pair in
+ the dict. `set $dict $key $value`. For convenience, it returns the dict,
+ even though the dict was modified in place.
+ - unset: Takes a dict and a key, and deletes that key/value pair from the
+ dict. `unset $dict $key`. This returns the dict for convenience.
+ - hasKey: Takes a dict and a key, and returns boolean true if the key is in
+ the dict.
+
+Math Functions:
+
+Integer functions will convert integers of any width to `int64`. If a
+string is passed in, functions will attempt to convert with
+`strconv.ParseInt(s, 1064)`. If this fails, the value will be treated as 0.
+
+ - add1: Increment an integer by 1
+ - add: Sum an arbitrary number of integers
+ - sub: Subtract the second integer from the first
+ - div: Divide the first integer by the second
+ - mod: Module of first integer divided by second
+ - mul: Multiply integers
+ - max: Return the biggest of a series of one or more integers
+ - min: Return the smallest of a series of one or more integers
+ - biggest: DEPRECATED. Return the biggest of a series of one or more integers
+
+Crypto Functions:
+
+ - genPrivateKey: Generate a private key for the given cryptosystem. If no
+ argument is supplied, by default it will generate a private key using
+ the RSA algorithm. Accepted values are `rsa`, `dsa`, and `ecdsa`.
+
+*/
+package sprig
+
+import (
+ "crypto/dsa"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/sha256"
+ "crypto/x509"
+ "encoding/asn1"
+ "encoding/base32"
+ "encoding/base64"
+ "encoding/hex"
+ "encoding/pem"
+ "fmt"
+ "html/template"
+ "math"
+ "math/big"
+ "os"
+ "path"
+ "reflect"
+ "strconv"
+ "strings"
+ ttemplate "text/template"
+ "time"
+
+ util "github.com/aokoli/goutils"
+ uuid "github.com/satori/go.uuid"
+)
+
+// Produce the function map.
+//
+// Use this to pass the functions into the template engine:
+//
+// tpl := template.New("foo").Funcs(sprig.FuncMap))
+//
+func FuncMap() template.FuncMap {
+ return HtmlFuncMap()
+}
+
+// HermeticTextFuncMap returns a 'text/template'.FuncMap with only repeatable functions.
+func HermeticTxtFuncMap() ttemplate.FuncMap {
+ r := TxtFuncMap()
+ for _, name := range nonhermeticFunctions {
+ delete(r, name)
+ }
+ return r
+}
+
+// HermeticHtmlFuncMap returns an 'html/template'.Funcmap with only repeatable functions.
+func HermeticHtmlFuncMap() template.FuncMap {
+ r := HtmlFuncMap()
+ for _, name := range nonhermeticFunctions {
+ delete(r, name)
+ }
+ return r
+}
+
+// TextFuncMap returns a 'text/template'.FuncMap
+func TxtFuncMap() ttemplate.FuncMap {
+ return ttemplate.FuncMap(genericMap)
+}
+
+// HtmlFuncMap returns an 'html/template'.Funcmap
+func HtmlFuncMap() template.FuncMap {
+ return template.FuncMap(genericMap)
+}
+
+// These functions are not guaranteed to evaluate to the same result for given input, because they
+// refer to the environemnt or global state.
+var nonhermeticFunctions = []string{
+ // Date functions
+ "date",
+ "date_in_zone",
+ "date_modify",
+ "now",
+ "htmlDate",
+ "htmlDateInZone",
+ "dateInZone",
+ "dateModify",
+
+ // Strings
+ "randAlphaNum",
+ "randAlpha",
+ "randAscii",
+ "randNumeric",
+ "uuidv4",
+
+ // OS
+ "env",
+ "expandenv",
+}
+
+var genericMap = map[string]interface{}{
+ "hello": func() string { return "Hello!" },
+
+ // Date functions
+ "date": date,
+ "date_in_zone": dateInZone,
+ "date_modify": dateModify,
+ "now": func() time.Time { return time.Now() },
+ "htmlDate": htmlDate,
+ "htmlDateInZone": htmlDateInZone,
+ "dateInZone": dateInZone,
+ "dateModify": dateModify,
+
+ // Strings
+ "abbrev": abbrev,
+ "abbrevboth": abbrevboth,
+ "trunc": trunc,
+ "trim": strings.TrimSpace,
+ "upper": strings.ToUpper,
+ "lower": strings.ToLower,
+ "title": strings.Title,
+ "untitle": untitle,
+ "substr": substring,
+ // Switch order so that "foo" | repeat 5
+ "repeat": func(count int, str string) string { return strings.Repeat(str, count) },
+ // Deprecated: Use trimAll.
+ "trimall": func(a, b string) string { return strings.Trim(b, a) },
+ // Switch order so that "$foo" | trimall "$"
+ "trimAll": func(a, b string) string { return strings.Trim(b, a) },
+ "trimSuffix": func(a, b string) string { return strings.TrimSuffix(b, a) },
+ "trimPrefix": func(a, b string) string { return strings.TrimPrefix(b, a) },
+ "nospace": util.DeleteWhiteSpace,
+ "initials": initials,
+ "randAlphaNum": randAlphaNumeric,
+ "randAlpha": randAlpha,
+ "randAscii": randAscii,
+ "randNumeric": randNumeric,
+ "swapcase": util.SwapCase,
+ "wrap": func(l int, s string) string { return util.Wrap(s, l) },
+ "wrapWith": func(l int, sep, str string) string { return util.WrapCustom(str, l, sep, true) },
+ // Switch order so that "foobar" | contains "foo"
+ "contains": func(substr string, str string) bool { return strings.Contains(str, substr) },
+ "hasPrefix": func(substr string, str string) bool { return strings.HasPrefix(str, substr) },
+ "hasSuffix": func(substr string, str string) bool { return strings.HasSuffix(str, substr) },
+ "quote": quote,
+ "squote": squote,
+ "cat": cat,
+ "indent": indent,
+ "replace": replace,
+ "plural": plural,
+ "sha256sum": sha256sum,
+
+ // Wrap Atoi to stop errors.
+ "atoi": func(a string) int { i, _ := strconv.Atoi(a); return i },
+ "int64": toInt64,
+ "int": toInt,
+ "float64": toFloat64,
+
+ //"gt": func(a, b int) bool {return a > b},
+ //"gte": func(a, b int) bool {return a >= b},
+ //"lt": func(a, b int) bool {return a < b},
+ //"lte": func(a, b int) bool {return a <= b},
+
+ // split "/" foo/bar returns map[int]string{0: foo, 1: bar}
+ "split": split,
+
+ "until": until,
+ "untilStep": untilStep,
+
+ // VERY basic arithmetic.
+ "add1": func(i interface{}) int64 { return toInt64(i) + 1 },
+ "add": func(i ...interface{}) int64 {
+ var a int64 = 0
+ for _, b := range i {
+ a += toInt64(b)
+ }
+ return a
+ },
+ "sub": func(a, b interface{}) int64 { return toInt64(a) - toInt64(b) },
+ "div": func(a, b interface{}) int64 { return toInt64(a) / toInt64(b) },
+ "mod": func(a, b interface{}) int64 { return toInt64(a) % toInt64(b) },
+ "mul": func(a interface{}, v ...interface{}) int64 {
+ val := toInt64(a)
+ for _, b := range v {
+ val = val * toInt64(b)
+ }
+ return val
+ },
+ "biggest": max,
+ "max": max,
+ "min": min,
+
+ // string slices. Note that we reverse the order b/c that's better
+ // for template processing.
+ "join": func(sep string, ss []string) string { return strings.Join(ss, sep) },
+
+ // Defaults
+ "default": dfault,
+ "empty": empty,
+
+ // Reflection
+ "typeOf": typeOf,
+ "typeIs": typeIs,
+ "typeIsLike": typeIsLike,
+ "kindOf": kindOf,
+ "kindIs": kindIs,
+
+ // OS:
+ "env": func(s string) string { return os.Getenv(s) },
+ "expandenv": func(s string) string { return os.ExpandEnv(s) },
+
+ // File Paths:
+ "base": path.Base,
+ "dir": path.Dir,
+ "clean": path.Clean,
+ "ext": path.Ext,
+ "isAbs": path.IsAbs,
+
+ // Encoding:
+ "b64enc": base64encode,
+ "b64dec": base64decode,
+ "b32enc": base32encode,
+ "b32dec": base32decode,
+
+ // Data Structures:
+ "tuple": tuple,
+ "dict": dict,
+ "set": set,
+ "unset": unset,
+ "hasKey": hasKey,
+
+ // Crypto:
+ "genPrivateKey": generatePrivateKey,
+
+ // UUIDs:
+ "uuidv4": uuidv4,
+}
+
+func split(sep, orig string) map[string]string {
+ parts := strings.Split(orig, sep)
+ res := make(map[string]string, len(parts))
+ for i, v := range parts {
+ res["_"+strconv.Itoa(i)] = v
+ }
+ return res
+}
+
+// substring creates a substring of the given string.
+//
+// If start is < 0, this calls string[:length].
+//
+// If start is >= 0 and length < 0, this calls string[start:]
+//
+// Otherwise, this calls string[start, length].
+func substring(start, length int, s string) string {
+ if start < 0 {
+ return s[:length]
+ }
+ if length < 0 {
+ return s[start:]
+ }
+ return s[start:length]
+}
+
+// Given a format and a date, format the date string.
+//
+// Date can be a `time.Time` or an `int, int32, int64`.
+// In the later case, it is treated as seconds since UNIX
+// epoch.
+func date(fmt string, date interface{}) string {
+ return dateInZone(fmt, date, "Local")
+}
+
+func htmlDate(date interface{}) string {
+ return dateInZone("2006-01-02", date, "Local")
+}
+
+func htmlDateInZone(date interface{}, zone string) string {
+ return dateInZone("2006-01-02", date, zone)
+}
+
+func dateInZone(fmt string, date interface{}, zone string) string {
+ var t time.Time
+ switch date := date.(type) {
+ default:
+ t = time.Now()
+ case time.Time:
+ t = date
+ case int64:
+ t = time.Unix(date, 0)
+ case int:
+ t = time.Unix(int64(date), 0)
+ case int32:
+ t = time.Unix(int64(date), 0)
+ }
+
+ loc, err := time.LoadLocation(zone)
+ if err != nil {
+ loc, _ = time.LoadLocation("UTC")
+ }
+
+ return t.In(loc).Format(fmt)
+}
+
+func dateModify(fmt string, date time.Time) time.Time {
+ d, err := time.ParseDuration(fmt)
+ if err != nil {
+ return date
+ }
+ return date.Add(d)
+}
+
+func max(a interface{}, i ...interface{}) int64 {
+ aa := toInt64(a)
+ for _, b := range i {
+ bb := toInt64(b)
+ if bb > aa {
+ aa = bb
+ }
+ }
+ return aa
+}
+
+func min(a interface{}, i ...interface{}) int64 {
+ aa := toInt64(a)
+ for _, b := range i {
+ bb := toInt64(b)
+ if bb < aa {
+ aa = bb
+ }
+ }
+ return aa
+}
+
+// dfault checks whether `given` is set, and returns default if not set.
+//
+// This returns `d` if `given` appears not to be set, and `given` otherwise.
+//
+// For numeric types 0 is unset.
+// For strings, maps, arrays, and slices, len() = 0 is considered unset.
+// For bool, false is unset.
+// Structs are never considered unset.
+//
+// For everything else, including pointers, a nil value is unset.
+func dfault(d interface{}, given ...interface{}) interface{} {
+
+ if empty(given) || empty(given[0]) {
+ return d
+ }
+ return given[0]
+}
+
+// empty returns true if the given value has the zero value for its type.
+func empty(given interface{}) bool {
+ g := reflect.ValueOf(given)
+ if !g.IsValid() {
+ return true
+ }
+
+ // Basically adapted from text/template.isTrue
+ switch g.Kind() {
+ default:
+ return g.IsNil()
+ case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
+ return g.Len() == 0
+ case reflect.Bool:
+ return g.Bool() == false
+ case reflect.Complex64, reflect.Complex128:
+ return g.Complex() == 0
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return g.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return g.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ return g.Float() == 0
+ case reflect.Struct:
+ return false
+ }
+ return true
+}
+
+// typeIs returns true if the src is the type named in target.
+func typeIs(target string, src interface{}) bool {
+ return target == typeOf(src)
+}
+
+func typeIsLike(target string, src interface{}) bool {
+ t := typeOf(src)
+ return target == t || "*"+target == t
+}
+
+func typeOf(src interface{}) string {
+ return fmt.Sprintf("%T", src)
+}
+
+func kindIs(target string, src interface{}) bool {
+ return target == kindOf(src)
+}
+
+func kindOf(src interface{}) string {
+ return reflect.ValueOf(src).Kind().String()
+}
+
+func base64encode(v string) string {
+ return base64.StdEncoding.EncodeToString([]byte(v))
+}
+
+func base64decode(v string) string {
+ data, err := base64.StdEncoding.DecodeString(v)
+ if err != nil {
+ return err.Error()
+ }
+ return string(data)
+}
+
+func base32encode(v string) string {
+ return base32.StdEncoding.EncodeToString([]byte(v))
+}
+
+func base32decode(v string) string {
+ data, err := base32.StdEncoding.DecodeString(v)
+ if err != nil {
+ return err.Error()
+ }
+ return string(data)
+}
+
+func abbrev(width int, s string) string {
+ if width < 4 {
+ return s
+ }
+ r, _ := util.Abbreviate(s, width)
+ return r
+}
+
+func abbrevboth(left, right int, s string) string {
+ if right < 4 || left > 0 && right < 7 {
+ return s
+ }
+ r, _ := util.AbbreviateFull(s, left, right)
+ return r
+}
+func initials(s string) string {
+ // Wrap this just to eliminate the var args, which templates don't do well.
+ return util.Initials(s)
+}
+
+func randAlphaNumeric(count int) string {
+ // It is not possible, it appears, to actually generate an error here.
+ r, _ := util.RandomAlphaNumeric(count)
+ return r
+}
+
+func randAlpha(count int) string {
+ r, _ := util.RandomAlphabetic(count)
+ return r
+}
+
+func randAscii(count int) string {
+ r, _ := util.RandomAscii(count)
+ return r
+}
+
+func randNumeric(count int) string {
+ r, _ := util.RandomNumeric(count)
+ return r
+}
+
+func untitle(str string) string {
+ return util.Uncapitalize(str)
+}
+
+func quote(str ...interface{}) string {
+ out := make([]string, len(str))
+ for i, s := range str {
+ out[i] = fmt.Sprintf("%q", strval(s))
+ }
+ return strings.Join(out, " ")
+}
+
+func squote(str ...interface{}) string {
+ out := make([]string, len(str))
+ for i, s := range str {
+ out[i] = fmt.Sprintf("'%v'", s)
+ }
+ return strings.Join(out, " ")
+}
+
+func tuple(v ...interface{}) []interface{} {
+ return v
+}
+
+func set(d map[string]interface{}, key string, value interface{}) map[string]interface{} {
+ d[key] = value
+ return d
+}
+
+func unset(d map[string]interface{}, key string) map[string]interface{} {
+ delete(d, key)
+ return d
+}
+
+func hasKey(d map[string]interface{}, key string) bool {
+ _, ok := d[key]
+ return ok
+}
+
+func dict(v ...interface{}) map[string]interface{} {
+ dict := map[string]interface{}{}
+ lenv := len(v)
+ for i := 0; i < lenv; i += 2 {
+ key := strval(v[i])
+ if i+1 >= lenv {
+ dict[key] = ""
+ continue
+ }
+ dict[key] = v[i+1]
+ }
+ return dict
+}
+
+func strval(v interface{}) string {
+ switch v := v.(type) {
+ case string:
+ return v
+ case []byte:
+ return string(v)
+ case error:
+ return v.Error()
+ case fmt.Stringer:
+ return v.String()
+ default:
+ return fmt.Sprintf("%v", v)
+ }
+}
+
+// toFloat64 converts 64-bit floats
+func toFloat64(v interface{}) float64 {
+ if str, ok := v.(string); ok {
+ iv, err := strconv.ParseFloat(str, 64)
+ if err != nil {
+ return 0
+ }
+ return iv
+ }
+
+ val := reflect.Indirect(reflect.ValueOf(v))
+ switch val.Kind() {
+ case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+ return float64(val.Int())
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32:
+ return float64(val.Uint())
+ case reflect.Uint, reflect.Uint64:
+ return float64(val.Uint())
+ case reflect.Float32, reflect.Float64:
+ return val.Float()
+ case reflect.Bool:
+ if val.Bool() == true {
+ return 1
+ }
+ return 0
+ default:
+ return 0
+ }
+}
+
+func toInt(v interface{}) int {
+ //It's not optimal. Bud I don't want duplicate toInt64 code.
+ return int(toInt64(v))
+}
+
+// toInt64 converts integer types to 64-bit integers
+func toInt64(v interface{}) int64 {
+ if str, ok := v.(string); ok {
+ iv, err := strconv.ParseInt(str, 10, 64)
+ if err != nil {
+ return 0
+ }
+ return iv
+ }
+
+ val := reflect.Indirect(reflect.ValueOf(v))
+ switch val.Kind() {
+ case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+ return val.Int()
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32:
+ return int64(val.Uint())
+ case reflect.Uint, reflect.Uint64:
+ tv := val.Uint()
+ if tv <= math.MaxInt64 {
+ return int64(tv)
+ }
+ // TODO: What is the sensible thing to do here?
+ return math.MaxInt64
+ case reflect.Float32, reflect.Float64:
+ return int64(val.Float())
+ case reflect.Bool:
+ if val.Bool() == true {
+ return 1
+ }
+ return 0
+ default:
+ return 0
+ }
+}
+
+func generatePrivateKey(typ string) string {
+ var priv interface{}
+ var err error
+ switch typ {
+ case "", "rsa":
+ // good enough for government work
+ priv, err = rsa.GenerateKey(rand.Reader, 4096)
+ case "dsa":
+ key := new(dsa.PrivateKey)
+ // again, good enough for government work
+ if err = dsa.GenerateParameters(&key.Parameters, rand.Reader, dsa.L2048N256); err != nil {
+ return fmt.Sprintf("failed to generate dsa params: %s", err)
+ }
+ err = dsa.GenerateKey(key, rand.Reader)
+ priv = key
+ case "ecdsa":
+ // again, good enough for government work
+ priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ default:
+ return "Unknown type " + typ
+ }
+ if err != nil {
+ return fmt.Sprintf("failed to generate private key: %s", err)
+ }
+
+ return string(pem.EncodeToMemory(pemBlockForKey(priv)))
+}
+
+type DSAKeyFormat struct {
+ Version int
+ P, Q, G, Y, X *big.Int
+}
+
+func pemBlockForKey(priv interface{}) *pem.Block {
+ switch k := priv.(type) {
+ case *rsa.PrivateKey:
+ return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
+ case *dsa.PrivateKey:
+ val := DSAKeyFormat{
+ P: k.P, Q: k.Q, G: k.G,
+ Y: k.Y, X: k.X,
+ }
+ bytes, _ := asn1.Marshal(val)
+ return &pem.Block{Type: "DSA PRIVATE KEY", Bytes: bytes}
+ case *ecdsa.PrivateKey:
+ b, _ := x509.MarshalECPrivateKey(k)
+ return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
+ default:
+ return nil
+ }
+}
+
+func trunc(c int, s string) string {
+ if len(s) <= c {
+ return s
+ }
+ return s[0:c]
+}
+
+func cat(v ...interface{}) string {
+ r := strings.TrimSpace(strings.Repeat("%v ", len(v)))
+ return fmt.Sprintf(r, v...)
+}
+
+func indent(spaces int, v string) string {
+ pad := strings.Repeat(" ", spaces)
+ return pad + strings.Replace(v, "\n", "\n"+pad, -1)
+}
+
+func replace(old, new, src string) string {
+ return strings.Replace(src, old, new, -1)
+}
+
+func plural(one, many string, count int) string {
+ if count == 1 {
+ return one
+ }
+ return many
+}
+
+func sha256sum(input string) string {
+ hash := sha256.Sum256([]byte(input))
+ return hex.EncodeToString(hash[:])
+}
+
+func until(count int) []int {
+ step := 1
+ if count < 0 {
+ step = -1
+ }
+ return untilStep(0, count, step)
+}
+
+func untilStep(start, stop, step int) []int {
+ v := []int{}
+
+ if stop < start {
+ if step >= 0 {
+ return v
+ }
+ for i := start; i > stop; i += step {
+ v = append(v, i)
+ }
+ return v
+ }
+
+ if step <= 0 {
+ return v
+ }
+ for i := start; i < stop; i += step {
+ v = append(v, i)
+ }
+ return v
+}
+
+// uuidv4 provides a safe and secure UUID v4 implementation
+func uuidv4() string {
+ return fmt.Sprintf("%s", uuid.NewV4())
+}
diff --git a/vendor/github.com/Masterminds/sprig/glide.lock b/vendor/github.com/Masterminds/sprig/glide.lock
new file mode 100644
index 000000000..c3894b565
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/glide.lock
@@ -0,0 +1,8 @@
+hash: a8ed42a70698b4d199b5de7fa33e7c48251651e6ccf97d007f546cb72a5d0f8f
+updated: 2016-09-30T12:23:39.512939213-06:00
+imports:
+- name: github.com/aokoli/goutils
+ version: 9c37978a95bd5c709a15883b6242714ea6709e64
+- name: github.com/satori/go.uuid
+ version: 879c5887cd475cd7864858769793b2ceb0d44feb
+testImports: []
diff --git a/vendor/github.com/Masterminds/sprig/glide.yaml b/vendor/github.com/Masterminds/sprig/glide.yaml
new file mode 100644
index 000000000..2fc21e24c
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/glide.yaml
@@ -0,0 +1,5 @@
+package: github.com/Masterminds/sprig
+import:
+- package: github.com/aokoli/goutils
+- package: github.com/satori/go.uuid
+ version: ^1.1.0
diff --git a/vendor/github.com/aokoli/goutils/LICENSE.txt b/vendor/github.com/aokoli/goutils/LICENSE.txt
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/vendor/github.com/aokoli/goutils/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/aokoli/goutils/README.md b/vendor/github.com/aokoli/goutils/README.md
new file mode 100644
index 000000000..9d8a42df8
--- /dev/null
+++ b/vendor/github.com/aokoli/goutils/README.md
@@ -0,0 +1,72 @@
+GoUtils
+===========
+
+GoUtils provides users with utility functions to manipulate strings in various ways. It is a Go implementation of some
+string manipulation libraries of Java Apache Commons. GoUtils includes the following Java Apache Commons classes:
+* WordUtils
+* RandomStringUtils
+* StringUtils (partial implementation)
+
+## Installation
+If you have Go set up on your system, from the GOPATH directory within the command line/terminal, enter this:
+
+ go get github.com/aokoli/goutils
+
+If you do not have Go set up on your system, please follow the [Go installation directions from the documenation](http://golang.org/doc/install), and then follow the instructions above to install GoUtils.
+
+
+## Documentation
+GoUtils doc is available here: [](https://godoc.org/github.com/aokoli/goutils)
+
+
+## Usage
+The code snippets below show examples of how to use GoUtils. Some functions return errors while others do not. The first instance below, which does not return an error, is the `Initials` function (located within the `wordutils.go` file).
+
+ package main
+
+ import (
+ "fmt"
+ "github.com/aokoli/goutils"
+ )
+
+ func main() {
+
+ // EXAMPLE 1: A goutils function which returns no errors
+ fmt.Println (goutils.Initials("John Doe Foo")) // Prints out "JDF"
+
+ }
+Some functions return errors mainly due to illegal arguements used as parameters. The code example below illustrates how to deal with function that returns an error. In this instance, the function is the `Random` function (located within the `randomstringutils.go` file).
+
+ package main
+
+ import (
+ "fmt"
+ "github.com/aokoli/goutils"
+ )
+
+ func main() {
+
+ // EXAMPLE 2: A goutils function which returns an error
+ rand1, err1 := goutils.Random (-1, 0, 0, true, true)
+
+ if err1 != nil {
+ fmt.Println(err1) // Prints out error message because -1 was entered as the first parameter in goutils.Random(...)
+ } else {
+ fmt.Println(rand1)
+ }
+
+ }
+
+## License
+GoUtils is licensed under the Apache License, Version 2.0. Please check the LICENSE.txt file or visit http://www.apache.org/licenses/LICENSE-2.0 for a copy of the license.
+
+## Issue Reporting
+Make suggestions or report issues using the Git issue tracker: https://github.com/aokoli/goutils/issues
+
+## Website
+* [GoUtils webpage](http://aokoli.github.io/goutils/)
+
+## Mailing List
+Contact [okolialex@gmail.com](mailto:okolialex@mail.com) to be added to the mailing list. You will get updates on the
+status of the project and the potential direction it will be heading.
+
diff --git a/vendor/github.com/aokoli/goutils/randomstringutils.go b/vendor/github.com/aokoli/goutils/randomstringutils.go
new file mode 100644
index 000000000..db395a0a1
--- /dev/null
+++ b/vendor/github.com/aokoli/goutils/randomstringutils.go
@@ -0,0 +1,259 @@
+/*
+Copyright 2014 Alexander Okoli
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package goutils
+
+
+import (
+ "fmt"
+ "unicode"
+ "math"
+ "math/rand"
+ "time"
+)
+
+
+// Provides the time-based seed used to generate random #s
+var RANDOM = rand.New(rand.NewSource(time.Now().UnixNano()))
+
+/*
+RandomNonAlphaNumeric creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of all characters (ASCII/Unicode values between 0 to 2,147,483,647 (math.MaxInt32)).
+
+Parameter:
+ count - the length of random string to create
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
+*/
+func RandomNonAlphaNumeric (count int) (string, error) {
+ return RandomAlphaNumericCustom(count, false, false)
+}
+
+
+/*
+RandomAscii creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of characters whose ASCII value is between 32 and 126 (inclusive).
+
+Parameter:
+ count - the length of random string to create
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
+*/
+func RandomAscii(count int) (string, error) {
+ return Random(count, 32, 127, false, false)
+}
+
+
+/*
+RandomNumeric creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of numeric characters.
+
+Parameter:
+ count - the length of random string to create
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
+*/
+func RandomNumeric (count int) (string, error) {
+ return Random(count, 0, 0, false, true)
+}
+
+
+/*
+RandomAlphabetic creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments.
+
+Parameters:
+ count - the length of random string to create
+ letters - if true, generated string may include alphabetic characters
+ numbers - if true, generated string may include numeric characters
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
+*/
+func RandomAlphabetic (count int) (string, error) {
+ return Random(count, 0, 0, true, false)
+}
+
+
+/*
+RandomAlphaNumeric creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of alpha-numeric characters.
+
+Parameter:
+ count - the length of random string to create
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
+*/
+func RandomAlphaNumeric (count int) (string, error) {
+ return Random(count, 0, 0, true, true)
+}
+
+/*
+RandomAlphaNumericCustom creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments.
+
+Parameters:
+ count - the length of random string to create
+ letters - if true, generated string may include alphabetic characters
+ numbers - if true, generated string may include numeric characters
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
+*/
+func RandomAlphaNumericCustom (count int, letters bool, numbers bool) (string, error) {
+ return Random(count, 0, 0, letters, numbers)
+}
+
+
+/*
+Random creates a random string based on a variety of options, using default source of randomness.
+This method has exactly the same semantics as RandomSeed(int, int, int, bool, bool, []char, *rand.Rand), but
+instead of using an externally supplied source of randomness, it uses the internal *rand.Rand instance.
+
+Parameters:
+ count - the length of random string to create
+ start - the position in set of chars (ASCII/Unicode int) to start at
+ end - the position in set of chars (ASCII/Unicode int) to end before
+ letters - if true, generated string may include alphabetic characters
+ numbers - if true, generated string may include numeric characters
+ chars - the set of chars to choose randoms from. If nil, then it will use the set of all chars.
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
+*/
+func Random (count int, start int, end int, letters bool, numbers bool, chars ...rune) (string, error) {
+ return RandomSeed (count, start, end, letters, numbers, chars, RANDOM)
+}
+
+
+/*
+RandomSeed creates a random string based on a variety of options, using supplied source of randomness.
+If the parameters start and end are both 0, start and end are set to ' ' and 'z', the ASCII printable characters, will be used,
+unless letters and numbers are both false, in which case, start and end are set to 0 and math.MaxInt32, respectively.
+If chars is not nil, characters stored in chars that are between start and end are chosen.
+This method accepts a user-supplied *rand.Rand instance to use as a source of randomness. By seeding a single *rand.Rand instance
+with a fixed seed and using it for each call, the same random sequence of strings can be generated repeatedly and predictably.
+
+Parameters:
+ count - the length of random string to create
+ start - the position in set of chars (ASCII/Unicode decimals) to start at
+ end - the position in set of chars (ASCII/Unicode decimals) to end before
+ letters - if true, generated string may include alphabetic characters
+ numbers - if true, generated string may include numeric characters
+ chars - the set of chars to choose randoms from. If nil, then it will use the set of all chars.
+ random - a source of randomness.
+
+Returns:
+ string - the random string
+ error - an error stemming from invalid parameters: if count < 0; or the provided chars array is empty; or end <= start; or end > len(chars)
+*/
+func RandomSeed (count int, start int, end int, letters bool, numbers bool, chars []rune, random *rand.Rand) (string, error) {
+
+ if count == 0 {
+ return "", nil
+ } else if count < 0 {
+ err := fmt.Errorf("randomstringutils illegal argument: Requested random string length %v is less than 0.", count) // equiv to err := errors.New("...")
+ return "", err
+ }
+ if chars != nil && len(chars) == 0 {
+ err := fmt.Errorf("randomstringutils illegal argument: The chars array must not be empty")
+ return "", err
+ }
+
+ if start == 0 && end == 0 {
+ if chars != nil {
+ end = len(chars)
+ } else {
+ if !letters && !numbers {
+ end = math.MaxInt32
+ } else {
+ end = 'z' + 1
+ start = ' '
+ }
+ }
+ } else {
+ if end <= start {
+ err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) must be greater than start (%v)", end, start)
+ return "", err
+ }
+
+ if chars != nil && end > len(chars) {
+ err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) cannot be greater than len(chars) (%v)", end, len(chars))
+ return "", err
+ }
+ }
+
+ buffer := make([]rune, count)
+ gap := end - start
+
+
+ // high-surrogates range, (\uD800-\uDBFF) = 55296 - 56319
+ // low-surrogates range, (\uDC00-\uDFFF) = 56320 - 57343
+
+ for count != 0 {
+ count--
+ var ch rune
+ if chars == nil {
+ ch = rune(random.Intn(gap) + start)
+ } else {
+ ch = chars[random.Intn(gap) + start]
+ }
+
+ if letters && unicode.IsLetter(ch) || numbers && unicode.IsDigit(ch) || !letters && !numbers {
+ if ch >= 56320 && ch <= 57343 { // low surrogate range
+ if count == 0 {
+ count++
+ } else {
+ // Insert low surrogate
+ buffer[count] = ch
+ count--
+ // Insert high surrogate
+ buffer[count] = rune(55296 + random.Intn(128))
+ }
+ } else if ch >= 55296 && ch <= 56191 { // High surrogates range (Partial)
+ if count == 0 {
+ count++
+ } else {
+ // Insert low surrogate
+ buffer[count] = rune(56320 + random.Intn(128))
+ count--
+ // Insert high surrogate
+ buffer[count] = ch
+ }
+ } else if ch >= 56192 && ch <= 56319 {
+ // private high surrogate, skip it
+ count++
+ } else {
+ // not one of the surrogates*
+ buffer[count] = ch
+ }
+ } else {
+ count++
+ }
+ }
+ return string(buffer), nil
+}
diff --git a/vendor/github.com/aokoli/goutils/stringutils.go b/vendor/github.com/aokoli/goutils/stringutils.go
new file mode 100644
index 000000000..6a956f25b
--- /dev/null
+++ b/vendor/github.com/aokoli/goutils/stringutils.go
@@ -0,0 +1,232 @@
+/*
+Copyright 2014 Alexander Okoli
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package goutils
+
+
+import (
+ "fmt"
+ "unicode"
+ "bytes"
+ "strings"
+)
+
+// Typically returned by functions where a searched item cannot be found
+const INDEX_NOT_FOUND = -1
+
+
+/*
+Abbreviate abbreviates a string using ellipses. This will turn the string "Now is the time for all good men" into "Now is the time for..."
+
+Specifically, the algorithm is as follows:
+
+ - If str is less than maxWidth characters long, return it.
+ - Else abbreviate it to (str[0:maxWidth - 3] + "...").
+ - If maxWidth is less than 4, return an illegal argument error.
+ - In no case will it return a string of length greater than maxWidth.
+
+Parameters:
+ str - the string to check
+ maxWidth - maximum length of result string, must be at least 4
+
+Returns:
+ string - abbreviated string
+ error - if the width is too small
+*/
+func Abbreviate (str string, maxWidth int) (string, error) {
+ return AbbreviateFull(str, 0, maxWidth)
+}
+
+
+/*
+AbbreviateFull abbreviates a string using ellipses. This will turn the string "Now is the time for all good men" into "...is the time for..."
+This function works like Abbreviate(string, int), but allows you to specify a "left edge" offset. Note that this left edge is not
+necessarily going to be the leftmost character in the result, or the first character following the ellipses, but it will appear
+somewhere in the result.
+In no case will it return a string of length greater than maxWidth.
+
+Parameters:
+ str - the string to check
+ offset - left edge of source string
+ maxWidth - maximum length of result string, must be at least 4
+
+Returns:
+ string - abbreviated string
+ error - if the width is too small
+*/
+func AbbreviateFull (str string, offset int, maxWidth int) (string, error) {
+ if str == "" {
+ return "", nil
+ }
+ if maxWidth < 4 {
+ err := fmt.Errorf("stringutils illegal argument: Minimum abbreviation width is 4")
+ return "", err
+ }
+ if len(str) <= maxWidth {
+ return str, nil
+ }
+ if offset > len(str) {
+ offset = len(str)
+ }
+ if len(str) - offset < (maxWidth - 3) { // 15 - 5 < 10 - 3 = 10 < 7
+ offset = len(str) - (maxWidth - 3)
+ }
+ abrevMarker := "..."
+ if offset <= 4 {
+ return str[0:maxWidth - 3] + abrevMarker, nil// str.substring(0, maxWidth - 3) + abrevMarker;
+ }
+ if maxWidth < 7 {
+ err := fmt.Errorf("stringutils illegal argument: Minimum abbreviation width with offset is 7")
+ return "", err
+ }
+ if (offset + maxWidth - 3) < len(str) { // 5 + (10-3) < 15 = 12 < 15
+ abrevStr, _ := Abbreviate(str[offset:len(str)], (maxWidth - 3))
+ return abrevMarker + abrevStr, nil// abrevMarker + abbreviate(str.substring(offset), maxWidth - 3);
+ }
+ return abrevMarker + str[(len(str) - (maxWidth - 3)):len(str)], nil // abrevMarker + str.substring(str.length() - (maxWidth - 3));
+}
+
+
+/*
+DeleteWhiteSpace deletes all whitespaces from a string as defined by unicode.IsSpace(rune).
+It returns the string without whitespaces.
+
+Parameter:
+ str - the string to delete whitespace from, may be nil
+
+Returns:
+ the string without whitespaces
+*/
+func DeleteWhiteSpace(str string) string {
+ if str == "" {
+ return str
+ }
+ sz := len(str)
+ var chs bytes.Buffer
+ count := 0
+ for i := 0; i < sz; i++ {
+ ch := rune(str[i])
+ if !unicode.IsSpace(ch) {
+ chs.WriteRune(ch)
+ count++
+ }
+ }
+ if count == sz {
+ return str
+ }
+ return chs.String()
+}
+
+
+/*
+IndexOfDifference compares two strings, and returns the index at which the strings begin to differ.
+
+Parameters:
+ str1 - the first string
+ str2 - the second string
+
+Returns:
+ the index where str1 and str2 begin to differ; -1 if they are equal
+*/
+func IndexOfDifference(str1 string, str2 string) int {
+ if str1 == str2 {
+ return INDEX_NOT_FOUND
+ }
+ if IsEmpty(str1) || IsEmpty(str2) {
+ return 0
+ }
+ var i int;
+ for i = 0; i < len(str1) && i < len(str2); i++ {
+ if rune(str1[i]) != rune(str2[i]) {
+ break
+ }
+ }
+ if i < len(str2) || i < len(str1) {
+ return i
+ }
+ return INDEX_NOT_FOUND
+}
+
+
+
+/*
+IsBlank checks if a string is whitespace or empty (""). Observe the following behavior:
+
+ goutils.IsBlank("") = true
+ goutils.IsBlank(" ") = true
+ goutils.IsBlank("bob") = false
+ goutils.IsBlank(" bob ") = false
+
+Parameter:
+ str - the string to check
+
+Returns:
+ true - if the string is whitespace or empty ("")
+*/
+func IsBlank(str string) bool {
+ strLen := len(str)
+ if str == "" || strLen == 0 {
+ return true
+ }
+ for i := 0; i < strLen; i++ {
+ if unicode.IsSpace(rune(str[i])) == false {
+ return false
+ }
+ }
+ return true
+}
+
+
+/*
+IndexOf returns the index of the first instance of sub in str, with the search beginning from the
+index start point specified. -1 is returned if sub is not present in str.
+
+An empty string ("") will return -1 (INDEX_NOT_FOUND). A negative start position is treated as zero.
+A start position greater than the string length returns -1.
+
+Parameters:
+ str - the string to check
+ sub - the substring to find
+ start - the start position; negative treated as zero
+
+Returns:
+ the first index where the sub string was found (always >= start)
+*/
+func IndexOf(str string, sub string, start int) int {
+
+ if (start < 0) {
+ start = 0
+ }
+
+ if len(str) < start {
+ return INDEX_NOT_FOUND
+ }
+
+ if IsEmpty(str) || IsEmpty(sub) {
+ return INDEX_NOT_FOUND
+ }
+
+ partialIndex := strings.Index(str[start:len(str)], sub)
+ if partialIndex == -1 {
+ return INDEX_NOT_FOUND
+ }
+ return partialIndex + start
+}
+
+// IsEmpty checks if a string is empty (""). Returns true if empty, and false otherwise.
+func IsEmpty(str string) bool {
+ return len(str) == 0
+}
diff --git a/vendor/github.com/aokoli/goutils/wordutils.go b/vendor/github.com/aokoli/goutils/wordutils.go
new file mode 100644
index 000000000..872964af0
--- /dev/null
+++ b/vendor/github.com/aokoli/goutils/wordutils.go
@@ -0,0 +1,365 @@
+/*
+Copyright 2014 Alexander Okoli
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package goutils provides utility functions to manipulate strings in various ways.
+The code snippets below show examples of how to use goutils. Some functions return
+errors while others do not, so usage would vary as a result.
+
+Example:
+
+ package main
+
+ import (
+ "fmt"
+ "github.com/aokoli/goutils"
+ )
+
+ func main() {
+
+ // EXAMPLE 1: A goutils function which returns no errors
+ fmt.Println (goutils.Initials("John Doe Foo")) // Prints out "JDF"
+
+
+
+ // EXAMPLE 2: A goutils function which returns an error
+ rand1, err1 := goutils.Random (-1, 0, 0, true, true)
+
+ if err1 != nil {
+ fmt.Println(err1) // Prints out error message because -1 was entered as the first parameter in goutils.Random(...)
+ } else {
+ fmt.Println(rand1)
+ }
+ }
+*/
+package goutils
+
+import (
+ "bytes"
+ "strings"
+ "unicode"
+)
+
+// VERSION indicates the current version of goutils
+const VERSION = "1.0.0"
+
+/*
+Wrap wraps a single line of text, identifying words by ' '.
+New lines will be separated by '\n'. Very long words, such as URLs will not be wrapped.
+Leading spaces on a new line are stripped. Trailing spaces are not stripped.
+
+Parameters:
+ str - the string to be word wrapped
+ wrapLength - the column (a column can fit only one character) to wrap the words at, less than 1 is treated as 1
+
+Returns:
+ a line with newlines inserted
+*/
+func Wrap (str string, wrapLength int) string {
+ return WrapCustom (str, wrapLength, "", false)
+}
+
+/*
+WrapCustom wraps a single line of text, identifying words by ' '.
+Leading spaces on a new line are stripped. Trailing spaces are not stripped.
+
+Parameters:
+ str - the string to be word wrapped
+ wrapLength - the column number (a column can fit only one character) to wrap the words at, less than 1 is treated as 1
+ newLineStr - the string to insert for a new line, "" uses '\n'
+ wrapLongWords - true if long words (such as URLs) should be wrapped
+
+Returns:
+ a line with newlines inserted
+*/
+func WrapCustom (str string, wrapLength int, newLineStr string, wrapLongWords bool) string {
+
+ if str == "" {
+ return ""
+ }
+ if newLineStr == "" {
+ newLineStr = "\n" // TODO Assumes "\n" is seperator. Explore SystemUtils.LINE_SEPARATOR from Apache Commons
+ }
+ if wrapLength < 1 {
+ wrapLength = 1
+ }
+
+ inputLineLength := len(str)
+ offset := 0
+
+ var wrappedLine bytes.Buffer
+
+ for inputLineLength-offset > wrapLength {
+
+ if rune(str[offset]) == ' ' {
+ offset++
+ continue
+ }
+
+ end := wrapLength + offset + 1
+ spaceToWrapAt := strings.LastIndex(str[offset:end], " ") + offset
+
+ if spaceToWrapAt >= offset {
+ // normal word (not longer than wrapLength)
+ wrappedLine.WriteString(str[offset:spaceToWrapAt])
+ wrappedLine.WriteString(newLineStr)
+ offset = spaceToWrapAt + 1
+
+ } else {
+ // long word or URL
+ if wrapLongWords {
+ end := wrapLength + offset
+ // long words are wrapped one line at a time
+ wrappedLine.WriteString(str[offset:end])
+ wrappedLine.WriteString(newLineStr)
+ offset += wrapLength
+ } else {
+ // long words aren't wrapped, just extended beyond limit
+ end := wrapLength + offset
+ spaceToWrapAt = strings.IndexRune(str[end:len(str)], ' ') + end
+ if spaceToWrapAt >= 0 {
+ wrappedLine.WriteString(str[offset:spaceToWrapAt])
+ wrappedLine.WriteString(newLineStr)
+ offset = spaceToWrapAt + 1
+ } else {
+ wrappedLine.WriteString(str[offset:len(str)])
+ offset = inputLineLength
+ }
+ }
+ }
+ }
+
+ wrappedLine.WriteString(str[offset:len(str)])
+
+ return wrappedLine.String()
+
+}
+
+
+/*
+Capitalize capitalizes all the delimiter separated words in a string. Only the first letter of each word is changed.
+To convert the rest of each word to lowercase at the same time, use CapitalizeFully(str string, delimiters ...rune).
+The delimiters represent a set of characters understood to separate words. The first string character
+and the first non-delimiter character after a delimiter will be capitalized. A "" input string returns "".
+Capitalization uses the Unicode title case, normally equivalent to upper case.
+
+Parameters:
+ str - the string to capitalize
+ delimiters - set of characters to determine capitalization, exclusion of this parameter means whitespace would be delimeter
+
+Returns:
+ capitalized string
+*/
+func Capitalize (str string, delimiters ...rune) string {
+
+ var delimLen int
+
+ if delimiters == nil {
+ delimLen = -1
+ } else {
+ delimLen = len(delimiters)
+ }
+
+ if str == "" || delimLen == 0 {
+ return str;
+ }
+
+ buffer := []rune(str)
+ capitalizeNext := true
+ for i := 0; i < len(buffer); i++ {
+ ch := buffer[i]
+ if isDelimiter(ch, delimiters...) {
+ capitalizeNext = true
+ } else if capitalizeNext {
+ buffer[i] = unicode.ToTitle(ch)
+ capitalizeNext = false
+ }
+ }
+ return string(buffer)
+
+}
+
+
+
+/*
+CapitalizeFully converts all the delimiter separated words in a string into capitalized words, that is each word is made up of a
+titlecase character and then a series of lowercase characters. The delimiters represent a set of characters understood
+to separate words. The first string character and the first non-delimiter character after a delimiter will be capitalized.
+Capitalization uses the Unicode title case, normally equivalent to upper case.
+
+Parameters:
+ str - the string to capitalize fully
+ delimiters - set of characters to determine capitalization, exclusion of this parameter means whitespace would be delimeter
+
+Returns:
+ capitalized string
+*/
+func CapitalizeFully (str string, delimiters ...rune) string {
+
+ var delimLen int
+
+ if delimiters == nil {
+ delimLen = -1
+ } else {
+ delimLen = len(delimiters)
+ }
+
+
+ if str == "" || delimLen == 0 {
+ return str;
+ }
+ str = strings.ToLower(str)
+ return Capitalize(str, delimiters...);
+}
+
+
+/*
+Uncapitalize uncapitalizes all the whitespace separated words in a string. Only the first letter of each word is changed.
+The delimiters represent a set of characters understood to separate words. The first string character and the first non-delimiter
+character after a delimiter will be uncapitalized. Whitespace is defined by unicode.IsSpace(char).
+
+Parameters:
+ str - the string to uncapitalize fully
+ delimiters - set of characters to determine capitalization, exclusion of this parameter means whitespace would be delimeter
+
+Returns:
+ uncapitalized string
+*/
+func Uncapitalize (str string, delimiters ...rune) string {
+
+ var delimLen int
+
+ if delimiters == nil {
+ delimLen = -1
+ } else {
+ delimLen = len(delimiters)
+ }
+
+ if str == "" || delimLen == 0 {
+ return str;
+ }
+
+ buffer := []rune(str)
+ uncapitalizeNext := true // TODO Always makes capitalize/un apply to first char.
+ for i := 0; i < len(buffer); i++ {
+ ch := buffer[i]
+ if isDelimiter(ch, delimiters...) {
+ uncapitalizeNext = true
+ } else if uncapitalizeNext {
+ buffer[i] = unicode.ToLower(ch)
+ uncapitalizeNext = false
+ }
+ }
+ return string(buffer)
+}
+
+
+/*
+SwapCase swaps the case of a string using a word based algorithm.
+
+Conversion algorithm:
+
+ Upper case character converts to Lower case
+ Title case character converts to Lower case
+ Lower case character after Whitespace or at start converts to Title case
+ Other Lower case character converts to Upper case
+ Whitespace is defined by unicode.IsSpace(char).
+
+Parameters:
+ str - the string to swap case
+
+Returns:
+ the changed string
+*/
+func SwapCase(str string) string {
+ if str == "" {
+ return str
+ }
+ buffer := []rune(str)
+
+ whitespace := true
+
+ for i := 0; i < len(buffer); i++ {
+ ch := buffer[i]
+ if unicode.IsUpper(ch) {
+ buffer[i] = unicode.ToLower(ch)
+ whitespace = false
+ } else if unicode.IsTitle(ch) {
+ buffer[i] = unicode.ToLower(ch)
+ whitespace = false
+ } else if unicode.IsLower(ch) {
+ if whitespace {
+ buffer[i] = unicode.ToTitle(ch)
+ whitespace = false
+ } else {
+ buffer[i] = unicode.ToUpper(ch)
+ }
+ } else {
+ whitespace = unicode.IsSpace(ch)
+ }
+ }
+ return string(buffer);
+}
+
+
+/*
+Initials extracts the initial letters from each word in the string. The first letter of the string and all first
+letters after the defined delimiters are returned as a new string. Their case is not changed. If the delimiters
+parameter is excluded, then Whitespace is used. Whitespace is defined by unicode.IsSpacea(char). An empty delimiter array returns an empty string.
+
+Parameters:
+ str - the string to get initials from
+ delimiters - set of characters to determine words, exclusion of this parameter means whitespace would be delimeter
+Returns:
+ string of initial letters
+*/
+func Initials(str string, delimiters ...rune) string {
+ if str == "" {
+ return str
+ }
+ if delimiters != nil && len(delimiters) == 0 {
+ return ""
+ }
+ strLen := len(str)
+ var buf bytes.Buffer
+ lastWasGap := true
+ for i := 0; i < strLen; i++ {
+ ch := rune(str[i])
+
+ if isDelimiter(ch, delimiters...) {
+ lastWasGap = true
+ } else if lastWasGap {
+ buf.WriteRune(ch)
+ lastWasGap = false
+ }
+ }
+ return buf.String()
+ }
+
+
+
+ // private function (lower case func name)
+func isDelimiter(ch rune, delimiters ...rune) bool {
+ if delimiters == nil {
+ return unicode.IsSpace(ch)
+ }
+ for _, delimiter := range delimiters {
+ if ch == delimiter {
+ return true
+ }
+ }
+ return false
+}
\ No newline at end of file
diff --git a/vendor/github.com/docker/distribution/registry/api/errcode/errors.go b/vendor/github.com/docker/distribution/registry/api/errcode/errors.go
deleted file mode 100644
index 6d9bb4b62..000000000
--- a/vendor/github.com/docker/distribution/registry/api/errcode/errors.go
+++ /dev/null
@@ -1,267 +0,0 @@
-package errcode
-
-import (
- "encoding/json"
- "fmt"
- "strings"
-)
-
-// ErrorCoder is the base interface for ErrorCode and Error allowing
-// users of each to just call ErrorCode to get the real ID of each
-type ErrorCoder interface {
- ErrorCode() ErrorCode
-}
-
-// ErrorCode represents the error type. The errors are serialized via strings
-// and the integer format may change and should *never* be exported.
-type ErrorCode int
-
-var _ error = ErrorCode(0)
-
-// ErrorCode just returns itself
-func (ec ErrorCode) ErrorCode() ErrorCode {
- return ec
-}
-
-// Error returns the ID/Value
-func (ec ErrorCode) Error() string {
- // NOTE(stevvooe): Cannot use message here since it may have unpopulated args.
- return strings.ToLower(strings.Replace(ec.String(), "_", " ", -1))
-}
-
-// Descriptor returns the descriptor for the error code.
-func (ec ErrorCode) Descriptor() ErrorDescriptor {
- d, ok := errorCodeToDescriptors[ec]
-
- if !ok {
- return ErrorCodeUnknown.Descriptor()
- }
-
- return d
-}
-
-// String returns the canonical identifier for this error code.
-func (ec ErrorCode) String() string {
- return ec.Descriptor().Value
-}
-
-// Message returned the human-readable error message for this error code.
-func (ec ErrorCode) Message() string {
- return ec.Descriptor().Message
-}
-
-// MarshalText encodes the receiver into UTF-8-encoded text and returns the
-// result.
-func (ec ErrorCode) MarshalText() (text []byte, err error) {
- return []byte(ec.String()), nil
-}
-
-// UnmarshalText decodes the form generated by MarshalText.
-func (ec *ErrorCode) UnmarshalText(text []byte) error {
- desc, ok := idToDescriptors[string(text)]
-
- if !ok {
- desc = ErrorCodeUnknown.Descriptor()
- }
-
- *ec = desc.Code
-
- return nil
-}
-
-// WithMessage creates a new Error struct based on the passed-in info and
-// overrides the Message property.
-func (ec ErrorCode) WithMessage(message string) Error {
- return Error{
- Code: ec,
- Message: message,
- }
-}
-
-// WithDetail creates a new Error struct based on the passed-in info and
-// set the Detail property appropriately
-func (ec ErrorCode) WithDetail(detail interface{}) Error {
- return Error{
- Code: ec,
- Message: ec.Message(),
- }.WithDetail(detail)
-}
-
-// WithArgs creates a new Error struct and sets the Args slice
-func (ec ErrorCode) WithArgs(args ...interface{}) Error {
- return Error{
- Code: ec,
- Message: ec.Message(),
- }.WithArgs(args...)
-}
-
-// Error provides a wrapper around ErrorCode with extra Details provided.
-type Error struct {
- Code ErrorCode `json:"code"`
- Message string `json:"message"`
- Detail interface{} `json:"detail,omitempty"`
-
- // TODO(duglin): See if we need an "args" property so we can do the
- // variable substitution right before showing the message to the user
-}
-
-var _ error = Error{}
-
-// ErrorCode returns the ID/Value of this Error
-func (e Error) ErrorCode() ErrorCode {
- return e.Code
-}
-
-// Error returns a human readable representation of the error.
-func (e Error) Error() string {
- return fmt.Sprintf("%s: %s", e.Code.Error(), e.Message)
-}
-
-// WithDetail will return a new Error, based on the current one, but with
-// some Detail info added
-func (e Error) WithDetail(detail interface{}) Error {
- return Error{
- Code: e.Code,
- Message: e.Message,
- Detail: detail,
- }
-}
-
-// WithArgs uses the passed-in list of interface{} as the substitution
-// variables in the Error's Message string, but returns a new Error
-func (e Error) WithArgs(args ...interface{}) Error {
- return Error{
- Code: e.Code,
- Message: fmt.Sprintf(e.Code.Message(), args...),
- Detail: e.Detail,
- }
-}
-
-// ErrorDescriptor provides relevant information about a given error code.
-type ErrorDescriptor struct {
- // Code is the error code that this descriptor describes.
- Code ErrorCode
-
- // Value provides a unique, string key, often captilized with
- // underscores, to identify the error code. This value is used as the
- // keyed value when serializing api errors.
- Value string
-
- // Message is a short, human readable decription of the error condition
- // included in API responses.
- Message string
-
- // Description provides a complete account of the errors purpose, suitable
- // for use in documentation.
- Description string
-
- // HTTPStatusCode provides the http status code that is associated with
- // this error condition.
- HTTPStatusCode int
-}
-
-// ParseErrorCode returns the value by the string error code.
-// `ErrorCodeUnknown` will be returned if the error is not known.
-func ParseErrorCode(value string) ErrorCode {
- ed, ok := idToDescriptors[value]
- if ok {
- return ed.Code
- }
-
- return ErrorCodeUnknown
-}
-
-// Errors provides the envelope for multiple errors and a few sugar methods
-// for use within the application.
-type Errors []error
-
-var _ error = Errors{}
-
-func (errs Errors) Error() string {
- switch len(errs) {
- case 0:
- return ""
- case 1:
- return errs[0].Error()
- default:
- msg := "errors:\n"
- for _, err := range errs {
- msg += err.Error() + "\n"
- }
- return msg
- }
-}
-
-// Len returns the current number of errors.
-func (errs Errors) Len() int {
- return len(errs)
-}
-
-// MarshalJSON converts slice of error, ErrorCode or Error into a
-// slice of Error - then serializes
-func (errs Errors) MarshalJSON() ([]byte, error) {
- var tmpErrs struct {
- Errors []Error `json:"errors,omitempty"`
- }
-
- for _, daErr := range errs {
- var err Error
-
- switch daErr.(type) {
- case ErrorCode:
- err = daErr.(ErrorCode).WithDetail(nil)
- case Error:
- err = daErr.(Error)
- default:
- err = ErrorCodeUnknown.WithDetail(daErr)
-
- }
-
- // If the Error struct was setup and they forgot to set the
- // Message field (meaning its "") then grab it from the ErrCode
- msg := err.Message
- if msg == "" {
- msg = err.Code.Message()
- }
-
- tmpErrs.Errors = append(tmpErrs.Errors, Error{
- Code: err.Code,
- Message: msg,
- Detail: err.Detail,
- })
- }
-
- return json.Marshal(tmpErrs)
-}
-
-// UnmarshalJSON deserializes []Error and then converts it into slice of
-// Error or ErrorCode
-func (errs *Errors) UnmarshalJSON(data []byte) error {
- var tmpErrs struct {
- Errors []Error
- }
-
- if err := json.Unmarshal(data, &tmpErrs); err != nil {
- return err
- }
-
- var newErrs Errors
- for _, daErr := range tmpErrs.Errors {
- // If Message is empty or exactly matches the Code's message string
- // then just use the Code, no need for a full Error struct
- if daErr.Detail == nil && (daErr.Message == "" || daErr.Message == daErr.Code.Message()) {
- // Error's w/o details get converted to ErrorCode
- newErrs = append(newErrs, daErr.Code)
- } else {
- // Error's w/ details are untouched
- newErrs = append(newErrs, Error{
- Code: daErr.Code,
- Message: daErr.Message,
- Detail: daErr.Detail,
- })
- }
- }
-
- *errs = newErrs
- return nil
-}
diff --git a/vendor/github.com/docker/distribution/registry/api/errcode/handler.go b/vendor/github.com/docker/distribution/registry/api/errcode/handler.go
deleted file mode 100644
index 49a64a86e..000000000
--- a/vendor/github.com/docker/distribution/registry/api/errcode/handler.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package errcode
-
-import (
- "encoding/json"
- "net/http"
-)
-
-// ServeJSON attempts to serve the errcode in a JSON envelope. It marshals err
-// and sets the content-type header to 'application/json'. It will handle
-// ErrorCoder and Errors, and if necessary will create an envelope.
-func ServeJSON(w http.ResponseWriter, err error) error {
- w.Header().Set("Content-Type", "application/json; charset=utf-8")
- var sc int
-
- switch errs := err.(type) {
- case Errors:
- if len(errs) < 1 {
- break
- }
-
- if err, ok := errs[0].(ErrorCoder); ok {
- sc = err.ErrorCode().Descriptor().HTTPStatusCode
- }
- case ErrorCoder:
- sc = errs.ErrorCode().Descriptor().HTTPStatusCode
- err = Errors{err} // create an envelope.
- default:
- // We just have an unhandled error type, so just place in an envelope
- // and move along.
- err = Errors{err}
- }
-
- if sc == 0 {
- sc = http.StatusInternalServerError
- }
-
- w.WriteHeader(sc)
-
- if err := json.NewEncoder(w).Encode(err); err != nil {
- return err
- }
-
- return nil
-}
diff --git a/vendor/github.com/docker/distribution/registry/api/errcode/register.go b/vendor/github.com/docker/distribution/registry/api/errcode/register.go
deleted file mode 100644
index d1e8826c6..000000000
--- a/vendor/github.com/docker/distribution/registry/api/errcode/register.go
+++ /dev/null
@@ -1,138 +0,0 @@
-package errcode
-
-import (
- "fmt"
- "net/http"
- "sort"
- "sync"
-)
-
-var (
- errorCodeToDescriptors = map[ErrorCode]ErrorDescriptor{}
- idToDescriptors = map[string]ErrorDescriptor{}
- groupToDescriptors = map[string][]ErrorDescriptor{}
-)
-
-var (
- // ErrorCodeUnknown is a generic error that can be used as a last
- // resort if there is no situation-specific error message that can be used
- ErrorCodeUnknown = Register("errcode", ErrorDescriptor{
- Value: "UNKNOWN",
- Message: "unknown error",
- Description: `Generic error returned when the error does not have an
- API classification.`,
- HTTPStatusCode: http.StatusInternalServerError,
- })
-
- // ErrorCodeUnsupported is returned when an operation is not supported.
- ErrorCodeUnsupported = Register("errcode", ErrorDescriptor{
- Value: "UNSUPPORTED",
- Message: "The operation is unsupported.",
- Description: `The operation was unsupported due to a missing
- implementation or invalid set of parameters.`,
- HTTPStatusCode: http.StatusMethodNotAllowed,
- })
-
- // ErrorCodeUnauthorized is returned if a request requires
- // authentication.
- ErrorCodeUnauthorized = Register("errcode", ErrorDescriptor{
- Value: "UNAUTHORIZED",
- Message: "authentication required",
- Description: `The access controller was unable to authenticate
- the client. Often this will be accompanied by a
- Www-Authenticate HTTP response header indicating how to
- authenticate.`,
- HTTPStatusCode: http.StatusUnauthorized,
- })
-
- // ErrorCodeDenied is returned if a client does not have sufficient
- // permission to perform an action.
- ErrorCodeDenied = Register("errcode", ErrorDescriptor{
- Value: "DENIED",
- Message: "requested access to the resource is denied",
- Description: `The access controller denied access for the
- operation on a resource.`,
- HTTPStatusCode: http.StatusForbidden,
- })
-
- // ErrorCodeUnavailable provides a common error to report unavailability
- // of a service or endpoint.
- ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{
- Value: "UNAVAILABLE",
- Message: "service unavailable",
- Description: "Returned when a service is not available",
- HTTPStatusCode: http.StatusServiceUnavailable,
- })
-
- // ErrorCodeTooManyRequests is returned if a client attempts too many
- // times to contact a service endpoint.
- ErrorCodeTooManyRequests = Register("errcode", ErrorDescriptor{
- Value: "TOOMANYREQUESTS",
- Message: "too many requests",
- Description: `Returned when a client attempts to contact a
- service too many times`,
- HTTPStatusCode: http.StatusTooManyRequests,
- })
-)
-
-var nextCode = 1000
-var registerLock sync.Mutex
-
-// Register will make the passed-in error known to the environment and
-// return a new ErrorCode
-func Register(group string, descriptor ErrorDescriptor) ErrorCode {
- registerLock.Lock()
- defer registerLock.Unlock()
-
- descriptor.Code = ErrorCode(nextCode)
-
- if _, ok := idToDescriptors[descriptor.Value]; ok {
- panic(fmt.Sprintf("ErrorValue %q is already registered", descriptor.Value))
- }
- if _, ok := errorCodeToDescriptors[descriptor.Code]; ok {
- panic(fmt.Sprintf("ErrorCode %v is already registered", descriptor.Code))
- }
-
- groupToDescriptors[group] = append(groupToDescriptors[group], descriptor)
- errorCodeToDescriptors[descriptor.Code] = descriptor
- idToDescriptors[descriptor.Value] = descriptor
-
- nextCode++
- return descriptor.Code
-}
-
-type byValue []ErrorDescriptor
-
-func (a byValue) Len() int { return len(a) }
-func (a byValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
-func (a byValue) Less(i, j int) bool { return a[i].Value < a[j].Value }
-
-// GetGroupNames returns the list of Error group names that are registered
-func GetGroupNames() []string {
- keys := []string{}
-
- for k := range groupToDescriptors {
- keys = append(keys, k)
- }
- sort.Strings(keys)
- return keys
-}
-
-// GetErrorCodeGroup returns the named group of error descriptors
-func GetErrorCodeGroup(name string) []ErrorDescriptor {
- desc := groupToDescriptors[name]
- sort.Sort(byValue(desc))
- return desc
-}
-
-// GetErrorAllDescriptors returns a slice of all ErrorDescriptors that are
-// registered, irrespective of what group they're in
-func GetErrorAllDescriptors() []ErrorDescriptor {
- result := []ErrorDescriptor{}
-
- for _, group := range GetGroupNames() {
- result = append(result, GetErrorCodeGroup(group)...)
- }
- sort.Sort(byValue(result))
- return result
-}
diff --git a/vendor/github.com/docker/distribution/registry/api/v2/descriptors.go b/vendor/github.com/docker/distribution/registry/api/v2/descriptors.go
deleted file mode 100644
index 9979abae6..000000000
--- a/vendor/github.com/docker/distribution/registry/api/v2/descriptors.go
+++ /dev/null
@@ -1,1596 +0,0 @@
-package v2
-
-import (
- "net/http"
- "regexp"
-
- "github.com/docker/distribution/digest"
- "github.com/docker/distribution/reference"
- "github.com/docker/distribution/registry/api/errcode"
-)
-
-var (
- nameParameterDescriptor = ParameterDescriptor{
- Name: "name",
- Type: "string",
- Format: reference.NameRegexp.String(),
- Required: true,
- Description: `Name of the target repository.`,
- }
-
- referenceParameterDescriptor = ParameterDescriptor{
- Name: "reference",
- Type: "string",
- Format: reference.TagRegexp.String(),
- Required: true,
- Description: `Tag or digest of the target manifest.`,
- }
-
- uuidParameterDescriptor = ParameterDescriptor{
- Name: "uuid",
- Type: "opaque",
- Required: true,
- Description: "A uuid identifying the upload. This field can accept characters that match `[a-zA-Z0-9-_.=]+`.",
- }
-
- digestPathParameter = ParameterDescriptor{
- Name: "digest",
- Type: "path",
- Required: true,
- Format: digest.DigestRegexp.String(),
- Description: `Digest of desired blob.`,
- }
-
- hostHeader = ParameterDescriptor{
- Name: "Host",
- Type: "string",
- Description: "Standard HTTP Host Header. Should be set to the registry host.",
- Format: "",
- Examples: []string{"registry-1.docker.io"},
- }
-
- authHeader = ParameterDescriptor{
- Name: "Authorization",
- Type: "string",
- Description: "An RFC7235 compliant authorization header.",
- Format: " ",
- Examples: []string{"Bearer dGhpcyBpcyBhIGZha2UgYmVhcmVyIHRva2VuIQ=="},
- }
-
- authChallengeHeader = ParameterDescriptor{
- Name: "WWW-Authenticate",
- Type: "string",
- Description: "An RFC7235 compliant authentication challenge header.",
- Format: ` realm="", ..."`,
- Examples: []string{
- `Bearer realm="https://auth.docker.com/", service="registry.docker.com", scopes="repository:library/ubuntu:pull"`,
- },
- }
-
- contentLengthZeroHeader = ParameterDescriptor{
- Name: "Content-Length",
- Description: "The `Content-Length` header must be zero and the body must be empty.",
- Type: "integer",
- Format: "0",
- }
-
- dockerUploadUUIDHeader = ParameterDescriptor{
- Name: "Docker-Upload-UUID",
- Description: "Identifies the docker upload uuid for the current request.",
- Type: "uuid",
- Format: "",
- }
-
- digestHeader = ParameterDescriptor{
- Name: "Docker-Content-Digest",
- Description: "Digest of the targeted content for the request.",
- Type: "digest",
- Format: "",
- }
-
- linkHeader = ParameterDescriptor{
- Name: "Link",
- Type: "link",
- Description: "RFC5988 compliant rel='next' with URL to next result set, if available",
- Format: `<?n=&last=>; rel="next"`,
- }
-
- paginationParameters = []ParameterDescriptor{
- {
- Name: "n",
- Type: "integer",
- Description: "Limit the number of entries in each response. It not present, all entries will be returned.",
- Format: "",
- Required: false,
- },
- {
- Name: "last",
- Type: "string",
- Description: "Result set will include values lexically after last.",
- Format: "",
- Required: false,
- },
- }
-
- unauthorizedResponseDescriptor = ResponseDescriptor{
- Name: "Authentication Required",
- StatusCode: http.StatusUnauthorized,
- Description: "The client is not authenticated.",
- Headers: []ParameterDescriptor{
- authChallengeHeader,
- {
- Name: "Content-Length",
- Type: "integer",
- Description: "Length of the JSON response body.",
- Format: "",
- },
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- ErrorCodes: []errcode.ErrorCode{
- errcode.ErrorCodeUnauthorized,
- },
- }
-
- repositoryNotFoundResponseDescriptor = ResponseDescriptor{
- Name: "No Such Repository Error",
- StatusCode: http.StatusNotFound,
- Description: "The repository is not known to the registry.",
- Headers: []ParameterDescriptor{
- {
- Name: "Content-Length",
- Type: "integer",
- Description: "Length of the JSON response body.",
- Format: "",
- },
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeNameUnknown,
- },
- }
-
- deniedResponseDescriptor = ResponseDescriptor{
- Name: "Access Denied",
- StatusCode: http.StatusForbidden,
- Description: "The client does not have required access to the repository.",
- Headers: []ParameterDescriptor{
- {
- Name: "Content-Length",
- Type: "integer",
- Description: "Length of the JSON response body.",
- Format: "",
- },
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- ErrorCodes: []errcode.ErrorCode{
- errcode.ErrorCodeDenied,
- },
- }
-
- tooManyRequestsDescriptor = ResponseDescriptor{
- Name: "Too Many Requests",
- StatusCode: http.StatusTooManyRequests,
- Description: "The client made too many requests within a time interval.",
- Headers: []ParameterDescriptor{
- {
- Name: "Content-Length",
- Type: "integer",
- Description: "Length of the JSON response body.",
- Format: "",
- },
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- ErrorCodes: []errcode.ErrorCode{
- errcode.ErrorCodeTooManyRequests,
- },
- }
-)
-
-const (
- manifestBody = `{
- "name": ,
- "tag": ,
- "fsLayers": [
- {
- "blobSum": ""
- },
- ...
- ]
- ],
- "history": ,
- "signature":
-}`
-
- errorsBody = `{
- "errors:" [
- {
- "code": ,
- "message": "",
- "detail": ...
- },
- ...
- ]
-}`
-)
-
-// APIDescriptor exports descriptions of the layout of the v2 registry API.
-var APIDescriptor = struct {
- // RouteDescriptors provides a list of the routes available in the API.
- RouteDescriptors []RouteDescriptor
-}{
- RouteDescriptors: routeDescriptors,
-}
-
-// RouteDescriptor describes a route specified by name.
-type RouteDescriptor struct {
- // Name is the name of the route, as specified in RouteNameXXX exports.
- // These names a should be considered a unique reference for a route. If
- // the route is registered with gorilla, this is the name that will be
- // used.
- Name string
-
- // Path is a gorilla/mux-compatible regexp that can be used to match the
- // route. For any incoming method and path, only one route descriptor
- // should match.
- Path string
-
- // Entity should be a short, human-readalbe description of the object
- // targeted by the endpoint.
- Entity string
-
- // Description should provide an accurate overview of the functionality
- // provided by the route.
- Description string
-
- // Methods should describe the various HTTP methods that may be used on
- // this route, including request and response formats.
- Methods []MethodDescriptor
-}
-
-// MethodDescriptor provides a description of the requests that may be
-// conducted with the target method.
-type MethodDescriptor struct {
-
- // Method is an HTTP method, such as GET, PUT or POST.
- Method string
-
- // Description should provide an overview of the functionality provided by
- // the covered method, suitable for use in documentation. Use of markdown
- // here is encouraged.
- Description string
-
- // Requests is a slice of request descriptors enumerating how this
- // endpoint may be used.
- Requests []RequestDescriptor
-}
-
-// RequestDescriptor covers a particular set of headers and parameters that
-// can be carried out with the parent method. Its most helpful to have one
-// RequestDescriptor per API use case.
-type RequestDescriptor struct {
- // Name provides a short identifier for the request, usable as a title or
- // to provide quick context for the particular request.
- Name string
-
- // Description should cover the requests purpose, covering any details for
- // this particular use case.
- Description string
-
- // Headers describes headers that must be used with the HTTP request.
- Headers []ParameterDescriptor
-
- // PathParameters enumerate the parameterized path components for the
- // given request, as defined in the route's regular expression.
- PathParameters []ParameterDescriptor
-
- // QueryParameters provides a list of query parameters for the given
- // request.
- QueryParameters []ParameterDescriptor
-
- // Body describes the format of the request body.
- Body BodyDescriptor
-
- // Successes enumerates the possible responses that are considered to be
- // the result of a successful request.
- Successes []ResponseDescriptor
-
- // Failures covers the possible failures from this particular request.
- Failures []ResponseDescriptor
-}
-
-// ResponseDescriptor describes the components of an API response.
-type ResponseDescriptor struct {
- // Name provides a short identifier for the response, usable as a title or
- // to provide quick context for the particular response.
- Name string
-
- // Description should provide a brief overview of the role of the
- // response.
- Description string
-
- // StatusCode specifies the status received by this particular response.
- StatusCode int
-
- // Headers covers any headers that may be returned from the response.
- Headers []ParameterDescriptor
-
- // Fields describes any fields that may be present in the response.
- Fields []ParameterDescriptor
-
- // ErrorCodes enumerates the error codes that may be returned along with
- // the response.
- ErrorCodes []errcode.ErrorCode
-
- // Body describes the body of the response, if any.
- Body BodyDescriptor
-}
-
-// BodyDescriptor describes a request body and its expected content type. For
-// the most part, it should be example json or some placeholder for body
-// data in documentation.
-type BodyDescriptor struct {
- ContentType string
- Format string
-}
-
-// ParameterDescriptor describes the format of a request parameter, which may
-// be a header, path parameter or query parameter.
-type ParameterDescriptor struct {
- // Name is the name of the parameter, either of the path component or
- // query parameter.
- Name string
-
- // Type specifies the type of the parameter, such as string, integer, etc.
- Type string
-
- // Description provides a human-readable description of the parameter.
- Description string
-
- // Required means the field is required when set.
- Required bool
-
- // Format is a specifying the string format accepted by this parameter.
- Format string
-
- // Regexp is a compiled regular expression that can be used to validate
- // the contents of the parameter.
- Regexp *regexp.Regexp
-
- // Examples provides multiple examples for the values that might be valid
- // for this parameter.
- Examples []string
-}
-
-var routeDescriptors = []RouteDescriptor{
- {
- Name: RouteNameBase,
- Path: "/v2/",
- Entity: "Base",
- Description: `Base V2 API route. Typically, this can be used for lightweight version checks and to validate registry authentication.`,
- Methods: []MethodDescriptor{
- {
- Method: "GET",
- Description: "Check that the endpoint implements Docker Registry API V2.",
- Requests: []RequestDescriptor{
- {
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- },
- Successes: []ResponseDescriptor{
- {
- Description: "The API implements V2 protocol and is accessible.",
- StatusCode: http.StatusOK,
- },
- },
- Failures: []ResponseDescriptor{
- {
- Description: "The registry does not implement the V2 API.",
- StatusCode: http.StatusNotFound,
- },
- unauthorizedResponseDescriptor,
- tooManyRequestsDescriptor,
- },
- },
- },
- },
- },
- },
- {
- Name: RouteNameTags,
- Path: "/v2/{name:" + reference.NameRegexp.String() + "}/tags/list",
- Entity: "Tags",
- Description: "Retrieve information about tags.",
- Methods: []MethodDescriptor{
- {
- Method: "GET",
- Description: "Fetch the tags under the repository identified by `name`.",
- Requests: []RequestDescriptor{
- {
- Name: "Tags",
- Description: "Return all tags for the repository",
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- },
- PathParameters: []ParameterDescriptor{
- nameParameterDescriptor,
- },
- Successes: []ResponseDescriptor{
- {
- StatusCode: http.StatusOK,
- Description: "A list of tags for the named repository.",
- Headers: []ParameterDescriptor{
- {
- Name: "Content-Length",
- Type: "integer",
- Description: "Length of the JSON response body.",
- Format: "",
- },
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: `{
- "name": ,
- "tags": [
- ,
- ...
- ]
-}`,
- },
- },
- },
- Failures: []ResponseDescriptor{
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- },
- },
- {
- Name: "Tags Paginated",
- Description: "Return a portion of the tags for the specified repository.",
- PathParameters: []ParameterDescriptor{nameParameterDescriptor},
- QueryParameters: paginationParameters,
- Successes: []ResponseDescriptor{
- {
- StatusCode: http.StatusOK,
- Description: "A list of tags for the named repository.",
- Headers: []ParameterDescriptor{
- {
- Name: "Content-Length",
- Type: "integer",
- Description: "Length of the JSON response body.",
- Format: "",
- },
- linkHeader,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: `{
- "name": ,
- "tags": [
- ,
- ...
- ],
-}`,
- },
- },
- },
- Failures: []ResponseDescriptor{
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- },
- },
- },
- },
- },
- },
- {
- Name: RouteNameManifest,
- Path: "/v2/{name:" + reference.NameRegexp.String() + "}/manifests/{reference:" + reference.TagRegexp.String() + "|" + digest.DigestRegexp.String() + "}",
- Entity: "Manifest",
- Description: "Create, update, delete and retrieve manifests.",
- Methods: []MethodDescriptor{
- {
- Method: "GET",
- Description: "Fetch the manifest identified by `name` and `reference` where `reference` can be a tag or digest. A `HEAD` request can also be issued to this endpoint to obtain resource information without receiving all data.",
- Requests: []RequestDescriptor{
- {
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- },
- PathParameters: []ParameterDescriptor{
- nameParameterDescriptor,
- referenceParameterDescriptor,
- },
- Successes: []ResponseDescriptor{
- {
- Description: "The manifest identified by `name` and `reference`. The contents can be used to identify and resolve resources required to run the specified image.",
- StatusCode: http.StatusOK,
- Headers: []ParameterDescriptor{
- digestHeader,
- },
- Body: BodyDescriptor{
- ContentType: "",
- Format: manifestBody,
- },
- },
- },
- Failures: []ResponseDescriptor{
- {
- Description: "The name or reference was invalid.",
- StatusCode: http.StatusBadRequest,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeNameInvalid,
- ErrorCodeTagInvalid,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- },
- },
- },
- },
- {
- Method: "PUT",
- Description: "Put the manifest identified by `name` and `reference` where `reference` can be a tag or digest.",
- Requests: []RequestDescriptor{
- {
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- },
- PathParameters: []ParameterDescriptor{
- nameParameterDescriptor,
- referenceParameterDescriptor,
- },
- Body: BodyDescriptor{
- ContentType: "",
- Format: manifestBody,
- },
- Successes: []ResponseDescriptor{
- {
- Description: "The manifest has been accepted by the registry and is stored under the specified `name` and `tag`.",
- StatusCode: http.StatusCreated,
- Headers: []ParameterDescriptor{
- {
- Name: "Location",
- Type: "url",
- Description: "The canonical location url of the uploaded manifest.",
- Format: "",
- },
- contentLengthZeroHeader,
- digestHeader,
- },
- },
- },
- Failures: []ResponseDescriptor{
- {
- Name: "Invalid Manifest",
- Description: "The received manifest was invalid in some way, as described by the error codes. The client should resolve the issue and retry the request.",
- StatusCode: http.StatusBadRequest,
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeNameInvalid,
- ErrorCodeTagInvalid,
- ErrorCodeManifestInvalid,
- ErrorCodeManifestUnverified,
- ErrorCodeBlobUnknown,
- },
- },
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- {
- Name: "Missing Layer(s)",
- Description: "One or more layers may be missing during a manifest upload. If so, the missing layers will be enumerated in the error response.",
- StatusCode: http.StatusBadRequest,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeBlobUnknown,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: `{
- "errors:" [{
- "code": "BLOB_UNKNOWN",
- "message": "blob unknown to registry",
- "detail": {
- "digest": ""
- }
- },
- ...
- ]
-}`,
- },
- },
- {
- Name: "Not allowed",
- Description: "Manifest put is not allowed because the registry is configured as a pull-through cache or for some other reason",
- StatusCode: http.StatusMethodNotAllowed,
- ErrorCodes: []errcode.ErrorCode{
- errcode.ErrorCodeUnsupported,
- },
- },
- },
- },
- },
- },
- {
- Method: "DELETE",
- Description: "Delete the manifest identified by `name` and `reference`. Note that a manifest can _only_ be deleted by `digest`.",
- Requests: []RequestDescriptor{
- {
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- },
- PathParameters: []ParameterDescriptor{
- nameParameterDescriptor,
- referenceParameterDescriptor,
- },
- Successes: []ResponseDescriptor{
- {
- StatusCode: http.StatusAccepted,
- },
- },
- Failures: []ResponseDescriptor{
- {
- Name: "Invalid Name or Reference",
- Description: "The specified `name` or `reference` were invalid and the delete was unable to proceed.",
- StatusCode: http.StatusBadRequest,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeNameInvalid,
- ErrorCodeTagInvalid,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- {
- Name: "Unknown Manifest",
- Description: "The specified `name` or `reference` are unknown to the registry and the delete was unable to proceed. Clients can assume the manifest was already deleted if this response is returned.",
- StatusCode: http.StatusNotFound,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeNameUnknown,
- ErrorCodeManifestUnknown,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- {
- Name: "Not allowed",
- Description: "Manifest delete is not allowed because the registry is configured as a pull-through cache or `delete` has been disabled.",
- StatusCode: http.StatusMethodNotAllowed,
- ErrorCodes: []errcode.ErrorCode{
- errcode.ErrorCodeUnsupported,
- },
- },
- },
- },
- },
- },
- },
- },
-
- {
- Name: RouteNameBlob,
- Path: "/v2/{name:" + reference.NameRegexp.String() + "}/blobs/{digest:" + digest.DigestRegexp.String() + "}",
- Entity: "Blob",
- Description: "Operations on blobs identified by `name` and `digest`. Used to fetch or delete layers by digest.",
- Methods: []MethodDescriptor{
- {
- Method: "GET",
- Description: "Retrieve the blob from the registry identified by `digest`. A `HEAD` request can also be issued to this endpoint to obtain resource information without receiving all data.",
- Requests: []RequestDescriptor{
- {
- Name: "Fetch Blob",
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- },
- PathParameters: []ParameterDescriptor{
- nameParameterDescriptor,
- digestPathParameter,
- },
- Successes: []ResponseDescriptor{
- {
- Description: "The blob identified by `digest` is available. The blob content will be present in the body of the request.",
- StatusCode: http.StatusOK,
- Headers: []ParameterDescriptor{
- {
- Name: "Content-Length",
- Type: "integer",
- Description: "The length of the requested blob content.",
- Format: "",
- },
- digestHeader,
- },
- Body: BodyDescriptor{
- ContentType: "application/octet-stream",
- Format: "",
- },
- },
- {
- Description: "The blob identified by `digest` is available at the provided location.",
- StatusCode: http.StatusTemporaryRedirect,
- Headers: []ParameterDescriptor{
- {
- Name: "Location",
- Type: "url",
- Description: "The location where the layer should be accessible.",
- Format: "",
- },
- digestHeader,
- },
- },
- },
- Failures: []ResponseDescriptor{
- {
- Description: "There was a problem with the request that needs to be addressed by the client, such as an invalid `name` or `tag`.",
- StatusCode: http.StatusBadRequest,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeNameInvalid,
- ErrorCodeDigestInvalid,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- {
- Description: "The blob, identified by `name` and `digest`, is unknown to the registry.",
- StatusCode: http.StatusNotFound,
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeNameUnknown,
- ErrorCodeBlobUnknown,
- },
- },
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- },
- },
- {
- Name: "Fetch Blob Part",
- Description: "This endpoint may also support RFC7233 compliant range requests. Support can be detected by issuing a HEAD request. If the header `Accept-Range: bytes` is returned, range requests can be used to fetch partial content.",
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- {
- Name: "Range",
- Type: "string",
- Description: "HTTP Range header specifying blob chunk.",
- Format: "bytes=-",
- },
- },
- PathParameters: []ParameterDescriptor{
- nameParameterDescriptor,
- digestPathParameter,
- },
- Successes: []ResponseDescriptor{
- {
- Description: "The blob identified by `digest` is available. The specified chunk of blob content will be present in the body of the request.",
- StatusCode: http.StatusPartialContent,
- Headers: []ParameterDescriptor{
- {
- Name: "Content-Length",
- Type: "integer",
- Description: "The length of the requested blob chunk.",
- Format: "",
- },
- {
- Name: "Content-Range",
- Type: "byte range",
- Description: "Content range of blob chunk.",
- Format: "bytes -/",
- },
- },
- Body: BodyDescriptor{
- ContentType: "application/octet-stream",
- Format: "",
- },
- },
- },
- Failures: []ResponseDescriptor{
- {
- Description: "There was a problem with the request that needs to be addressed by the client, such as an invalid `name` or `tag`.",
- StatusCode: http.StatusBadRequest,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeNameInvalid,
- ErrorCodeDigestInvalid,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- {
- StatusCode: http.StatusNotFound,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeNameUnknown,
- ErrorCodeBlobUnknown,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- {
- Description: "The range specification cannot be satisfied for the requested content. This can happen when the range is not formatted correctly or if the range is outside of the valid size of the content.",
- StatusCode: http.StatusRequestedRangeNotSatisfiable,
- },
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- },
- },
- },
- },
- {
- Method: "DELETE",
- Description: "Delete the blob identified by `name` and `digest`",
- Requests: []RequestDescriptor{
- {
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- },
- PathParameters: []ParameterDescriptor{
- nameParameterDescriptor,
- digestPathParameter,
- },
- Successes: []ResponseDescriptor{
- {
- StatusCode: http.StatusAccepted,
- Headers: []ParameterDescriptor{
- {
- Name: "Content-Length",
- Type: "integer",
- Description: "0",
- Format: "0",
- },
- digestHeader,
- },
- },
- },
- Failures: []ResponseDescriptor{
- {
- Name: "Invalid Name or Digest",
- StatusCode: http.StatusBadRequest,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeDigestInvalid,
- ErrorCodeNameInvalid,
- },
- },
- {
- Description: "The blob, identified by `name` and `digest`, is unknown to the registry.",
- StatusCode: http.StatusNotFound,
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeNameUnknown,
- ErrorCodeBlobUnknown,
- },
- },
- {
- Description: "Blob delete is not allowed because the registry is configured as a pull-through cache or `delete` has been disabled",
- StatusCode: http.StatusMethodNotAllowed,
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- ErrorCodes: []errcode.ErrorCode{
- errcode.ErrorCodeUnsupported,
- },
- },
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- },
- },
- },
- },
-
- // TODO(stevvooe): We may want to add a PUT request here to
- // kickoff an upload of a blob, integrated with the blob upload
- // API.
- },
- },
-
- {
- Name: RouteNameBlobUpload,
- Path: "/v2/{name:" + reference.NameRegexp.String() + "}/blobs/uploads/",
- Entity: "Initiate Blob Upload",
- Description: "Initiate a blob upload. This endpoint can be used to create resumable uploads or monolithic uploads.",
- Methods: []MethodDescriptor{
- {
- Method: "POST",
- Description: "Initiate a resumable blob upload. If successful, an upload location will be provided to complete the upload. Optionally, if the `digest` parameter is present, the request body will be used to complete the upload in a single request.",
- Requests: []RequestDescriptor{
- {
- Name: "Initiate Monolithic Blob Upload",
- Description: "Upload a blob identified by the `digest` parameter in single request. This upload will not be resumable unless a recoverable error is returned.",
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- {
- Name: "Content-Length",
- Type: "integer",
- Format: "",
- },
- },
- PathParameters: []ParameterDescriptor{
- nameParameterDescriptor,
- },
- QueryParameters: []ParameterDescriptor{
- {
- Name: "digest",
- Type: "query",
- Format: "",
- Regexp: digest.DigestRegexp,
- Description: `Digest of uploaded blob. If present, the upload will be completed, in a single request, with contents of the request body as the resulting blob.`,
- },
- },
- Body: BodyDescriptor{
- ContentType: "application/octect-stream",
- Format: "",
- },
- Successes: []ResponseDescriptor{
- {
- Description: "The blob has been created in the registry and is available at the provided location.",
- StatusCode: http.StatusCreated,
- Headers: []ParameterDescriptor{
- {
- Name: "Location",
- Type: "url",
- Format: "",
- },
- contentLengthZeroHeader,
- dockerUploadUUIDHeader,
- },
- },
- },
- Failures: []ResponseDescriptor{
- {
- Name: "Invalid Name or Digest",
- StatusCode: http.StatusBadRequest,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeDigestInvalid,
- ErrorCodeNameInvalid,
- },
- },
- {
- Name: "Not allowed",
- Description: "Blob upload is not allowed because the registry is configured as a pull-through cache or for some other reason",
- StatusCode: http.StatusMethodNotAllowed,
- ErrorCodes: []errcode.ErrorCode{
- errcode.ErrorCodeUnsupported,
- },
- },
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- },
- },
- {
- Name: "Initiate Resumable Blob Upload",
- Description: "Initiate a resumable blob upload with an empty request body.",
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- contentLengthZeroHeader,
- },
- PathParameters: []ParameterDescriptor{
- nameParameterDescriptor,
- },
- Successes: []ResponseDescriptor{
- {
- Description: "The upload has been created. The `Location` header must be used to complete the upload. The response should be identical to a `GET` request on the contents of the returned `Location` header.",
- StatusCode: http.StatusAccepted,
- Headers: []ParameterDescriptor{
- contentLengthZeroHeader,
- {
- Name: "Location",
- Type: "url",
- Format: "/v2//blobs/uploads/",
- Description: "The location of the created upload. Clients should use the contents verbatim to complete the upload, adding parameters where required.",
- },
- {
- Name: "Range",
- Format: "0-0",
- Description: "Range header indicating the progress of the upload. When starting an upload, it will return an empty range, since no content has been received.",
- },
- dockerUploadUUIDHeader,
- },
- },
- },
- Failures: []ResponseDescriptor{
- {
- Name: "Invalid Name or Digest",
- StatusCode: http.StatusBadRequest,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeDigestInvalid,
- ErrorCodeNameInvalid,
- },
- },
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- },
- },
- {
- Name: "Mount Blob",
- Description: "Mount a blob identified by the `mount` parameter from another repository.",
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- contentLengthZeroHeader,
- },
- PathParameters: []ParameterDescriptor{
- nameParameterDescriptor,
- },
- QueryParameters: []ParameterDescriptor{
- {
- Name: "mount",
- Type: "query",
- Format: "",
- Regexp: digest.DigestRegexp,
- Description: `Digest of blob to mount from the source repository.`,
- },
- {
- Name: "from",
- Type: "query",
- Format: "",
- Regexp: reference.NameRegexp,
- Description: `Name of the source repository.`,
- },
- },
- Successes: []ResponseDescriptor{
- {
- Description: "The blob has been mounted in the repository and is available at the provided location.",
- StatusCode: http.StatusCreated,
- Headers: []ParameterDescriptor{
- {
- Name: "Location",
- Type: "url",
- Format: "",
- },
- contentLengthZeroHeader,
- dockerUploadUUIDHeader,
- },
- },
- },
- Failures: []ResponseDescriptor{
- {
- Name: "Invalid Name or Digest",
- StatusCode: http.StatusBadRequest,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeDigestInvalid,
- ErrorCodeNameInvalid,
- },
- },
- {
- Name: "Not allowed",
- Description: "Blob mount is not allowed because the registry is configured as a pull-through cache or for some other reason",
- StatusCode: http.StatusMethodNotAllowed,
- ErrorCodes: []errcode.ErrorCode{
- errcode.ErrorCodeUnsupported,
- },
- },
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- },
- },
- },
- },
- },
- },
-
- {
- Name: RouteNameBlobUploadChunk,
- Path: "/v2/{name:" + reference.NameRegexp.String() + "}/blobs/uploads/{uuid:[a-zA-Z0-9-_.=]+}",
- Entity: "Blob Upload",
- Description: "Interact with blob uploads. Clients should never assemble URLs for this endpoint and should only take it through the `Location` header on related API requests. The `Location` header and its parameters should be preserved by clients, using the latest value returned via upload related API calls.",
- Methods: []MethodDescriptor{
- {
- Method: "GET",
- Description: "Retrieve status of upload identified by `uuid`. The primary purpose of this endpoint is to resolve the current status of a resumable upload.",
- Requests: []RequestDescriptor{
- {
- Description: "Retrieve the progress of the current upload, as reported by the `Range` header.",
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- },
- PathParameters: []ParameterDescriptor{
- nameParameterDescriptor,
- uuidParameterDescriptor,
- },
- Successes: []ResponseDescriptor{
- {
- Name: "Upload Progress",
- Description: "The upload is known and in progress. The last received offset is available in the `Range` header.",
- StatusCode: http.StatusNoContent,
- Headers: []ParameterDescriptor{
- {
- Name: "Range",
- Type: "header",
- Format: "0-",
- Description: "Range indicating the current progress of the upload.",
- },
- contentLengthZeroHeader,
- dockerUploadUUIDHeader,
- },
- },
- },
- Failures: []ResponseDescriptor{
- {
- Description: "There was an error processing the upload and it must be restarted.",
- StatusCode: http.StatusBadRequest,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeDigestInvalid,
- ErrorCodeNameInvalid,
- ErrorCodeBlobUploadInvalid,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- {
- Description: "The upload is unknown to the registry. The upload must be restarted.",
- StatusCode: http.StatusNotFound,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeBlobUploadUnknown,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- },
- },
- },
- },
- {
- Method: "PATCH",
- Description: "Upload a chunk of data for the specified upload.",
- Requests: []RequestDescriptor{
- {
- Name: "Stream upload",
- Description: "Upload a stream of data to upload without completing the upload.",
- PathParameters: []ParameterDescriptor{
- nameParameterDescriptor,
- uuidParameterDescriptor,
- },
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- },
- Body: BodyDescriptor{
- ContentType: "application/octet-stream",
- Format: "",
- },
- Successes: []ResponseDescriptor{
- {
- Name: "Data Accepted",
- Description: "The stream of data has been accepted and the current progress is available in the range header. The updated upload location is available in the `Location` header.",
- StatusCode: http.StatusNoContent,
- Headers: []ParameterDescriptor{
- {
- Name: "Location",
- Type: "url",
- Format: "/v2//blobs/uploads/",
- Description: "The location of the upload. Clients should assume this changes after each request. Clients should use the contents verbatim to complete the upload, adding parameters where required.",
- },
- {
- Name: "Range",
- Type: "header",
- Format: "0-",
- Description: "Range indicating the current progress of the upload.",
- },
- contentLengthZeroHeader,
- dockerUploadUUIDHeader,
- },
- },
- },
- Failures: []ResponseDescriptor{
- {
- Description: "There was an error processing the upload and it must be restarted.",
- StatusCode: http.StatusBadRequest,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeDigestInvalid,
- ErrorCodeNameInvalid,
- ErrorCodeBlobUploadInvalid,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- {
- Description: "The upload is unknown to the registry. The upload must be restarted.",
- StatusCode: http.StatusNotFound,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeBlobUploadUnknown,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- },
- },
- {
- Name: "Chunked upload",
- Description: "Upload a chunk of data to specified upload without completing the upload. The data will be uploaded to the specified Content Range.",
- PathParameters: []ParameterDescriptor{
- nameParameterDescriptor,
- uuidParameterDescriptor,
- },
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- {
- Name: "Content-Range",
- Type: "header",
- Format: "-",
- Required: true,
- Description: "Range of bytes identifying the desired block of content represented by the body. Start must the end offset retrieved via status check plus one. Note that this is a non-standard use of the `Content-Range` header.",
- },
- {
- Name: "Content-Length",
- Type: "integer",
- Format: "",
- Description: "Length of the chunk being uploaded, corresponding the length of the request body.",
- },
- },
- Body: BodyDescriptor{
- ContentType: "application/octet-stream",
- Format: "",
- },
- Successes: []ResponseDescriptor{
- {
- Name: "Chunk Accepted",
- Description: "The chunk of data has been accepted and the current progress is available in the range header. The updated upload location is available in the `Location` header.",
- StatusCode: http.StatusNoContent,
- Headers: []ParameterDescriptor{
- {
- Name: "Location",
- Type: "url",
- Format: "/v2//blobs/uploads/",
- Description: "The location of the upload. Clients should assume this changes after each request. Clients should use the contents verbatim to complete the upload, adding parameters where required.",
- },
- {
- Name: "Range",
- Type: "header",
- Format: "0-",
- Description: "Range indicating the current progress of the upload.",
- },
- contentLengthZeroHeader,
- dockerUploadUUIDHeader,
- },
- },
- },
- Failures: []ResponseDescriptor{
- {
- Description: "There was an error processing the upload and it must be restarted.",
- StatusCode: http.StatusBadRequest,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeDigestInvalid,
- ErrorCodeNameInvalid,
- ErrorCodeBlobUploadInvalid,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- {
- Description: "The upload is unknown to the registry. The upload must be restarted.",
- StatusCode: http.StatusNotFound,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeBlobUploadUnknown,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- {
- Description: "The `Content-Range` specification cannot be accepted, either because it does not overlap with the current progress or it is invalid.",
- StatusCode: http.StatusRequestedRangeNotSatisfiable,
- },
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- },
- },
- },
- },
- {
- Method: "PUT",
- Description: "Complete the upload specified by `uuid`, optionally appending the body as the final chunk.",
- Requests: []RequestDescriptor{
- {
- Description: "Complete the upload, providing all the data in the body, if necessary. A request without a body will just complete the upload with previously uploaded content.",
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- {
- Name: "Content-Length",
- Type: "integer",
- Format: "",
- Description: "Length of the data being uploaded, corresponding to the length of the request body. May be zero if no data is provided.",
- },
- },
- PathParameters: []ParameterDescriptor{
- nameParameterDescriptor,
- uuidParameterDescriptor,
- },
- QueryParameters: []ParameterDescriptor{
- {
- Name: "digest",
- Type: "string",
- Format: "",
- Regexp: digest.DigestRegexp,
- Required: true,
- Description: `Digest of uploaded blob.`,
- },
- },
- Body: BodyDescriptor{
- ContentType: "application/octet-stream",
- Format: "",
- },
- Successes: []ResponseDescriptor{
- {
- Name: "Upload Complete",
- Description: "The upload has been completed and accepted by the registry. The canonical location will be available in the `Location` header.",
- StatusCode: http.StatusNoContent,
- Headers: []ParameterDescriptor{
- {
- Name: "Location",
- Type: "url",
- Format: "",
- Description: "The canonical location of the blob for retrieval",
- },
- {
- Name: "Content-Range",
- Type: "header",
- Format: "-",
- Description: "Range of bytes identifying the desired block of content represented by the body. Start must match the end of offset retrieved via status check. Note that this is a non-standard use of the `Content-Range` header.",
- },
- contentLengthZeroHeader,
- digestHeader,
- },
- },
- },
- Failures: []ResponseDescriptor{
- {
- Description: "There was an error processing the upload and it must be restarted.",
- StatusCode: http.StatusBadRequest,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeDigestInvalid,
- ErrorCodeNameInvalid,
- ErrorCodeBlobUploadInvalid,
- errcode.ErrorCodeUnsupported,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- {
- Description: "The upload is unknown to the registry. The upload must be restarted.",
- StatusCode: http.StatusNotFound,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeBlobUploadUnknown,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- },
- },
- },
- },
- {
- Method: "DELETE",
- Description: "Cancel outstanding upload processes, releasing associated resources. If this is not called, the unfinished uploads will eventually timeout.",
- Requests: []RequestDescriptor{
- {
- Description: "Cancel the upload specified by `uuid`.",
- PathParameters: []ParameterDescriptor{
- nameParameterDescriptor,
- uuidParameterDescriptor,
- },
- Headers: []ParameterDescriptor{
- hostHeader,
- authHeader,
- contentLengthZeroHeader,
- },
- Successes: []ResponseDescriptor{
- {
- Name: "Upload Deleted",
- Description: "The upload has been successfully deleted.",
- StatusCode: http.StatusNoContent,
- Headers: []ParameterDescriptor{
- contentLengthZeroHeader,
- },
- },
- },
- Failures: []ResponseDescriptor{
- {
- Description: "An error was encountered processing the delete. The client may ignore this error.",
- StatusCode: http.StatusBadRequest,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeNameInvalid,
- ErrorCodeBlobUploadInvalid,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- {
- Description: "The upload is unknown to the registry. The client may ignore this error and assume the upload has been deleted.",
- StatusCode: http.StatusNotFound,
- ErrorCodes: []errcode.ErrorCode{
- ErrorCodeBlobUploadUnknown,
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: errorsBody,
- },
- },
- unauthorizedResponseDescriptor,
- repositoryNotFoundResponseDescriptor,
- deniedResponseDescriptor,
- tooManyRequestsDescriptor,
- },
- },
- },
- },
- },
- },
- {
- Name: RouteNameCatalog,
- Path: "/v2/_catalog",
- Entity: "Catalog",
- Description: "List a set of available repositories in the local registry cluster. Does not provide any indication of what may be available upstream. Applications can only determine if a repository is available but not if it is not available.",
- Methods: []MethodDescriptor{
- {
- Method: "GET",
- Description: "Retrieve a sorted, json list of repositories available in the registry.",
- Requests: []RequestDescriptor{
- {
- Name: "Catalog Fetch",
- Description: "Request an unabridged list of repositories available. The implementation may impose a maximum limit and return a partial set with pagination links.",
- Successes: []ResponseDescriptor{
- {
- Description: "Returns the unabridged list of repositories as a json response.",
- StatusCode: http.StatusOK,
- Headers: []ParameterDescriptor{
- {
- Name: "Content-Length",
- Type: "integer",
- Description: "Length of the JSON response body.",
- Format: "",
- },
- },
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: `{
- "repositories": [
- ,
- ...
- ]
-}`,
- },
- },
- },
- },
- {
- Name: "Catalog Fetch Paginated",
- Description: "Return the specified portion of repositories.",
- QueryParameters: paginationParameters,
- Successes: []ResponseDescriptor{
- {
- StatusCode: http.StatusOK,
- Body: BodyDescriptor{
- ContentType: "application/json; charset=utf-8",
- Format: `{
- "repositories": [
- ,
- ...
- ]
- "next": "?last=&n="
-}`,
- },
- Headers: []ParameterDescriptor{
- {
- Name: "Content-Length",
- Type: "integer",
- Description: "Length of the JSON response body.",
- Format: "",
- },
- linkHeader,
- },
- },
- },
- },
- },
- },
- },
- },
-}
-
-var routeDescriptorsMap map[string]RouteDescriptor
-
-func init() {
- routeDescriptorsMap = make(map[string]RouteDescriptor, len(routeDescriptors))
-
- for _, descriptor := range routeDescriptors {
- routeDescriptorsMap[descriptor.Name] = descriptor
- }
-}
diff --git a/vendor/github.com/docker/distribution/registry/api/v2/doc.go b/vendor/github.com/docker/distribution/registry/api/v2/doc.go
deleted file mode 100644
index cde011959..000000000
--- a/vendor/github.com/docker/distribution/registry/api/v2/doc.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// Package v2 describes routes, urls and the error codes used in the Docker
-// Registry JSON HTTP API V2. In addition to declarations, descriptors are
-// provided for routes and error codes that can be used for implementation and
-// automatically generating documentation.
-//
-// Definitions here are considered to be locked down for the V2 registry api.
-// Any changes must be considered carefully and should not proceed without a
-// change proposal in docker core.
-package v2
diff --git a/vendor/github.com/docker/distribution/registry/api/v2/errors.go b/vendor/github.com/docker/distribution/registry/api/v2/errors.go
deleted file mode 100644
index 97d6923aa..000000000
--- a/vendor/github.com/docker/distribution/registry/api/v2/errors.go
+++ /dev/null
@@ -1,136 +0,0 @@
-package v2
-
-import (
- "net/http"
-
- "github.com/docker/distribution/registry/api/errcode"
-)
-
-const errGroup = "registry.api.v2"
-
-var (
- // ErrorCodeDigestInvalid is returned when uploading a blob if the
- // provided digest does not match the blob contents.
- ErrorCodeDigestInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{
- Value: "DIGEST_INVALID",
- Message: "provided digest did not match uploaded content",
- Description: `When a blob is uploaded, the registry will check that
- the content matches the digest provided by the client. The error may
- include a detail structure with the key "digest", including the
- invalid digest string. This error may also be returned when a manifest
- includes an invalid layer digest.`,
- HTTPStatusCode: http.StatusBadRequest,
- })
-
- // ErrorCodeSizeInvalid is returned when uploading a blob if the provided
- ErrorCodeSizeInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{
- Value: "SIZE_INVALID",
- Message: "provided length did not match content length",
- Description: `When a layer is uploaded, the provided size will be
- checked against the uploaded content. If they do not match, this error
- will be returned.`,
- HTTPStatusCode: http.StatusBadRequest,
- })
-
- // ErrorCodeNameInvalid is returned when the name in the manifest does not
- // match the provided name.
- ErrorCodeNameInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{
- Value: "NAME_INVALID",
- Message: "invalid repository name",
- Description: `Invalid repository name encountered either during
- manifest validation or any API operation.`,
- HTTPStatusCode: http.StatusBadRequest,
- })
-
- // ErrorCodeTagInvalid is returned when the tag in the manifest does not
- // match the provided tag.
- ErrorCodeTagInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{
- Value: "TAG_INVALID",
- Message: "manifest tag did not match URI",
- Description: `During a manifest upload, if the tag in the manifest
- does not match the uri tag, this error will be returned.`,
- HTTPStatusCode: http.StatusBadRequest,
- })
-
- // ErrorCodeNameUnknown when the repository name is not known.
- ErrorCodeNameUnknown = errcode.Register(errGroup, errcode.ErrorDescriptor{
- Value: "NAME_UNKNOWN",
- Message: "repository name not known to registry",
- Description: `This is returned if the name used during an operation is
- unknown to the registry.`,
- HTTPStatusCode: http.StatusNotFound,
- })
-
- // ErrorCodeManifestUnknown returned when image manifest is unknown.
- ErrorCodeManifestUnknown = errcode.Register(errGroup, errcode.ErrorDescriptor{
- Value: "MANIFEST_UNKNOWN",
- Message: "manifest unknown",
- Description: `This error is returned when the manifest, identified by
- name and tag is unknown to the repository.`,
- HTTPStatusCode: http.StatusNotFound,
- })
-
- // ErrorCodeManifestInvalid returned when an image manifest is invalid,
- // typically during a PUT operation. This error encompasses all errors
- // encountered during manifest validation that aren't signature errors.
- ErrorCodeManifestInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{
- Value: "MANIFEST_INVALID",
- Message: "manifest invalid",
- Description: `During upload, manifests undergo several checks ensuring
- validity. If those checks fail, this error may be returned, unless a
- more specific error is included. The detail will contain information
- the failed validation.`,
- HTTPStatusCode: http.StatusBadRequest,
- })
-
- // ErrorCodeManifestUnverified is returned when the manifest fails
- // signature verification.
- ErrorCodeManifestUnverified = errcode.Register(errGroup, errcode.ErrorDescriptor{
- Value: "MANIFEST_UNVERIFIED",
- Message: "manifest failed signature verification",
- Description: `During manifest upload, if the manifest fails signature
- verification, this error will be returned.`,
- HTTPStatusCode: http.StatusBadRequest,
- })
-
- // ErrorCodeManifestBlobUnknown is returned when a manifest blob is
- // unknown to the registry.
- ErrorCodeManifestBlobUnknown = errcode.Register(errGroup, errcode.ErrorDescriptor{
- Value: "MANIFEST_BLOB_UNKNOWN",
- Message: "blob unknown to registry",
- Description: `This error may be returned when a manifest blob is
- unknown to the registry.`,
- HTTPStatusCode: http.StatusBadRequest,
- })
-
- // ErrorCodeBlobUnknown is returned when a blob is unknown to the
- // registry. This can happen when the manifest references a nonexistent
- // layer or the result is not found by a blob fetch.
- ErrorCodeBlobUnknown = errcode.Register(errGroup, errcode.ErrorDescriptor{
- Value: "BLOB_UNKNOWN",
- Message: "blob unknown to registry",
- Description: `This error may be returned when a blob is unknown to the
- registry in a specified repository. This can be returned with a
- standard get or if a manifest references an unknown layer during
- upload.`,
- HTTPStatusCode: http.StatusNotFound,
- })
-
- // ErrorCodeBlobUploadUnknown is returned when an upload is unknown.
- ErrorCodeBlobUploadUnknown = errcode.Register(errGroup, errcode.ErrorDescriptor{
- Value: "BLOB_UPLOAD_UNKNOWN",
- Message: "blob upload unknown to registry",
- Description: `If a blob upload has been cancelled or was never
- started, this error code may be returned.`,
- HTTPStatusCode: http.StatusNotFound,
- })
-
- // ErrorCodeBlobUploadInvalid is returned when an upload is invalid.
- ErrorCodeBlobUploadInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{
- Value: "BLOB_UPLOAD_INVALID",
- Message: "blob upload invalid",
- Description: `The blob upload encountered an error and can no
- longer proceed.`,
- HTTPStatusCode: http.StatusNotFound,
- })
-)
diff --git a/vendor/github.com/docker/distribution/registry/api/v2/routes.go b/vendor/github.com/docker/distribution/registry/api/v2/routes.go
deleted file mode 100644
index 5b80d5be7..000000000
--- a/vendor/github.com/docker/distribution/registry/api/v2/routes.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package v2
-
-import "github.com/gorilla/mux"
-
-// The following are definitions of the name under which all V2 routes are
-// registered. These symbols can be used to look up a route based on the name.
-const (
- RouteNameBase = "base"
- RouteNameManifest = "manifest"
- RouteNameTags = "tags"
- RouteNameBlob = "blob"
- RouteNameBlobUpload = "blob-upload"
- RouteNameBlobUploadChunk = "blob-upload-chunk"
- RouteNameCatalog = "catalog"
-)
-
-var allEndpoints = []string{
- RouteNameManifest,
- RouteNameCatalog,
- RouteNameTags,
- RouteNameBlob,
- RouteNameBlobUpload,
- RouteNameBlobUploadChunk,
-}
-
-// Router builds a gorilla router with named routes for the various API
-// methods. This can be used directly by both server implementations and
-// clients.
-func Router() *mux.Router {
- return RouterWithPrefix("")
-}
-
-// RouterWithPrefix builds a gorilla router with a configured prefix
-// on all routes.
-func RouterWithPrefix(prefix string) *mux.Router {
- rootRouter := mux.NewRouter()
- router := rootRouter
- if prefix != "" {
- router = router.PathPrefix(prefix).Subrouter()
- }
-
- router.StrictSlash(true)
-
- for _, descriptor := range routeDescriptors {
- router.Path(descriptor.Path).Name(descriptor.Name)
- }
-
- return rootRouter
-}
diff --git a/vendor/github.com/docker/distribution/registry/api/v2/urls.go b/vendor/github.com/docker/distribution/registry/api/v2/urls.go
deleted file mode 100644
index a959aaa89..000000000
--- a/vendor/github.com/docker/distribution/registry/api/v2/urls.go
+++ /dev/null
@@ -1,251 +0,0 @@
-package v2
-
-import (
- "net/http"
- "net/url"
- "strings"
-
- "github.com/docker/distribution/reference"
- "github.com/gorilla/mux"
-)
-
-// URLBuilder creates registry API urls from a single base endpoint. It can be
-// used to create urls for use in a registry client or server.
-//
-// All urls will be created from the given base, including the api version.
-// For example, if a root of "/foo/" is provided, urls generated will be fall
-// under "/foo/v2/...". Most application will only provide a schema, host and
-// port, such as "https://localhost:5000/".
-type URLBuilder struct {
- root *url.URL // url root (ie http://localhost/)
- router *mux.Router
- relative bool
-}
-
-// NewURLBuilder creates a URLBuilder with provided root url object.
-func NewURLBuilder(root *url.URL, relative bool) *URLBuilder {
- return &URLBuilder{
- root: root,
- router: Router(),
- relative: relative,
- }
-}
-
-// NewURLBuilderFromString workes identically to NewURLBuilder except it takes
-// a string argument for the root, returning an error if it is not a valid
-// url.
-func NewURLBuilderFromString(root string, relative bool) (*URLBuilder, error) {
- u, err := url.Parse(root)
- if err != nil {
- return nil, err
- }
-
- return NewURLBuilder(u, relative), nil
-}
-
-// NewURLBuilderFromRequest uses information from an *http.Request to
-// construct the root url.
-func NewURLBuilderFromRequest(r *http.Request, relative bool) *URLBuilder {
- var scheme string
-
- forwardedProto := r.Header.Get("X-Forwarded-Proto")
-
- switch {
- case len(forwardedProto) > 0:
- scheme = forwardedProto
- case r.TLS != nil:
- scheme = "https"
- case len(r.URL.Scheme) > 0:
- scheme = r.URL.Scheme
- default:
- scheme = "http"
- }
-
- host := r.Host
- forwardedHost := r.Header.Get("X-Forwarded-Host")
- if len(forwardedHost) > 0 {
- // According to the Apache mod_proxy docs, X-Forwarded-Host can be a
- // comma-separated list of hosts, to which each proxy appends the
- // requested host. We want to grab the first from this comma-separated
- // list.
- hosts := strings.SplitN(forwardedHost, ",", 2)
- host = strings.TrimSpace(hosts[0])
- }
-
- basePath := routeDescriptorsMap[RouteNameBase].Path
-
- requestPath := r.URL.Path
- index := strings.Index(requestPath, basePath)
-
- u := &url.URL{
- Scheme: scheme,
- Host: host,
- }
-
- if index > 0 {
- // N.B. index+1 is important because we want to include the trailing /
- u.Path = requestPath[0 : index+1]
- }
-
- return NewURLBuilder(u, relative)
-}
-
-// BuildBaseURL constructs a base url for the API, typically just "/v2/".
-func (ub *URLBuilder) BuildBaseURL() (string, error) {
- route := ub.cloneRoute(RouteNameBase)
-
- baseURL, err := route.URL()
- if err != nil {
- return "", err
- }
-
- return baseURL.String(), nil
-}
-
-// BuildCatalogURL constructs a url get a catalog of repositories
-func (ub *URLBuilder) BuildCatalogURL(values ...url.Values) (string, error) {
- route := ub.cloneRoute(RouteNameCatalog)
-
- catalogURL, err := route.URL()
- if err != nil {
- return "", err
- }
-
- return appendValuesURL(catalogURL, values...).String(), nil
-}
-
-// BuildTagsURL constructs a url to list the tags in the named repository.
-func (ub *URLBuilder) BuildTagsURL(name reference.Named) (string, error) {
- route := ub.cloneRoute(RouteNameTags)
-
- tagsURL, err := route.URL("name", name.Name())
- if err != nil {
- return "", err
- }
-
- return tagsURL.String(), nil
-}
-
-// BuildManifestURL constructs a url for the manifest identified by name and
-// reference. The argument reference may be either a tag or digest.
-func (ub *URLBuilder) BuildManifestURL(ref reference.Named) (string, error) {
- route := ub.cloneRoute(RouteNameManifest)
-
- tagOrDigest := ""
- switch v := ref.(type) {
- case reference.Tagged:
- tagOrDigest = v.Tag()
- case reference.Digested:
- tagOrDigest = v.Digest().String()
- }
-
- manifestURL, err := route.URL("name", ref.Name(), "reference", tagOrDigest)
- if err != nil {
- return "", err
- }
-
- return manifestURL.String(), nil
-}
-
-// BuildBlobURL constructs the url for the blob identified by name and dgst.
-func (ub *URLBuilder) BuildBlobURL(ref reference.Canonical) (string, error) {
- route := ub.cloneRoute(RouteNameBlob)
-
- layerURL, err := route.URL("name", ref.Name(), "digest", ref.Digest().String())
- if err != nil {
- return "", err
- }
-
- return layerURL.String(), nil
-}
-
-// BuildBlobUploadURL constructs a url to begin a blob upload in the
-// repository identified by name.
-func (ub *URLBuilder) BuildBlobUploadURL(name reference.Named, values ...url.Values) (string, error) {
- route := ub.cloneRoute(RouteNameBlobUpload)
-
- uploadURL, err := route.URL("name", name.Name())
- if err != nil {
- return "", err
- }
-
- return appendValuesURL(uploadURL, values...).String(), nil
-}
-
-// BuildBlobUploadChunkURL constructs a url for the upload identified by uuid,
-// including any url values. This should generally not be used by clients, as
-// this url is provided by server implementations during the blob upload
-// process.
-func (ub *URLBuilder) BuildBlobUploadChunkURL(name reference.Named, uuid string, values ...url.Values) (string, error) {
- route := ub.cloneRoute(RouteNameBlobUploadChunk)
-
- uploadURL, err := route.URL("name", name.Name(), "uuid", uuid)
- if err != nil {
- return "", err
- }
-
- return appendValuesURL(uploadURL, values...).String(), nil
-}
-
-// clondedRoute returns a clone of the named route from the router. Routes
-// must be cloned to avoid modifying them during url generation.
-func (ub *URLBuilder) cloneRoute(name string) clonedRoute {
- route := new(mux.Route)
- root := new(url.URL)
-
- *route = *ub.router.GetRoute(name) // clone the route
- *root = *ub.root
-
- return clonedRoute{Route: route, root: root, relative: ub.relative}
-}
-
-type clonedRoute struct {
- *mux.Route
- root *url.URL
- relative bool
-}
-
-func (cr clonedRoute) URL(pairs ...string) (*url.URL, error) {
- routeURL, err := cr.Route.URL(pairs...)
- if err != nil {
- return nil, err
- }
-
- if cr.relative {
- return routeURL, nil
- }
-
- if routeURL.Scheme == "" && routeURL.User == nil && routeURL.Host == "" {
- routeURL.Path = routeURL.Path[1:]
- }
-
- url := cr.root.ResolveReference(routeURL)
- url.Scheme = cr.root.Scheme
- return url, nil
-}
-
-// appendValuesURL appends the parameters to the url.
-func appendValuesURL(u *url.URL, values ...url.Values) *url.URL {
- merged := u.Query()
-
- for _, v := range values {
- for k, vv := range v {
- merged[k] = append(merged[k], vv...)
- }
- }
-
- u.RawQuery = merged.Encode()
- return u
-}
-
-// appendValues appends the parameters to the url. Panics if the string is not
-// a url.
-func appendValues(u string, values ...url.Values) string {
- up, err := url.Parse(u)
-
- if err != nil {
- panic(err) // should never happen
- }
-
- return appendValuesURL(up, values...).String()
-}
diff --git a/vendor/github.com/docker/distribution/registry/client/auth/api_version.go b/vendor/github.com/docker/distribution/registry/client/auth/api_version.go
deleted file mode 100644
index 7d8f1d957..000000000
--- a/vendor/github.com/docker/distribution/registry/client/auth/api_version.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package auth
-
-import (
- "net/http"
- "strings"
-)
-
-// APIVersion represents a version of an API including its
-// type and version number.
-type APIVersion struct {
- // Type refers to the name of a specific API specification
- // such as "registry"
- Type string
-
- // Version is the version of the API specification implemented,
- // This may omit the revision number and only include
- // the major and minor version, such as "2.0"
- Version string
-}
-
-// String returns the string formatted API Version
-func (v APIVersion) String() string {
- return v.Type + "/" + v.Version
-}
-
-// APIVersions gets the API versions out of an HTTP response using the provided
-// version header as the key for the HTTP header.
-func APIVersions(resp *http.Response, versionHeader string) []APIVersion {
- versions := []APIVersion{}
- if versionHeader != "" {
- for _, supportedVersions := range resp.Header[http.CanonicalHeaderKey(versionHeader)] {
- for _, version := range strings.Fields(supportedVersions) {
- versions = append(versions, ParseAPIVersion(version))
- }
- }
- }
- return versions
-}
-
-// ParseAPIVersion parses an API version string into an APIVersion
-// Format (Expected, not enforced):
-// API version string = '/'
-// API type = [a-z][a-z0-9]*
-// API version = [0-9]+(\.[0-9]+)?
-// TODO(dmcgowan): Enforce format, add error condition, remove unknown type
-func ParseAPIVersion(versionStr string) APIVersion {
- idx := strings.IndexRune(versionStr, '/')
- if idx == -1 {
- return APIVersion{
- Type: "unknown",
- Version: versionStr,
- }
- }
- return APIVersion{
- Type: strings.ToLower(versionStr[:idx]),
- Version: versionStr[idx+1:],
- }
-}
diff --git a/vendor/github.com/docker/distribution/registry/client/auth/authchallenge.go b/vendor/github.com/docker/distribution/registry/client/auth/authchallenge.go
deleted file mode 100644
index c8cd83bb9..000000000
--- a/vendor/github.com/docker/distribution/registry/client/auth/authchallenge.go
+++ /dev/null
@@ -1,220 +0,0 @@
-package auth
-
-import (
- "fmt"
- "net/http"
- "net/url"
- "strings"
-)
-
-// Challenge carries information from a WWW-Authenticate response header.
-// See RFC 2617.
-type Challenge struct {
- // Scheme is the auth-scheme according to RFC 2617
- Scheme string
-
- // Parameters are the auth-params according to RFC 2617
- Parameters map[string]string
-}
-
-// ChallengeManager manages the challenges for endpoints.
-// The challenges are pulled out of HTTP responses. Only
-// responses which expect challenges should be added to
-// the manager, since a non-unauthorized request will be
-// viewed as not requiring challenges.
-type ChallengeManager interface {
- // GetChallenges returns the challenges for the given
- // endpoint URL.
- GetChallenges(endpoint url.URL) ([]Challenge, error)
-
- // AddResponse adds the response to the challenge
- // manager. The challenges will be parsed out of
- // the WWW-Authenicate headers and added to the
- // URL which was produced the response. If the
- // response was authorized, any challenges for the
- // endpoint will be cleared.
- AddResponse(resp *http.Response) error
-}
-
-// NewSimpleChallengeManager returns an instance of
-// ChallengeManger which only maps endpoints to challenges
-// based on the responses which have been added the
-// manager. The simple manager will make no attempt to
-// perform requests on the endpoints or cache the responses
-// to a backend.
-func NewSimpleChallengeManager() ChallengeManager {
- return simpleChallengeManager{}
-}
-
-type simpleChallengeManager map[string][]Challenge
-
-func (m simpleChallengeManager) GetChallenges(endpoint url.URL) ([]Challenge, error) {
- endpoint.Host = strings.ToLower(endpoint.Host)
-
- challenges := m[endpoint.String()]
- return challenges, nil
-}
-
-func (m simpleChallengeManager) AddResponse(resp *http.Response) error {
- challenges := ResponseChallenges(resp)
- if resp.Request == nil {
- return fmt.Errorf("missing request reference")
- }
- urlCopy := url.URL{
- Path: resp.Request.URL.Path,
- Host: strings.ToLower(resp.Request.URL.Host),
- Scheme: resp.Request.URL.Scheme,
- }
- m[urlCopy.String()] = challenges
- return nil
-}
-
-// Octet types from RFC 2616.
-type octetType byte
-
-var octetTypes [256]octetType
-
-const (
- isToken octetType = 1 << iota
- isSpace
-)
-
-func init() {
- // OCTET =
- // CHAR =
- // CTL =
- // CR =
- // LF =
- // SP =
- // HT =
- // <"> =
- // CRLF = CR LF
- // LWS = [CRLF] 1*( SP | HT )
- // TEXT =
- // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <">
- // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
- // token = 1*
- // qdtext = >
-
- for c := 0; c < 256; c++ {
- var t octetType
- isCtl := c <= 31 || c == 127
- isChar := 0 <= c && c <= 127
- isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0
- if strings.IndexRune(" \t\r\n", rune(c)) >= 0 {
- t |= isSpace
- }
- if isChar && !isCtl && !isSeparator {
- t |= isToken
- }
- octetTypes[c] = t
- }
-}
-
-// ResponseChallenges returns a list of authorization challenges
-// for the given http Response. Challenges are only checked if
-// the response status code was a 401.
-func ResponseChallenges(resp *http.Response) []Challenge {
- if resp.StatusCode == http.StatusUnauthorized {
- // Parse the WWW-Authenticate Header and store the challenges
- // on this endpoint object.
- return parseAuthHeader(resp.Header)
- }
-
- return nil
-}
-
-func parseAuthHeader(header http.Header) []Challenge {
- challenges := []Challenge{}
- for _, h := range header[http.CanonicalHeaderKey("WWW-Authenticate")] {
- v, p := parseValueAndParams(h)
- if v != "" {
- challenges = append(challenges, Challenge{Scheme: v, Parameters: p})
- }
- }
- return challenges
-}
-
-func parseValueAndParams(header string) (value string, params map[string]string) {
- params = make(map[string]string)
- value, s := expectToken(header)
- if value == "" {
- return
- }
- value = strings.ToLower(value)
- s = "," + skipSpace(s)
- for strings.HasPrefix(s, ",") {
- var pkey string
- pkey, s = expectToken(skipSpace(s[1:]))
- if pkey == "" {
- return
- }
- if !strings.HasPrefix(s, "=") {
- return
- }
- var pvalue string
- pvalue, s = expectTokenOrQuoted(s[1:])
- if pvalue == "" {
- return
- }
- pkey = strings.ToLower(pkey)
- params[pkey] = pvalue
- s = skipSpace(s)
- }
- return
-}
-
-func skipSpace(s string) (rest string) {
- i := 0
- for ; i < len(s); i++ {
- if octetTypes[s[i]]&isSpace == 0 {
- break
- }
- }
- return s[i:]
-}
-
-func expectToken(s string) (token, rest string) {
- i := 0
- for ; i < len(s); i++ {
- if octetTypes[s[i]]&isToken == 0 {
- break
- }
- }
- return s[:i], s[i:]
-}
-
-func expectTokenOrQuoted(s string) (value string, rest string) {
- if !strings.HasPrefix(s, "\"") {
- return expectToken(s)
- }
- s = s[1:]
- for i := 0; i < len(s); i++ {
- switch s[i] {
- case '"':
- return s[:i], s[i+1:]
- case '\\':
- p := make([]byte, len(s)-1)
- j := copy(p, s[:i])
- escape := true
- for i = i + 1; i < len(s); i++ {
- b := s[i]
- switch {
- case escape:
- escape = false
- p[j] = b
- j++
- case b == '\\':
- escape = true
- case b == '"':
- return string(p[:j]), s[i+1:]
- default:
- p[j] = b
- j++
- }
- }
- return "", ""
- }
- }
- return "", ""
-}
diff --git a/vendor/github.com/docker/distribution/registry/client/auth/session.go b/vendor/github.com/docker/distribution/registry/client/auth/session.go
deleted file mode 100644
index d03d8ff0e..000000000
--- a/vendor/github.com/docker/distribution/registry/client/auth/session.go
+++ /dev/null
@@ -1,497 +0,0 @@
-package auth
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "net/http"
- "net/url"
- "strings"
- "sync"
- "time"
-
- "github.com/Sirupsen/logrus"
- "github.com/docker/distribution/registry/client"
- "github.com/docker/distribution/registry/client/transport"
-)
-
-var (
- // ErrNoBasicAuthCredentials is returned if a request can't be authorized with
- // basic auth due to lack of credentials.
- ErrNoBasicAuthCredentials = errors.New("no basic auth credentials")
-
- // ErrNoToken is returned if a request is successful but the body does not
- // contain an authorization token.
- ErrNoToken = errors.New("authorization server did not include a token in the response")
-)
-
-const defaultClientID = "registry-client"
-
-// AuthenticationHandler is an interface for authorizing a request from
-// params from a "WWW-Authenicate" header for a single scheme.
-type AuthenticationHandler interface {
- // Scheme returns the scheme as expected from the "WWW-Authenicate" header.
- Scheme() string
-
- // AuthorizeRequest adds the authorization header to a request (if needed)
- // using the parameters from "WWW-Authenticate" method. The parameters
- // values depend on the scheme.
- AuthorizeRequest(req *http.Request, params map[string]string) error
-}
-
-// CredentialStore is an interface for getting credentials for
-// a given URL
-type CredentialStore interface {
- // Basic returns basic auth for the given URL
- Basic(*url.URL) (string, string)
-
- // RefreshToken returns a refresh token for the
- // given URL and service
- RefreshToken(*url.URL, string) string
-
- // SetRefreshToken sets the refresh token if none
- // is provided for the given url and service
- SetRefreshToken(realm *url.URL, service, token string)
-}
-
-// NewAuthorizer creates an authorizer which can handle multiple authentication
-// schemes. The handlers are tried in order, the higher priority authentication
-// methods should be first. The challengeMap holds a list of challenges for
-// a given root API endpoint (for example "https://registry-1.docker.io/v2/").
-func NewAuthorizer(manager ChallengeManager, handlers ...AuthenticationHandler) transport.RequestModifier {
- return &endpointAuthorizer{
- challenges: manager,
- handlers: handlers,
- }
-}
-
-type endpointAuthorizer struct {
- challenges ChallengeManager
- handlers []AuthenticationHandler
- transport http.RoundTripper
-}
-
-func (ea *endpointAuthorizer) ModifyRequest(req *http.Request) error {
- pingPath := req.URL.Path
- if v2Root := strings.Index(req.URL.Path, "/v2/"); v2Root != -1 {
- pingPath = pingPath[:v2Root+4]
- } else if v1Root := strings.Index(req.URL.Path, "/v1/"); v1Root != -1 {
- pingPath = pingPath[:v1Root] + "/v2/"
- } else {
- return nil
- }
-
- ping := url.URL{
- Host: req.URL.Host,
- Scheme: req.URL.Scheme,
- Path: pingPath,
- }
-
- challenges, err := ea.challenges.GetChallenges(ping)
- if err != nil {
- return err
- }
-
- if len(challenges) > 0 {
- for _, handler := range ea.handlers {
- for _, challenge := range challenges {
- if challenge.Scheme != handler.Scheme() {
- continue
- }
- if err := handler.AuthorizeRequest(req, challenge.Parameters); err != nil {
- return err
- }
- }
- }
- }
-
- return nil
-}
-
-// This is the minimum duration a token can last (in seconds).
-// A token must not live less than 60 seconds because older versions
-// of the Docker client didn't read their expiration from the token
-// response and assumed 60 seconds. So to remain compatible with
-// those implementations, a token must live at least this long.
-const minimumTokenLifetimeSeconds = 60
-
-// Private interface for time used by this package to enable tests to provide their own implementation.
-type clock interface {
- Now() time.Time
-}
-
-type tokenHandler struct {
- header http.Header
- creds CredentialStore
- transport http.RoundTripper
- clock clock
-
- offlineAccess bool
- forceOAuth bool
- clientID string
- scopes []Scope
-
- tokenLock sync.Mutex
- tokenCache string
- tokenExpiration time.Time
-}
-
-// Scope is a type which is serializable to a string
-// using the allow scope grammar.
-type Scope interface {
- String() string
-}
-
-// RepositoryScope represents a token scope for access
-// to a repository.
-type RepositoryScope struct {
- Repository string
- Actions []string
-}
-
-// String returns the string representation of the repository
-// using the scope grammar
-func (rs RepositoryScope) String() string {
- return fmt.Sprintf("repository:%s:%s", rs.Repository, strings.Join(rs.Actions, ","))
-}
-
-// RegistryScope represents a token scope for access
-// to resources in the registry.
-type RegistryScope struct {
- Name string
- Actions []string
-}
-
-// String returns the string representation of the user
-// using the scope grammar
-func (rs RegistryScope) String() string {
- return fmt.Sprintf("registry:%s:%s", rs.Name, strings.Join(rs.Actions, ","))
-}
-
-// TokenHandlerOptions is used to configure a new token handler
-type TokenHandlerOptions struct {
- Transport http.RoundTripper
- Credentials CredentialStore
-
- OfflineAccess bool
- ForceOAuth bool
- ClientID string
- Scopes []Scope
-}
-
-// An implementation of clock for providing real time data.
-type realClock struct{}
-
-// Now implements clock
-func (realClock) Now() time.Time { return time.Now() }
-
-// NewTokenHandler creates a new AuthenicationHandler which supports
-// fetching tokens from a remote token server.
-func NewTokenHandler(transport http.RoundTripper, creds CredentialStore, scope string, actions ...string) AuthenticationHandler {
- // Create options...
- return NewTokenHandlerWithOptions(TokenHandlerOptions{
- Transport: transport,
- Credentials: creds,
- Scopes: []Scope{
- RepositoryScope{
- Repository: scope,
- Actions: actions,
- },
- },
- })
-}
-
-// NewTokenHandlerWithOptions creates a new token handler using the provided
-// options structure.
-func NewTokenHandlerWithOptions(options TokenHandlerOptions) AuthenticationHandler {
- handler := &tokenHandler{
- transport: options.Transport,
- creds: options.Credentials,
- offlineAccess: options.OfflineAccess,
- forceOAuth: options.ForceOAuth,
- clientID: options.ClientID,
- scopes: options.Scopes,
- clock: realClock{},
- }
-
- return handler
-}
-
-func (th *tokenHandler) client() *http.Client {
- return &http.Client{
- Transport: th.transport,
- Timeout: 15 * time.Second,
- }
-}
-
-func (th *tokenHandler) Scheme() string {
- return "bearer"
-}
-
-func (th *tokenHandler) AuthorizeRequest(req *http.Request, params map[string]string) error {
- var additionalScopes []string
- if fromParam := req.URL.Query().Get("from"); fromParam != "" {
- additionalScopes = append(additionalScopes, RepositoryScope{
- Repository: fromParam,
- Actions: []string{"pull"},
- }.String())
- }
-
- token, err := th.getToken(params, additionalScopes...)
- if err != nil {
- return err
- }
-
- req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
-
- return nil
-}
-
-func (th *tokenHandler) getToken(params map[string]string, additionalScopes ...string) (string, error) {
- th.tokenLock.Lock()
- defer th.tokenLock.Unlock()
- scopes := make([]string, 0, len(th.scopes)+len(additionalScopes))
- for _, scope := range th.scopes {
- scopes = append(scopes, scope.String())
- }
- var addedScopes bool
- for _, scope := range additionalScopes {
- scopes = append(scopes, scope)
- addedScopes = true
- }
-
- now := th.clock.Now()
- if now.After(th.tokenExpiration) || addedScopes {
- token, expiration, err := th.fetchToken(params, scopes)
- if err != nil {
- return "", err
- }
-
- // do not update cache for added scope tokens
- if !addedScopes {
- th.tokenCache = token
- th.tokenExpiration = expiration
- }
-
- return token, nil
- }
-
- return th.tokenCache, nil
-}
-
-type postTokenResponse struct {
- AccessToken string `json:"access_token"`
- RefreshToken string `json:"refresh_token"`
- ExpiresIn int `json:"expires_in"`
- IssuedAt time.Time `json:"issued_at"`
- Scope string `json:"scope"`
-}
-
-func (th *tokenHandler) fetchTokenWithOAuth(realm *url.URL, refreshToken, service string, scopes []string) (token string, expiration time.Time, err error) {
- form := url.Values{}
- form.Set("scope", strings.Join(scopes, " "))
- form.Set("service", service)
-
- clientID := th.clientID
- if clientID == "" {
- // Use default client, this is a required field
- clientID = defaultClientID
- }
- form.Set("client_id", clientID)
-
- if refreshToken != "" {
- form.Set("grant_type", "refresh_token")
- form.Set("refresh_token", refreshToken)
- } else if th.creds != nil {
- form.Set("grant_type", "password")
- username, password := th.creds.Basic(realm)
- form.Set("username", username)
- form.Set("password", password)
-
- // attempt to get a refresh token
- form.Set("access_type", "offline")
- } else {
- // refuse to do oauth without a grant type
- return "", time.Time{}, fmt.Errorf("no supported grant type")
- }
-
- resp, err := th.client().PostForm(realm.String(), form)
- if err != nil {
- return "", time.Time{}, err
- }
- defer resp.Body.Close()
-
- if !client.SuccessStatus(resp.StatusCode) {
- err := client.HandleErrorResponse(resp)
- return "", time.Time{}, err
- }
-
- decoder := json.NewDecoder(resp.Body)
-
- var tr postTokenResponse
- if err = decoder.Decode(&tr); err != nil {
- return "", time.Time{}, fmt.Errorf("unable to decode token response: %s", err)
- }
-
- if tr.RefreshToken != "" && tr.RefreshToken != refreshToken {
- th.creds.SetRefreshToken(realm, service, tr.RefreshToken)
- }
-
- if tr.ExpiresIn < minimumTokenLifetimeSeconds {
- // The default/minimum lifetime.
- tr.ExpiresIn = minimumTokenLifetimeSeconds
- logrus.Debugf("Increasing token expiration to: %d seconds", tr.ExpiresIn)
- }
-
- if tr.IssuedAt.IsZero() {
- // issued_at is optional in the token response.
- tr.IssuedAt = th.clock.Now().UTC()
- }
-
- return tr.AccessToken, tr.IssuedAt.Add(time.Duration(tr.ExpiresIn) * time.Second), nil
-}
-
-type getTokenResponse struct {
- Token string `json:"token"`
- AccessToken string `json:"access_token"`
- ExpiresIn int `json:"expires_in"`
- IssuedAt time.Time `json:"issued_at"`
- RefreshToken string `json:"refresh_token"`
-}
-
-func (th *tokenHandler) fetchTokenWithBasicAuth(realm *url.URL, service string, scopes []string) (token string, expiration time.Time, err error) {
-
- req, err := http.NewRequest("GET", realm.String(), nil)
- if err != nil {
- return "", time.Time{}, err
- }
-
- reqParams := req.URL.Query()
-
- if service != "" {
- reqParams.Add("service", service)
- }
-
- for _, scope := range scopes {
- reqParams.Add("scope", scope)
- }
-
- if th.offlineAccess {
- reqParams.Add("offline_token", "true")
- clientID := th.clientID
- if clientID == "" {
- clientID = defaultClientID
- }
- reqParams.Add("client_id", clientID)
- }
-
- if th.creds != nil {
- username, password := th.creds.Basic(realm)
- if username != "" && password != "" {
- reqParams.Add("account", username)
- req.SetBasicAuth(username, password)
- }
- }
-
- req.URL.RawQuery = reqParams.Encode()
-
- resp, err := th.client().Do(req)
- if err != nil {
- return "", time.Time{}, err
- }
- defer resp.Body.Close()
-
- if !client.SuccessStatus(resp.StatusCode) {
- err := client.HandleErrorResponse(resp)
- return "", time.Time{}, err
- }
-
- decoder := json.NewDecoder(resp.Body)
-
- var tr getTokenResponse
- if err = decoder.Decode(&tr); err != nil {
- return "", time.Time{}, fmt.Errorf("unable to decode token response: %s", err)
- }
-
- if tr.RefreshToken != "" && th.creds != nil {
- th.creds.SetRefreshToken(realm, service, tr.RefreshToken)
- }
-
- // `access_token` is equivalent to `token` and if both are specified
- // the choice is undefined. Canonicalize `access_token` by sticking
- // things in `token`.
- if tr.AccessToken != "" {
- tr.Token = tr.AccessToken
- }
-
- if tr.Token == "" {
- return "", time.Time{}, ErrNoToken
- }
-
- if tr.ExpiresIn < minimumTokenLifetimeSeconds {
- // The default/minimum lifetime.
- tr.ExpiresIn = minimumTokenLifetimeSeconds
- logrus.Debugf("Increasing token expiration to: %d seconds", tr.ExpiresIn)
- }
-
- if tr.IssuedAt.IsZero() {
- // issued_at is optional in the token response.
- tr.IssuedAt = th.clock.Now().UTC()
- }
-
- return tr.Token, tr.IssuedAt.Add(time.Duration(tr.ExpiresIn) * time.Second), nil
-}
-
-func (th *tokenHandler) fetchToken(params map[string]string, scopes []string) (token string, expiration time.Time, err error) {
- realm, ok := params["realm"]
- if !ok {
- return "", time.Time{}, errors.New("no realm specified for token auth challenge")
- }
-
- // TODO(dmcgowan): Handle empty scheme and relative realm
- realmURL, err := url.Parse(realm)
- if err != nil {
- return "", time.Time{}, fmt.Errorf("invalid token auth challenge realm: %s", err)
- }
-
- service := params["service"]
-
- var refreshToken string
-
- if th.creds != nil {
- refreshToken = th.creds.RefreshToken(realmURL, service)
- }
-
- if refreshToken != "" || th.forceOAuth {
- return th.fetchTokenWithOAuth(realmURL, refreshToken, service, scopes)
- }
-
- return th.fetchTokenWithBasicAuth(realmURL, service, scopes)
-}
-
-type basicHandler struct {
- creds CredentialStore
-}
-
-// NewBasicHandler creaters a new authentiation handler which adds
-// basic authentication credentials to a request.
-func NewBasicHandler(creds CredentialStore) AuthenticationHandler {
- return &basicHandler{
- creds: creds,
- }
-}
-
-func (*basicHandler) Scheme() string {
- return "basic"
-}
-
-func (bh *basicHandler) AuthorizeRequest(req *http.Request, params map[string]string) error {
- if bh.creds != nil {
- username, password := bh.creds.Basic(req.URL)
- if username != "" && password != "" {
- req.SetBasicAuth(username, password)
- return nil
- }
- }
- return ErrNoBasicAuthCredentials
-}
diff --git a/vendor/github.com/docker/distribution/registry/client/blob_writer.go b/vendor/github.com/docker/distribution/registry/client/blob_writer.go
deleted file mode 100644
index e3ffcb00f..000000000
--- a/vendor/github.com/docker/distribution/registry/client/blob_writer.go
+++ /dev/null
@@ -1,162 +0,0 @@
-package client
-
-import (
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "time"
-
- "github.com/docker/distribution"
- "github.com/docker/distribution/context"
-)
-
-type httpBlobUpload struct {
- statter distribution.BlobStatter
- client *http.Client
-
- uuid string
- startedAt time.Time
-
- location string // always the last value of the location header.
- offset int64
- closed bool
-}
-
-func (hbu *httpBlobUpload) Reader() (io.ReadCloser, error) {
- panic("Not implemented")
-}
-
-func (hbu *httpBlobUpload) handleErrorResponse(resp *http.Response) error {
- if resp.StatusCode == http.StatusNotFound {
- return distribution.ErrBlobUploadUnknown
- }
- return HandleErrorResponse(resp)
-}
-
-func (hbu *httpBlobUpload) ReadFrom(r io.Reader) (n int64, err error) {
- req, err := http.NewRequest("PATCH", hbu.location, ioutil.NopCloser(r))
- if err != nil {
- return 0, err
- }
- defer req.Body.Close()
-
- resp, err := hbu.client.Do(req)
- if err != nil {
- return 0, err
- }
-
- if !SuccessStatus(resp.StatusCode) {
- return 0, hbu.handleErrorResponse(resp)
- }
-
- hbu.uuid = resp.Header.Get("Docker-Upload-UUID")
- hbu.location, err = sanitizeLocation(resp.Header.Get("Location"), hbu.location)
- if err != nil {
- return 0, err
- }
- rng := resp.Header.Get("Range")
- var start, end int64
- if n, err := fmt.Sscanf(rng, "%d-%d", &start, &end); err != nil {
- return 0, err
- } else if n != 2 || end < start {
- return 0, fmt.Errorf("bad range format: %s", rng)
- }
-
- return (end - start + 1), nil
-
-}
-
-func (hbu *httpBlobUpload) Write(p []byte) (n int, err error) {
- req, err := http.NewRequest("PATCH", hbu.location, bytes.NewReader(p))
- if err != nil {
- return 0, err
- }
- req.Header.Set("Content-Range", fmt.Sprintf("%d-%d", hbu.offset, hbu.offset+int64(len(p)-1)))
- req.Header.Set("Content-Length", fmt.Sprintf("%d", len(p)))
- req.Header.Set("Content-Type", "application/octet-stream")
-
- resp, err := hbu.client.Do(req)
- if err != nil {
- return 0, err
- }
-
- if !SuccessStatus(resp.StatusCode) {
- return 0, hbu.handleErrorResponse(resp)
- }
-
- hbu.uuid = resp.Header.Get("Docker-Upload-UUID")
- hbu.location, err = sanitizeLocation(resp.Header.Get("Location"), hbu.location)
- if err != nil {
- return 0, err
- }
- rng := resp.Header.Get("Range")
- var start, end int
- if n, err := fmt.Sscanf(rng, "%d-%d", &start, &end); err != nil {
- return 0, err
- } else if n != 2 || end < start {
- return 0, fmt.Errorf("bad range format: %s", rng)
- }
-
- return (end - start + 1), nil
-
-}
-
-func (hbu *httpBlobUpload) Size() int64 {
- return hbu.offset
-}
-
-func (hbu *httpBlobUpload) ID() string {
- return hbu.uuid
-}
-
-func (hbu *httpBlobUpload) StartedAt() time.Time {
- return hbu.startedAt
-}
-
-func (hbu *httpBlobUpload) Commit(ctx context.Context, desc distribution.Descriptor) (distribution.Descriptor, error) {
- // TODO(dmcgowan): Check if already finished, if so just fetch
- req, err := http.NewRequest("PUT", hbu.location, nil)
- if err != nil {
- return distribution.Descriptor{}, err
- }
-
- values := req.URL.Query()
- values.Set("digest", desc.Digest.String())
- req.URL.RawQuery = values.Encode()
-
- resp, err := hbu.client.Do(req)
- if err != nil {
- return distribution.Descriptor{}, err
- }
- defer resp.Body.Close()
-
- if !SuccessStatus(resp.StatusCode) {
- return distribution.Descriptor{}, hbu.handleErrorResponse(resp)
- }
-
- return hbu.statter.Stat(ctx, desc.Digest)
-}
-
-func (hbu *httpBlobUpload) Cancel(ctx context.Context) error {
- req, err := http.NewRequest("DELETE", hbu.location, nil)
- if err != nil {
- return err
- }
- resp, err := hbu.client.Do(req)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
-
- if resp.StatusCode == http.StatusNotFound || SuccessStatus(resp.StatusCode) {
- return nil
- }
- return hbu.handleErrorResponse(resp)
-}
-
-func (hbu *httpBlobUpload) Close() error {
- hbu.closed = true
- return nil
-}
diff --git a/vendor/github.com/docker/distribution/registry/client/errors.go b/vendor/github.com/docker/distribution/registry/client/errors.go
deleted file mode 100644
index f73e3c230..000000000
--- a/vendor/github.com/docker/distribution/registry/client/errors.go
+++ /dev/null
@@ -1,107 +0,0 @@
-package client
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
-
- "github.com/docker/distribution/registry/api/errcode"
-)
-
-// ErrNoErrorsInBody is returned when an HTTP response body parses to an empty
-// errcode.Errors slice.
-var ErrNoErrorsInBody = errors.New("no error details found in HTTP response body")
-
-// UnexpectedHTTPStatusError is returned when an unexpected HTTP status is
-// returned when making a registry api call.
-type UnexpectedHTTPStatusError struct {
- Status string
-}
-
-func (e *UnexpectedHTTPStatusError) Error() string {
- return fmt.Sprintf("received unexpected HTTP status: %s", e.Status)
-}
-
-// UnexpectedHTTPResponseError is returned when an expected HTTP status code
-// is returned, but the content was unexpected and failed to be parsed.
-type UnexpectedHTTPResponseError struct {
- ParseErr error
- StatusCode int
- Response []byte
-}
-
-func (e *UnexpectedHTTPResponseError) Error() string {
- return fmt.Sprintf("error parsing HTTP %d response body: %s: %q", e.StatusCode, e.ParseErr.Error(), string(e.Response))
-}
-
-func parseHTTPErrorResponse(statusCode int, r io.Reader) error {
- var errors errcode.Errors
- body, err := ioutil.ReadAll(r)
- if err != nil {
- return err
- }
-
- // For backward compatibility, handle irregularly formatted
- // messages that contain a "details" field.
- var detailsErr struct {
- Details string `json:"details"`
- }
- err = json.Unmarshal(body, &detailsErr)
- if err == nil && detailsErr.Details != "" {
- switch statusCode {
- case http.StatusUnauthorized:
- return errcode.ErrorCodeUnauthorized.WithMessage(detailsErr.Details)
- case http.StatusTooManyRequests:
- return errcode.ErrorCodeTooManyRequests.WithMessage(detailsErr.Details)
- default:
- return errcode.ErrorCodeUnknown.WithMessage(detailsErr.Details)
- }
- }
-
- if err := json.Unmarshal(body, &errors); err != nil {
- return &UnexpectedHTTPResponseError{
- ParseErr: err,
- StatusCode: statusCode,
- Response: body,
- }
- }
-
- if len(errors) == 0 {
- // If there was no error specified in the body, return
- // UnexpectedHTTPResponseError.
- return &UnexpectedHTTPResponseError{
- ParseErr: ErrNoErrorsInBody,
- StatusCode: statusCode,
- Response: body,
- }
- }
-
- return errors
-}
-
-// HandleErrorResponse returns error parsed from HTTP response for an
-// unsuccessful HTTP response code (in the range 400 - 499 inclusive). An
-// UnexpectedHTTPStatusError returned for response code outside of expected
-// range.
-func HandleErrorResponse(resp *http.Response) error {
- if resp.StatusCode == 401 {
- err := parseHTTPErrorResponse(resp.StatusCode, resp.Body)
- if uErr, ok := err.(*UnexpectedHTTPResponseError); ok {
- return errcode.ErrorCodeUnauthorized.WithDetail(uErr.Response)
- }
- return err
- }
- if resp.StatusCode >= 400 && resp.StatusCode < 500 {
- return parseHTTPErrorResponse(resp.StatusCode, resp.Body)
- }
- return &UnexpectedHTTPStatusError{Status: resp.Status}
-}
-
-// SuccessStatus returns true if the argument is a successful HTTP response
-// code (in the range 200 - 399 inclusive).
-func SuccessStatus(status int) bool {
- return status >= 200 && status <= 399
-}
diff --git a/vendor/github.com/docker/distribution/registry/client/repository.go b/vendor/github.com/docker/distribution/registry/client/repository.go
deleted file mode 100644
index 0d4050771..000000000
--- a/vendor/github.com/docker/distribution/registry/client/repository.go
+++ /dev/null
@@ -1,854 +0,0 @@
-package client
-
-import (
- "bytes"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "net/url"
- "strconv"
- "strings"
- "time"
-
- "github.com/docker/distribution"
- "github.com/docker/distribution/context"
- "github.com/docker/distribution/digest"
- "github.com/docker/distribution/reference"
- "github.com/docker/distribution/registry/api/v2"
- "github.com/docker/distribution/registry/client/transport"
- "github.com/docker/distribution/registry/storage/cache"
- "github.com/docker/distribution/registry/storage/cache/memory"
-)
-
-// Registry provides an interface for calling Repositories, which returns a catalog of repositories.
-type Registry interface {
- Repositories(ctx context.Context, repos []string, last string) (n int, err error)
-}
-
-// checkHTTPRedirect is a callback that can manipulate redirected HTTP
-// requests. It is used to preserve Accept and Range headers.
-func checkHTTPRedirect(req *http.Request, via []*http.Request) error {
- if len(via) >= 10 {
- return errors.New("stopped after 10 redirects")
- }
-
- if len(via) > 0 {
- for headerName, headerVals := range via[0].Header {
- if headerName != "Accept" && headerName != "Range" {
- continue
- }
- for _, val := range headerVals {
- // Don't add to redirected request if redirected
- // request already has a header with the same
- // name and value.
- hasValue := false
- for _, existingVal := range req.Header[headerName] {
- if existingVal == val {
- hasValue = true
- break
- }
- }
- if !hasValue {
- req.Header.Add(headerName, val)
- }
- }
- }
- }
-
- return nil
-}
-
-// NewRegistry creates a registry namespace which can be used to get a listing of repositories
-func NewRegistry(ctx context.Context, baseURL string, transport http.RoundTripper) (Registry, error) {
- ub, err := v2.NewURLBuilderFromString(baseURL, false)
- if err != nil {
- return nil, err
- }
-
- client := &http.Client{
- Transport: transport,
- Timeout: 1 * time.Minute,
- CheckRedirect: checkHTTPRedirect,
- }
-
- return ®istry{
- client: client,
- ub: ub,
- context: ctx,
- }, nil
-}
-
-type registry struct {
- client *http.Client
- ub *v2.URLBuilder
- context context.Context
-}
-
-// Repositories returns a lexigraphically sorted catalog given a base URL. The 'entries' slice will be filled up to the size
-// of the slice, starting at the value provided in 'last'. The number of entries will be returned along with io.EOF if there
-// are no more entries
-func (r *registry) Repositories(ctx context.Context, entries []string, last string) (int, error) {
- var numFilled int
- var returnErr error
-
- values := buildCatalogValues(len(entries), last)
- u, err := r.ub.BuildCatalogURL(values)
- if err != nil {
- return 0, err
- }
-
- resp, err := r.client.Get(u)
- if err != nil {
- return 0, err
- }
- defer resp.Body.Close()
-
- if SuccessStatus(resp.StatusCode) {
- var ctlg struct {
- Repositories []string `json:"repositories"`
- }
- decoder := json.NewDecoder(resp.Body)
-
- if err := decoder.Decode(&ctlg); err != nil {
- return 0, err
- }
-
- for cnt := range ctlg.Repositories {
- entries[cnt] = ctlg.Repositories[cnt]
- }
- numFilled = len(ctlg.Repositories)
-
- link := resp.Header.Get("Link")
- if link == "" {
- returnErr = io.EOF
- }
- } else {
- return 0, HandleErrorResponse(resp)
- }
-
- return numFilled, returnErr
-}
-
-// NewRepository creates a new Repository for the given repository name and base URL.
-func NewRepository(ctx context.Context, name reference.Named, baseURL string, transport http.RoundTripper) (distribution.Repository, error) {
- ub, err := v2.NewURLBuilderFromString(baseURL, false)
- if err != nil {
- return nil, err
- }
-
- client := &http.Client{
- Transport: transport,
- CheckRedirect: checkHTTPRedirect,
- // TODO(dmcgowan): create cookie jar
- }
-
- return &repository{
- client: client,
- ub: ub,
- name: name,
- context: ctx,
- }, nil
-}
-
-type repository struct {
- client *http.Client
- ub *v2.URLBuilder
- context context.Context
- name reference.Named
-}
-
-func (r *repository) Named() reference.Named {
- return r.name
-}
-
-func (r *repository) Blobs(ctx context.Context) distribution.BlobStore {
- statter := &blobStatter{
- name: r.name,
- ub: r.ub,
- client: r.client,
- }
- return &blobs{
- name: r.name,
- ub: r.ub,
- client: r.client,
- statter: cache.NewCachedBlobStatter(memory.NewInMemoryBlobDescriptorCacheProvider(), statter),
- }
-}
-
-func (r *repository) Manifests(ctx context.Context, options ...distribution.ManifestServiceOption) (distribution.ManifestService, error) {
- // todo(richardscothern): options should be sent over the wire
- return &manifests{
- name: r.name,
- ub: r.ub,
- client: r.client,
- etags: make(map[string]string),
- }, nil
-}
-
-func (r *repository) Tags(ctx context.Context) distribution.TagService {
- return &tags{
- client: r.client,
- ub: r.ub,
- context: r.context,
- name: r.Named(),
- }
-}
-
-// tags implements remote tagging operations.
-type tags struct {
- client *http.Client
- ub *v2.URLBuilder
- context context.Context
- name reference.Named
-}
-
-// All returns all tags
-func (t *tags) All(ctx context.Context) ([]string, error) {
- var tags []string
-
- u, err := t.ub.BuildTagsURL(t.name)
- if err != nil {
- return tags, err
- }
-
- for {
- resp, err := t.client.Get(u)
- if err != nil {
- return tags, err
- }
- defer resp.Body.Close()
-
- if SuccessStatus(resp.StatusCode) {
- b, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return tags, err
- }
-
- tagsResponse := struct {
- Tags []string `json:"tags"`
- }{}
- if err := json.Unmarshal(b, &tagsResponse); err != nil {
- return tags, err
- }
- tags = append(tags, tagsResponse.Tags...)
- if link := resp.Header.Get("Link"); link != "" {
- u = strings.Trim(strings.Split(link, ";")[0], "<>")
- } else {
- return tags, nil
- }
- } else {
- return tags, HandleErrorResponse(resp)
- }
- }
-}
-
-func descriptorFromResponse(response *http.Response) (distribution.Descriptor, error) {
- desc := distribution.Descriptor{}
- headers := response.Header
-
- ctHeader := headers.Get("Content-Type")
- if ctHeader == "" {
- return distribution.Descriptor{}, errors.New("missing or empty Content-Type header")
- }
- desc.MediaType = ctHeader
-
- digestHeader := headers.Get("Docker-Content-Digest")
- if digestHeader == "" {
- bytes, err := ioutil.ReadAll(response.Body)
- if err != nil {
- return distribution.Descriptor{}, err
- }
- _, desc, err := distribution.UnmarshalManifest(ctHeader, bytes)
- if err != nil {
- return distribution.Descriptor{}, err
- }
- return desc, nil
- }
-
- dgst, err := digest.ParseDigest(digestHeader)
- if err != nil {
- return distribution.Descriptor{}, err
- }
- desc.Digest = dgst
-
- lengthHeader := headers.Get("Content-Length")
- if lengthHeader == "" {
- return distribution.Descriptor{}, errors.New("missing or empty Content-Length header")
- }
- length, err := strconv.ParseInt(lengthHeader, 10, 64)
- if err != nil {
- return distribution.Descriptor{}, err
- }
- desc.Size = length
-
- return desc, nil
-
-}
-
-// Get issues a HEAD request for a Manifest against its named endpoint in order
-// to construct a descriptor for the tag. If the registry doesn't support HEADing
-// a manifest, fallback to GET.
-func (t *tags) Get(ctx context.Context, tag string) (distribution.Descriptor, error) {
- ref, err := reference.WithTag(t.name, tag)
- if err != nil {
- return distribution.Descriptor{}, err
- }
- u, err := t.ub.BuildManifestURL(ref)
- if err != nil {
- return distribution.Descriptor{}, err
- }
-
- req, err := http.NewRequest("HEAD", u, nil)
- if err != nil {
- return distribution.Descriptor{}, err
- }
-
- for _, t := range distribution.ManifestMediaTypes() {
- req.Header.Add("Accept", t)
- }
-
- var attempts int
- resp, err := t.client.Do(req)
-check:
- if err != nil {
- return distribution.Descriptor{}, err
- }
- defer resp.Body.Close()
-
- switch {
- case resp.StatusCode >= 200 && resp.StatusCode < 400:
- return descriptorFromResponse(resp)
- case resp.StatusCode == http.StatusMethodNotAllowed:
- req, err = http.NewRequest("GET", u, nil)
- if err != nil {
- return distribution.Descriptor{}, err
- }
-
- for _, t := range distribution.ManifestMediaTypes() {
- req.Header.Add("Accept", t)
- }
-
- resp, err = t.client.Do(req)
- attempts++
- if attempts > 1 {
- return distribution.Descriptor{}, err
- }
- goto check
- default:
- return distribution.Descriptor{}, HandleErrorResponse(resp)
- }
-}
-
-func (t *tags) Lookup(ctx context.Context, digest distribution.Descriptor) ([]string, error) {
- panic("not implemented")
-}
-
-func (t *tags) Tag(ctx context.Context, tag string, desc distribution.Descriptor) error {
- panic("not implemented")
-}
-
-func (t *tags) Untag(ctx context.Context, tag string) error {
- panic("not implemented")
-}
-
-type manifests struct {
- name reference.Named
- ub *v2.URLBuilder
- client *http.Client
- etags map[string]string
-}
-
-func (ms *manifests) Exists(ctx context.Context, dgst digest.Digest) (bool, error) {
- ref, err := reference.WithDigest(ms.name, dgst)
- if err != nil {
- return false, err
- }
- u, err := ms.ub.BuildManifestURL(ref)
- if err != nil {
- return false, err
- }
-
- resp, err := ms.client.Head(u)
- if err != nil {
- return false, err
- }
-
- if SuccessStatus(resp.StatusCode) {
- return true, nil
- } else if resp.StatusCode == http.StatusNotFound {
- return false, nil
- }
- return false, HandleErrorResponse(resp)
-}
-
-// AddEtagToTag allows a client to supply an eTag to Get which will be
-// used for a conditional HTTP request. If the eTag matches, a nil manifest
-// and ErrManifestNotModified error will be returned. etag is automatically
-// quoted when added to this map.
-func AddEtagToTag(tag, etag string) distribution.ManifestServiceOption {
- return etagOption{tag, etag}
-}
-
-type etagOption struct{ tag, etag string }
-
-func (o etagOption) Apply(ms distribution.ManifestService) error {
- if ms, ok := ms.(*manifests); ok {
- ms.etags[o.tag] = fmt.Sprintf(`"%s"`, o.etag)
- return nil
- }
- return fmt.Errorf("etag options is a client-only option")
-}
-
-// ReturnContentDigest allows a client to set a the content digest on
-// a successful request from the 'Docker-Content-Digest' header. This
-// returned digest is represents the digest which the registry uses
-// to refer to the content and can be used to delete the content.
-func ReturnContentDigest(dgst *digest.Digest) distribution.ManifestServiceOption {
- return contentDigestOption{dgst}
-}
-
-type contentDigestOption struct{ digest *digest.Digest }
-
-func (o contentDigestOption) Apply(ms distribution.ManifestService) error {
- return nil
-}
-
-func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...distribution.ManifestServiceOption) (distribution.Manifest, error) {
- var (
- digestOrTag string
- ref reference.Named
- err error
- contentDgst *digest.Digest
- )
-
- for _, option := range options {
- if opt, ok := option.(distribution.WithTagOption); ok {
- digestOrTag = opt.Tag
- ref, err = reference.WithTag(ms.name, opt.Tag)
- if err != nil {
- return nil, err
- }
- } else if opt, ok := option.(contentDigestOption); ok {
- contentDgst = opt.digest
- } else {
- err := option.Apply(ms)
- if err != nil {
- return nil, err
- }
- }
- }
-
- if digestOrTag == "" {
- digestOrTag = dgst.String()
- ref, err = reference.WithDigest(ms.name, dgst)
- if err != nil {
- return nil, err
- }
- }
-
- u, err := ms.ub.BuildManifestURL(ref)
- if err != nil {
- return nil, err
- }
-
- req, err := http.NewRequest("GET", u, nil)
- if err != nil {
- return nil, err
- }
-
- for _, t := range distribution.ManifestMediaTypes() {
- req.Header.Add("Accept", t)
- }
-
- if _, ok := ms.etags[digestOrTag]; ok {
- req.Header.Set("If-None-Match", ms.etags[digestOrTag])
- }
-
- resp, err := ms.client.Do(req)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
- if resp.StatusCode == http.StatusNotModified {
- return nil, distribution.ErrManifestNotModified
- } else if SuccessStatus(resp.StatusCode) {
- if contentDgst != nil {
- dgst, err := digest.ParseDigest(resp.Header.Get("Docker-Content-Digest"))
- if err == nil {
- *contentDgst = dgst
- }
- }
- mt := resp.Header.Get("Content-Type")
- body, err := ioutil.ReadAll(resp.Body)
-
- if err != nil {
- return nil, err
- }
- m, _, err := distribution.UnmarshalManifest(mt, body)
- if err != nil {
- return nil, err
- }
- return m, nil
- }
- return nil, HandleErrorResponse(resp)
-}
-
-// Put puts a manifest. A tag can be specified using an options parameter which uses some shared state to hold the
-// tag name in order to build the correct upload URL.
-func (ms *manifests) Put(ctx context.Context, m distribution.Manifest, options ...distribution.ManifestServiceOption) (digest.Digest, error) {
- ref := ms.name
- var tagged bool
-
- for _, option := range options {
- if opt, ok := option.(distribution.WithTagOption); ok {
- var err error
- ref, err = reference.WithTag(ref, opt.Tag)
- if err != nil {
- return "", err
- }
- tagged = true
- } else {
- err := option.Apply(ms)
- if err != nil {
- return "", err
- }
- }
- }
- mediaType, p, err := m.Payload()
- if err != nil {
- return "", err
- }
-
- if !tagged {
- // generate a canonical digest and Put by digest
- _, d, err := distribution.UnmarshalManifest(mediaType, p)
- if err != nil {
- return "", err
- }
- ref, err = reference.WithDigest(ref, d.Digest)
- if err != nil {
- return "", err
- }
- }
-
- manifestURL, err := ms.ub.BuildManifestURL(ref)
- if err != nil {
- return "", err
- }
-
- putRequest, err := http.NewRequest("PUT", manifestURL, bytes.NewReader(p))
- if err != nil {
- return "", err
- }
-
- putRequest.Header.Set("Content-Type", mediaType)
-
- resp, err := ms.client.Do(putRequest)
- if err != nil {
- return "", err
- }
- defer resp.Body.Close()
-
- if SuccessStatus(resp.StatusCode) {
- dgstHeader := resp.Header.Get("Docker-Content-Digest")
- dgst, err := digest.ParseDigest(dgstHeader)
- if err != nil {
- return "", err
- }
-
- return dgst, nil
- }
-
- return "", HandleErrorResponse(resp)
-}
-
-func (ms *manifests) Delete(ctx context.Context, dgst digest.Digest) error {
- ref, err := reference.WithDigest(ms.name, dgst)
- if err != nil {
- return err
- }
- u, err := ms.ub.BuildManifestURL(ref)
- if err != nil {
- return err
- }
- req, err := http.NewRequest("DELETE", u, nil)
- if err != nil {
- return err
- }
-
- resp, err := ms.client.Do(req)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
-
- if SuccessStatus(resp.StatusCode) {
- return nil
- }
- return HandleErrorResponse(resp)
-}
-
-// todo(richardscothern): Restore interface and implementation with merge of #1050
-/*func (ms *manifests) Enumerate(ctx context.Context, manifests []distribution.Manifest, last distribution.Manifest) (n int, err error) {
- panic("not supported")
-}*/
-
-type blobs struct {
- name reference.Named
- ub *v2.URLBuilder
- client *http.Client
-
- statter distribution.BlobDescriptorService
- distribution.BlobDeleter
-}
-
-func sanitizeLocation(location, base string) (string, error) {
- baseURL, err := url.Parse(base)
- if err != nil {
- return "", err
- }
-
- locationURL, err := url.Parse(location)
- if err != nil {
- return "", err
- }
-
- return baseURL.ResolveReference(locationURL).String(), nil
-}
-
-func (bs *blobs) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
- return bs.statter.Stat(ctx, dgst)
-
-}
-
-func (bs *blobs) Get(ctx context.Context, dgst digest.Digest) ([]byte, error) {
- reader, err := bs.Open(ctx, dgst)
- if err != nil {
- return nil, err
- }
- defer reader.Close()
-
- return ioutil.ReadAll(reader)
-}
-
-func (bs *blobs) Open(ctx context.Context, dgst digest.Digest) (distribution.ReadSeekCloser, error) {
- ref, err := reference.WithDigest(bs.name, dgst)
- if err != nil {
- return nil, err
- }
- blobURL, err := bs.ub.BuildBlobURL(ref)
- if err != nil {
- return nil, err
- }
-
- return transport.NewHTTPReadSeeker(bs.client, blobURL,
- func(resp *http.Response) error {
- if resp.StatusCode == http.StatusNotFound {
- return distribution.ErrBlobUnknown
- }
- return HandleErrorResponse(resp)
- }), nil
-}
-
-func (bs *blobs) ServeBlob(ctx context.Context, w http.ResponseWriter, r *http.Request, dgst digest.Digest) error {
- panic("not implemented")
-}
-
-func (bs *blobs) Put(ctx context.Context, mediaType string, p []byte) (distribution.Descriptor, error) {
- writer, err := bs.Create(ctx)
- if err != nil {
- return distribution.Descriptor{}, err
- }
- dgstr := digest.Canonical.New()
- n, err := io.Copy(writer, io.TeeReader(bytes.NewReader(p), dgstr.Hash()))
- if err != nil {
- return distribution.Descriptor{}, err
- }
- if n < int64(len(p)) {
- return distribution.Descriptor{}, fmt.Errorf("short copy: wrote %d of %d", n, len(p))
- }
-
- desc := distribution.Descriptor{
- MediaType: mediaType,
- Size: int64(len(p)),
- Digest: dgstr.Digest(),
- }
-
- return writer.Commit(ctx, desc)
-}
-
-type optionFunc func(interface{}) error
-
-func (f optionFunc) Apply(v interface{}) error {
- return f(v)
-}
-
-// WithMountFrom returns a BlobCreateOption which designates that the blob should be
-// mounted from the given canonical reference.
-func WithMountFrom(ref reference.Canonical) distribution.BlobCreateOption {
- return optionFunc(func(v interface{}) error {
- opts, ok := v.(*distribution.CreateOptions)
- if !ok {
- return fmt.Errorf("unexpected options type: %T", v)
- }
-
- opts.Mount.ShouldMount = true
- opts.Mount.From = ref
-
- return nil
- })
-}
-
-func (bs *blobs) Create(ctx context.Context, options ...distribution.BlobCreateOption) (distribution.BlobWriter, error) {
- var opts distribution.CreateOptions
-
- for _, option := range options {
- err := option.Apply(&opts)
- if err != nil {
- return nil, err
- }
- }
-
- var values []url.Values
-
- if opts.Mount.ShouldMount {
- values = append(values, url.Values{"from": {opts.Mount.From.Name()}, "mount": {opts.Mount.From.Digest().String()}})
- }
-
- u, err := bs.ub.BuildBlobUploadURL(bs.name, values...)
- if err != nil {
- return nil, err
- }
-
- resp, err := bs.client.Post(u, "", nil)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- switch resp.StatusCode {
- case http.StatusCreated:
- desc, err := bs.statter.Stat(ctx, opts.Mount.From.Digest())
- if err != nil {
- return nil, err
- }
- return nil, distribution.ErrBlobMounted{From: opts.Mount.From, Descriptor: desc}
- case http.StatusAccepted:
- // TODO(dmcgowan): Check for invalid UUID
- uuid := resp.Header.Get("Docker-Upload-UUID")
- location, err := sanitizeLocation(resp.Header.Get("Location"), u)
- if err != nil {
- return nil, err
- }
-
- return &httpBlobUpload{
- statter: bs.statter,
- client: bs.client,
- uuid: uuid,
- startedAt: time.Now(),
- location: location,
- }, nil
- default:
- return nil, HandleErrorResponse(resp)
- }
-}
-
-func (bs *blobs) Resume(ctx context.Context, id string) (distribution.BlobWriter, error) {
- panic("not implemented")
-}
-
-func (bs *blobs) Delete(ctx context.Context, dgst digest.Digest) error {
- return bs.statter.Clear(ctx, dgst)
-}
-
-type blobStatter struct {
- name reference.Named
- ub *v2.URLBuilder
- client *http.Client
-}
-
-func (bs *blobStatter) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
- ref, err := reference.WithDigest(bs.name, dgst)
- if err != nil {
- return distribution.Descriptor{}, err
- }
- u, err := bs.ub.BuildBlobURL(ref)
- if err != nil {
- return distribution.Descriptor{}, err
- }
-
- resp, err := bs.client.Head(u)
- if err != nil {
- return distribution.Descriptor{}, err
- }
- defer resp.Body.Close()
-
- if SuccessStatus(resp.StatusCode) {
- lengthHeader := resp.Header.Get("Content-Length")
- if lengthHeader == "" {
- return distribution.Descriptor{}, fmt.Errorf("missing content-length header for request: %s", u)
- }
-
- length, err := strconv.ParseInt(lengthHeader, 10, 64)
- if err != nil {
- return distribution.Descriptor{}, fmt.Errorf("error parsing content-length: %v", err)
- }
-
- return distribution.Descriptor{
- MediaType: resp.Header.Get("Content-Type"),
- Size: length,
- Digest: dgst,
- }, nil
- } else if resp.StatusCode == http.StatusNotFound {
- return distribution.Descriptor{}, distribution.ErrBlobUnknown
- }
- return distribution.Descriptor{}, HandleErrorResponse(resp)
-}
-
-func buildCatalogValues(maxEntries int, last string) url.Values {
- values := url.Values{}
-
- if maxEntries > 0 {
- values.Add("n", strconv.Itoa(maxEntries))
- }
-
- if last != "" {
- values.Add("last", last)
- }
-
- return values
-}
-
-func (bs *blobStatter) Clear(ctx context.Context, dgst digest.Digest) error {
- ref, err := reference.WithDigest(bs.name, dgst)
- if err != nil {
- return err
- }
- blobURL, err := bs.ub.BuildBlobURL(ref)
- if err != nil {
- return err
- }
-
- req, err := http.NewRequest("DELETE", blobURL, nil)
- if err != nil {
- return err
- }
-
- resp, err := bs.client.Do(req)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
-
- if SuccessStatus(resp.StatusCode) {
- return nil
- }
- return HandleErrorResponse(resp)
-}
-
-func (bs *blobStatter) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
- return nil
-}
diff --git a/vendor/github.com/docker/distribution/registry/client/transport/http_reader.go b/vendor/github.com/docker/distribution/registry/client/transport/http_reader.go
deleted file mode 100644
index e1b17a03a..000000000
--- a/vendor/github.com/docker/distribution/registry/client/transport/http_reader.go
+++ /dev/null
@@ -1,250 +0,0 @@
-package transport
-
-import (
- "errors"
- "fmt"
- "io"
- "net/http"
- "os"
- "regexp"
- "strconv"
-)
-
-var (
- contentRangeRegexp = regexp.MustCompile(`bytes ([0-9]+)-([0-9]+)/([0-9]+|\\*)`)
-
- // ErrWrongCodeForByteRange is returned if the client sends a request
- // with a Range header but the server returns a 2xx or 3xx code other
- // than 206 Partial Content.
- ErrWrongCodeForByteRange = errors.New("expected HTTP 206 from byte range request")
-)
-
-// ReadSeekCloser combines io.ReadSeeker with io.Closer.
-type ReadSeekCloser interface {
- io.ReadSeeker
- io.Closer
-}
-
-// NewHTTPReadSeeker handles reading from an HTTP endpoint using a GET
-// request. When seeking and starting a read from a non-zero offset
-// the a "Range" header will be added which sets the offset.
-// TODO(dmcgowan): Move this into a separate utility package
-func NewHTTPReadSeeker(client *http.Client, url string, errorHandler func(*http.Response) error) ReadSeekCloser {
- return &httpReadSeeker{
- client: client,
- url: url,
- errorHandler: errorHandler,
- }
-}
-
-type httpReadSeeker struct {
- client *http.Client
- url string
-
- // errorHandler creates an error from an unsuccessful HTTP response.
- // This allows the error to be created with the HTTP response body
- // without leaking the body through a returned error.
- errorHandler func(*http.Response) error
-
- size int64
-
- // rc is the remote read closer.
- rc io.ReadCloser
- // readerOffset tracks the offset as of the last read.
- readerOffset int64
- // seekOffset allows Seek to override the offset. Seek changes
- // seekOffset instead of changing readOffset directly so that
- // connection resets can be delayed and possibly avoided if the
- // seek is undone (i.e. seeking to the end and then back to the
- // beginning).
- seekOffset int64
- err error
-}
-
-func (hrs *httpReadSeeker) Read(p []byte) (n int, err error) {
- if hrs.err != nil {
- return 0, hrs.err
- }
-
- // If we sought to a different position, we need to reset the
- // connection. This logic is here instead of Seek so that if
- // a seek is undone before the next read, the connection doesn't
- // need to be closed and reopened. A common example of this is
- // seeking to the end to determine the length, and then seeking
- // back to the original position.
- if hrs.readerOffset != hrs.seekOffset {
- hrs.reset()
- }
-
- hrs.readerOffset = hrs.seekOffset
-
- rd, err := hrs.reader()
- if err != nil {
- return 0, err
- }
-
- n, err = rd.Read(p)
- hrs.seekOffset += int64(n)
- hrs.readerOffset += int64(n)
-
- return n, err
-}
-
-func (hrs *httpReadSeeker) Seek(offset int64, whence int) (int64, error) {
- if hrs.err != nil {
- return 0, hrs.err
- }
-
- lastReaderOffset := hrs.readerOffset
-
- if whence == os.SEEK_SET && hrs.rc == nil {
- // If no request has been made yet, and we are seeking to an
- // absolute position, set the read offset as well to avoid an
- // unnecessary request.
- hrs.readerOffset = offset
- }
-
- _, err := hrs.reader()
- if err != nil {
- hrs.readerOffset = lastReaderOffset
- return 0, err
- }
-
- newOffset := hrs.seekOffset
-
- switch whence {
- case os.SEEK_CUR:
- newOffset += offset
- case os.SEEK_END:
- if hrs.size < 0 {
- return 0, errors.New("content length not known")
- }
- newOffset = hrs.size + offset
- case os.SEEK_SET:
- newOffset = offset
- }
-
- if newOffset < 0 {
- err = errors.New("cannot seek to negative position")
- } else {
- hrs.seekOffset = newOffset
- }
-
- return hrs.seekOffset, err
-}
-
-func (hrs *httpReadSeeker) Close() error {
- if hrs.err != nil {
- return hrs.err
- }
-
- // close and release reader chain
- if hrs.rc != nil {
- hrs.rc.Close()
- }
-
- hrs.rc = nil
-
- hrs.err = errors.New("httpLayer: closed")
-
- return nil
-}
-
-func (hrs *httpReadSeeker) reset() {
- if hrs.err != nil {
- return
- }
- if hrs.rc != nil {
- hrs.rc.Close()
- hrs.rc = nil
- }
-}
-
-func (hrs *httpReadSeeker) reader() (io.Reader, error) {
- if hrs.err != nil {
- return nil, hrs.err
- }
-
- if hrs.rc != nil {
- return hrs.rc, nil
- }
-
- req, err := http.NewRequest("GET", hrs.url, nil)
- if err != nil {
- return nil, err
- }
-
- if hrs.readerOffset > 0 {
- // If we are at different offset, issue a range request from there.
- req.Header.Add("Range", fmt.Sprintf("bytes=%d-", hrs.readerOffset))
- // TODO: get context in here
- // context.GetLogger(hrs.context).Infof("Range: %s", req.Header.Get("Range"))
- }
-
- resp, err := hrs.client.Do(req)
- if err != nil {
- return nil, err
- }
-
- // Normally would use client.SuccessStatus, but that would be a cyclic
- // import
- if resp.StatusCode >= 200 && resp.StatusCode <= 399 {
- if hrs.readerOffset > 0 {
- if resp.StatusCode != http.StatusPartialContent {
- return nil, ErrWrongCodeForByteRange
- }
-
- contentRange := resp.Header.Get("Content-Range")
- if contentRange == "" {
- return nil, errors.New("no Content-Range header found in HTTP 206 response")
- }
-
- submatches := contentRangeRegexp.FindStringSubmatch(contentRange)
- if len(submatches) < 4 {
- return nil, fmt.Errorf("could not parse Content-Range header: %s", contentRange)
- }
-
- startByte, err := strconv.ParseUint(submatches[1], 10, 64)
- if err != nil {
- return nil, fmt.Errorf("could not parse start of range in Content-Range header: %s", contentRange)
- }
-
- if startByte != uint64(hrs.readerOffset) {
- return nil, fmt.Errorf("received Content-Range starting at offset %d instead of requested %d", startByte, hrs.readerOffset)
- }
-
- endByte, err := strconv.ParseUint(submatches[2], 10, 64)
- if err != nil {
- return nil, fmt.Errorf("could not parse end of range in Content-Range header: %s", contentRange)
- }
-
- if submatches[3] == "*" {
- hrs.size = -1
- } else {
- size, err := strconv.ParseUint(submatches[3], 10, 64)
- if err != nil {
- return nil, fmt.Errorf("could not parse total size in Content-Range header: %s", contentRange)
- }
-
- if endByte+1 != size {
- return nil, fmt.Errorf("range in Content-Range stops before the end of the content: %s", contentRange)
- }
-
- hrs.size = int64(size)
- }
- } else if resp.StatusCode == http.StatusOK {
- hrs.size = resp.ContentLength
- } else {
- hrs.size = -1
- }
- hrs.rc = resp.Body
- } else {
- defer resp.Body.Close()
- if hrs.errorHandler != nil {
- return nil, hrs.errorHandler(resp)
- }
- return nil, fmt.Errorf("unexpected status resolving reader: %v", resp.Status)
- }
-
- return hrs.rc, nil
-}
diff --git a/vendor/github.com/docker/distribution/registry/client/transport/transport.go b/vendor/github.com/docker/distribution/registry/client/transport/transport.go
deleted file mode 100644
index 30e45fab0..000000000
--- a/vendor/github.com/docker/distribution/registry/client/transport/transport.go
+++ /dev/null
@@ -1,147 +0,0 @@
-package transport
-
-import (
- "io"
- "net/http"
- "sync"
-)
-
-// RequestModifier represents an object which will do an inplace
-// modification of an HTTP request.
-type RequestModifier interface {
- ModifyRequest(*http.Request) error
-}
-
-type headerModifier http.Header
-
-// NewHeaderRequestModifier returns a new RequestModifier which will
-// add the given headers to a request.
-func NewHeaderRequestModifier(header http.Header) RequestModifier {
- return headerModifier(header)
-}
-
-func (h headerModifier) ModifyRequest(req *http.Request) error {
- for k, s := range http.Header(h) {
- req.Header[k] = append(req.Header[k], s...)
- }
-
- return nil
-}
-
-// NewTransport creates a new transport which will apply modifiers to
-// the request on a RoundTrip call.
-func NewTransport(base http.RoundTripper, modifiers ...RequestModifier) http.RoundTripper {
- return &transport{
- Modifiers: modifiers,
- Base: base,
- }
-}
-
-// transport is an http.RoundTripper that makes HTTP requests after
-// copying and modifying the request
-type transport struct {
- Modifiers []RequestModifier
- Base http.RoundTripper
-
- mu sync.Mutex // guards modReq
- modReq map[*http.Request]*http.Request // original -> modified
-}
-
-// RoundTrip authorizes and authenticates the request with an
-// access token. If no token exists or token is expired,
-// tries to refresh/fetch a new token.
-func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
- req2 := cloneRequest(req)
- for _, modifier := range t.Modifiers {
- if err := modifier.ModifyRequest(req2); err != nil {
- return nil, err
- }
- }
-
- t.setModReq(req, req2)
- res, err := t.base().RoundTrip(req2)
- if err != nil {
- t.setModReq(req, nil)
- return nil, err
- }
- res.Body = &onEOFReader{
- rc: res.Body,
- fn: func() { t.setModReq(req, nil) },
- }
- return res, nil
-}
-
-// CancelRequest cancels an in-flight request by closing its connection.
-func (t *transport) CancelRequest(req *http.Request) {
- type canceler interface {
- CancelRequest(*http.Request)
- }
- if cr, ok := t.base().(canceler); ok {
- t.mu.Lock()
- modReq := t.modReq[req]
- delete(t.modReq, req)
- t.mu.Unlock()
- cr.CancelRequest(modReq)
- }
-}
-
-func (t *transport) base() http.RoundTripper {
- if t.Base != nil {
- return t.Base
- }
- return http.DefaultTransport
-}
-
-func (t *transport) setModReq(orig, mod *http.Request) {
- t.mu.Lock()
- defer t.mu.Unlock()
- if t.modReq == nil {
- t.modReq = make(map[*http.Request]*http.Request)
- }
- if mod == nil {
- delete(t.modReq, orig)
- } else {
- t.modReq[orig] = mod
- }
-}
-
-// cloneRequest returns a clone of the provided *http.Request.
-// The clone is a shallow copy of the struct and its Header map.
-func cloneRequest(r *http.Request) *http.Request {
- // shallow copy of the struct
- r2 := new(http.Request)
- *r2 = *r
- // deep copy of the Header
- r2.Header = make(http.Header, len(r.Header))
- for k, s := range r.Header {
- r2.Header[k] = append([]string(nil), s...)
- }
-
- return r2
-}
-
-type onEOFReader struct {
- rc io.ReadCloser
- fn func()
-}
-
-func (r *onEOFReader) Read(p []byte) (n int, err error) {
- n, err = r.rc.Read(p)
- if err == io.EOF {
- r.runFunc()
- }
- return
-}
-
-func (r *onEOFReader) Close() error {
- err := r.rc.Close()
- r.runFunc()
- return err
-}
-
-func (r *onEOFReader) runFunc() {
- if fn := r.fn; fn != nil {
- fn()
- r.fn = nil
- }
-}
diff --git a/vendor/github.com/docker/distribution/registry/storage/cache/cache.go b/vendor/github.com/docker/distribution/registry/storage/cache/cache.go
deleted file mode 100644
index 10a390919..000000000
--- a/vendor/github.com/docker/distribution/registry/storage/cache/cache.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Package cache provides facilities to speed up access to the storage
-// backend.
-package cache
-
-import (
- "fmt"
-
- "github.com/docker/distribution"
-)
-
-// BlobDescriptorCacheProvider provides repository scoped
-// BlobDescriptorService cache instances and a global descriptor cache.
-type BlobDescriptorCacheProvider interface {
- distribution.BlobDescriptorService
-
- RepositoryScoped(repo string) (distribution.BlobDescriptorService, error)
-}
-
-// ValidateDescriptor provides a helper function to ensure that caches have
-// common criteria for admitting descriptors.
-func ValidateDescriptor(desc distribution.Descriptor) error {
- if err := desc.Digest.Validate(); err != nil {
- return err
- }
-
- if desc.Size < 0 {
- return fmt.Errorf("cache: invalid length in descriptor: %v < 0", desc.Size)
- }
-
- if desc.MediaType == "" {
- return fmt.Errorf("cache: empty mediatype on descriptor: %v", desc)
- }
-
- return nil
-}
diff --git a/vendor/github.com/docker/distribution/registry/storage/cache/cachedblobdescriptorstore.go b/vendor/github.com/docker/distribution/registry/storage/cache/cachedblobdescriptorstore.go
deleted file mode 100644
index 94ca8a90c..000000000
--- a/vendor/github.com/docker/distribution/registry/storage/cache/cachedblobdescriptorstore.go
+++ /dev/null
@@ -1,101 +0,0 @@
-package cache
-
-import (
- "github.com/docker/distribution/context"
- "github.com/docker/distribution/digest"
-
- "github.com/docker/distribution"
-)
-
-// Metrics is used to hold metric counters
-// related to the number of times a cache was
-// hit or missed.
-type Metrics struct {
- Requests uint64
- Hits uint64
- Misses uint64
-}
-
-// MetricsTracker represents a metric tracker
-// which simply counts the number of hits and misses.
-type MetricsTracker interface {
- Hit()
- Miss()
- Metrics() Metrics
-}
-
-type cachedBlobStatter struct {
- cache distribution.BlobDescriptorService
- backend distribution.BlobDescriptorService
- tracker MetricsTracker
-}
-
-// NewCachedBlobStatter creates a new statter which prefers a cache and
-// falls back to a backend.
-func NewCachedBlobStatter(cache distribution.BlobDescriptorService, backend distribution.BlobDescriptorService) distribution.BlobDescriptorService {
- return &cachedBlobStatter{
- cache: cache,
- backend: backend,
- }
-}
-
-// NewCachedBlobStatterWithMetrics creates a new statter which prefers a cache and
-// falls back to a backend. Hits and misses will send to the tracker.
-func NewCachedBlobStatterWithMetrics(cache distribution.BlobDescriptorService, backend distribution.BlobDescriptorService, tracker MetricsTracker) distribution.BlobStatter {
- return &cachedBlobStatter{
- cache: cache,
- backend: backend,
- tracker: tracker,
- }
-}
-
-func (cbds *cachedBlobStatter) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
- desc, err := cbds.cache.Stat(ctx, dgst)
- if err != nil {
- if err != distribution.ErrBlobUnknown {
- context.GetLogger(ctx).Errorf("error retrieving descriptor from cache: %v", err)
- }
-
- goto fallback
- }
-
- if cbds.tracker != nil {
- cbds.tracker.Hit()
- }
- return desc, nil
-fallback:
- if cbds.tracker != nil {
- cbds.tracker.Miss()
- }
- desc, err = cbds.backend.Stat(ctx, dgst)
- if err != nil {
- return desc, err
- }
-
- if err := cbds.cache.SetDescriptor(ctx, dgst, desc); err != nil {
- context.GetLogger(ctx).Errorf("error adding descriptor %v to cache: %v", desc.Digest, err)
- }
-
- return desc, err
-
-}
-
-func (cbds *cachedBlobStatter) Clear(ctx context.Context, dgst digest.Digest) error {
- err := cbds.cache.Clear(ctx, dgst)
- if err != nil {
- return err
- }
-
- err = cbds.backend.Clear(ctx, dgst)
- if err != nil {
- return err
- }
- return nil
-}
-
-func (cbds *cachedBlobStatter) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
- if err := cbds.cache.SetDescriptor(ctx, dgst, desc); err != nil {
- context.GetLogger(ctx).Errorf("error adding descriptor %v to cache: %v", desc.Digest, err)
- }
- return nil
-}
diff --git a/vendor/github.com/docker/distribution/registry/storage/cache/memory/memory.go b/vendor/github.com/docker/distribution/registry/storage/cache/memory/memory.go
deleted file mode 100644
index 68a68f081..000000000
--- a/vendor/github.com/docker/distribution/registry/storage/cache/memory/memory.go
+++ /dev/null
@@ -1,170 +0,0 @@
-package memory
-
-import (
- "sync"
-
- "github.com/docker/distribution"
- "github.com/docker/distribution/context"
- "github.com/docker/distribution/digest"
- "github.com/docker/distribution/reference"
- "github.com/docker/distribution/registry/storage/cache"
-)
-
-type inMemoryBlobDescriptorCacheProvider struct {
- global *mapBlobDescriptorCache
- repositories map[string]*mapBlobDescriptorCache
- mu sync.RWMutex
-}
-
-// NewInMemoryBlobDescriptorCacheProvider returns a new mapped-based cache for
-// storing blob descriptor data.
-func NewInMemoryBlobDescriptorCacheProvider() cache.BlobDescriptorCacheProvider {
- return &inMemoryBlobDescriptorCacheProvider{
- global: newMapBlobDescriptorCache(),
- repositories: make(map[string]*mapBlobDescriptorCache),
- }
-}
-
-func (imbdcp *inMemoryBlobDescriptorCacheProvider) RepositoryScoped(repo string) (distribution.BlobDescriptorService, error) {
- if _, err := reference.ParseNamed(repo); err != nil {
- return nil, err
- }
-
- imbdcp.mu.RLock()
- defer imbdcp.mu.RUnlock()
-
- return &repositoryScopedInMemoryBlobDescriptorCache{
- repo: repo,
- parent: imbdcp,
- repository: imbdcp.repositories[repo],
- }, nil
-}
-
-func (imbdcp *inMemoryBlobDescriptorCacheProvider) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
- return imbdcp.global.Stat(ctx, dgst)
-}
-
-func (imbdcp *inMemoryBlobDescriptorCacheProvider) Clear(ctx context.Context, dgst digest.Digest) error {
- return imbdcp.global.Clear(ctx, dgst)
-}
-
-func (imbdcp *inMemoryBlobDescriptorCacheProvider) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
- _, err := imbdcp.Stat(ctx, dgst)
- if err == distribution.ErrBlobUnknown {
-
- if dgst.Algorithm() != desc.Digest.Algorithm() && dgst != desc.Digest {
- // if the digests differ, set the other canonical mapping
- if err := imbdcp.global.SetDescriptor(ctx, desc.Digest, desc); err != nil {
- return err
- }
- }
-
- // unknown, just set it
- return imbdcp.global.SetDescriptor(ctx, dgst, desc)
- }
-
- // we already know it, do nothing
- return err
-}
-
-// repositoryScopedInMemoryBlobDescriptorCache provides the request scoped
-// repository cache. Instances are not thread-safe but the delegated
-// operations are.
-type repositoryScopedInMemoryBlobDescriptorCache struct {
- repo string
- parent *inMemoryBlobDescriptorCacheProvider // allows lazy allocation of repo's map
- repository *mapBlobDescriptorCache
-}
-
-func (rsimbdcp *repositoryScopedInMemoryBlobDescriptorCache) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
- if rsimbdcp.repository == nil {
- return distribution.Descriptor{}, distribution.ErrBlobUnknown
- }
-
- return rsimbdcp.repository.Stat(ctx, dgst)
-}
-
-func (rsimbdcp *repositoryScopedInMemoryBlobDescriptorCache) Clear(ctx context.Context, dgst digest.Digest) error {
- if rsimbdcp.repository == nil {
- return distribution.ErrBlobUnknown
- }
-
- return rsimbdcp.repository.Clear(ctx, dgst)
-}
-
-func (rsimbdcp *repositoryScopedInMemoryBlobDescriptorCache) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
- if rsimbdcp.repository == nil {
- // allocate map since we are setting it now.
- rsimbdcp.parent.mu.Lock()
- var ok bool
- // have to read back value since we may have allocated elsewhere.
- rsimbdcp.repository, ok = rsimbdcp.parent.repositories[rsimbdcp.repo]
- if !ok {
- rsimbdcp.repository = newMapBlobDescriptorCache()
- rsimbdcp.parent.repositories[rsimbdcp.repo] = rsimbdcp.repository
- }
-
- rsimbdcp.parent.mu.Unlock()
- }
-
- if err := rsimbdcp.repository.SetDescriptor(ctx, dgst, desc); err != nil {
- return err
- }
-
- return rsimbdcp.parent.SetDescriptor(ctx, dgst, desc)
-}
-
-// mapBlobDescriptorCache provides a simple map-based implementation of the
-// descriptor cache.
-type mapBlobDescriptorCache struct {
- descriptors map[digest.Digest]distribution.Descriptor
- mu sync.RWMutex
-}
-
-var _ distribution.BlobDescriptorService = &mapBlobDescriptorCache{}
-
-func newMapBlobDescriptorCache() *mapBlobDescriptorCache {
- return &mapBlobDescriptorCache{
- descriptors: make(map[digest.Digest]distribution.Descriptor),
- }
-}
-
-func (mbdc *mapBlobDescriptorCache) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
- if err := dgst.Validate(); err != nil {
- return distribution.Descriptor{}, err
- }
-
- mbdc.mu.RLock()
- defer mbdc.mu.RUnlock()
-
- desc, ok := mbdc.descriptors[dgst]
- if !ok {
- return distribution.Descriptor{}, distribution.ErrBlobUnknown
- }
-
- return desc, nil
-}
-
-func (mbdc *mapBlobDescriptorCache) Clear(ctx context.Context, dgst digest.Digest) error {
- mbdc.mu.Lock()
- defer mbdc.mu.Unlock()
-
- delete(mbdc.descriptors, dgst)
- return nil
-}
-
-func (mbdc *mapBlobDescriptorCache) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
- if err := dgst.Validate(); err != nil {
- return err
- }
-
- if err := cache.ValidateDescriptor(desc); err != nil {
- return err
- }
-
- mbdc.mu.Lock()
- defer mbdc.mu.Unlock()
-
- mbdc.descriptors[dgst] = desc
- return nil
-}
diff --git a/vendor/github.com/docker/docker/cliconfig/config.go b/vendor/github.com/docker/docker/cliconfig/config.go
deleted file mode 100644
index d81bf86b7..000000000
--- a/vendor/github.com/docker/docker/cliconfig/config.go
+++ /dev/null
@@ -1,120 +0,0 @@
-package cliconfig
-
-import (
- "fmt"
- "io"
- "os"
- "path/filepath"
-
- "github.com/docker/docker/api/types"
- "github.com/docker/docker/cliconfig/configfile"
- "github.com/docker/docker/pkg/homedir"
-)
-
-const (
- // ConfigFileName is the name of config file
- ConfigFileName = "config.json"
- configFileDir = ".docker"
- oldConfigfile = ".dockercfg"
-)
-
-var (
- configDir = os.Getenv("DOCKER_CONFIG")
-)
-
-func init() {
- if configDir == "" {
- configDir = filepath.Join(homedir.Get(), configFileDir)
- }
-}
-
-// ConfigDir returns the directory the configuration file is stored in
-func ConfigDir() string {
- return configDir
-}
-
-// SetConfigDir sets the directory the configuration file is stored in
-func SetConfigDir(dir string) {
- configDir = dir
-}
-
-// NewConfigFile initializes an empty configuration file for the given filename 'fn'
-func NewConfigFile(fn string) *configfile.ConfigFile {
- return &configfile.ConfigFile{
- AuthConfigs: make(map[string]types.AuthConfig),
- HTTPHeaders: make(map[string]string),
- Filename: fn,
- }
-}
-
-// LegacyLoadFromReader is a convenience function that creates a ConfigFile object from
-// a non-nested reader
-func LegacyLoadFromReader(configData io.Reader) (*configfile.ConfigFile, error) {
- configFile := configfile.ConfigFile{
- AuthConfigs: make(map[string]types.AuthConfig),
- }
- err := configFile.LegacyLoadFromReader(configData)
- return &configFile, err
-}
-
-// LoadFromReader is a convenience function that creates a ConfigFile object from
-// a reader
-func LoadFromReader(configData io.Reader) (*configfile.ConfigFile, error) {
- configFile := configfile.ConfigFile{
- AuthConfigs: make(map[string]types.AuthConfig),
- }
- err := configFile.LoadFromReader(configData)
- return &configFile, err
-}
-
-// Load reads the configuration files in the given directory, and sets up
-// the auth config information and returns values.
-// FIXME: use the internal golang config parser
-func Load(configDir string) (*configfile.ConfigFile, error) {
- if configDir == "" {
- configDir = ConfigDir()
- }
-
- configFile := configfile.ConfigFile{
- AuthConfigs: make(map[string]types.AuthConfig),
- Filename: filepath.Join(configDir, ConfigFileName),
- }
-
- // Try happy path first - latest config file
- if _, err := os.Stat(configFile.Filename); err == nil {
- file, err := os.Open(configFile.Filename)
- if err != nil {
- return &configFile, fmt.Errorf("%s - %v", configFile.Filename, err)
- }
- defer file.Close()
- err = configFile.LoadFromReader(file)
- if err != nil {
- err = fmt.Errorf("%s - %v", configFile.Filename, err)
- }
- return &configFile, err
- } else if !os.IsNotExist(err) {
- // if file is there but we can't stat it for any reason other
- // than it doesn't exist then stop
- return &configFile, fmt.Errorf("%s - %v", configFile.Filename, err)
- }
-
- // Can't find latest config file so check for the old one
- confFile := filepath.Join(homedir.Get(), oldConfigfile)
- if _, err := os.Stat(confFile); err != nil {
- return &configFile, nil //missing file is not an error
- }
- file, err := os.Open(confFile)
- if err != nil {
- return &configFile, fmt.Errorf("%s - %v", confFile, err)
- }
- defer file.Close()
- err = configFile.LegacyLoadFromReader(file)
- if err != nil {
- return &configFile, fmt.Errorf("%s - %v", confFile, err)
- }
-
- if configFile.HTTPHeaders == nil {
- configFile.HTTPHeaders = map[string]string{}
- }
- return &configFile, nil
-}
diff --git a/vendor/github.com/docker/docker/cliconfig/configfile/file.go b/vendor/github.com/docker/docker/cliconfig/configfile/file.go
deleted file mode 100644
index d9ba28ee6..000000000
--- a/vendor/github.com/docker/docker/cliconfig/configfile/file.go
+++ /dev/null
@@ -1,180 +0,0 @@
-package configfile
-
-import (
- "encoding/base64"
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/docker/docker/api/types"
-)
-
-const (
- // This constant is only used for really old config files when the
- // URL wasn't saved as part of the config file and it was just
- // assumed to be this value.
- defaultIndexserver = "https://index.docker.io/v1/"
-)
-
-// ConfigFile ~/.docker/config.json file info
-type ConfigFile struct {
- AuthConfigs map[string]types.AuthConfig `json:"auths"`
- HTTPHeaders map[string]string `json:"HttpHeaders,omitempty"`
- PsFormat string `json:"psFormat,omitempty"`
- ImagesFormat string `json:"imagesFormat,omitempty"`
- NetworksFormat string `json:"networksFormat,omitempty"`
- VolumesFormat string `json:"volumesFormat,omitempty"`
- DetachKeys string `json:"detachKeys,omitempty"`
- CredentialsStore string `json:"credsStore,omitempty"`
- Filename string `json:"-"` // Note: for internal use only
- ServiceInspectFormat string `json:"serviceInspectFormat,omitempty"`
-}
-
-// LegacyLoadFromReader reads the non-nested configuration data given and sets up the
-// auth config information with given directory and populates the receiver object
-func (configFile *ConfigFile) LegacyLoadFromReader(configData io.Reader) error {
- b, err := ioutil.ReadAll(configData)
- if err != nil {
- return err
- }
-
- if err := json.Unmarshal(b, &configFile.AuthConfigs); err != nil {
- arr := strings.Split(string(b), "\n")
- if len(arr) < 2 {
- return fmt.Errorf("The Auth config file is empty")
- }
- authConfig := types.AuthConfig{}
- origAuth := strings.Split(arr[0], " = ")
- if len(origAuth) != 2 {
- return fmt.Errorf("Invalid Auth config file")
- }
- authConfig.Username, authConfig.Password, err = decodeAuth(origAuth[1])
- if err != nil {
- return err
- }
- authConfig.ServerAddress = defaultIndexserver
- configFile.AuthConfigs[defaultIndexserver] = authConfig
- } else {
- for k, authConfig := range configFile.AuthConfigs {
- authConfig.Username, authConfig.Password, err = decodeAuth(authConfig.Auth)
- if err != nil {
- return err
- }
- authConfig.Auth = ""
- authConfig.ServerAddress = k
- configFile.AuthConfigs[k] = authConfig
- }
- }
- return nil
-}
-
-// LoadFromReader reads the configuration data given and sets up the auth config
-// information with given directory and populates the receiver object
-func (configFile *ConfigFile) LoadFromReader(configData io.Reader) error {
- if err := json.NewDecoder(configData).Decode(&configFile); err != nil {
- return err
- }
- var err error
- for addr, ac := range configFile.AuthConfigs {
- ac.Username, ac.Password, err = decodeAuth(ac.Auth)
- if err != nil {
- return err
- }
- ac.Auth = ""
- ac.ServerAddress = addr
- configFile.AuthConfigs[addr] = ac
- }
- return nil
-}
-
-// ContainsAuth returns whether there is authentication configured
-// in this file or not.
-func (configFile *ConfigFile) ContainsAuth() bool {
- return configFile.CredentialsStore != "" ||
- (configFile.AuthConfigs != nil && len(configFile.AuthConfigs) > 0)
-}
-
-// SaveToWriter encodes and writes out all the authorization information to
-// the given writer
-func (configFile *ConfigFile) SaveToWriter(writer io.Writer) error {
- // Encode sensitive data into a new/temp struct
- tmpAuthConfigs := make(map[string]types.AuthConfig, len(configFile.AuthConfigs))
- for k, authConfig := range configFile.AuthConfigs {
- authCopy := authConfig
- // encode and save the authstring, while blanking out the original fields
- authCopy.Auth = encodeAuth(&authCopy)
- authCopy.Username = ""
- authCopy.Password = ""
- authCopy.ServerAddress = ""
- tmpAuthConfigs[k] = authCopy
- }
-
- saveAuthConfigs := configFile.AuthConfigs
- configFile.AuthConfigs = tmpAuthConfigs
- defer func() { configFile.AuthConfigs = saveAuthConfigs }()
-
- data, err := json.MarshalIndent(configFile, "", "\t")
- if err != nil {
- return err
- }
- _, err = writer.Write(data)
- return err
-}
-
-// Save encodes and writes out all the authorization information
-func (configFile *ConfigFile) Save() error {
- if configFile.Filename == "" {
- return fmt.Errorf("Can't save config with empty filename")
- }
-
- if err := os.MkdirAll(filepath.Dir(configFile.Filename), 0700); err != nil {
- return err
- }
- f, err := os.OpenFile(configFile.Filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
- if err != nil {
- return err
- }
- defer f.Close()
- return configFile.SaveToWriter(f)
-}
-
-// encodeAuth creates a base64 encoded string to containing authorization information
-func encodeAuth(authConfig *types.AuthConfig) string {
- if authConfig.Username == "" && authConfig.Password == "" {
- return ""
- }
-
- authStr := authConfig.Username + ":" + authConfig.Password
- msg := []byte(authStr)
- encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg)))
- base64.StdEncoding.Encode(encoded, msg)
- return string(encoded)
-}
-
-// decodeAuth decodes a base64 encoded string and returns username and password
-func decodeAuth(authStr string) (string, string, error) {
- if authStr == "" {
- return "", "", nil
- }
-
- decLen := base64.StdEncoding.DecodedLen(len(authStr))
- decoded := make([]byte, decLen)
- authByte := []byte(authStr)
- n, err := base64.StdEncoding.Decode(decoded, authByte)
- if err != nil {
- return "", "", err
- }
- if n > decLen {
- return "", "", fmt.Errorf("Something went wrong decoding auth config")
- }
- arr := strings.SplitN(string(decoded), ":", 2)
- if len(arr) != 2 {
- return "", "", fmt.Errorf("Invalid auth configuration file")
- }
- password := strings.Trim(arr[1], "\x00")
- return arr[0], password, nil
-}
diff --git a/vendor/github.com/docker/docker/pkg/homedir/homedir.go b/vendor/github.com/docker/docker/pkg/homedir/homedir.go
deleted file mode 100644
index 8154e83f0..000000000
--- a/vendor/github.com/docker/docker/pkg/homedir/homedir.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package homedir
-
-import (
- "os"
- "runtime"
-
- "github.com/opencontainers/runc/libcontainer/user"
-)
-
-// Key returns the env var name for the user's home dir based on
-// the platform being run on
-func Key() string {
- if runtime.GOOS == "windows" {
- return "USERPROFILE"
- }
- return "HOME"
-}
-
-// Get returns the home directory of the current user with the help of
-// environment variables depending on the target operating system.
-// Returned path should be used with "path/filepath" to form new paths.
-func Get() string {
- home := os.Getenv(Key())
- if home == "" && runtime.GOOS != "windows" {
- if u, err := user.CurrentUser(); err == nil {
- return u.Home
- }
- }
- return home
-}
-
-// GetShortcutString returns the string that is shortcut to user's home directory
-// in the native shell of the platform running on.
-func GetShortcutString() string {
- if runtime.GOOS == "windows" {
- return "%USERPROFILE%" // be careful while using in format functions
- }
- return "~"
-}
diff --git a/vendor/github.com/docker/docker/registry/auth.go b/vendor/github.com/docker/docker/registry/auth.go
deleted file mode 100644
index 0bf0450b2..000000000
--- a/vendor/github.com/docker/docker/registry/auth.go
+++ /dev/null
@@ -1,302 +0,0 @@
-package registry
-
-import (
- "fmt"
- "io/ioutil"
- "net/http"
- "net/url"
- "strings"
- "time"
-
- "github.com/Sirupsen/logrus"
- "github.com/docker/distribution/registry/client/auth"
- "github.com/docker/distribution/registry/client/transport"
- "github.com/docker/docker/api/types"
- registrytypes "github.com/docker/docker/api/types/registry"
-)
-
-const (
- // AuthClientID is used the ClientID used for the token server
- AuthClientID = "docker"
-)
-
-// loginV1 tries to register/login to the v1 registry server.
-func loginV1(authConfig *types.AuthConfig, apiEndpoint APIEndpoint, userAgent string) (string, string, error) {
- registryEndpoint, err := apiEndpoint.ToV1Endpoint(userAgent, nil)
- if err != nil {
- return "", "", err
- }
-
- serverAddress := registryEndpoint.String()
-
- logrus.Debugf("attempting v1 login to registry endpoint %s", serverAddress)
-
- if serverAddress == "" {
- return "", "", fmt.Errorf("Server Error: Server Address not set.")
- }
-
- loginAgainstOfficialIndex := serverAddress == IndexServer
-
- req, err := http.NewRequest("GET", serverAddress+"users/", nil)
- if err != nil {
- return "", "", err
- }
- req.SetBasicAuth(authConfig.Username, authConfig.Password)
- resp, err := registryEndpoint.client.Do(req)
- if err != nil {
- // fallback when request could not be completed
- return "", "", fallbackError{
- err: err,
- }
- }
- defer resp.Body.Close()
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return "", "", err
- }
- if resp.StatusCode == http.StatusOK {
- return "Login Succeeded", "", nil
- } else if resp.StatusCode == http.StatusUnauthorized {
- if loginAgainstOfficialIndex {
- return "", "", fmt.Errorf("Wrong login/password, please try again. Haven't got a Docker ID? Create one at https://hub.docker.com")
- }
- return "", "", fmt.Errorf("Wrong login/password, please try again")
- } else if resp.StatusCode == http.StatusForbidden {
- if loginAgainstOfficialIndex {
- return "", "", fmt.Errorf("Login: Account is not active. Please check your e-mail for a confirmation link.")
- }
- // *TODO: Use registry configuration to determine what this says, if anything?
- return "", "", fmt.Errorf("Login: Account is not active. Please see the documentation of the registry %s for instructions how to activate it.", serverAddress)
- } else if resp.StatusCode == http.StatusInternalServerError { // Issue #14326
- logrus.Errorf("%s returned status code %d. Response Body :\n%s", req.URL.String(), resp.StatusCode, body)
- return "", "", fmt.Errorf("Internal Server Error")
- }
- return "", "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body,
- resp.StatusCode, resp.Header)
-}
-
-type loginCredentialStore struct {
- authConfig *types.AuthConfig
-}
-
-func (lcs loginCredentialStore) Basic(*url.URL) (string, string) {
- return lcs.authConfig.Username, lcs.authConfig.Password
-}
-
-func (lcs loginCredentialStore) RefreshToken(*url.URL, string) string {
- return lcs.authConfig.IdentityToken
-}
-
-func (lcs loginCredentialStore) SetRefreshToken(u *url.URL, service, token string) {
- lcs.authConfig.IdentityToken = token
-}
-
-type staticCredentialStore struct {
- auth *types.AuthConfig
-}
-
-// NewStaticCredentialStore returns a credential store
-// which always returns the same credential values.
-func NewStaticCredentialStore(auth *types.AuthConfig) auth.CredentialStore {
- return staticCredentialStore{
- auth: auth,
- }
-}
-
-func (scs staticCredentialStore) Basic(*url.URL) (string, string) {
- if scs.auth == nil {
- return "", ""
- }
- return scs.auth.Username, scs.auth.Password
-}
-
-func (scs staticCredentialStore) RefreshToken(*url.URL, string) string {
- if scs.auth == nil {
- return ""
- }
- return scs.auth.IdentityToken
-}
-
-func (scs staticCredentialStore) SetRefreshToken(*url.URL, string, string) {
-}
-
-type fallbackError struct {
- err error
-}
-
-func (err fallbackError) Error() string {
- return err.err.Error()
-}
-
-// loginV2 tries to login to the v2 registry server. The given registry
-// endpoint will be pinged to get authorization challenges. These challenges
-// will be used to authenticate against the registry to validate credentials.
-func loginV2(authConfig *types.AuthConfig, endpoint APIEndpoint, userAgent string) (string, string, error) {
- logrus.Debugf("attempting v2 login to registry endpoint %s", strings.TrimRight(endpoint.URL.String(), "/")+"/v2/")
-
- modifiers := DockerHeaders(userAgent, nil)
- authTransport := transport.NewTransport(NewTransport(endpoint.TLSConfig), modifiers...)
-
- credentialAuthConfig := *authConfig
- creds := loginCredentialStore{
- authConfig: &credentialAuthConfig,
- }
-
- loginClient, foundV2, err := v2AuthHTTPClient(endpoint.URL, authTransport, modifiers, creds, nil)
- if err != nil {
- return "", "", err
- }
-
- endpointStr := strings.TrimRight(endpoint.URL.String(), "/") + "/v2/"
- req, err := http.NewRequest("GET", endpointStr, nil)
- if err != nil {
- if !foundV2 {
- err = fallbackError{err: err}
- }
- return "", "", err
- }
-
- resp, err := loginClient.Do(req)
- if err != nil {
- if !foundV2 {
- err = fallbackError{err: err}
- }
- return "", "", err
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- // TODO(dmcgowan): Attempt to further interpret result, status code and error code string
- err := fmt.Errorf("login attempt to %s failed with status: %d %s", endpointStr, resp.StatusCode, http.StatusText(resp.StatusCode))
- if !foundV2 {
- err = fallbackError{err: err}
- }
- return "", "", err
- }
-
- return "Login Succeeded", credentialAuthConfig.IdentityToken, nil
-
-}
-
-func v2AuthHTTPClient(endpoint *url.URL, authTransport http.RoundTripper, modifiers []transport.RequestModifier, creds auth.CredentialStore, scopes []auth.Scope) (*http.Client, bool, error) {
- challengeManager, foundV2, err := PingV2Registry(endpoint, authTransport)
- if err != nil {
- if !foundV2 {
- err = fallbackError{err: err}
- }
- return nil, foundV2, err
- }
-
- tokenHandlerOptions := auth.TokenHandlerOptions{
- Transport: authTransport,
- Credentials: creds,
- OfflineAccess: true,
- ClientID: AuthClientID,
- Scopes: scopes,
- }
- tokenHandler := auth.NewTokenHandlerWithOptions(tokenHandlerOptions)
- basicHandler := auth.NewBasicHandler(creds)
- modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
- tr := transport.NewTransport(authTransport, modifiers...)
-
- return &http.Client{
- Transport: tr,
- Timeout: 15 * time.Second,
- }, foundV2, nil
-
-}
-
-// ConvertToHostname converts a registry url which has http|https prepended
-// to just an hostname.
-func ConvertToHostname(url string) string {
- stripped := url
- if strings.HasPrefix(url, "http://") {
- stripped = strings.TrimPrefix(url, "http://")
- } else if strings.HasPrefix(url, "https://") {
- stripped = strings.TrimPrefix(url, "https://")
- }
-
- nameParts := strings.SplitN(stripped, "/", 2)
-
- return nameParts[0]
-}
-
-// ResolveAuthConfig matches an auth configuration to a server address or a URL
-func ResolveAuthConfig(authConfigs map[string]types.AuthConfig, index *registrytypes.IndexInfo) types.AuthConfig {
- configKey := GetAuthConfigKey(index)
- // First try the happy case
- if c, found := authConfigs[configKey]; found || index.Official {
- return c
- }
-
- // Maybe they have a legacy config file, we will iterate the keys converting
- // them to the new format and testing
- for registry, ac := range authConfigs {
- if configKey == ConvertToHostname(registry) {
- return ac
- }
- }
-
- // When all else fails, return an empty auth config
- return types.AuthConfig{}
-}
-
-// PingResponseError is used when the response from a ping
-// was received but invalid.
-type PingResponseError struct {
- Err error
-}
-
-func (err PingResponseError) Error() string {
- return err.Error()
-}
-
-// PingV2Registry attempts to ping a v2 registry and on success return a
-// challenge manager for the supported authentication types and
-// whether v2 was confirmed by the response. If a response is received but
-// cannot be interpreted a PingResponseError will be returned.
-func PingV2Registry(endpoint *url.URL, transport http.RoundTripper) (auth.ChallengeManager, bool, error) {
- var (
- foundV2 = false
- v2Version = auth.APIVersion{
- Type: "registry",
- Version: "2.0",
- }
- )
-
- pingClient := &http.Client{
- Transport: transport,
- Timeout: 15 * time.Second,
- }
- endpointStr := strings.TrimRight(endpoint.String(), "/") + "/v2/"
- req, err := http.NewRequest("GET", endpointStr, nil)
- if err != nil {
- return nil, false, err
- }
- resp, err := pingClient.Do(req)
- if err != nil {
- return nil, false, err
- }
- defer resp.Body.Close()
-
- versions := auth.APIVersions(resp, DefaultRegistryVersionHeader)
- for _, pingVersion := range versions {
- if pingVersion == v2Version {
- // The version header indicates we're definitely
- // talking to a v2 registry. So don't allow future
- // fallbacks to the v1 protocol.
-
- foundV2 = true
- break
- }
- }
-
- challengeManager := auth.NewSimpleChallengeManager()
- if err := challengeManager.AddResponse(resp); err != nil {
- return nil, foundV2, PingResponseError{
- Err: err,
- }
- }
-
- return challengeManager, foundV2, nil
-}
diff --git a/vendor/github.com/docker/docker/registry/config.go b/vendor/github.com/docker/docker/registry/config.go
deleted file mode 100644
index 588720475..000000000
--- a/vendor/github.com/docker/docker/registry/config.go
+++ /dev/null
@@ -1,274 +0,0 @@
-package registry
-
-import (
- "errors"
- "fmt"
- "net"
- "net/url"
- "strings"
-
- registrytypes "github.com/docker/docker/api/types/registry"
- "github.com/docker/docker/opts"
- "github.com/docker/docker/reference"
- "github.com/spf13/pflag"
-)
-
-// ServiceOptions holds command line options.
-type ServiceOptions struct {
- Mirrors []string `json:"registry-mirrors,omitempty"`
- InsecureRegistries []string `json:"insecure-registries,omitempty"`
-
- // V2Only controls access to legacy registries. If it is set to true via the
- // command line flag the daemon will not attempt to contact v1 legacy registries
- V2Only bool `json:"disable-legacy-registry,omitempty"`
-}
-
-// serviceConfig holds daemon configuration for the registry service.
-type serviceConfig struct {
- registrytypes.ServiceConfig
- V2Only bool
-}
-
-var (
- // DefaultNamespace is the default namespace
- DefaultNamespace = "docker.io"
- // DefaultRegistryVersionHeader is the name of the default HTTP header
- // that carries Registry version info
- DefaultRegistryVersionHeader = "Docker-Distribution-Api-Version"
-
- // IndexServer is the v1 registry server used for user auth + account creation
- IndexServer = DefaultV1Registry.String() + "/v1/"
- // IndexName is the name of the index
- IndexName = "docker.io"
-
- // NotaryServer is the endpoint serving the Notary trust server
- NotaryServer = "https://notary.docker.io"
-
- // DefaultV1Registry is the URI of the default v1 registry
- DefaultV1Registry = &url.URL{
- Scheme: "https",
- Host: "index.docker.io",
- }
-
- // DefaultV2Registry is the URI of the default v2 registry
- DefaultV2Registry = &url.URL{
- Scheme: "https",
- Host: "registry-1.docker.io",
- }
-)
-
-var (
- // ErrInvalidRepositoryName is an error returned if the repository name did
- // not have the correct form
- ErrInvalidRepositoryName = errors.New("Invalid repository name (ex: \"registry.domain.tld/myrepos\")")
-
- emptyServiceConfig = newServiceConfig(ServiceOptions{})
-)
-
-// for mocking in unit tests
-var lookupIP = net.LookupIP
-
-// InstallCliFlags adds command-line options to the top-level flag parser for
-// the current process.
-func (options *ServiceOptions) InstallCliFlags(flags *pflag.FlagSet) {
- mirrors := opts.NewNamedListOptsRef("registry-mirrors", &options.Mirrors, ValidateMirror)
- insecureRegistries := opts.NewNamedListOptsRef("insecure-registries", &options.InsecureRegistries, ValidateIndexName)
-
- flags.Var(mirrors, "registry-mirror", "Preferred Docker registry mirror")
- flags.Var(insecureRegistries, "insecure-registry", "Enable insecure registry communication")
-
- options.installCliPlatformFlags(flags)
-}
-
-// newServiceConfig returns a new instance of ServiceConfig
-func newServiceConfig(options ServiceOptions) *serviceConfig {
- // Localhost is by default considered as an insecure registry
- // This is a stop-gap for people who are running a private registry on localhost (especially on Boot2docker).
- //
- // TODO: should we deprecate this once it is easier for people to set up a TLS registry or change
- // daemon flags on boot2docker?
- options.InsecureRegistries = append(options.InsecureRegistries, "127.0.0.0/8")
-
- config := &serviceConfig{
- ServiceConfig: registrytypes.ServiceConfig{
- InsecureRegistryCIDRs: make([]*registrytypes.NetIPNet, 0),
- IndexConfigs: make(map[string]*registrytypes.IndexInfo, 0),
- // Hack: Bypass setting the mirrors to IndexConfigs since they are going away
- // and Mirrors are only for the official registry anyways.
- Mirrors: options.Mirrors,
- },
- V2Only: options.V2Only,
- }
- // Split --insecure-registry into CIDR and registry-specific settings.
- for _, r := range options.InsecureRegistries {
- // Check if CIDR was passed to --insecure-registry
- _, ipnet, err := net.ParseCIDR(r)
- if err == nil {
- // Valid CIDR.
- config.InsecureRegistryCIDRs = append(config.InsecureRegistryCIDRs, (*registrytypes.NetIPNet)(ipnet))
- } else {
- // Assume `host:port` if not CIDR.
- config.IndexConfigs[r] = ®istrytypes.IndexInfo{
- Name: r,
- Mirrors: make([]string, 0),
- Secure: false,
- Official: false,
- }
- }
- }
-
- // Configure public registry.
- config.IndexConfigs[IndexName] = ®istrytypes.IndexInfo{
- Name: IndexName,
- Mirrors: config.Mirrors,
- Secure: true,
- Official: true,
- }
-
- return config
-}
-
-// isSecureIndex returns false if the provided indexName is part of the list of insecure registries
-// Insecure registries accept HTTP and/or accept HTTPS with certificates from unknown CAs.
-//
-// The list of insecure registries can contain an element with CIDR notation to specify a whole subnet.
-// If the subnet contains one of the IPs of the registry specified by indexName, the latter is considered
-// insecure.
-//
-// indexName should be a URL.Host (`host:port` or `host`) where the `host` part can be either a domain name
-// or an IP address. If it is a domain name, then it will be resolved in order to check if the IP is contained
-// in a subnet. If the resolving is not successful, isSecureIndex will only try to match hostname to any element
-// of insecureRegistries.
-func isSecureIndex(config *serviceConfig, indexName string) bool {
- // Check for configured index, first. This is needed in case isSecureIndex
- // is called from anything besides newIndexInfo, in order to honor per-index configurations.
- if index, ok := config.IndexConfigs[indexName]; ok {
- return index.Secure
- }
-
- host, _, err := net.SplitHostPort(indexName)
- if err != nil {
- // assume indexName is of the form `host` without the port and go on.
- host = indexName
- }
-
- addrs, err := lookupIP(host)
- if err != nil {
- ip := net.ParseIP(host)
- if ip != nil {
- addrs = []net.IP{ip}
- }
-
- // if ip == nil, then `host` is neither an IP nor it could be looked up,
- // either because the index is unreachable, or because the index is behind an HTTP proxy.
- // So, len(addrs) == 0 and we're not aborting.
- }
-
- // Try CIDR notation only if addrs has any elements, i.e. if `host`'s IP could be determined.
- for _, addr := range addrs {
- for _, ipnet := range config.InsecureRegistryCIDRs {
- // check if the addr falls in the subnet
- if (*net.IPNet)(ipnet).Contains(addr) {
- return false
- }
- }
- }
-
- return true
-}
-
-// ValidateMirror validates an HTTP(S) registry mirror
-func ValidateMirror(val string) (string, error) {
- uri, err := url.Parse(val)
- if err != nil {
- return "", fmt.Errorf("%s is not a valid URI", val)
- }
-
- if uri.Scheme != "http" && uri.Scheme != "https" {
- return "", fmt.Errorf("Unsupported scheme %s", uri.Scheme)
- }
-
- if uri.Path != "" || uri.RawQuery != "" || uri.Fragment != "" {
- return "", fmt.Errorf("Unsupported path/query/fragment at end of the URI")
- }
-
- return fmt.Sprintf("%s://%s/", uri.Scheme, uri.Host), nil
-}
-
-// ValidateIndexName validates an index name.
-func ValidateIndexName(val string) (string, error) {
- if val == reference.LegacyDefaultHostname {
- val = reference.DefaultHostname
- }
- if strings.HasPrefix(val, "-") || strings.HasSuffix(val, "-") {
- return "", fmt.Errorf("Invalid index name (%s). Cannot begin or end with a hyphen.", val)
- }
- return val, nil
-}
-
-func validateNoScheme(reposName string) error {
- if strings.Contains(reposName, "://") {
- // It cannot contain a scheme!
- return ErrInvalidRepositoryName
- }
- return nil
-}
-
-// newIndexInfo returns IndexInfo configuration from indexName
-func newIndexInfo(config *serviceConfig, indexName string) (*registrytypes.IndexInfo, error) {
- var err error
- indexName, err = ValidateIndexName(indexName)
- if err != nil {
- return nil, err
- }
-
- // Return any configured index info, first.
- if index, ok := config.IndexConfigs[indexName]; ok {
- return index, nil
- }
-
- // Construct a non-configured index info.
- index := ®istrytypes.IndexInfo{
- Name: indexName,
- Mirrors: make([]string, 0),
- Official: false,
- }
- index.Secure = isSecureIndex(config, indexName)
- return index, nil
-}
-
-// GetAuthConfigKey special-cases using the full index address of the official
-// index as the AuthConfig key, and uses the (host)name[:port] for private indexes.
-func GetAuthConfigKey(index *registrytypes.IndexInfo) string {
- if index.Official {
- return IndexServer
- }
- return index.Name
-}
-
-// newRepositoryInfo validates and breaks down a repository name into a RepositoryInfo
-func newRepositoryInfo(config *serviceConfig, name reference.Named) (*RepositoryInfo, error) {
- index, err := newIndexInfo(config, name.Hostname())
- if err != nil {
- return nil, err
- }
- official := !strings.ContainsRune(name.Name(), '/')
- return &RepositoryInfo{name, index, official}, nil
-}
-
-// ParseRepositoryInfo performs the breakdown of a repository name into a RepositoryInfo, but
-// lacks registry configuration.
-func ParseRepositoryInfo(reposName reference.Named) (*RepositoryInfo, error) {
- return newRepositoryInfo(emptyServiceConfig, reposName)
-}
-
-// ParseSearchIndexInfo will use repository name to get back an indexInfo.
-func ParseSearchIndexInfo(reposName string) (*registrytypes.IndexInfo, error) {
- indexName, _ := splitReposSearchTerm(reposName)
-
- indexInfo, err := newIndexInfo(emptyServiceConfig, indexName)
- if err != nil {
- return nil, err
- }
- return indexInfo, nil
-}
diff --git a/vendor/github.com/docker/docker/registry/config_unix.go b/vendor/github.com/docker/docker/registry/config_unix.go
deleted file mode 100644
index d692e8ef5..000000000
--- a/vendor/github.com/docker/docker/registry/config_unix.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// +build !windows
-
-package registry
-
-import (
- "github.com/spf13/pflag"
-)
-
-var (
- // CertsDir is the directory where certificates are stored
- CertsDir = "/etc/docker/certs.d"
-)
-
-// cleanPath is used to ensure that a directory name is valid on the target
-// platform. It will be passed in something *similar* to a URL such as
-// https:/index.docker.io/v1. Not all platforms support directory names
-// which contain those characters (such as : on Windows)
-func cleanPath(s string) string {
- return s
-}
-
-// installCliPlatformFlags handles any platform specific flags for the service.
-func (options *ServiceOptions) installCliPlatformFlags(flags *pflag.FlagSet) {
- flags.BoolVar(&options.V2Only, "disable-legacy-registry", false, "Disable contacting legacy registries")
-}
diff --git a/vendor/github.com/docker/docker/registry/config_windows.go b/vendor/github.com/docker/docker/registry/config_windows.go
deleted file mode 100644
index d1b313dc1..000000000
--- a/vendor/github.com/docker/docker/registry/config_windows.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package registry
-
-import (
- "os"
- "path/filepath"
- "strings"
-
- "github.com/spf13/pflag"
-)
-
-// CertsDir is the directory where certificates are stored
-var CertsDir = os.Getenv("programdata") + `\docker\certs.d`
-
-// cleanPath is used to ensure that a directory name is valid on the target
-// platform. It will be passed in something *similar* to a URL such as
-// https:\index.docker.io\v1. Not all platforms support directory names
-// which contain those characters (such as : on Windows)
-func cleanPath(s string) string {
- return filepath.FromSlash(strings.Replace(s, ":", "", -1))
-}
-
-// installCliPlatformFlags handles any platform specific flags for the service.
-func (options *ServiceOptions) installCliPlatformFlags(flags *pflag.FlagSet) {
- // No Windows specific flags.
-}
diff --git a/vendor/github.com/docker/docker/registry/endpoint_v1.go b/vendor/github.com/docker/docker/registry/endpoint_v1.go
deleted file mode 100644
index 6bcf8c935..000000000
--- a/vendor/github.com/docker/docker/registry/endpoint_v1.go
+++ /dev/null
@@ -1,198 +0,0 @@
-package registry
-
-import (
- "crypto/tls"
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net/http"
- "net/url"
- "strings"
-
- "github.com/Sirupsen/logrus"
- "github.com/docker/distribution/registry/client/transport"
- registrytypes "github.com/docker/docker/api/types/registry"
-)
-
-// V1Endpoint stores basic information about a V1 registry endpoint.
-type V1Endpoint struct {
- client *http.Client
- URL *url.URL
- IsSecure bool
-}
-
-// NewV1Endpoint parses the given address to return a registry endpoint.
-func NewV1Endpoint(index *registrytypes.IndexInfo, userAgent string, metaHeaders http.Header) (*V1Endpoint, error) {
- tlsConfig, err := newTLSConfig(index.Name, index.Secure)
- if err != nil {
- return nil, err
- }
-
- endpoint, err := newV1EndpointFromStr(GetAuthConfigKey(index), tlsConfig, userAgent, metaHeaders)
- if err != nil {
- return nil, err
- }
-
- if err := validateEndpoint(endpoint); err != nil {
- return nil, err
- }
-
- return endpoint, nil
-}
-
-func validateEndpoint(endpoint *V1Endpoint) error {
- logrus.Debugf("pinging registry endpoint %s", endpoint)
-
- // Try HTTPS ping to registry
- endpoint.URL.Scheme = "https"
- if _, err := endpoint.Ping(); err != nil {
- if endpoint.IsSecure {
- // If registry is secure and HTTPS failed, show user the error and tell them about `--insecure-registry`
- // in case that's what they need. DO NOT accept unknown CA certificates, and DO NOT fallback to HTTP.
- return fmt.Errorf("invalid registry endpoint %s: %v. If this private registry supports only HTTP or HTTPS with an unknown CA certificate, please add `--insecure-registry %s` to the daemon's arguments. In the case of HTTPS, if you have access to the registry's CA certificate, no need for the flag; simply place the CA certificate at /etc/docker/certs.d/%s/ca.crt", endpoint, err, endpoint.URL.Host, endpoint.URL.Host)
- }
-
- // If registry is insecure and HTTPS failed, fallback to HTTP.
- logrus.Debugf("Error from registry %q marked as insecure: %v. Insecurely falling back to HTTP", endpoint, err)
- endpoint.URL.Scheme = "http"
-
- var err2 error
- if _, err2 = endpoint.Ping(); err2 == nil {
- return nil
- }
-
- return fmt.Errorf("invalid registry endpoint %q. HTTPS attempt: %v. HTTP attempt: %v", endpoint, err, err2)
- }
-
- return nil
-}
-
-func newV1Endpoint(address url.URL, tlsConfig *tls.Config, userAgent string, metaHeaders http.Header) (*V1Endpoint, error) {
- endpoint := &V1Endpoint{
- IsSecure: (tlsConfig == nil || !tlsConfig.InsecureSkipVerify),
- URL: new(url.URL),
- }
-
- *endpoint.URL = address
-
- // TODO(tiborvass): make sure a ConnectTimeout transport is used
- tr := NewTransport(tlsConfig)
- endpoint.client = HTTPClient(transport.NewTransport(tr, DockerHeaders(userAgent, metaHeaders)...))
- return endpoint, nil
-}
-
-// trimV1Address trims the version off the address and returns the
-// trimmed address or an error if there is a non-V1 version.
-func trimV1Address(address string) (string, error) {
- var (
- chunks []string
- apiVersionStr string
- )
-
- if strings.HasSuffix(address, "/") {
- address = address[:len(address)-1]
- }
-
- chunks = strings.Split(address, "/")
- apiVersionStr = chunks[len(chunks)-1]
- if apiVersionStr == "v1" {
- return strings.Join(chunks[:len(chunks)-1], "/"), nil
- }
-
- for k, v := range apiVersions {
- if k != APIVersion1 && apiVersionStr == v {
- return "", fmt.Errorf("unsupported V1 version path %s", apiVersionStr)
- }
- }
-
- return address, nil
-}
-
-func newV1EndpointFromStr(address string, tlsConfig *tls.Config, userAgent string, metaHeaders http.Header) (*V1Endpoint, error) {
- if !strings.HasPrefix(address, "http://") && !strings.HasPrefix(address, "https://") {
- address = "https://" + address
- }
-
- address, err := trimV1Address(address)
- if err != nil {
- return nil, err
- }
-
- uri, err := url.Parse(address)
- if err != nil {
- return nil, err
- }
-
- endpoint, err := newV1Endpoint(*uri, tlsConfig, userAgent, metaHeaders)
- if err != nil {
- return nil, err
- }
-
- return endpoint, nil
-}
-
-// Get the formatted URL for the root of this registry Endpoint
-func (e *V1Endpoint) String() string {
- return e.URL.String() + "/v1/"
-}
-
-// Path returns a formatted string for the URL
-// of this endpoint with the given path appended.
-func (e *V1Endpoint) Path(path string) string {
- return e.URL.String() + "/v1/" + path
-}
-
-// Ping returns a PingResult which indicates whether the registry is standalone or not.
-func (e *V1Endpoint) Ping() (PingResult, error) {
- logrus.Debugf("attempting v1 ping for registry endpoint %s", e)
-
- if e.String() == IndexServer {
- // Skip the check, we know this one is valid
- // (and we never want to fallback to http in case of error)
- return PingResult{Standalone: false}, nil
- }
-
- req, err := http.NewRequest("GET", e.Path("_ping"), nil)
- if err != nil {
- return PingResult{Standalone: false}, err
- }
-
- resp, err := e.client.Do(req)
- if err != nil {
- return PingResult{Standalone: false}, err
- }
-
- defer resp.Body.Close()
-
- jsonString, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return PingResult{Standalone: false}, fmt.Errorf("error while reading the http response: %s", err)
- }
-
- // If the header is absent, we assume true for compatibility with earlier
- // versions of the registry. default to true
- info := PingResult{
- Standalone: true,
- }
- if err := json.Unmarshal(jsonString, &info); err != nil {
- logrus.Debugf("Error unmarshalling the _ping PingResult: %s", err)
- // don't stop here. Just assume sane defaults
- }
- if hdr := resp.Header.Get("X-Docker-Registry-Version"); hdr != "" {
- logrus.Debugf("Registry version header: '%s'", hdr)
- info.Version = hdr
- }
- logrus.Debugf("PingResult.Version: %q", info.Version)
-
- standalone := resp.Header.Get("X-Docker-Registry-Standalone")
- logrus.Debugf("Registry standalone header: '%s'", standalone)
- // Accepted values are "true" (case-insensitive) and "1".
- if strings.EqualFold(standalone, "true") || standalone == "1" {
- info.Standalone = true
- } else if len(standalone) > 0 {
- // there is a header set, and it is not "true" or "1", so assume fails
- info.Standalone = false
- }
- logrus.Debugf("PingResult.Standalone: %t", info.Standalone)
- return info, nil
-}
diff --git a/vendor/github.com/docker/docker/registry/reference.go b/vendor/github.com/docker/docker/registry/reference.go
deleted file mode 100644
index e15f83eee..000000000
--- a/vendor/github.com/docker/docker/registry/reference.go
+++ /dev/null
@@ -1,68 +0,0 @@
-package registry
-
-import (
- "strings"
-
- "github.com/docker/distribution/digest"
-)
-
-// Reference represents a tag or digest within a repository
-type Reference interface {
- // HasDigest returns whether the reference has a verifiable
- // content addressable reference which may be considered secure.
- HasDigest() bool
-
- // ImageName returns an image name for the given repository
- ImageName(string) string
-
- // Returns a string representation of the reference
- String() string
-}
-
-type tagReference struct {
- tag string
-}
-
-func (tr tagReference) HasDigest() bool {
- return false
-}
-
-func (tr tagReference) ImageName(repo string) string {
- return repo + ":" + tr.tag
-}
-
-func (tr tagReference) String() string {
- return tr.tag
-}
-
-type digestReference struct {
- digest digest.Digest
-}
-
-func (dr digestReference) HasDigest() bool {
- return true
-}
-
-func (dr digestReference) ImageName(repo string) string {
- return repo + "@" + dr.String()
-}
-
-func (dr digestReference) String() string {
- return dr.digest.String()
-}
-
-// ParseReference parses a reference into either a digest or tag reference
-func ParseReference(ref string) Reference {
- if strings.Contains(ref, ":") {
- dgst, err := digest.ParseDigest(ref)
- if err == nil {
- return digestReference{digest: dgst}
- }
- }
- return tagReference{tag: ref}
-}
-
-// DigestReference creates a digest reference using a digest
-func DigestReference(dgst digest.Digest) Reference {
- return digestReference{digest: dgst}
-}
diff --git a/vendor/github.com/docker/docker/registry/registry.go b/vendor/github.com/docker/docker/registry/registry.go
deleted file mode 100644
index a139981b0..000000000
--- a/vendor/github.com/docker/docker/registry/registry.go
+++ /dev/null
@@ -1,189 +0,0 @@
-// Package registry contains client primitives to interact with a remote Docker registry.
-package registry
-
-import (
- "crypto/tls"
- "crypto/x509"
- "errors"
- "fmt"
- "io/ioutil"
- "net"
- "net/http"
- "os"
- "path/filepath"
- "strings"
- "time"
-
- "github.com/Sirupsen/logrus"
- "github.com/docker/distribution/registry/client/transport"
- "github.com/docker/go-connections/sockets"
- "github.com/docker/go-connections/tlsconfig"
-)
-
-var (
- // ErrAlreadyExists is an error returned if an image being pushed
- // already exists on the remote side
- ErrAlreadyExists = errors.New("Image already exists")
-)
-
-func newTLSConfig(hostname string, isSecure bool) (*tls.Config, error) {
- // PreferredServerCipherSuites should have no effect
- tlsConfig := tlsconfig.ServerDefault()
-
- tlsConfig.InsecureSkipVerify = !isSecure
-
- if isSecure && CertsDir != "" {
- hostDir := filepath.Join(CertsDir, cleanPath(hostname))
- logrus.Debugf("hostDir: %s", hostDir)
- if err := ReadCertsDirectory(tlsConfig, hostDir); err != nil {
- return nil, err
- }
- }
-
- return tlsConfig, nil
-}
-
-func hasFile(files []os.FileInfo, name string) bool {
- for _, f := range files {
- if f.Name() == name {
- return true
- }
- }
- return false
-}
-
-// ReadCertsDirectory reads the directory for TLS certificates
-// including roots and certificate pairs and updates the
-// provided TLS configuration.
-func ReadCertsDirectory(tlsConfig *tls.Config, directory string) error {
- fs, err := ioutil.ReadDir(directory)
- if err != nil && !os.IsNotExist(err) {
- return err
- }
-
- for _, f := range fs {
- if strings.HasSuffix(f.Name(), ".crt") {
- if tlsConfig.RootCAs == nil {
- // TODO(dmcgowan): Copy system pool
- tlsConfig.RootCAs = x509.NewCertPool()
- }
- logrus.Debugf("crt: %s", filepath.Join(directory, f.Name()))
- data, err := ioutil.ReadFile(filepath.Join(directory, f.Name()))
- if err != nil {
- return err
- }
- tlsConfig.RootCAs.AppendCertsFromPEM(data)
- }
- if strings.HasSuffix(f.Name(), ".cert") {
- certName := f.Name()
- keyName := certName[:len(certName)-5] + ".key"
- logrus.Debugf("cert: %s", filepath.Join(directory, f.Name()))
- if !hasFile(fs, keyName) {
- return fmt.Errorf("Missing key %s for client certificate %s. Note that CA certificates should use the extension .crt.", keyName, certName)
- }
- cert, err := tls.LoadX509KeyPair(filepath.Join(directory, certName), filepath.Join(directory, keyName))
- if err != nil {
- return err
- }
- tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
- }
- if strings.HasSuffix(f.Name(), ".key") {
- keyName := f.Name()
- certName := keyName[:len(keyName)-4] + ".cert"
- logrus.Debugf("key: %s", filepath.Join(directory, f.Name()))
- if !hasFile(fs, certName) {
- return fmt.Errorf("Missing client certificate %s for key %s", certName, keyName)
- }
- }
- }
-
- return nil
-}
-
-// DockerHeaders returns request modifiers with a User-Agent and metaHeaders
-func DockerHeaders(userAgent string, metaHeaders http.Header) []transport.RequestModifier {
- modifiers := []transport.RequestModifier{}
- if userAgent != "" {
- modifiers = append(modifiers, transport.NewHeaderRequestModifier(http.Header{
- "User-Agent": []string{userAgent},
- }))
- }
- if metaHeaders != nil {
- modifiers = append(modifiers, transport.NewHeaderRequestModifier(metaHeaders))
- }
- return modifiers
-}
-
-// HTTPClient returns an HTTP client structure which uses the given transport
-// and contains the necessary headers for redirected requests
-func HTTPClient(transport http.RoundTripper) *http.Client {
- return &http.Client{
- Transport: transport,
- CheckRedirect: addRequiredHeadersToRedirectedRequests,
- }
-}
-
-func trustedLocation(req *http.Request) bool {
- var (
- trusteds = []string{"docker.com", "docker.io"}
- hostname = strings.SplitN(req.Host, ":", 2)[0]
- )
- if req.URL.Scheme != "https" {
- return false
- }
-
- for _, trusted := range trusteds {
- if hostname == trusted || strings.HasSuffix(hostname, "."+trusted) {
- return true
- }
- }
- return false
-}
-
-// addRequiredHeadersToRedirectedRequests adds the necessary redirection headers
-// for redirected requests
-func addRequiredHeadersToRedirectedRequests(req *http.Request, via []*http.Request) error {
- if via != nil && via[0] != nil {
- if trustedLocation(req) && trustedLocation(via[0]) {
- req.Header = via[0].Header
- return nil
- }
- for k, v := range via[0].Header {
- if k != "Authorization" {
- for _, vv := range v {
- req.Header.Add(k, vv)
- }
- }
- }
- }
- return nil
-}
-
-// NewTransport returns a new HTTP transport. If tlsConfig is nil, it uses the
-// default TLS configuration.
-func NewTransport(tlsConfig *tls.Config) *http.Transport {
- if tlsConfig == nil {
- tlsConfig = tlsconfig.ServerDefault()
- }
-
- direct := &net.Dialer{
- Timeout: 30 * time.Second,
- KeepAlive: 30 * time.Second,
- DualStack: true,
- }
-
- base := &http.Transport{
- Proxy: http.ProxyFromEnvironment,
- Dial: direct.Dial,
- TLSHandshakeTimeout: 10 * time.Second,
- TLSClientConfig: tlsConfig,
- // TODO(dmcgowan): Call close idle connections when complete and use keep alive
- DisableKeepAlives: true,
- }
-
- proxyDialer, err := sockets.DialerFromEnvironment(direct)
- if err == nil {
- base.Dial = proxyDialer.Dial
- }
- return base
-}
diff --git a/vendor/github.com/docker/docker/registry/service.go b/vendor/github.com/docker/docker/registry/service.go
deleted file mode 100644
index 808d4555c..000000000
--- a/vendor/github.com/docker/docker/registry/service.go
+++ /dev/null
@@ -1,260 +0,0 @@
-package registry
-
-import (
- "crypto/tls"
- "fmt"
- "net/http"
- "net/url"
- "strings"
-
- "golang.org/x/net/context"
-
- "github.com/Sirupsen/logrus"
- "github.com/docker/distribution/registry/client/auth"
- "github.com/docker/docker/api/types"
- registrytypes "github.com/docker/docker/api/types/registry"
- "github.com/docker/docker/reference"
-)
-
-const (
- // DefaultSearchLimit is the default value for maximum number of returned search results.
- DefaultSearchLimit = 25
-)
-
-// Service is the interface defining what a registry service should implement.
-type Service interface {
- Auth(ctx context.Context, authConfig *types.AuthConfig, userAgent string) (status, token string, err error)
- LookupPullEndpoints(hostname string) (endpoints []APIEndpoint, err error)
- LookupPushEndpoints(hostname string) (endpoints []APIEndpoint, err error)
- ResolveRepository(name reference.Named) (*RepositoryInfo, error)
- ResolveIndex(name string) (*registrytypes.IndexInfo, error)
- Search(ctx context.Context, term string, limit int, authConfig *types.AuthConfig, userAgent string, headers map[string][]string) (*registrytypes.SearchResults, error)
- ServiceConfig() *registrytypes.ServiceConfig
- TLSConfig(hostname string) (*tls.Config, error)
-}
-
-// DefaultService is a registry service. It tracks configuration data such as a list
-// of mirrors.
-type DefaultService struct {
- config *serviceConfig
-}
-
-// NewService returns a new instance of DefaultService ready to be
-// installed into an engine.
-func NewService(options ServiceOptions) *DefaultService {
- return &DefaultService{
- config: newServiceConfig(options),
- }
-}
-
-// ServiceConfig returns the public registry service configuration.
-func (s *DefaultService) ServiceConfig() *registrytypes.ServiceConfig {
- return &s.config.ServiceConfig
-}
-
-// Auth contacts the public registry with the provided credentials,
-// and returns OK if authentication was successful.
-// It can be used to verify the validity of a client's credentials.
-func (s *DefaultService) Auth(ctx context.Context, authConfig *types.AuthConfig, userAgent string) (status, token string, err error) {
- // TODO Use ctx when searching for repositories
- serverAddress := authConfig.ServerAddress
- if serverAddress == "" {
- serverAddress = IndexServer
- }
- if !strings.HasPrefix(serverAddress, "https://") && !strings.HasPrefix(serverAddress, "http://") {
- serverAddress = "https://" + serverAddress
- }
- u, err := url.Parse(serverAddress)
- if err != nil {
- return "", "", fmt.Errorf("unable to parse server address: %v", err)
- }
-
- endpoints, err := s.LookupPushEndpoints(u.Host)
- if err != nil {
- return "", "", err
- }
-
- for _, endpoint := range endpoints {
- login := loginV2
- if endpoint.Version == APIVersion1 {
- login = loginV1
- }
-
- status, token, err = login(authConfig, endpoint, userAgent)
- if err == nil {
- return
- }
- if fErr, ok := err.(fallbackError); ok {
- err = fErr.err
- logrus.Infof("Error logging in to %s endpoint, trying next endpoint: %v", endpoint.Version, err)
- continue
- }
- return "", "", err
- }
-
- return "", "", err
-}
-
-// splitReposSearchTerm breaks a search term into an index name and remote name
-func splitReposSearchTerm(reposName string) (string, string) {
- nameParts := strings.SplitN(reposName, "/", 2)
- var indexName, remoteName string
- if len(nameParts) == 1 || (!strings.Contains(nameParts[0], ".") &&
- !strings.Contains(nameParts[0], ":") && nameParts[0] != "localhost") {
- // This is a Docker Index repos (ex: samalba/hipache or ubuntu)
- // 'docker.io'
- indexName = IndexName
- remoteName = reposName
- } else {
- indexName = nameParts[0]
- remoteName = nameParts[1]
- }
- return indexName, remoteName
-}
-
-// Search queries the public registry for images matching the specified
-// search terms, and returns the results.
-func (s *DefaultService) Search(ctx context.Context, term string, limit int, authConfig *types.AuthConfig, userAgent string, headers map[string][]string) (*registrytypes.SearchResults, error) {
- // TODO Use ctx when searching for repositories
- if err := validateNoScheme(term); err != nil {
- return nil, err
- }
-
- indexName, remoteName := splitReposSearchTerm(term)
-
- index, err := newIndexInfo(s.config, indexName)
- if err != nil {
- return nil, err
- }
-
- // *TODO: Search multiple indexes.
- endpoint, err := NewV1Endpoint(index, userAgent, http.Header(headers))
- if err != nil {
- return nil, err
- }
-
- var client *http.Client
- if authConfig != nil && authConfig.IdentityToken != "" && authConfig.Username != "" {
- creds := NewStaticCredentialStore(authConfig)
- scopes := []auth.Scope{
- auth.RegistryScope{
- Name: "catalog",
- Actions: []string{"search"},
- },
- }
-
- modifiers := DockerHeaders(userAgent, nil)
- v2Client, foundV2, err := v2AuthHTTPClient(endpoint.URL, endpoint.client.Transport, modifiers, creds, scopes)
- if err != nil {
- if fErr, ok := err.(fallbackError); ok {
- logrus.Errorf("Cannot use identity token for search, v2 auth not supported: %v", fErr.err)
- } else {
- return nil, err
- }
- } else if foundV2 {
- // Copy non transport http client features
- v2Client.Timeout = endpoint.client.Timeout
- v2Client.CheckRedirect = endpoint.client.CheckRedirect
- v2Client.Jar = endpoint.client.Jar
-
- logrus.Debugf("using v2 client for search to %s", endpoint.URL)
- client = v2Client
- }
- }
-
- if client == nil {
- client = endpoint.client
- if err := authorizeClient(client, authConfig, endpoint); err != nil {
- return nil, err
- }
- }
-
- r := newSession(client, authConfig, endpoint)
-
- if index.Official {
- localName := remoteName
- if strings.HasPrefix(localName, "library/") {
- // If pull "library/foo", it's stored locally under "foo"
- localName = strings.SplitN(localName, "/", 2)[1]
- }
-
- return r.SearchRepositories(localName, limit)
- }
- return r.SearchRepositories(remoteName, limit)
-}
-
-// ResolveRepository splits a repository name into its components
-// and configuration of the associated registry.
-func (s *DefaultService) ResolveRepository(name reference.Named) (*RepositoryInfo, error) {
- return newRepositoryInfo(s.config, name)
-}
-
-// ResolveIndex takes indexName and returns index info
-func (s *DefaultService) ResolveIndex(name string) (*registrytypes.IndexInfo, error) {
- return newIndexInfo(s.config, name)
-}
-
-// APIEndpoint represents a remote API endpoint
-type APIEndpoint struct {
- Mirror bool
- URL *url.URL
- Version APIVersion
- Official bool
- TrimHostname bool
- TLSConfig *tls.Config
-}
-
-// ToV1Endpoint returns a V1 API endpoint based on the APIEndpoint
-func (e APIEndpoint) ToV1Endpoint(userAgent string, metaHeaders http.Header) (*V1Endpoint, error) {
- return newV1Endpoint(*e.URL, e.TLSConfig, userAgent, metaHeaders)
-}
-
-// TLSConfig constructs a client TLS configuration based on server defaults
-func (s *DefaultService) TLSConfig(hostname string) (*tls.Config, error) {
- return newTLSConfig(hostname, isSecureIndex(s.config, hostname))
-}
-
-func (s *DefaultService) tlsConfigForMirror(mirrorURL *url.URL) (*tls.Config, error) {
- return s.TLSConfig(mirrorURL.Host)
-}
-
-// LookupPullEndpoints creates a list of endpoints to try to pull from, in order of preference.
-// It gives preference to v2 endpoints over v1, mirrors over the actual
-// registry, and HTTPS over plain HTTP.
-func (s *DefaultService) LookupPullEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
- return s.lookupEndpoints(hostname)
-}
-
-// LookupPushEndpoints creates a list of endpoints to try to push to, in order of preference.
-// It gives preference to v2 endpoints over v1, and HTTPS over plain HTTP.
-// Mirrors are not included.
-func (s *DefaultService) LookupPushEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
- allEndpoints, err := s.lookupEndpoints(hostname)
- if err == nil {
- for _, endpoint := range allEndpoints {
- if !endpoint.Mirror {
- endpoints = append(endpoints, endpoint)
- }
- }
- }
- return endpoints, err
-}
-
-func (s *DefaultService) lookupEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
- endpoints, err = s.lookupV2Endpoints(hostname)
- if err != nil {
- return nil, err
- }
-
- if s.config.V2Only {
- return endpoints, nil
- }
-
- legacyEndpoints, err := s.lookupV1Endpoints(hostname)
- if err != nil {
- return nil, err
- }
- endpoints = append(endpoints, legacyEndpoints...)
-
- return endpoints, nil
-}
diff --git a/vendor/github.com/docker/docker/registry/service_v1.go b/vendor/github.com/docker/docker/registry/service_v1.go
deleted file mode 100644
index 33ab312c0..000000000
--- a/vendor/github.com/docker/docker/registry/service_v1.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package registry
-
-import (
- "net/url"
-
- "github.com/docker/go-connections/tlsconfig"
-)
-
-func (s *DefaultService) lookupV1Endpoints(hostname string) (endpoints []APIEndpoint, err error) {
- tlsConfig := tlsconfig.ServerDefault()
- if hostname == DefaultNamespace {
- endpoints = append(endpoints, APIEndpoint{
- URL: DefaultV1Registry,
- Version: APIVersion1,
- Official: true,
- TrimHostname: true,
- TLSConfig: tlsConfig,
- })
- return endpoints, nil
- }
-
- tlsConfig, err = s.TLSConfig(hostname)
- if err != nil {
- return nil, err
- }
-
- endpoints = []APIEndpoint{
- {
- URL: &url.URL{
- Scheme: "https",
- Host: hostname,
- },
- Version: APIVersion1,
- TrimHostname: true,
- TLSConfig: tlsConfig,
- },
- }
-
- if tlsConfig.InsecureSkipVerify {
- endpoints = append(endpoints, APIEndpoint{ // or this
- URL: &url.URL{
- Scheme: "http",
- Host: hostname,
- },
- Version: APIVersion1,
- TrimHostname: true,
- // used to check if supposed to be secure via InsecureSkipVerify
- TLSConfig: tlsConfig,
- })
- }
- return endpoints, nil
-}
diff --git a/vendor/github.com/docker/docker/registry/service_v2.go b/vendor/github.com/docker/docker/registry/service_v2.go
deleted file mode 100644
index 60ed1357d..000000000
--- a/vendor/github.com/docker/docker/registry/service_v2.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package registry
-
-import (
- "net/url"
- "strings"
-
- "github.com/docker/go-connections/tlsconfig"
-)
-
-func (s *DefaultService) lookupV2Endpoints(hostname string) (endpoints []APIEndpoint, err error) {
- tlsConfig := tlsconfig.ServerDefault()
- if hostname == DefaultNamespace || hostname == DefaultV1Registry.Host {
- // v2 mirrors
- for _, mirror := range s.config.Mirrors {
- if !strings.HasPrefix(mirror, "http://") && !strings.HasPrefix(mirror, "https://") {
- mirror = "https://" + mirror
- }
- mirrorURL, err := url.Parse(mirror)
- if err != nil {
- return nil, err
- }
- mirrorTLSConfig, err := s.tlsConfigForMirror(mirrorURL)
- if err != nil {
- return nil, err
- }
- endpoints = append(endpoints, APIEndpoint{
- URL: mirrorURL,
- // guess mirrors are v2
- Version: APIVersion2,
- Mirror: true,
- TrimHostname: true,
- TLSConfig: mirrorTLSConfig,
- })
- }
- // v2 registry
- endpoints = append(endpoints, APIEndpoint{
- URL: DefaultV2Registry,
- Version: APIVersion2,
- Official: true,
- TrimHostname: true,
- TLSConfig: tlsConfig,
- })
-
- return endpoints, nil
- }
-
- tlsConfig, err = s.TLSConfig(hostname)
- if err != nil {
- return nil, err
- }
-
- endpoints = []APIEndpoint{
- {
- URL: &url.URL{
- Scheme: "https",
- Host: hostname,
- },
- Version: APIVersion2,
- TrimHostname: true,
- TLSConfig: tlsConfig,
- },
- }
-
- if tlsConfig.InsecureSkipVerify {
- endpoints = append(endpoints, APIEndpoint{
- URL: &url.URL{
- Scheme: "http",
- Host: hostname,
- },
- Version: APIVersion2,
- TrimHostname: true,
- // used to check if supposed to be secure via InsecureSkipVerify
- TLSConfig: tlsConfig,
- })
- }
-
- return endpoints, nil
-}
diff --git a/vendor/github.com/docker/docker/registry/session.go b/vendor/github.com/docker/docker/registry/session.go
deleted file mode 100644
index 72e286ab4..000000000
--- a/vendor/github.com/docker/docker/registry/session.go
+++ /dev/null
@@ -1,783 +0,0 @@
-package registry
-
-import (
- "bytes"
- "crypto/sha256"
- "errors"
- "sync"
- // this is required for some certificates
- _ "crypto/sha512"
- "encoding/hex"
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "net/http/cookiejar"
- "net/url"
- "strconv"
- "strings"
-
- "github.com/Sirupsen/logrus"
- "github.com/docker/distribution/registry/api/errcode"
- "github.com/docker/docker/api/types"
- registrytypes "github.com/docker/docker/api/types/registry"
- "github.com/docker/docker/pkg/httputils"
- "github.com/docker/docker/pkg/ioutils"
- "github.com/docker/docker/pkg/stringid"
- "github.com/docker/docker/pkg/tarsum"
- "github.com/docker/docker/reference"
-)
-
-var (
- // ErrRepoNotFound is returned if the repository didn't exist on the
- // remote side
- ErrRepoNotFound = errors.New("Repository not found")
-)
-
-// A Session is used to communicate with a V1 registry
-type Session struct {
- indexEndpoint *V1Endpoint
- client *http.Client
- // TODO(tiborvass): remove authConfig
- authConfig *types.AuthConfig
- id string
-}
-
-type authTransport struct {
- http.RoundTripper
- *types.AuthConfig
-
- alwaysSetBasicAuth bool
- token []string
-
- mu sync.Mutex // guards modReq
- modReq map[*http.Request]*http.Request // original -> modified
-}
-
-// AuthTransport handles the auth layer when communicating with a v1 registry (private or official)
-//
-// For private v1 registries, set alwaysSetBasicAuth to true.
-//
-// For the official v1 registry, if there isn't already an Authorization header in the request,
-// but there is an X-Docker-Token header set to true, then Basic Auth will be used to set the Authorization header.
-// After sending the request with the provided base http.RoundTripper, if an X-Docker-Token header, representing
-// a token, is present in the response, then it gets cached and sent in the Authorization header of all subsequent
-// requests.
-//
-// If the server sends a token without the client having requested it, it is ignored.
-//
-// This RoundTripper also has a CancelRequest method important for correct timeout handling.
-func AuthTransport(base http.RoundTripper, authConfig *types.AuthConfig, alwaysSetBasicAuth bool) http.RoundTripper {
- if base == nil {
- base = http.DefaultTransport
- }
- return &authTransport{
- RoundTripper: base,
- AuthConfig: authConfig,
- alwaysSetBasicAuth: alwaysSetBasicAuth,
- modReq: make(map[*http.Request]*http.Request),
- }
-}
-
-// cloneRequest returns a clone of the provided *http.Request.
-// The clone is a shallow copy of the struct and its Header map.
-func cloneRequest(r *http.Request) *http.Request {
- // shallow copy of the struct
- r2 := new(http.Request)
- *r2 = *r
- // deep copy of the Header
- r2.Header = make(http.Header, len(r.Header))
- for k, s := range r.Header {
- r2.Header[k] = append([]string(nil), s...)
- }
-
- return r2
-}
-
-// RoundTrip changes an HTTP request's headers to add the necessary
-// authentication-related headers
-func (tr *authTransport) RoundTrip(orig *http.Request) (*http.Response, error) {
- // Authorization should not be set on 302 redirect for untrusted locations.
- // This logic mirrors the behavior in addRequiredHeadersToRedirectedRequests.
- // As the authorization logic is currently implemented in RoundTrip,
- // a 302 redirect is detected by looking at the Referrer header as go http package adds said header.
- // This is safe as Docker doesn't set Referrer in other scenarios.
- if orig.Header.Get("Referer") != "" && !trustedLocation(orig) {
- return tr.RoundTripper.RoundTrip(orig)
- }
-
- req := cloneRequest(orig)
- tr.mu.Lock()
- tr.modReq[orig] = req
- tr.mu.Unlock()
-
- if tr.alwaysSetBasicAuth {
- if tr.AuthConfig == nil {
- return nil, errors.New("unexpected error: empty auth config")
- }
- req.SetBasicAuth(tr.Username, tr.Password)
- return tr.RoundTripper.RoundTrip(req)
- }
-
- // Don't override
- if req.Header.Get("Authorization") == "" {
- if req.Header.Get("X-Docker-Token") == "true" && tr.AuthConfig != nil && len(tr.Username) > 0 {
- req.SetBasicAuth(tr.Username, tr.Password)
- } else if len(tr.token) > 0 {
- req.Header.Set("Authorization", "Token "+strings.Join(tr.token, ","))
- }
- }
- resp, err := tr.RoundTripper.RoundTrip(req)
- if err != nil {
- delete(tr.modReq, orig)
- return nil, err
- }
- if len(resp.Header["X-Docker-Token"]) > 0 {
- tr.token = resp.Header["X-Docker-Token"]
- }
- resp.Body = &ioutils.OnEOFReader{
- Rc: resp.Body,
- Fn: func() {
- tr.mu.Lock()
- delete(tr.modReq, orig)
- tr.mu.Unlock()
- },
- }
- return resp, nil
-}
-
-// CancelRequest cancels an in-flight request by closing its connection.
-func (tr *authTransport) CancelRequest(req *http.Request) {
- type canceler interface {
- CancelRequest(*http.Request)
- }
- if cr, ok := tr.RoundTripper.(canceler); ok {
- tr.mu.Lock()
- modReq := tr.modReq[req]
- delete(tr.modReq, req)
- tr.mu.Unlock()
- cr.CancelRequest(modReq)
- }
-}
-
-func authorizeClient(client *http.Client, authConfig *types.AuthConfig, endpoint *V1Endpoint) error {
- var alwaysSetBasicAuth bool
-
- // If we're working with a standalone private registry over HTTPS, send Basic Auth headers
- // alongside all our requests.
- if endpoint.String() != IndexServer && endpoint.URL.Scheme == "https" {
- info, err := endpoint.Ping()
- if err != nil {
- return err
- }
- if info.Standalone && authConfig != nil {
- logrus.Debugf("Endpoint %s is eligible for private registry. Enabling decorator.", endpoint.String())
- alwaysSetBasicAuth = true
- }
- }
-
- // Annotate the transport unconditionally so that v2 can
- // properly fallback on v1 when an image is not found.
- client.Transport = AuthTransport(client.Transport, authConfig, alwaysSetBasicAuth)
-
- jar, err := cookiejar.New(nil)
- if err != nil {
- return errors.New("cookiejar.New is not supposed to return an error")
- }
- client.Jar = jar
-
- return nil
-}
-
-func newSession(client *http.Client, authConfig *types.AuthConfig, endpoint *V1Endpoint) *Session {
- return &Session{
- authConfig: authConfig,
- client: client,
- indexEndpoint: endpoint,
- id: stringid.GenerateRandomID(),
- }
-}
-
-// NewSession creates a new session
-// TODO(tiborvass): remove authConfig param once registry client v2 is vendored
-func NewSession(client *http.Client, authConfig *types.AuthConfig, endpoint *V1Endpoint) (*Session, error) {
- if err := authorizeClient(client, authConfig, endpoint); err != nil {
- return nil, err
- }
-
- return newSession(client, authConfig, endpoint), nil
-}
-
-// ID returns this registry session's ID.
-func (r *Session) ID() string {
- return r.id
-}
-
-// GetRemoteHistory retrieves the history of a given image from the registry.
-// It returns a list of the parent's JSON files (including the requested image).
-func (r *Session) GetRemoteHistory(imgID, registry string) ([]string, error) {
- res, err := r.client.Get(registry + "images/" + imgID + "/ancestry")
- if err != nil {
- return nil, err
- }
- defer res.Body.Close()
- if res.StatusCode != 200 {
- if res.StatusCode == 401 {
- return nil, errcode.ErrorCodeUnauthorized.WithArgs()
- }
- return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch remote history for %s", res.StatusCode, imgID), res)
- }
-
- var history []string
- if err := json.NewDecoder(res.Body).Decode(&history); err != nil {
- return nil, fmt.Errorf("Error while reading the http response: %v", err)
- }
-
- logrus.Debugf("Ancestry: %v", history)
- return history, nil
-}
-
-// LookupRemoteImage checks if an image exists in the registry
-func (r *Session) LookupRemoteImage(imgID, registry string) error {
- res, err := r.client.Get(registry + "images/" + imgID + "/json")
- if err != nil {
- return err
- }
- res.Body.Close()
- if res.StatusCode != 200 {
- return httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d", res.StatusCode), res)
- }
- return nil
-}
-
-// GetRemoteImageJSON retrieves an image's JSON metadata from the registry.
-func (r *Session) GetRemoteImageJSON(imgID, registry string) ([]byte, int64, error) {
- res, err := r.client.Get(registry + "images/" + imgID + "/json")
- if err != nil {
- return nil, -1, fmt.Errorf("Failed to download json: %s", err)
- }
- defer res.Body.Close()
- if res.StatusCode != 200 {
- return nil, -1, httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d", res.StatusCode), res)
- }
- // if the size header is not present, then set it to '-1'
- imageSize := int64(-1)
- if hdr := res.Header.Get("X-Docker-Size"); hdr != "" {
- imageSize, err = strconv.ParseInt(hdr, 10, 64)
- if err != nil {
- return nil, -1, err
- }
- }
-
- jsonString, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return nil, -1, fmt.Errorf("Failed to parse downloaded json: %v (%s)", err, jsonString)
- }
- return jsonString, imageSize, nil
-}
-
-// GetRemoteImageLayer retrieves an image layer from the registry
-func (r *Session) GetRemoteImageLayer(imgID, registry string, imgSize int64) (io.ReadCloser, error) {
- var (
- statusCode = 0
- res *http.Response
- err error
- imageURL = fmt.Sprintf("%simages/%s/layer", registry, imgID)
- )
-
- req, err := http.NewRequest("GET", imageURL, nil)
- if err != nil {
- return nil, fmt.Errorf("Error while getting from the server: %v", err)
- }
- statusCode = 0
- res, err = r.client.Do(req)
- if err != nil {
- logrus.Debugf("Error contacting registry %s: %v", registry, err)
- // the only case err != nil && res != nil is https://golang.org/src/net/http/client.go#L515
- if res != nil {
- if res.Body != nil {
- res.Body.Close()
- }
- statusCode = res.StatusCode
- }
- return nil, fmt.Errorf("Server error: Status %d while fetching image layer (%s)",
- statusCode, imgID)
- }
-
- if res.StatusCode != 200 {
- res.Body.Close()
- return nil, fmt.Errorf("Server error: Status %d while fetching image layer (%s)",
- res.StatusCode, imgID)
- }
-
- if res.Header.Get("Accept-Ranges") == "bytes" && imgSize > 0 {
- logrus.Debug("server supports resume")
- return httputils.ResumableRequestReaderWithInitialResponse(r.client, req, 5, imgSize, res), nil
- }
- logrus.Debug("server doesn't support resume")
- return res.Body, nil
-}
-
-// GetRemoteTag retrieves the tag named in the askedTag argument from the given
-// repository. It queries each of the registries supplied in the registries
-// argument, and returns data from the first one that answers the query
-// successfully.
-func (r *Session) GetRemoteTag(registries []string, repositoryRef reference.Named, askedTag string) (string, error) {
- repository := repositoryRef.RemoteName()
-
- if strings.Count(repository, "/") == 0 {
- // This will be removed once the registry supports auto-resolution on
- // the "library" namespace
- repository = "library/" + repository
- }
- for _, host := range registries {
- endpoint := fmt.Sprintf("%srepositories/%s/tags/%s", host, repository, askedTag)
- res, err := r.client.Get(endpoint)
- if err != nil {
- return "", err
- }
-
- logrus.Debugf("Got status code %d from %s", res.StatusCode, endpoint)
- defer res.Body.Close()
-
- if res.StatusCode == 404 {
- return "", ErrRepoNotFound
- }
- if res.StatusCode != 200 {
- continue
- }
-
- var tagID string
- if err := json.NewDecoder(res.Body).Decode(&tagID); err != nil {
- return "", err
- }
- return tagID, nil
- }
- return "", fmt.Errorf("Could not reach any registry endpoint")
-}
-
-// GetRemoteTags retrieves all tags from the given repository. It queries each
-// of the registries supplied in the registries argument, and returns data from
-// the first one that answers the query successfully. It returns a map with
-// tag names as the keys and image IDs as the values.
-func (r *Session) GetRemoteTags(registries []string, repositoryRef reference.Named) (map[string]string, error) {
- repository := repositoryRef.RemoteName()
-
- if strings.Count(repository, "/") == 0 {
- // This will be removed once the registry supports auto-resolution on
- // the "library" namespace
- repository = "library/" + repository
- }
- for _, host := range registries {
- endpoint := fmt.Sprintf("%srepositories/%s/tags", host, repository)
- res, err := r.client.Get(endpoint)
- if err != nil {
- return nil, err
- }
-
- logrus.Debugf("Got status code %d from %s", res.StatusCode, endpoint)
- defer res.Body.Close()
-
- if res.StatusCode == 404 {
- return nil, ErrRepoNotFound
- }
- if res.StatusCode != 200 {
- continue
- }
-
- result := make(map[string]string)
- if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
- return nil, err
- }
- return result, nil
- }
- return nil, fmt.Errorf("Could not reach any registry endpoint")
-}
-
-func buildEndpointsList(headers []string, indexEp string) ([]string, error) {
- var endpoints []string
- parsedURL, err := url.Parse(indexEp)
- if err != nil {
- return nil, err
- }
- var urlScheme = parsedURL.Scheme
- // The registry's URL scheme has to match the Index'
- for _, ep := range headers {
- epList := strings.Split(ep, ",")
- for _, epListElement := range epList {
- endpoints = append(
- endpoints,
- fmt.Sprintf("%s://%s/v1/", urlScheme, strings.TrimSpace(epListElement)))
- }
- }
- return endpoints, nil
-}
-
-// GetRepositoryData returns lists of images and endpoints for the repository
-func (r *Session) GetRepositoryData(name reference.Named) (*RepositoryData, error) {
- repositoryTarget := fmt.Sprintf("%srepositories/%s/images", r.indexEndpoint.String(), name.RemoteName())
-
- logrus.Debugf("[registry] Calling GET %s", repositoryTarget)
-
- req, err := http.NewRequest("GET", repositoryTarget, nil)
- if err != nil {
- return nil, err
- }
- // this will set basic auth in r.client.Transport and send cached X-Docker-Token headers for all subsequent requests
- req.Header.Set("X-Docker-Token", "true")
- res, err := r.client.Do(req)
- if err != nil {
- // check if the error is because of i/o timeout
- // and return a non-obtuse error message for users
- // "Get https://index.docker.io/v1/repositories/library/busybox/images: i/o timeout"
- // was a top search on the docker user forum
- if isTimeout(err) {
- return nil, fmt.Errorf("Network timed out while trying to connect to %s. You may want to check your internet connection or if you are behind a proxy.", repositoryTarget)
- }
- return nil, fmt.Errorf("Error while pulling image: %v", err)
- }
- defer res.Body.Close()
- if res.StatusCode == 401 {
- return nil, errcode.ErrorCodeUnauthorized.WithArgs()
- }
- // TODO: Right now we're ignoring checksums in the response body.
- // In the future, we need to use them to check image validity.
- if res.StatusCode == 404 {
- return nil, httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code: %d", res.StatusCode), res)
- } else if res.StatusCode != 200 {
- errBody, err := ioutil.ReadAll(res.Body)
- if err != nil {
- logrus.Debugf("Error reading response body: %s", err)
- }
- return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to pull repository %s: %q", res.StatusCode, name.RemoteName(), errBody), res)
- }
-
- var endpoints []string
- if res.Header.Get("X-Docker-Endpoints") != "" {
- endpoints, err = buildEndpointsList(res.Header["X-Docker-Endpoints"], r.indexEndpoint.String())
- if err != nil {
- return nil, err
- }
- } else {
- // Assume the endpoint is on the same host
- endpoints = append(endpoints, fmt.Sprintf("%s://%s/v1/", r.indexEndpoint.URL.Scheme, req.URL.Host))
- }
-
- remoteChecksums := []*ImgData{}
- if err := json.NewDecoder(res.Body).Decode(&remoteChecksums); err != nil {
- return nil, err
- }
-
- // Forge a better object from the retrieved data
- imgsData := make(map[string]*ImgData, len(remoteChecksums))
- for _, elem := range remoteChecksums {
- imgsData[elem.ID] = elem
- }
-
- return &RepositoryData{
- ImgList: imgsData,
- Endpoints: endpoints,
- }, nil
-}
-
-// PushImageChecksumRegistry uploads checksums for an image
-func (r *Session) PushImageChecksumRegistry(imgData *ImgData, registry string) error {
- u := registry + "images/" + imgData.ID + "/checksum"
-
- logrus.Debugf("[registry] Calling PUT %s", u)
-
- req, err := http.NewRequest("PUT", u, nil)
- if err != nil {
- return err
- }
- req.Header.Set("X-Docker-Checksum", imgData.Checksum)
- req.Header.Set("X-Docker-Checksum-Payload", imgData.ChecksumPayload)
-
- res, err := r.client.Do(req)
- if err != nil {
- return fmt.Errorf("Failed to upload metadata: %v", err)
- }
- defer res.Body.Close()
- if len(res.Cookies()) > 0 {
- r.client.Jar.SetCookies(req.URL, res.Cookies())
- }
- if res.StatusCode != 200 {
- errBody, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return fmt.Errorf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err)
- }
- var jsonBody map[string]string
- if err := json.Unmarshal(errBody, &jsonBody); err != nil {
- errBody = []byte(err.Error())
- } else if jsonBody["error"] == "Image already exists" {
- return ErrAlreadyExists
- }
- return fmt.Errorf("HTTP code %d while uploading metadata: %q", res.StatusCode, errBody)
- }
- return nil
-}
-
-// PushImageJSONRegistry pushes JSON metadata for a local image to the registry
-func (r *Session) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, registry string) error {
-
- u := registry + "images/" + imgData.ID + "/json"
-
- logrus.Debugf("[registry] Calling PUT %s", u)
-
- req, err := http.NewRequest("PUT", u, bytes.NewReader(jsonRaw))
- if err != nil {
- return err
- }
- req.Header.Add("Content-type", "application/json")
-
- res, err := r.client.Do(req)
- if err != nil {
- return fmt.Errorf("Failed to upload metadata: %s", err)
- }
- defer res.Body.Close()
- if res.StatusCode == 401 && strings.HasPrefix(registry, "http://") {
- return httputils.NewHTTPRequestError("HTTP code 401, Docker will not send auth headers over HTTP.", res)
- }
- if res.StatusCode != 200 {
- errBody, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
- }
- var jsonBody map[string]string
- if err := json.Unmarshal(errBody, &jsonBody); err != nil {
- errBody = []byte(err.Error())
- } else if jsonBody["error"] == "Image already exists" {
- return ErrAlreadyExists
- }
- return httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata: %q", res.StatusCode, errBody), res)
- }
- return nil
-}
-
-// PushImageLayerRegistry sends the checksum of an image layer to the registry
-func (r *Session) PushImageLayerRegistry(imgID string, layer io.Reader, registry string, jsonRaw []byte) (checksum string, checksumPayload string, err error) {
- u := registry + "images/" + imgID + "/layer"
-
- logrus.Debugf("[registry] Calling PUT %s", u)
-
- tarsumLayer, err := tarsum.NewTarSum(layer, false, tarsum.Version0)
- if err != nil {
- return "", "", err
- }
- h := sha256.New()
- h.Write(jsonRaw)
- h.Write([]byte{'\n'})
- checksumLayer := io.TeeReader(tarsumLayer, h)
-
- req, err := http.NewRequest("PUT", u, checksumLayer)
- if err != nil {
- return "", "", err
- }
- req.Header.Add("Content-Type", "application/octet-stream")
- req.ContentLength = -1
- req.TransferEncoding = []string{"chunked"}
- res, err := r.client.Do(req)
- if err != nil {
- return "", "", fmt.Errorf("Failed to upload layer: %v", err)
- }
- if rc, ok := layer.(io.Closer); ok {
- if err := rc.Close(); err != nil {
- return "", "", err
- }
- }
- defer res.Body.Close()
-
- if res.StatusCode != 200 {
- errBody, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return "", "", httputils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
- }
- return "", "", httputils.NewHTTPRequestError(fmt.Sprintf("Received HTTP code %d while uploading layer: %q", res.StatusCode, errBody), res)
- }
-
- checksumPayload = "sha256:" + hex.EncodeToString(h.Sum(nil))
- return tarsumLayer.Sum(jsonRaw), checksumPayload, nil
-}
-
-// PushRegistryTag pushes a tag on the registry.
-// Remote has the format '/
-func (r *Session) PushRegistryTag(remote reference.Named, revision, tag, registry string) error {
- // "jsonify" the string
- revision = "\"" + revision + "\""
- path := fmt.Sprintf("repositories/%s/tags/%s", remote.RemoteName(), tag)
-
- req, err := http.NewRequest("PUT", registry+path, strings.NewReader(revision))
- if err != nil {
- return err
- }
- req.Header.Add("Content-type", "application/json")
- req.ContentLength = int64(len(revision))
- res, err := r.client.Do(req)
- if err != nil {
- return err
- }
- res.Body.Close()
- if res.StatusCode != 200 && res.StatusCode != 201 {
- return httputils.NewHTTPRequestError(fmt.Sprintf("Internal server error: %d trying to push tag %s on %s", res.StatusCode, tag, remote.RemoteName()), res)
- }
- return nil
-}
-
-// PushImageJSONIndex uploads an image list to the repository
-func (r *Session) PushImageJSONIndex(remote reference.Named, imgList []*ImgData, validate bool, regs []string) (*RepositoryData, error) {
- cleanImgList := []*ImgData{}
- if validate {
- for _, elem := range imgList {
- if elem.Checksum != "" {
- cleanImgList = append(cleanImgList, elem)
- }
- }
- } else {
- cleanImgList = imgList
- }
-
- imgListJSON, err := json.Marshal(cleanImgList)
- if err != nil {
- return nil, err
- }
- var suffix string
- if validate {
- suffix = "images"
- }
- u := fmt.Sprintf("%srepositories/%s/%s", r.indexEndpoint.String(), remote.RemoteName(), suffix)
- logrus.Debugf("[registry] PUT %s", u)
- logrus.Debugf("Image list pushed to index:\n%s", imgListJSON)
- headers := map[string][]string{
- "Content-type": {"application/json"},
- // this will set basic auth in r.client.Transport and send cached X-Docker-Token headers for all subsequent requests
- "X-Docker-Token": {"true"},
- }
- if validate {
- headers["X-Docker-Endpoints"] = regs
- }
-
- // Redirect if necessary
- var res *http.Response
- for {
- if res, err = r.putImageRequest(u, headers, imgListJSON); err != nil {
- return nil, err
- }
- if !shouldRedirect(res) {
- break
- }
- res.Body.Close()
- u = res.Header.Get("Location")
- logrus.Debugf("Redirected to %s", u)
- }
- defer res.Body.Close()
-
- if res.StatusCode == 401 {
- return nil, errcode.ErrorCodeUnauthorized.WithArgs()
- }
-
- var tokens, endpoints []string
- if !validate {
- if res.StatusCode != 200 && res.StatusCode != 201 {
- errBody, err := ioutil.ReadAll(res.Body)
- if err != nil {
- logrus.Debugf("Error reading response body: %s", err)
- }
- return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push repository %s: %q", res.StatusCode, remote.RemoteName(), errBody), res)
- }
- tokens = res.Header["X-Docker-Token"]
- logrus.Debugf("Auth token: %v", tokens)
-
- if res.Header.Get("X-Docker-Endpoints") == "" {
- return nil, fmt.Errorf("Index response didn't contain any endpoints")
- }
- endpoints, err = buildEndpointsList(res.Header["X-Docker-Endpoints"], r.indexEndpoint.String())
- if err != nil {
- return nil, err
- }
- } else {
- if res.StatusCode != 204 {
- errBody, err := ioutil.ReadAll(res.Body)
- if err != nil {
- logrus.Debugf("Error reading response body: %s", err)
- }
- return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push checksums %s: %q", res.StatusCode, remote.RemoteName(), errBody), res)
- }
- }
-
- return &RepositoryData{
- Endpoints: endpoints,
- }, nil
-}
-
-func (r *Session) putImageRequest(u string, headers map[string][]string, body []byte) (*http.Response, error) {
- req, err := http.NewRequest("PUT", u, bytes.NewReader(body))
- if err != nil {
- return nil, err
- }
- req.ContentLength = int64(len(body))
- for k, v := range headers {
- req.Header[k] = v
- }
- response, err := r.client.Do(req)
- if err != nil {
- return nil, err
- }
- return response, nil
-}
-
-func shouldRedirect(response *http.Response) bool {
- return response.StatusCode >= 300 && response.StatusCode < 400
-}
-
-// SearchRepositories performs a search against the remote repository
-func (r *Session) SearchRepositories(term string, limit int) (*registrytypes.SearchResults, error) {
- if limit < 1 || limit > 100 {
- return nil, fmt.Errorf("Limit %d is outside the range of [1, 100]", limit)
- }
- logrus.Debugf("Index server: %s", r.indexEndpoint)
- u := r.indexEndpoint.String() + "search?q=" + url.QueryEscape(term) + "&n=" + url.QueryEscape(fmt.Sprintf("%d", limit))
-
- req, err := http.NewRequest("GET", u, nil)
- if err != nil {
- return nil, fmt.Errorf("Error while getting from the server: %v", err)
- }
- // Have the AuthTransport send authentication, when logged in.
- req.Header.Set("X-Docker-Token", "true")
- res, err := r.client.Do(req)
- if err != nil {
- return nil, err
- }
- defer res.Body.Close()
- if res.StatusCode != 200 {
- return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Unexpected status code %d", res.StatusCode), res)
- }
- result := new(registrytypes.SearchResults)
- return result, json.NewDecoder(res.Body).Decode(result)
-}
-
-// GetAuthConfig returns the authentication settings for a session
-// TODO(tiborvass): remove this once registry client v2 is vendored
-func (r *Session) GetAuthConfig(withPasswd bool) *types.AuthConfig {
- password := ""
- if withPasswd {
- password = r.authConfig.Password
- }
- return &types.AuthConfig{
- Username: r.authConfig.Username,
- Password: password,
- }
-}
-
-func isTimeout(err error) bool {
- type timeout interface {
- Timeout() bool
- }
- e := err
- switch urlErr := err.(type) {
- case *url.Error:
- e = urlErr.Err
- }
- t, ok := e.(timeout)
- return ok && t.Timeout()
-}
diff --git a/vendor/github.com/docker/docker/registry/types.go b/vendor/github.com/docker/docker/registry/types.go
deleted file mode 100644
index 479d22a7a..000000000
--- a/vendor/github.com/docker/docker/registry/types.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package registry
-
-import (
- registrytypes "github.com/docker/docker/api/types/registry"
- "github.com/docker/docker/reference"
-)
-
-// RepositoryData tracks the image list, list of endpoints, and list of tokens
-// for a repository
-type RepositoryData struct {
- // ImgList is a list of images in the repository
- ImgList map[string]*ImgData
- // Endpoints is a list of endpoints returned in X-Docker-Endpoints
- Endpoints []string
- // Tokens is currently unused (remove it?)
- Tokens []string
-}
-
-// ImgData is used to transfer image checksums to and from the registry
-type ImgData struct {
- // ID is an opaque string that identifies the image
- ID string `json:"id"`
- Checksum string `json:"checksum,omitempty"`
- ChecksumPayload string `json:"-"`
- Tag string `json:",omitempty"`
-}
-
-// PingResult contains the information returned when pinging a registry. It
-// indicates the registry's version and whether the registry claims to be a
-// standalone registry.
-type PingResult struct {
- // Version is the registry version supplied by the registry in an HTTP
- // header
- Version string `json:"version"`
- // Standalone is set to true if the registry indicates it is a
- // standalone registry in the X-Docker-Registry-Standalone
- // header
- Standalone bool `json:"standalone"`
-}
-
-// APIVersion is an integral representation of an API version (presently
-// either 1 or 2)
-type APIVersion int
-
-func (av APIVersion) String() string {
- return apiVersions[av]
-}
-
-// API Version identifiers.
-const (
- _ = iota
- APIVersion1 APIVersion = iota
- APIVersion2
-)
-
-var apiVersions = map[APIVersion]string{
- APIVersion1: "v1",
- APIVersion2: "v2",
-}
-
-// RepositoryInfo describes a repository
-type RepositoryInfo struct {
- reference.Named
- // Index points to registry information
- Index *registrytypes.IndexInfo
- // Official indicates whether the repository is considered official.
- // If the registry is official, and the normalized name does not
- // contain a '/' (e.g. "foo"), then it is considered an official repo.
- Official bool
-}
diff --git a/vendor/github.com/docker/libcompose/cli/app/app.go b/vendor/github.com/docker/libcompose/cli/app/app.go
deleted file mode 100644
index 9d7498946..000000000
--- a/vendor/github.com/docker/libcompose/cli/app/app.go
+++ /dev/null
@@ -1,312 +0,0 @@
-package app
-
-import (
- "fmt"
- "os"
- "os/signal"
- "strconv"
- "strings"
- "syscall"
-
- "golang.org/x/net/context"
-
- "github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/project"
- "github.com/docker/libcompose/project/options"
- "github.com/docker/libcompose/version"
- "github.com/urfave/cli"
-)
-
-// ProjectAction is an adapter to allow the use of ordinary functions as libcompose actions.
-// Any function that has the appropriate signature can be register as an action on a codegansta/cli command.
-//
-// cli.Command{
-// Name: "ps",
-// Usage: "List containers",
-// Action: app.WithProject(factory, app.ProjectPs),
-// }
-type ProjectAction func(project project.APIProject, c *cli.Context) error
-
-// BeforeApp is an action that is executed before any cli command.
-func BeforeApp(c *cli.Context) error {
- if c.GlobalBool("verbose") {
- logrus.SetLevel(logrus.DebugLevel)
- }
-
- if version.ShowWarning() {
- logrus.Warning("Note: This is an experimental alternate implementation of the Compose CLI (https://github.com/docker/compose)")
- }
- return nil
-}
-
-// WithProject is a helper function to create a cli.Command action with a ProjectFactory.
-func WithProject(factory ProjectFactory, action ProjectAction) func(context *cli.Context) error {
- return func(context *cli.Context) error {
- p, err := factory.Create(context)
- if err != nil {
- logrus.Fatalf("Failed to read project: %v", err)
- }
- return action(p, context)
- }
-}
-
-// ProjectPs lists the containers.
-func ProjectPs(p project.APIProject, c *cli.Context) error {
- qFlag := c.Bool("q")
- allInfo, err := p.Ps(context.Background(), c.Args()...)
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- columns := []string{"Name", "Command", "State", "Ports"}
- if qFlag {
- columns = []string{"Id"}
- }
- os.Stdout.WriteString(allInfo.String(columns, !qFlag))
- return nil
-}
-
-// ProjectPort prints the public port for a port binding.
-func ProjectPort(p project.APIProject, c *cli.Context) error {
- if len(c.Args()) != 2 {
- return cli.NewExitError("Please pass arguments in the form: SERVICE PORT", 1)
- }
-
- index := c.Int("index")
- protocol := c.String("protocol")
- serviceName := c.Args()[0]
- privatePort := c.Args()[1]
-
- port, err := p.Port(context.Background(), index, protocol, serviceName, privatePort)
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- fmt.Println(port)
- return nil
-}
-
-// ProjectStop stops all services.
-func ProjectStop(p project.APIProject, c *cli.Context) error {
- err := p.Stop(context.Background(), c.Int("timeout"), c.Args()...)
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- return nil
-}
-
-// ProjectDown brings all services down (stops and clean containers).
-func ProjectDown(p project.APIProject, c *cli.Context) error {
- options := options.Down{
- RemoveVolume: c.Bool("volumes"),
- RemoveImages: options.ImageType(c.String("rmi")),
- RemoveOrphans: c.Bool("remove-orphans"),
- }
- err := p.Down(context.Background(), options, c.Args()...)
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- return nil
-}
-
-// ProjectBuild builds or rebuilds services.
-func ProjectBuild(p project.APIProject, c *cli.Context) error {
- config := options.Build{
- NoCache: c.Bool("no-cache"),
- ForceRemove: c.Bool("force-rm"),
- Pull: c.Bool("pull"),
- }
- err := p.Build(context.Background(), config, c.Args()...)
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- return nil
-}
-
-// ProjectCreate creates all services but do not start them.
-func ProjectCreate(p project.APIProject, c *cli.Context) error {
- options := options.Create{
- NoRecreate: c.Bool("no-recreate"),
- ForceRecreate: c.Bool("force-recreate"),
- NoBuild: c.Bool("no-build"),
- }
- err := p.Create(context.Background(), options, c.Args()...)
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- return nil
-}
-
-// ProjectUp brings all services up.
-func ProjectUp(p project.APIProject, c *cli.Context) error {
- options := options.Up{
- Create: options.Create{
- NoRecreate: c.Bool("no-recreate"),
- ForceRecreate: c.Bool("force-recreate"),
- NoBuild: c.Bool("no-build"),
- ForceBuild: c.Bool("build"),
- },
- }
- ctx, cancelFun := context.WithCancel(context.Background())
- err := p.Up(ctx, options, c.Args()...)
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- if !c.Bool("d") {
- signalChan := make(chan os.Signal, 1)
- cleanupDone := make(chan bool)
- signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
- errChan := make(chan error)
- go func() {
- errChan <- p.Log(ctx, true, c.Args()...)
- }()
- go func() {
- select {
- case <-signalChan:
- fmt.Printf("\nGracefully stopping...\n")
- cancelFun()
- ProjectStop(p, c)
- cleanupDone <- true
- case err := <-errChan:
- if err != nil {
- logrus.Fatal(err)
- }
- cleanupDone <- true
- }
- }()
- <-cleanupDone
- return nil
- }
- return nil
-}
-
-// ProjectRun runs a given command within a service's container.
-func ProjectRun(p project.APIProject, c *cli.Context) error {
- if len(c.Args()) == 0 {
- logrus.Fatal("No service specified")
- }
-
- serviceName := c.Args()[0]
- commandParts := c.Args()[1:]
-
- options := options.Run{
- Detached: c.Bool("d"),
- }
-
- exitCode, err := p.Run(context.Background(), serviceName, commandParts, options)
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- return cli.NewExitError("", exitCode)
-}
-
-// ProjectStart starts services.
-func ProjectStart(p project.APIProject, c *cli.Context) error {
- err := p.Start(context.Background(), c.Args()...)
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- return nil
-}
-
-// ProjectRestart restarts services.
-func ProjectRestart(p project.APIProject, c *cli.Context) error {
- err := p.Restart(context.Background(), c.Int("timeout"), c.Args()...)
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- return nil
-}
-
-// ProjectLog gets services logs.
-func ProjectLog(p project.APIProject, c *cli.Context) error {
- err := p.Log(context.Background(), c.Bool("follow"), c.Args()...)
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- return nil
-}
-
-// ProjectPull pulls images for services.
-func ProjectPull(p project.APIProject, c *cli.Context) error {
- err := p.Pull(context.Background(), c.Args()...)
- if err != nil && !c.Bool("ignore-pull-failures") {
- return cli.NewExitError(err.Error(), 1)
- }
- return nil
-}
-
-// ProjectDelete deletes services.
-func ProjectDelete(p project.APIProject, c *cli.Context) error {
- options := options.Delete{
- RemoveVolume: c.Bool("v"),
- }
- err := p.Delete(context.Background(), options, c.Args()...)
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- return nil
-}
-
-// ProjectKill forces stop service containers.
-func ProjectKill(p project.APIProject, c *cli.Context) error {
- err := p.Kill(context.Background(), c.String("signal"), c.Args()...)
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- return nil
-}
-
-// ProjectConfig validates and print the compose file.
-func ProjectConfig(p project.APIProject, c *cli.Context) error {
- yaml, err := p.Config()
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- if !c.Bool("quiet") {
- fmt.Println(yaml)
- }
- return nil
-}
-
-// ProjectPause pauses service containers.
-func ProjectPause(p project.APIProject, c *cli.Context) error {
- err := p.Pause(context.Background(), c.Args()...)
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- return nil
-}
-
-// ProjectUnpause unpauses service containers.
-func ProjectUnpause(p project.APIProject, c *cli.Context) error {
- err := p.Unpause(context.Background(), c.Args()...)
- if err != nil {
- return cli.NewExitError(err.Error(), 1)
- }
- return nil
-}
-
-// ProjectScale scales services.
-func ProjectScale(p project.APIProject, c *cli.Context) error {
- servicesScale := map[string]int{}
- for _, arg := range c.Args() {
- kv := strings.SplitN(arg, "=", 2)
- if len(kv) != 2 {
- return cli.NewExitError(fmt.Sprintf("Invalid scale parameter: %s", arg), 2)
- }
-
- name := kv[0]
-
- count, err := strconv.Atoi(kv[1])
- if err != nil {
- return cli.NewExitError(fmt.Sprintf("Invalid scale parameter: %v", err), 2)
- }
-
- servicesScale[name] = count
- }
-
- err := p.Scale(context.Background(), c.Int("timeout"), servicesScale)
- if err != nil {
- return cli.NewExitError(err.Error(), 0)
- }
- return nil
-}
diff --git a/vendor/github.com/docker/libcompose/cli/app/events.go b/vendor/github.com/docker/libcompose/cli/app/events.go
deleted file mode 100644
index 905045189..000000000
--- a/vendor/github.com/docker/libcompose/cli/app/events.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package app
-
-import (
- "encoding/json"
- "fmt"
- "os"
- "strings"
-
- "golang.org/x/net/context"
-
- "github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/project"
- "github.com/docker/libcompose/project/events"
- "github.com/urfave/cli"
-)
-
-// ProjectEvents listen for real-time events of containers.
-func ProjectEvents(p project.APIProject, c *cli.Context) error {
- evts, err := p.Events(context.Background(), c.Args()...)
- if err != nil {
- return err
- }
- var printfn func(events.ContainerEvent)
-
- if c.Bool("json") {
- printfn = printJSON
- } else {
- printfn = printStd
- }
- for event := range evts {
- printfn(event)
- }
- return nil
-}
-
-func printStd(event events.ContainerEvent) {
- output := os.Stdout
- fmt.Fprintf(output, "%s ", event.Time.Format("2006-01-02 15:04:05.999999999"))
- fmt.Fprintf(output, "%s %s %s", event.Type, event.Event, event.ID)
- attrs := []string{}
- for attr, value := range event.Attributes {
- attrs = append(attrs, fmt.Sprintf("%s=%s", attr, value))
- }
-
- fmt.Fprintf(output, " (%s)", strings.Join(attrs, ", "))
- fmt.Fprint(output, "\n")
-}
-
-func printJSON(event events.ContainerEvent) {
- json, err := json.Marshal(event)
- if err != nil {
- logrus.Warn(err)
- }
- output := os.Stdout
- fmt.Fprintf(output, "%s", json)
-}
diff --git a/vendor/github.com/docker/libcompose/cli/app/types.go b/vendor/github.com/docker/libcompose/cli/app/types.go
deleted file mode 100644
index 1c61be45a..000000000
--- a/vendor/github.com/docker/libcompose/cli/app/types.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package app
-
-import (
- "github.com/docker/libcompose/project"
- "github.com/urfave/cli"
-)
-
-// ProjectFactory is an interface that helps creating libcompose project.
-type ProjectFactory interface {
- // Create creates a libcompose project from the command line options (urfave cli context).
- Create(c *cli.Context) (project.APIProject, error)
-}
diff --git a/vendor/github.com/docker/libcompose/cli/app/version.go b/vendor/github.com/docker/libcompose/cli/app/version.go
deleted file mode 100644
index 1e77519f8..000000000
--- a/vendor/github.com/docker/libcompose/cli/app/version.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package app
-
-import (
- "fmt"
- "os"
- "runtime"
- "text/template"
-
- "github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/version"
- "github.com/urfave/cli"
-)
-
-var versionTemplate = `Version: {{.Version}} ({{.GitCommit}})
-Go version: {{.GoVersion}}
-Built: {{.BuildTime}}
-OS/Arch: {{.Os}}/{{.Arch}}`
-
-// Version prints the libcompose version number and additionnal informations.
-func Version(c *cli.Context) error {
- if c.Bool("short") {
- fmt.Println(version.VERSION)
- return nil
- }
-
- tmpl, err := template.New("").Parse(versionTemplate)
- if err != nil {
- logrus.Fatal(err)
- }
-
- v := struct {
- Version string
- GitCommit string
- GoVersion string
- BuildTime string
- Os string
- Arch string
- }{
- Version: version.VERSION,
- GitCommit: version.GITCOMMIT,
- GoVersion: runtime.Version(),
- BuildTime: version.BUILDTIME,
- Os: runtime.GOOS,
- Arch: runtime.GOARCH,
- }
-
- if err := tmpl.Execute(os.Stdout, v); err != nil {
- logrus.Fatal(err)
- }
- fmt.Printf("\n")
- return nil
-}
diff --git a/vendor/github.com/docker/libcompose/cli/command/command.go b/vendor/github.com/docker/libcompose/cli/command/command.go
deleted file mode 100644
index 005ad22ba..000000000
--- a/vendor/github.com/docker/libcompose/cli/command/command.go
+++ /dev/null
@@ -1,395 +0,0 @@
-package command
-
-import (
- "os"
- "strings"
-
- "github.com/docker/libcompose/cli/app"
- "github.com/docker/libcompose/project"
- "github.com/urfave/cli"
-)
-
-// Populate updates the specified project context based on command line arguments and subcommands.
-func Populate(context *project.Context, c *cli.Context) {
- // urfave/cli does not distinguish whether the first string in the slice comes from the envvar
- // or is from a flag. Worse off, it appends the flag values to the envvar value instead of
- // overriding it. To ensure the multifile envvar case is always handled, the first string
- // must always be split. It gives a more consistent behavior, then, to split each string in
- // the slice.
- for _, v := range c.GlobalStringSlice("file") {
- context.ComposeFiles = append(context.ComposeFiles, strings.Split(v, string(os.PathListSeparator))...)
- }
-
- if len(context.ComposeFiles) == 0 {
- context.ComposeFiles = []string{"docker-compose.yml"}
- if _, err := os.Stat("docker-compose.override.yml"); err == nil {
- context.ComposeFiles = append(context.ComposeFiles, "docker-compose.override.yml")
- }
- }
-
- context.ProjectName = c.GlobalString("project-name")
-}
-
-// CreateCommand defines the libcompose create subcommand.
-func CreateCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "create",
- Usage: "Create all services but do not start",
- Action: app.WithProject(factory, app.ProjectCreate),
- Flags: []cli.Flag{
- cli.BoolFlag{
- Name: "no-recreate",
- Usage: "If containers already exist, don't recreate them. Incompatible with --force-recreate.",
- },
- cli.BoolFlag{
- Name: "force-recreate",
- Usage: "Recreate containers even if their configuration and image haven't changed. Incompatible with --no-recreate.",
- },
- cli.BoolFlag{
- Name: "no-build",
- Usage: "Don't build an image, even if it's missing.",
- },
- },
- }
-}
-
-// ConfigCommand defines the libcompose config subcommand
-func ConfigCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "config",
- Usage: "Validate and view the compose file.",
- Action: app.WithProject(factory, app.ProjectConfig),
- Flags: []cli.Flag{
- cli.BoolFlag{
- Name: "quiet,q",
- Usage: "Only validate the configuration, don't print anything.",
- },
- },
- }
-}
-
-// BuildCommand defines the libcompose build subcommand.
-func BuildCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "build",
- Usage: "Build or rebuild services.",
- Action: app.WithProject(factory, app.ProjectBuild),
- Flags: []cli.Flag{
- cli.BoolFlag{
- Name: "no-cache",
- Usage: "Do not use cache when building the image",
- },
- cli.BoolFlag{
- Name: "force-rm",
- Usage: "Always remove intermediate containers",
- },
- cli.BoolFlag{
- Name: "pull",
- Usage: "Always attempt to pull a newer version of the image",
- },
- },
- }
-}
-
-// PsCommand defines the libcompose ps subcommand.
-func PsCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "ps",
- Usage: "List containers",
- Action: app.WithProject(factory, app.ProjectPs),
- Flags: []cli.Flag{
- cli.BoolFlag{
- Name: "q",
- Usage: "Only display IDs",
- },
- },
- }
-}
-
-// PortCommand defines the libcompose port subcommand.
-func PortCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "port",
- Usage: "Print the public port for a port binding",
- Action: app.WithProject(factory, app.ProjectPort),
- Flags: []cli.Flag{
- cli.StringFlag{
- Name: "protocol",
- Usage: "tcp or udp ",
- Value: "tcp",
- },
- cli.IntFlag{
- Name: "index",
- Usage: "index of the container if there are multiple instances of a service",
- Value: 1,
- },
- },
- }
-}
-
-// UpCommand defines the libcompose up subcommand.
-func UpCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "up",
- Usage: "Bring all services up",
- Action: app.WithProject(factory, app.ProjectUp),
- Flags: []cli.Flag{
- cli.BoolFlag{
- Name: "d",
- Usage: "Do not block and log",
- },
- cli.BoolFlag{
- Name: "no-build",
- Usage: "Don't build an image, even if it's missing.",
- },
- cli.BoolFlag{
- Name: "no-recreate",
- Usage: "If containers already exist, don't recreate them. Incompatible with --force-recreate.",
- },
- cli.BoolFlag{
- Name: "force-recreate",
- Usage: "Recreate containers even if their configuration and image haven't changed. Incompatible with --no-recreate.",
- },
- cli.BoolFlag{
- Name: "build",
- Usage: "Build images before starting containers.",
- },
- },
- }
-}
-
-// StartCommand defines the libcompose start subcommand.
-func StartCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "start",
- Usage: "Start services",
- Action: app.WithProject(factory, app.ProjectStart),
- Flags: []cli.Flag{
- cli.BoolTFlag{
- Name: "d",
- Usage: "Do not block and log",
- },
- },
- }
-}
-
-// RunCommand defines the libcompose run subcommand.
-func RunCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "run",
- Usage: "Run a one-off command",
- Action: app.WithProject(factory, app.ProjectRun),
- Flags: []cli.Flag{
- cli.BoolFlag{
- Name: "d",
- Usage: "Detached mode: Run container in the background, print new container name.",
- },
- },
- }
-}
-
-// PullCommand defines the libcompose pull subcommand.
-func PullCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "pull",
- Usage: "Pulls images for services",
- Action: app.WithProject(factory, app.ProjectPull),
- Flags: []cli.Flag{
- cli.BoolFlag{
- Name: "ignore-pull-failures",
- Usage: "Pull what it can and ignores images with pull failures.",
- },
- },
- }
-}
-
-// LogsCommand defines the libcompose logs subcommand.
-func LogsCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "logs",
- Usage: "Get service logs",
- Action: app.WithProject(factory, app.ProjectLog),
- Flags: []cli.Flag{
- cli.BoolFlag{
- Name: "follow",
- Usage: "Follow log output.",
- },
- },
- }
-}
-
-// RestartCommand defines the libcompose restart subcommand.
-func RestartCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "restart",
- Usage: "Restart services",
- Action: app.WithProject(factory, app.ProjectRestart),
- Flags: []cli.Flag{
- cli.IntFlag{
- Name: "timeout,t",
- Usage: "Specify a shutdown timeout in seconds.",
- Value: 10,
- },
- },
- }
-}
-
-// StopCommand defines the libcompose stop subcommand.
-func StopCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "stop",
- Usage: "Stop services",
- Action: app.WithProject(factory, app.ProjectStop),
- Flags: []cli.Flag{
- cli.IntFlag{
- Name: "timeout,t",
- Usage: "Specify a shutdown timeout in seconds.",
- Value: 10,
- },
- },
- }
-}
-
-// DownCommand defines the libcompose stop subcommand.
-func DownCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "down",
- Usage: "Stop and remove containers, networks, images, and volumes",
- Action: app.WithProject(factory, app.ProjectDown),
- Flags: []cli.Flag{
- cli.BoolFlag{
- Name: "volumes,v",
- Usage: "Remove data volumes",
- },
- cli.StringFlag{
- Name: "rmi",
- Usage: "Remove images, type may be one of: 'all' to remove all images, or 'local' to remove only images that don't have an custom name set by the `image` field",
- },
- cli.BoolFlag{
- Name: "remove-orphans",
- Usage: "Remove containers for services not defined in the Compose file",
- },
- },
- }
-}
-
-// ScaleCommand defines the libcompose scale subcommand.
-func ScaleCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "scale",
- Usage: "Scale services",
- Action: app.WithProject(factory, app.ProjectScale),
- Flags: []cli.Flag{
- cli.IntFlag{
- Name: "timeout,t",
- Usage: "Specify a shutdown timeout in seconds.",
- Value: 10,
- },
- },
- }
-}
-
-// RmCommand defines the libcompose rm subcommand.
-func RmCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "rm",
- Usage: "Delete services",
- Action: app.WithProject(factory, app.ProjectDelete),
- Flags: []cli.Flag{
- cli.BoolFlag{
- Name: "force,f",
- Usage: "Allow deletion of all services",
- },
- cli.BoolFlag{
- Name: "v",
- Usage: "Remove volumes associated with containers",
- },
- },
- }
-}
-
-// KillCommand defines the libcompose kill subcommand.
-func KillCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "kill",
- Usage: "Force stop service containers",
- Action: app.WithProject(factory, app.ProjectKill),
- Flags: []cli.Flag{
- cli.StringFlag{
- Name: "signal,s",
- Usage: "SIGNAL to send to the container",
- Value: "SIGKILL",
- },
- },
- }
-}
-
-// PauseCommand defines the libcompose pause subcommand.
-func PauseCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "pause",
- Usage: "Pause services.",
- // ArgsUsage: "[SERVICE...]",
- Action: app.WithProject(factory, app.ProjectPause),
- }
-}
-
-// UnpauseCommand defines the libcompose unpause subcommand.
-func UnpauseCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "unpause",
- Usage: "Unpause services.",
- // ArgsUsage: "[SERVICE...]",
- Action: app.WithProject(factory, app.ProjectUnpause),
- }
-}
-
-// EventsCommand defines the libcompose events subcommand
-func EventsCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "events",
- Usage: "Receive real time events from containers.",
- Action: app.WithProject(factory, app.ProjectEvents),
- Flags: []cli.Flag{
- cli.BoolFlag{
- Name: "json",
- Usage: "Output events as a stream of json objects",
- },
- },
- }
-}
-
-// VersionCommand defines the libcompose version subcommand.
-func VersionCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "version",
- Usage: "Show version informations",
- Action: app.Version,
- Flags: []cli.Flag{
- cli.BoolFlag{
- Name: "short",
- Usage: "Shows only Compose's version number.",
- },
- },
- }
-}
-
-// CommonFlags defines the flags that are in common for all subcommands.
-func CommonFlags() []cli.Flag {
- return []cli.Flag{
- cli.BoolFlag{
- Name: "verbose,debug",
- },
- cli.StringSliceFlag{
- Name: "file,f",
- Usage: "Specify one or more alternate compose files (default: docker-compose.yml)",
- Value: &cli.StringSlice{},
- EnvVar: "COMPOSE_FILE",
- },
- cli.StringFlag{
- Name: "project-name,p",
- Usage: "Specify an alternate project name (default: directory name)",
- EnvVar: "COMPOSE_PROJECT_NAME",
- },
- }
-}
diff --git a/vendor/github.com/docker/libcompose/cli/command/help.go b/vendor/github.com/docker/libcompose/cli/command/help.go
deleted file mode 100644
index fb7cf4a34..000000000
--- a/vendor/github.com/docker/libcompose/cli/command/help.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package command
-
-import (
- "github.com/urfave/cli"
- "os"
- "path"
-)
-
-func init() {
- cli.AppHelpTemplate = `Usage: {{.Name}} {{if .Flags}}[OPTIONS] {{end}}COMMAND [arg...]
-
-{{.Usage}}
-
-Version: {{.Version}}{{if or .Author .Email}}
-
-Author:{{if .Author}}
- {{.Author}}{{if .Email}} - <{{.Email}}>{{end}}{{else}}
- {{.Email}}{{end}}{{end}}
-{{if .Flags}}
-Options:
- {{range .Flags}}{{.}}
- {{end}}{{end}}
-Commands:
- {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
- {{end}}
-Run '{{.Name}} COMMAND --help' for more information on a command.
-`
- cli.CommandHelpTemplate = `Usage: ` + path.Base(os.Args[0]) + ` {{.Name}}{{if .Flags}} [OPTIONS]
-
-{{.Usage}}
-
-Options:
- {{range .Flags}}{{.}}
- {{end}}{{end}}
-`
-
-}
diff --git a/vendor/github.com/docker/libcompose/docker/auth/auth.go b/vendor/github.com/docker/libcompose/docker/auth/auth.go
deleted file mode 100644
index 76a73672a..000000000
--- a/vendor/github.com/docker/libcompose/docker/auth/auth.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package auth
-
-import (
- "github.com/docker/docker/api/types"
- "github.com/docker/docker/cliconfig/configfile"
- "github.com/docker/docker/registry"
-)
-
-// Lookup defines a method for looking up authentication information
-type Lookup interface {
- All() map[string]types.AuthConfig
- Lookup(repoInfo *registry.RepositoryInfo) types.AuthConfig
-}
-
-// ConfigLookup implements AuthLookup by reading a Docker config file
-type ConfigLookup struct {
- *configfile.ConfigFile
-}
-
-// NewConfigLookup creates a new ConfigLookup for a given context
-func NewConfigLookup(configfile *configfile.ConfigFile) *ConfigLookup {
- return &ConfigLookup{
- ConfigFile: configfile,
- }
-}
-
-// Lookup uses a Docker config file to lookup authentication information
-func (c *ConfigLookup) Lookup(repoInfo *registry.RepositoryInfo) types.AuthConfig {
- if c.ConfigFile == nil || repoInfo == nil || repoInfo.Index == nil {
- return types.AuthConfig{}
- }
- return registry.ResolveAuthConfig(c.ConfigFile.AuthConfigs, repoInfo.Index)
-}
-
-// All uses a Docker config file to get all authentication information
-func (c *ConfigLookup) All() map[string]types.AuthConfig {
- if c.ConfigFile == nil {
- return map[string]types.AuthConfig{}
- }
- return c.ConfigFile.AuthConfigs
-}
diff --git a/vendor/github.com/docker/libcompose/docker/client/client.go b/vendor/github.com/docker/libcompose/docker/client/client.go
deleted file mode 100644
index 1a4cd2c2a..000000000
--- a/vendor/github.com/docker/libcompose/docker/client/client.go
+++ /dev/null
@@ -1,115 +0,0 @@
-package client
-
-import (
- "fmt"
- "net/http"
- "os"
- "path/filepath"
- "runtime"
-
- "github.com/docker/docker/cliconfig"
- "github.com/docker/docker/client"
- "github.com/docker/docker/pkg/homedir"
- "github.com/docker/go-connections/sockets"
- "github.com/docker/go-connections/tlsconfig"
- "github.com/docker/libcompose/version"
-)
-
-const (
- // DefaultAPIVersion is the default docker API version set by libcompose
- DefaultAPIVersion = "v1.20"
- defaultTrustKeyFile = "key.json"
- defaultCaFile = "ca.pem"
- defaultKeyFile = "key.pem"
- defaultCertFile = "cert.pem"
-)
-
-var (
- dockerCertPath = os.Getenv("DOCKER_CERT_PATH")
-)
-
-func init() {
- if dockerCertPath == "" {
- dockerCertPath = cliconfig.ConfigDir()
- }
-}
-
-// Options holds docker client options (host, tls, ..)
-type Options struct {
- TLS bool
- TLSVerify bool
- TLSOptions tlsconfig.Options
- TrustKey string
- Host string
- APIVersion string
-}
-
-// Create creates a docker client based on the specified options.
-func Create(c Options) (client.APIClient, error) {
- if c.Host == "" {
- if os.Getenv("DOCKER_API_VERSION") == "" {
- os.Setenv("DOCKER_API_VERSION", DefaultAPIVersion)
- }
- client, err := client.NewEnvClient()
- if err != nil {
- return nil, err
- }
- return client, nil
- }
-
- apiVersion := c.APIVersion
- if apiVersion == "" {
- apiVersion = DefaultAPIVersion
- }
-
- if c.TLSOptions.CAFile == "" {
- c.TLSOptions.CAFile = filepath.Join(dockerCertPath, defaultCaFile)
- }
- if c.TLSOptions.CertFile == "" {
- c.TLSOptions.CertFile = filepath.Join(dockerCertPath, defaultCertFile)
- }
- if c.TLSOptions.KeyFile == "" {
- c.TLSOptions.KeyFile = filepath.Join(dockerCertPath, defaultKeyFile)
- }
- if c.TrustKey == "" {
- c.TrustKey = filepath.Join(homedir.Get(), ".docker", defaultTrustKeyFile)
- }
- if c.TLSVerify {
- c.TLS = true
- }
- if c.TLS {
- c.TLSOptions.InsecureSkipVerify = !c.TLSVerify
- }
-
- var httpClient *http.Client
- if c.TLS {
- config, err := tlsconfig.Client(c.TLSOptions)
- if err != nil {
- return nil, err
- }
- tr := &http.Transport{
- TLSClientConfig: config,
- }
- proto, addr, _, err := client.ParseHost(c.Host)
- if err != nil {
- return nil, err
- }
-
- if err := sockets.ConfigureTransport(tr, proto, addr); err != nil {
- return nil, err
- }
-
- httpClient = &http.Client{
- Transport: tr,
- }
- }
-
- customHeaders := map[string]string{}
- customHeaders["User-Agent"] = fmt.Sprintf("Libcompose-Client/%s (%s)", version.VERSION, runtime.GOOS)
-
- client, err := client.NewClient(c.Host, apiVersion, httpClient, customHeaders)
- if err != nil {
- return nil, err
- }
- return client, nil
-}
diff --git a/vendor/github.com/docker/libcompose/docker/client/client_factory.go b/vendor/github.com/docker/libcompose/docker/client/client_factory.go
deleted file mode 100644
index 26d88d70b..000000000
--- a/vendor/github.com/docker/libcompose/docker/client/client_factory.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package client
-
-import (
- "github.com/docker/docker/client"
- "github.com/docker/libcompose/project"
-)
-
-// Factory is a factory to create docker clients.
-type Factory interface {
- // Create constructs a Docker client for the given service. The passed in
- // config may be nil in which case a generic client for the project should
- // be returned.
- Create(service project.Service) client.APIClient
-}
-
-type defaultFactory struct {
- client client.APIClient
-}
-
-// NewDefaultFactory creates and returns the default client factory that uses
-// github.com/docker/docker client.
-func NewDefaultFactory(opts Options) (Factory, error) {
- client, err := Create(opts)
- if err != nil {
- return nil, err
- }
-
- return &defaultFactory{
- client: client,
- }, nil
-}
-
-func (s *defaultFactory) Create(service project.Service) client.APIClient {
- return s.client
-}
diff --git a/vendor/github.com/docker/libcompose/docker/container/container.go b/vendor/github.com/docker/libcompose/docker/container/container.go
deleted file mode 100644
index b2e93baab..000000000
--- a/vendor/github.com/docker/libcompose/docker/container/container.go
+++ /dev/null
@@ -1,379 +0,0 @@
-package container
-
-import (
- "fmt"
- "io"
- "math"
- "os"
- "strconv"
- "strings"
- "time"
-
- "golang.org/x/net/context"
-
- "github.com/Sirupsen/logrus"
- "github.com/docker/docker/api/types"
- "github.com/docker/docker/api/types/container"
- "github.com/docker/docker/api/types/network"
- "github.com/docker/docker/client"
- "github.com/docker/docker/pkg/promise"
- "github.com/docker/docker/pkg/stdcopy"
- "github.com/docker/docker/pkg/term"
- "github.com/docker/go-connections/nat"
- "github.com/docker/libcompose/config"
- "github.com/docker/libcompose/labels"
- "github.com/docker/libcompose/logger"
- "github.com/docker/libcompose/project"
-)
-
-// Container holds information about a docker container and the service it is tied on.
-type Container struct {
- client client.ContainerAPIClient
- id string
- container *types.ContainerJSON
-}
-
-// Create creates a container and return a Container struct (and an error if any)
-func Create(ctx context.Context, client client.ContainerAPIClient, name string, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig) (*Container, error) {
- container, err := client.ContainerCreate(ctx, config, hostConfig, networkingConfig, name)
- if err != nil {
- return nil, err
- }
- return New(ctx, client, container.ID)
-}
-
-// New creates a container struct with the specified client, id and name
-func New(ctx context.Context, client client.ContainerAPIClient, id string) (*Container, error) {
- container, err := Get(ctx, client, id)
- if err != nil {
- return nil, err
- }
- return &Container{
- client: client,
- id: id,
- container: container,
- }, nil
-}
-
-// NewInspected creates a container struct from an inspected container
-func NewInspected(client client.ContainerAPIClient, container *types.ContainerJSON) *Container {
- return &Container{
- client: client,
- id: container.ID,
- container: container,
- }
-}
-
-// Info returns info about the container, like name, command, state or ports.
-func (c *Container) Info(ctx context.Context) (project.Info, error) {
- infos, err := ListByFilter(ctx, c.client, map[string][]string{
- "name": {c.container.Name},
- })
- if err != nil || len(infos) == 0 {
- return nil, err
- }
- info := infos[0]
-
- result := project.Info{}
- result["Id"] = c.container.ID
- result["Name"] = name(info.Names)
- result["Command"] = info.Command
- result["State"] = info.Status
- result["Ports"] = portString(info.Ports)
-
- return result, nil
-}
-
-func portString(ports []types.Port) string {
- result := []string{}
-
- for _, port := range ports {
- if port.PublicPort > 0 {
- result = append(result, fmt.Sprintf("%s:%d->%d/%s", port.IP, port.PublicPort, port.PrivatePort, port.Type))
- } else {
- result = append(result, fmt.Sprintf("%d/%s", port.PrivatePort, port.Type))
- }
- }
-
- return strings.Join(result, ", ")
-}
-
-func name(names []string) string {
- max := math.MaxInt32
- var current string
-
- for _, v := range names {
- if len(v) < max {
- max = len(v)
- current = v
- }
- }
-
- return current[1:]
-}
-
-// Rename rename the container.
-func (c *Container) Rename(ctx context.Context, newName string) error {
- return c.client.ContainerRename(ctx, c.container.ID, newName)
-}
-
-// Remove removes the container.
-func (c *Container) Remove(ctx context.Context, removeVolume bool) error {
- return c.client.ContainerRemove(ctx, c.container.ID, types.ContainerRemoveOptions{
- Force: true,
- RemoveVolumes: removeVolume,
- })
-}
-
-// Stop stops the container.
-func (c *Container) Stop(ctx context.Context, timeout int) error {
- timeoutDuration := time.Duration(timeout) * time.Second
- return c.client.ContainerStop(ctx, c.container.ID, &timeoutDuration)
-}
-
-// Pause pauses the container. If the containers are already paused, don't fail.
-func (c *Container) Pause(ctx context.Context) error {
- if !c.container.State.Paused {
- if err := c.client.ContainerPause(ctx, c.container.ID); err != nil {
- return err
- }
- return c.updateInnerContainer(ctx)
- }
- return nil
-}
-
-// Unpause unpauses the container. If the containers are not paused, don't fail.
-func (c *Container) Unpause(ctx context.Context) error {
- if c.container.State.Paused {
- if err := c.client.ContainerUnpause(ctx, c.container.ID); err != nil {
- return err
- }
- return c.updateInnerContainer(ctx)
- }
- return nil
-}
-
-func (c *Container) updateInnerContainer(ctx context.Context) error {
- container, err := Get(ctx, c.client, c.container.ID)
- if err != nil {
- return err
- }
- c.container = container
- return nil
-}
-
-// Kill kill the container.
-func (c *Container) Kill(ctx context.Context, signal string) error {
- return c.client.ContainerKill(ctx, c.container.ID, signal)
-}
-
-// IsRunning returns the running state of the container.
-// FIXME(vdemeester): remove the nil error here
-func (c *Container) IsRunning(ctx context.Context) (bool, error) {
- return c.container.State.Running, nil
-}
-
-// Run creates, start and attach to the container based on the image name,
-// the specified configuration.
-// It will always create a new container.
-func (c *Container) Run(ctx context.Context, configOverride *config.ServiceConfig) (int, error) {
- var (
- errCh chan error
- out, stderr io.Writer
- in io.ReadCloser
- )
-
- if configOverride.StdinOpen {
- in = os.Stdin
- }
- if configOverride.Tty {
- out = os.Stdout
- }
- if configOverride.Tty {
- stderr = os.Stderr
- }
-
- options := types.ContainerAttachOptions{
- Stream: true,
- Stdin: configOverride.StdinOpen,
- Stdout: configOverride.Tty,
- Stderr: configOverride.Tty,
- }
-
- resp, err := c.client.ContainerAttach(ctx, c.container.ID, options)
- if err != nil {
- return -1, err
- }
-
- // set raw terminal
- inFd, _ := term.GetFdInfo(in)
- state, err := term.SetRawTerminal(inFd)
- if err != nil {
- return -1, err
- }
- // restore raw terminal
- defer term.RestoreTerminal(inFd, state)
- // holdHijackedConnection (in goroutine)
- errCh = promise.Go(func() error {
- return holdHijackedConnection(configOverride.Tty, in, out, stderr, resp)
- })
-
- if err := c.client.ContainerStart(ctx, c.container.ID, types.ContainerStartOptions{}); err != nil {
- return -1, err
- }
-
- if err := <-errCh; err != nil {
- logrus.Debugf("Error hijack: %s", err)
- return -1, err
- }
-
- exitedContainer, err := c.client.ContainerInspect(ctx, c.container.ID)
- if err != nil {
- return -1, err
- }
-
- return exitedContainer.State.ExitCode, nil
-}
-
-func holdHijackedConnection(tty bool, inputStream io.ReadCloser, outputStream, errorStream io.Writer, resp types.HijackedResponse) error {
- var err error
- receiveStdout := make(chan error, 1)
- if outputStream != nil || errorStream != nil {
- go func() {
- // When TTY is ON, use regular copy
- if tty && outputStream != nil {
- _, err = io.Copy(outputStream, resp.Reader)
- } else {
- _, err = stdcopy.StdCopy(outputStream, errorStream, resp.Reader)
- }
- logrus.Debugf("[hijack] End of stdout")
- receiveStdout <- err
- }()
- }
-
- stdinDone := make(chan struct{})
- go func() {
- if inputStream != nil {
- io.Copy(resp.Conn, inputStream)
- logrus.Debugf("[hijack] End of stdin")
- }
-
- if err := resp.CloseWrite(); err != nil {
- logrus.Debugf("Couldn't send EOF: %s", err)
- }
- close(stdinDone)
- }()
-
- select {
- case err := <-receiveStdout:
- if err != nil {
- logrus.Debugf("Error receiveStdout: %s", err)
- return err
- }
- case <-stdinDone:
- if outputStream != nil || errorStream != nil {
- if err := <-receiveStdout; err != nil {
- logrus.Debugf("Error receiveStdout: %s", err)
- return err
- }
- }
- }
-
- return nil
-}
-
-// Start the specified container with the specified host config
-func (c *Container) Start(ctx context.Context) error {
- logrus.WithFields(logrus.Fields{"container.ID": c.container.ID, "container.Name": c.container.Name}).Debug("Starting container")
- if err := c.client.ContainerStart(ctx, c.container.ID, types.ContainerStartOptions{}); err != nil {
- logrus.WithFields(logrus.Fields{"container.ID": c.container.ID, "container.Name": c.container.Name}).Debug("Failed to start container")
- return err
- }
- return nil
-}
-
-// ID returns the container Id.
-func (c *Container) ID() (string, error) {
- return c.container.ID, nil
-}
-
-// Name returns the container name.
-func (c *Container) Name() string {
- return c.container.Name
-}
-
-// Restart restarts the container if existing, does nothing otherwise.
-func (c *Container) Restart(ctx context.Context, timeout int) error {
- timeoutDuration := time.Duration(timeout) * time.Second
- return c.client.ContainerRestart(ctx, c.container.ID, &timeoutDuration)
-}
-
-// Log forwards container logs to the project configured logger.
-func (c *Container) Log(ctx context.Context, l logger.Logger, follow bool) error {
- info, err := c.client.ContainerInspect(ctx, c.container.ID)
- if err != nil {
- return err
- }
-
- options := types.ContainerLogsOptions{
- ShowStdout: true,
- ShowStderr: true,
- Follow: follow,
- Tail: "all",
- }
- responseBody, err := c.client.ContainerLogs(ctx, c.container.ID, options)
- if err != nil {
- return err
- }
- defer responseBody.Close()
-
- if info.Config.Tty {
- _, err = io.Copy(&logger.Wrapper{Logger: l}, responseBody)
- } else {
- _, err = stdcopy.StdCopy(&logger.Wrapper{Logger: l}, &logger.Wrapper{Logger: l, Err: true}, responseBody)
- }
- logrus.WithFields(logrus.Fields{"Logger": l, "err": err}).Debug("c.client.Logs() returned error")
-
- return err
-}
-
-// Port returns the host port the specified port is mapped on.
-func (c *Container) Port(ctx context.Context, port string) (string, error) {
- if bindings, ok := c.container.NetworkSettings.Ports[nat.Port(port)]; ok {
- result := []string{}
- for _, binding := range bindings {
- result = append(result, binding.HostIP+":"+binding.HostPort)
- }
-
- return strings.Join(result, "\n"), nil
- }
- return "", nil
-}
-
-// Networks returns the containers network
-func (c *Container) Networks() (map[string]*network.EndpointSettings, error) {
- return c.container.NetworkSettings.Networks, nil
-}
-
-// Image returns the container image. Depending on the engine version its either
-// the complete id or the digest reference the image.
-func (c *Container) Image() string {
- return c.container.Image
-}
-
-// ImageConfig returns the container image stored in the config. It's the
-// human-readable name of the image.
-func (c *Container) ImageConfig() string {
- return c.container.Config.Image
-}
-
-// Hash returns the container hash stored as label.
-func (c *Container) Hash() string {
- return c.container.Config.Labels[labels.HASH.Str()]
-}
-
-// Number returns the container number stored as label.
-func (c *Container) Number() (int, error) {
- numberStr := c.container.Config.Labels[labels.NUMBER.Str()]
- return strconv.Atoi(numberStr)
-}
diff --git a/vendor/github.com/docker/libcompose/docker/container/functions.go b/vendor/github.com/docker/libcompose/docker/container/functions.go
deleted file mode 100644
index 7f67aecd9..000000000
--- a/vendor/github.com/docker/libcompose/docker/container/functions.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package container
-
-import (
- "golang.org/x/net/context"
-
- "github.com/docker/docker/api/types"
- "github.com/docker/docker/api/types/filters"
- "github.com/docker/docker/client"
-)
-
-// ListByFilter looks up the hosts containers with the specified filters and
-// returns a list of container matching it, or an error.
-func ListByFilter(ctx context.Context, clientInstance client.ContainerAPIClient, containerFilters ...map[string][]string) ([]types.Container, error) {
- filterArgs := filters.NewArgs()
-
- // FIXME(vdemeester) I don't like 3 for loops >_<
- for _, filter := range containerFilters {
- for key, filterValue := range filter {
- for _, value := range filterValue {
- filterArgs.Add(key, value)
- }
- }
- }
-
- return clientInstance.ContainerList(ctx, types.ContainerListOptions{
- All: true,
- Filter: filterArgs,
- })
-}
-
-// Get looks up the hosts containers with the specified ID
-// or name and returns it, or an error.
-func Get(ctx context.Context, clientInstance client.ContainerAPIClient, id string) (*types.ContainerJSON, error) {
- container, err := clientInstance.ContainerInspect(ctx, id)
- if err != nil {
- if client.IsErrContainerNotFound(err) {
- return nil, nil
- }
- return nil, err
- }
- return &container, nil
-}
diff --git a/vendor/github.com/docker/libcompose/docker/ctx/context.go b/vendor/github.com/docker/libcompose/docker/ctx/context.go
deleted file mode 100644
index 3e001cedb..000000000
--- a/vendor/github.com/docker/libcompose/docker/ctx/context.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package ctx
-
-import (
- "github.com/docker/docker/cliconfig"
- "github.com/docker/docker/cliconfig/configfile"
- "github.com/docker/libcompose/docker/auth"
- "github.com/docker/libcompose/docker/client"
- "github.com/docker/libcompose/project"
-)
-
-// Context holds context meta information about a libcompose project and docker
-// client information (like configuration file, builder to use, …)
-type Context struct {
- project.Context
- ClientFactory client.Factory
- ConfigDir string
- ConfigFile *configfile.ConfigFile
- AuthLookup auth.Lookup
-}
-
-// LookupConfig tries to load the docker configuration files, if any.
-func (c *Context) LookupConfig() error {
- if c.ConfigFile != nil {
- return nil
- }
-
- config, err := cliconfig.Load(c.ConfigDir)
- if err != nil {
- return err
- }
-
- c.ConfigFile = config
-
- return nil
-}
diff --git a/vendor/github.com/docker/libcompose/docker/image/image.go b/vendor/github.com/docker/libcompose/docker/image/image.go
deleted file mode 100644
index 5e7aabc5a..000000000
--- a/vendor/github.com/docker/libcompose/docker/image/image.go
+++ /dev/null
@@ -1,105 +0,0 @@
-package image
-
-import (
- "encoding/base64"
- "encoding/json"
- "fmt"
- "io"
- "os"
-
- "golang.org/x/net/context"
-
- "github.com/Sirupsen/logrus"
- "github.com/docker/docker/api/types"
- "github.com/docker/docker/client"
- "github.com/docker/docker/pkg/jsonmessage"
- "github.com/docker/docker/pkg/term"
- "github.com/docker/docker/reference"
- "github.com/docker/docker/registry"
- "github.com/docker/libcompose/docker/auth"
-)
-
-// Exists return whether or not the service image already exists
-func Exists(ctx context.Context, clt client.ImageAPIClient, image string) (bool, error) {
- _, err := InspectImage(ctx, clt, image)
- if err != nil {
- if client.IsErrImageNotFound(err) {
- return false, nil
- }
- return false, err
- }
- return true, nil
-}
-
-// InspectImage inspect the specified image (can be a name, an id or a digest)
-// with the specified client.
-func InspectImage(ctx context.Context, client client.ImageAPIClient, image string) (types.ImageInspect, error) {
- imageInspect, _, err := client.ImageInspectWithRaw(ctx, image)
- return imageInspect, err
-}
-
-// RemoveImage removes the specified image (can be a name, an id or a digest)
-// from the daemon store with the specified client.
-func RemoveImage(ctx context.Context, client client.ImageAPIClient, image string) error {
- _, err := client.ImageRemove(ctx, image, types.ImageRemoveOptions{})
- return err
-}
-
-// PullImage pulls the specified image (can be a name, an id or a digest)
-// to the daemon store with the specified client.
-func PullImage(ctx context.Context, client client.ImageAPIClient, serviceName string, authLookup auth.Lookup, image string) error {
- fmt.Fprintf(os.Stderr, "Pulling %s (%s)...\n", serviceName, image)
- distributionRef, err := reference.ParseNamed(image)
- if err != nil {
- return err
- }
-
- repoInfo, err := registry.ParseRepositoryInfo(distributionRef)
- if err != nil {
- return err
- }
-
- authConfig := authLookup.Lookup(repoInfo)
-
- // Use ConfigFile.SaveToWriter to not re-define encodeAuthToBase64
- encodedAuth, err := encodeAuthToBase64(authConfig)
- if err != nil {
- return err
- }
-
- options := types.ImagePullOptions{
- RegistryAuth: encodedAuth,
- }
- responseBody, err := client.ImagePull(ctx, distributionRef.String(), options)
- if err != nil {
- logrus.Errorf("Failed to pull image %s: %v", image, err)
- return err
- }
- defer responseBody.Close()
-
- var writeBuff io.Writer = os.Stderr
-
- outFd, isTerminalOut := term.GetFdInfo(os.Stderr)
-
- err = jsonmessage.DisplayJSONMessagesStream(responseBody, writeBuff, outFd, isTerminalOut, nil)
- if err != nil {
- if jerr, ok := err.(*jsonmessage.JSONError); ok {
- // If no error code is set, default to 1
- if jerr.Code == 0 {
- jerr.Code = 1
- }
- fmt.Fprintf(os.Stderr, "%s", writeBuff)
- return fmt.Errorf("Status: %s, Code: %d", jerr.Message, jerr.Code)
- }
- }
- return err
-}
-
-// encodeAuthToBase64 serializes the auth configuration as JSON base64 payload
-func encodeAuthToBase64(authConfig types.AuthConfig) (string, error) {
- buf, err := json.Marshal(authConfig)
- if err != nil {
- return "", err
- }
- return base64.URLEncoding.EncodeToString(buf), nil
-}
diff --git a/vendor/github.com/docker/libcompose/docker/service/name.go b/vendor/github.com/docker/libcompose/docker/service/name.go
deleted file mode 100644
index a7e77d670..000000000
--- a/vendor/github.com/docker/libcompose/docker/service/name.go
+++ /dev/null
@@ -1,92 +0,0 @@
-package service
-
-import (
- "fmt"
- "strconv"
-
- "golang.org/x/net/context"
-
- "github.com/docker/docker/api/types"
- "github.com/docker/docker/api/types/filters"
- "github.com/docker/docker/client"
- "github.com/docker/libcompose/labels"
-)
-
-const format = "%s_%s_%d"
-
-// Namer defines method to provide container name.
-type Namer interface {
- Next() (string, int)
-}
-
-type defaultNamer struct {
- project string
- service string
- oneOff bool
- currentNumber int
-}
-
-type singleNamer struct {
- name string
-}
-
-// NewSingleNamer returns a namer that only allows a single name.
-func NewSingleNamer(name string) Namer {
- return &singleNamer{name}
-}
-
-// NewNamer returns a namer that returns names based on the specified project and
-// service name and an inner counter, e.g. project_service_1, project_service_2…
-func NewNamer(ctx context.Context, client client.ContainerAPIClient, project, service string, oneOff bool) (Namer, error) {
- namer := &defaultNamer{
- project: project,
- service: service,
- oneOff: oneOff,
- }
-
- filter := filters.NewArgs()
- filter.Add("label", fmt.Sprintf("%s=%s", labels.PROJECT.Str(), project))
- filter.Add("label", fmt.Sprintf("%s=%s", labels.SERVICE.Str(), service))
- if oneOff {
- filter.Add("label", fmt.Sprintf("%s=%s", labels.ONEOFF.Str(), "True"))
- } else {
- filter.Add("label", fmt.Sprintf("%s=%s", labels.ONEOFF.Str(), "False"))
- }
-
- containers, err := client.ContainerList(ctx, types.ContainerListOptions{
- All: true,
- Filter: filter,
- })
- if err != nil {
- return nil, err
- }
-
- maxNumber := 0
- for _, container := range containers {
- number, err := strconv.Atoi(container.Labels[labels.NUMBER.Str()])
- if err != nil {
- return nil, err
- }
- if number > maxNumber {
- maxNumber = number
- }
- }
- namer.currentNumber = maxNumber + 1
-
- return namer, nil
-}
-
-func (i *defaultNamer) Next() (string, int) {
- service := i.service
- if i.oneOff {
- service = i.service + "_run"
- }
- name := fmt.Sprintf(format, i.project, service, i.currentNumber)
- number := i.currentNumber
- i.currentNumber = i.currentNumber + 1
- return name, number
-}
-
-func (s *singleNamer) Next() (string, int) {
- return s.name, 1
-}
diff --git a/vendor/github.com/docker/libcompose/docker/service/service.go b/vendor/github.com/docker/libcompose/docker/service/service.go
deleted file mode 100644
index a1124564c..000000000
--- a/vendor/github.com/docker/libcompose/docker/service/service.go
+++ /dev/null
@@ -1,732 +0,0 @@
-package service
-
-import (
- "fmt"
- "strings"
- "time"
-
- "golang.org/x/net/context"
-
- "github.com/Sirupsen/logrus"
- "github.com/docker/docker/api/types"
- "github.com/docker/docker/api/types/filters"
- "github.com/docker/docker/api/types/network"
- "github.com/docker/docker/client"
- "github.com/docker/go-connections/nat"
- "github.com/docker/libcompose/config"
- "github.com/docker/libcompose/docker/auth"
- "github.com/docker/libcompose/docker/builder"
- composeclient "github.com/docker/libcompose/docker/client"
- "github.com/docker/libcompose/docker/container"
- "github.com/docker/libcompose/docker/ctx"
- "github.com/docker/libcompose/docker/image"
- "github.com/docker/libcompose/labels"
- "github.com/docker/libcompose/project"
- "github.com/docker/libcompose/project/events"
- "github.com/docker/libcompose/project/options"
- "github.com/docker/libcompose/utils"
- "github.com/docker/libcompose/yaml"
-)
-
-// Service is a project.Service implementations.
-type Service struct {
- name string
- project *project.Project
- serviceConfig *config.ServiceConfig
- clientFactory composeclient.Factory
- authLookup auth.Lookup
-
- // FIXME(vdemeester) remove this at some point
- context *ctx.Context
-}
-
-// NewService creates a service
-func NewService(name string, serviceConfig *config.ServiceConfig, context *ctx.Context) *Service {
- return &Service{
- name: name,
- project: context.Project,
- serviceConfig: serviceConfig,
- clientFactory: context.ClientFactory,
- authLookup: context.AuthLookup,
- context: context,
- }
-}
-
-// Name returns the service name.
-func (s *Service) Name() string {
- return s.name
-}
-
-// Config returns the configuration of the service (config.ServiceConfig).
-func (s *Service) Config() *config.ServiceConfig {
- return s.serviceConfig
-}
-
-// DependentServices returns the dependent services (as an array of ServiceRelationship) of the service.
-func (s *Service) DependentServices() []project.ServiceRelationship {
- return DefaultDependentServices(s.project, s)
-}
-
-// Create implements Service.Create. It ensures the image exists or build it
-// if it can and then create a container.
-func (s *Service) Create(ctx context.Context, options options.Create) error {
- containers, err := s.collectContainers(ctx)
- if err != nil {
- return err
- }
-
- if err := s.ensureImageExists(ctx, options.NoBuild, options.ForceBuild); err != nil {
- return err
- }
-
- if len(containers) != 0 {
- return s.eachContainer(ctx, containers, func(c *container.Container) error {
- _, err := s.recreateIfNeeded(ctx, c, options.NoRecreate, options.ForceRecreate)
- return err
- })
- }
-
- namer, err := s.namer(ctx, 1)
- if err != nil {
- return err
- }
-
- _, err = s.createContainer(ctx, namer, "", nil, false)
- return err
-}
-
-func (s *Service) namer(ctx context.Context, count int) (Namer, error) {
- var namer Namer
- var err error
-
- if s.serviceConfig.ContainerName != "" {
- if count > 1 {
- logrus.Warnf(`The "%s" service is using the custom container name "%s". Docker requires each container to have a unique name. Remove the custom name to scale the service.`, s.name, s.serviceConfig.ContainerName)
- }
- namer = NewSingleNamer(s.serviceConfig.ContainerName)
- } else {
- client := s.clientFactory.Create(s)
- namer, err = NewNamer(ctx, client, s.project.Name, s.name, false)
- if err != nil {
- return nil, err
- }
- }
- return namer, nil
-}
-
-func (s *Service) collectContainers(ctx context.Context) ([]*container.Container, error) {
- client := s.clientFactory.Create(s)
- containers, err := container.ListByFilter(ctx, client, labels.SERVICE.Eq(s.name), labels.PROJECT.Eq(s.project.Name))
- if err != nil {
- return nil, err
- }
-
- result := []*container.Container{}
-
- for _, cont := range containers {
- c, err := container.New(ctx, client, cont.ID)
- if err != nil {
- return nil, err
- }
- result = append(result, c)
- }
-
- return result, nil
-}
-
-func (s *Service) ensureImageExists(ctx context.Context, noBuild bool, forceBuild bool) error {
- if forceBuild {
- return s.build(ctx, options.Build{})
- }
-
- exists, err := image.Exists(ctx, s.clientFactory.Create(s), s.imageName())
- if err != nil {
- return err
- }
- if exists {
- return nil
- }
-
- if s.Config().Build.Context != "" {
- if noBuild {
- return fmt.Errorf("Service %q needs to be built, but no-build was specified", s.name)
- }
- return s.build(ctx, options.Build{})
- }
-
- return s.Pull(ctx)
-}
-
-func (s *Service) imageName() string {
- if s.Config().Image != "" {
- return s.Config().Image
- }
- return fmt.Sprintf("%s_%s", s.project.Name, s.Name())
-}
-
-// Build implements Service.Build. It will try to build the image and returns an error if any.
-func (s *Service) Build(ctx context.Context, buildOptions options.Build) error {
- return s.build(ctx, buildOptions)
-}
-
-func (s *Service) build(ctx context.Context, buildOptions options.Build) error {
- if s.Config().Build.Context == "" {
- return fmt.Errorf("Specified service does not have a build section")
- }
- builder := &builder.DaemonBuilder{
- Client: s.clientFactory.Create(s),
- ContextDirectory: s.Config().Build.Context,
- Dockerfile: s.Config().Build.Dockerfile,
- BuildArgs: s.Config().Build.Args,
- AuthConfigs: s.authLookup.All(),
- NoCache: buildOptions.NoCache,
- ForceRemove: buildOptions.ForceRemove,
- Pull: buildOptions.Pull,
- LoggerFactory: s.context.LoggerFactory,
- }
- return builder.Build(ctx, s.imageName())
-}
-
-func (s *Service) constructContainers(ctx context.Context, count int) ([]*container.Container, error) {
- result, err := s.collectContainers(ctx)
- if err != nil {
- return nil, err
- }
-
- client := s.clientFactory.Create(s)
-
- var namer Namer
-
- if s.serviceConfig.ContainerName != "" {
- if count > 1 {
- logrus.Warnf(`The "%s" service is using the custom container name "%s". Docker requires each container to have a unique name. Remove the custom name to scale the service.`, s.name, s.serviceConfig.ContainerName)
- }
- namer = NewSingleNamer(s.serviceConfig.ContainerName)
- } else {
- namer, err = NewNamer(ctx, client, s.project.Name, s.name, false)
- if err != nil {
- return nil, err
- }
- }
-
- for i := len(result); i < count; i++ {
- c, err := s.createContainer(ctx, namer, "", nil, false)
- if err != nil {
- return nil, err
- }
-
- // FIXME(vdemeester) use property/method instead
- id, _ := c.ID()
- logrus.Debugf("Created container %s: %v", id, c.Name())
-
- result = append(result, c)
- }
-
- return result, nil
-}
-
-// Up implements Service.Up. It builds the image if needed, creates a container
-// and start it.
-func (s *Service) Up(ctx context.Context, options options.Up) error {
- containers, err := s.collectContainers(ctx)
- if err != nil {
- return err
- }
-
- var imageName = s.imageName()
- if len(containers) == 0 || !options.NoRecreate {
- if err = s.ensureImageExists(ctx, options.NoBuild, options.ForceBuild); err != nil {
- return err
- }
- }
-
- return s.up(ctx, imageName, true, options)
-}
-
-// Run implements Service.Run. It runs a one of command within the service container.
-// It always create a new container.
-func (s *Service) Run(ctx context.Context, commandParts []string, options options.Run) (int, error) {
- err := s.ensureImageExists(ctx, false, false)
- if err != nil {
- return -1, err
- }
-
- client := s.clientFactory.Create(s)
-
- namer, err := NewNamer(ctx, client, s.project.Name, s.name, true)
- if err != nil {
- return -1, err
- }
-
- configOverride := &config.ServiceConfig{Command: commandParts, Tty: true, StdinOpen: true}
-
- c, err := s.createContainer(ctx, namer, "", configOverride, true)
- if err != nil {
- return -1, err
- }
-
- if err := s.connectContainerToNetworks(ctx, c, true); err != nil {
- return -1, err
- }
-
- if options.Detached {
- logrus.Infof("%s", c.Name())
- return 0, c.Start(ctx)
- }
- return c.Run(ctx, configOverride)
-}
-
-// Info implements Service.Info. It returns an project.InfoSet with the containers
-// related to this service (can be multiple if using the scale command).
-func (s *Service) Info(ctx context.Context) (project.InfoSet, error) {
- result := project.InfoSet{}
- containers, err := s.collectContainers(ctx)
- if err != nil {
- return nil, err
- }
-
- for _, c := range containers {
- info, err := c.Info(ctx)
- if err != nil {
- return nil, err
- }
- result = append(result, info)
- }
-
- return result, nil
-}
-
-// Start implements Service.Start. It tries to start a container without creating it.
-func (s *Service) Start(ctx context.Context) error {
- return s.collectContainersAndDo(ctx, func(c *container.Container) error {
- if err := s.connectContainerToNetworks(ctx, c, false); err != nil {
- return err
- }
- return c.Start(ctx)
- })
-}
-
-func (s *Service) up(ctx context.Context, imageName string, create bool, options options.Up) error {
- containers, err := s.collectContainers(ctx)
- if err != nil {
- return err
- }
-
- logrus.Debugf("Found %d existing containers for service %s", len(containers), s.name)
-
- if len(containers) == 0 && create {
- namer, err := s.namer(ctx, 1)
- if err != nil {
- return err
- }
- c, err := s.createContainer(ctx, namer, "", nil, false)
- if err != nil {
- return err
- }
- containers = []*container.Container{c}
- }
-
- return s.eachContainer(ctx, containers, func(c *container.Container) error {
- var err error
- if create {
- c, err = s.recreateIfNeeded(ctx, c, options.NoRecreate, options.ForceRecreate)
- if err != nil {
- return err
- }
- }
-
- if err := s.connectContainerToNetworks(ctx, c, false); err != nil {
- return err
- }
-
- err = c.Start(ctx)
-
- if err == nil {
- s.project.Notify(events.ContainerStarted, s.name, map[string]string{
- "name": c.Name(),
- })
- }
-
- return err
- })
-}
-
-func (s *Service) connectContainerToNetworks(ctx context.Context, c *container.Container, oneOff bool) error {
- connectedNetworks, err := c.Networks()
- if err != nil {
- return nil
- }
- if s.serviceConfig.Networks != nil {
- for _, network := range s.serviceConfig.Networks.Networks {
- existingNetwork, ok := connectedNetworks[network.Name]
- if ok {
- // FIXME(vdemeester) implement alias checking (to not disconnect/reconnect for nothing)
- aliasPresent := false
- for _, alias := range existingNetwork.Aliases {
- // FIXME(vdemeester) use shortID instead of ID
- ID, _ := c.ID()
- if alias == ID {
- aliasPresent = true
- }
- }
- if aliasPresent {
- continue
- }
- if err := s.NetworkDisconnect(ctx, c, network, oneOff); err != nil {
- return err
- }
- }
- if err := s.NetworkConnect(ctx, c, network, oneOff); err != nil {
- return err
- }
- }
- }
- return nil
-}
-
-// NetworkDisconnect disconnects the container from the specified network
-func (s *Service) NetworkDisconnect(ctx context.Context, c *container.Container, net *yaml.Network, oneOff bool) error {
- containerID, _ := c.ID()
- client := s.clientFactory.Create(s)
- return client.NetworkDisconnect(ctx, net.RealName, containerID, true)
-}
-
-// NetworkConnect connects the container to the specified network
-// FIXME(vdemeester) will be refactor with Container refactoring
-func (s *Service) NetworkConnect(ctx context.Context, c *container.Container, net *yaml.Network, oneOff bool) error {
- containerID, _ := c.ID()
- client := s.clientFactory.Create(s)
- internalLinks, err := s.getLinks()
- if err != nil {
- return err
- }
- links := []string{}
- // TODO(vdemeester) handle link to self (?)
- for k, v := range internalLinks {
- links = append(links, strings.Join([]string{v, k}, ":"))
- }
- for _, v := range s.serviceConfig.ExternalLinks {
- links = append(links, v)
- }
- aliases := []string{}
- if !oneOff {
- aliases = []string{s.Name()}
- }
- aliases = append(aliases, net.Aliases...)
- return client.NetworkConnect(ctx, net.RealName, containerID, &network.EndpointSettings{
- Aliases: aliases,
- Links: links,
- IPAddress: net.IPv4Address,
- IPAMConfig: &network.EndpointIPAMConfig{
- IPv4Address: net.IPv4Address,
- IPv6Address: net.IPv6Address,
- },
- })
-}
-
-func (s *Service) recreateIfNeeded(ctx context.Context, c *container.Container, noRecreate, forceRecreate bool) (*container.Container, error) {
- if noRecreate {
- return c, nil
- }
- outOfSync, err := s.OutOfSync(ctx, c)
- if err != nil {
- return c, err
- }
-
- logrus.WithFields(logrus.Fields{
- "outOfSync": outOfSync,
- "ForceRecreate": forceRecreate,
- "NoRecreate": noRecreate}).Debug("Going to decide if recreate is needed")
-
- if forceRecreate || outOfSync {
- logrus.Infof("Recreating %s", s.name)
- newContainer, err := s.recreate(ctx, c)
- if err != nil {
- return c, err
- }
- return newContainer, nil
- }
-
- return c, err
-}
-
-func (s *Service) recreate(ctx context.Context, c *container.Container) (*container.Container, error) {
- name := c.Name()
- id, _ := c.ID()
- newName := fmt.Sprintf("%s_%s", name, id[:12])
- logrus.Debugf("Renaming %s => %s", name, newName)
- if err := c.Rename(ctx, newName); err != nil {
- logrus.Errorf("Failed to rename old container %s", c.Name())
- return nil, err
- }
- namer := NewSingleNamer(name)
- newContainer, err := s.createContainer(ctx, namer, id, nil, false)
- if err != nil {
- return nil, err
- }
- newID, _ := newContainer.ID()
- logrus.Debugf("Created replacement container %s", newID)
- if err := c.Remove(ctx, false); err != nil {
- logrus.Errorf("Failed to remove old container %s", c.Name())
- return nil, err
- }
- logrus.Debugf("Removed old container %s %s", c.Name(), id)
- return newContainer, nil
-}
-
-// OutOfSync checks if the container is out of sync with the service definition.
-// It looks if the the service hash container label is the same as the computed one.
-func (s *Service) OutOfSync(ctx context.Context, c *container.Container) (bool, error) {
- if c.ImageConfig() != s.serviceConfig.Image {
- logrus.Debugf("Images for %s do not match %s!=%s", c.Name(), c.ImageConfig(), s.serviceConfig.Image)
- return true, nil
- }
-
- expectedHash := config.GetServiceHash(s.name, s.Config())
- if c.Hash() != expectedHash {
- logrus.Debugf("Hashes for %s do not match %s!=%s", c.Name(), c.Hash(), expectedHash)
- return true, nil
- }
-
- image, err := image.InspectImage(ctx, s.clientFactory.Create(s), c.ImageConfig())
- if err != nil {
- if client.IsErrImageNotFound(err) {
- logrus.Debugf("Image %s do not exist, do not know if it's out of sync", c.Image())
- return false, nil
- }
- return false, err
- }
-
- logrus.Debugf("Checking existing image name vs id: %s == %s", image.ID, c.Image())
- return image.ID != c.Image(), err
-}
-
-func (s *Service) collectContainersAndDo(ctx context.Context, action func(*container.Container) error) error {
- containers, err := s.collectContainers(ctx)
- if err != nil {
- return err
- }
- return s.eachContainer(ctx, containers, action)
-}
-
-func (s *Service) eachContainer(ctx context.Context, containers []*container.Container, action func(*container.Container) error) error {
-
- tasks := utils.InParallel{}
- for _, cont := range containers {
- task := func(cont *container.Container) func() error {
- return func() error {
- return action(cont)
- }
- }(cont)
-
- tasks.Add(task)
- }
-
- return tasks.Wait()
-}
-
-// Stop implements Service.Stop. It stops any containers related to the service.
-func (s *Service) Stop(ctx context.Context, timeout int) error {
- return s.collectContainersAndDo(ctx, func(c *container.Container) error {
- return c.Stop(ctx, timeout)
- })
-}
-
-// Restart implements Service.Restart. It restarts any containers related to the service.
-func (s *Service) Restart(ctx context.Context, timeout int) error {
- return s.collectContainersAndDo(ctx, func(c *container.Container) error {
- return c.Restart(ctx, timeout)
- })
-}
-
-// Kill implements Service.Kill. It kills any containers related to the service.
-func (s *Service) Kill(ctx context.Context, signal string) error {
- return s.collectContainersAndDo(ctx, func(c *container.Container) error {
- return c.Kill(ctx, signal)
- })
-}
-
-// Delete implements Service.Delete. It removes any containers related to the service.
-func (s *Service) Delete(ctx context.Context, options options.Delete) error {
- return s.collectContainersAndDo(ctx, func(c *container.Container) error {
- running, _ := c.IsRunning(ctx)
- if !running || options.RemoveRunning {
- return c.Remove(ctx, options.RemoveVolume)
- }
- return nil
- })
-}
-
-// Log implements Service.Log. It returns the docker logs for each container related to the service.
-func (s *Service) Log(ctx context.Context, follow bool) error {
- return s.collectContainersAndDo(ctx, func(c *container.Container) error {
- containerNumber, err := c.Number()
- if err != nil {
- return err
- }
- name := fmt.Sprintf("%s_%d", s.name, containerNumber)
- if s.Config().ContainerName != "" {
- name = s.Config().ContainerName
- }
- l := s.context.LoggerFactory.CreateContainerLogger(name)
- return c.Log(ctx, l, follow)
- })
-}
-
-// Scale implements Service.Scale. It creates or removes containers to have the specified number
-// of related container to the service to run.
-func (s *Service) Scale(ctx context.Context, scale int, timeout int) error {
- if s.specificiesHostPort() {
- logrus.Warnf("The \"%s\" service specifies a port on the host. If multiple containers for this service are created on a single host, the port will clash.", s.Name())
- }
-
- containers, err := s.collectContainers(ctx)
- if err != nil {
- return err
- }
- if len(containers) > scale {
- foundCount := 0
- for _, c := range containers {
- foundCount++
- if foundCount > scale {
- if err := c.Stop(ctx, timeout); err != nil {
- return err
- }
- // FIXME(vdemeester) remove volume in scale by default ?
- if err := c.Remove(ctx, false); err != nil {
- return err
- }
- }
- }
- }
-
- if err != nil {
- return err
- }
-
- if len(containers) < scale {
- err := s.ensureImageExists(ctx, false, false)
- if err != nil {
- return err
- }
-
- if _, err = s.constructContainers(ctx, scale); err != nil {
- return err
- }
- }
-
- return s.up(ctx, "", false, options.Up{})
-}
-
-// Pull implements Service.Pull. It pulls the image of the service and skip the service that
-// would need to be built.
-func (s *Service) Pull(ctx context.Context) error {
- if s.Config().Image == "" {
- return nil
- }
-
- return image.PullImage(ctx, s.clientFactory.Create(s), s.name, s.authLookup, s.Config().Image)
-}
-
-// Pause implements Service.Pause. It puts into pause the container(s) related
-// to the service.
-func (s *Service) Pause(ctx context.Context) error {
- return s.collectContainersAndDo(ctx, func(c *container.Container) error {
- return c.Pause(ctx)
- })
-}
-
-// Unpause implements Service.Pause. It brings back from pause the container(s)
-// related to the service.
-func (s *Service) Unpause(ctx context.Context) error {
- return s.collectContainersAndDo(ctx, func(c *container.Container) error {
- return c.Unpause(ctx)
- })
-}
-
-// RemoveImage implements Service.RemoveImage. It removes images used for the service
-// depending on the specified type.
-func (s *Service) RemoveImage(ctx context.Context, imageType options.ImageType) error {
- switch imageType {
- case "local":
- if s.Config().Image != "" {
- return nil
- }
- return image.RemoveImage(ctx, s.clientFactory.Create(s), s.imageName())
- case "all":
- return image.RemoveImage(ctx, s.clientFactory.Create(s), s.imageName())
- default:
- // Don't do a thing, should be validated up-front
- return nil
- }
-}
-
-var eventAttributes = []string{"image", "name"}
-
-// Events implements Service.Events. It listen to all real-time events happening
-// for the service, and put them into the specified chan.
-func (s *Service) Events(ctx context.Context, evts chan events.ContainerEvent) error {
- filter := filters.NewArgs()
- filter.Add("label", fmt.Sprintf("%s=%s", labels.PROJECT, s.project.Name))
- filter.Add("label", fmt.Sprintf("%s=%s", labels.SERVICE, s.name))
- client := s.clientFactory.Create(s)
- eventq, errq := client.Events(ctx, types.EventsOptions{
- Filters: filter,
- })
- go func() {
- for {
- select {
- case event := <-eventq:
- service := event.Actor.Attributes[labels.SERVICE.Str()]
- attributes := map[string]string{}
- for _, attr := range eventAttributes {
- attributes[attr] = event.Actor.Attributes[attr]
- }
- e := events.ContainerEvent{
- Service: service,
- Event: event.Action,
- Type: event.Type,
- ID: event.Actor.ID,
- Time: time.Unix(event.Time, 0),
- Attributes: attributes,
- }
- evts <- e
- }
- }
- }()
- return <-errq
-}
-
-// Containers implements Service.Containers. It returns the list of containers
-// that are related to the service.
-func (s *Service) Containers(ctx context.Context) ([]project.Container, error) {
- result := []project.Container{}
- containers, err := s.collectContainers(ctx)
- if err != nil {
- return nil, err
- }
-
- for _, c := range containers {
- result = append(result, c)
- }
-
- return result, nil
-}
-
-func (s *Service) specificiesHostPort() bool {
- _, bindings, err := nat.ParsePortSpecs(s.Config().Ports)
-
- if err != nil {
- fmt.Println(err)
- }
-
- for _, portBindings := range bindings {
- for _, portBinding := range portBindings {
- if portBinding.HostPort != "" {
- return true
- }
- }
- }
-
- return false
-}
diff --git a/vendor/github.com/docker/libcompose/docker/service/service_create.go b/vendor/github.com/docker/libcompose/docker/service/service_create.go
deleted file mode 100644
index 934bf9301..000000000
--- a/vendor/github.com/docker/libcompose/docker/service/service_create.go
+++ /dev/null
@@ -1,189 +0,0 @@
-package service
-
-import (
- "fmt"
- "strconv"
- "strings"
-
- "golang.org/x/net/context"
-
- "github.com/Sirupsen/logrus"
- "github.com/docker/docker/api/types"
- containertypes "github.com/docker/docker/api/types/container"
- "github.com/docker/libcompose/config"
- composecontainer "github.com/docker/libcompose/docker/container"
- "github.com/docker/libcompose/labels"
- "github.com/docker/libcompose/project"
- "github.com/docker/libcompose/project/events"
- util "github.com/docker/libcompose/utils"
-)
-
-func (s *Service) createContainer(ctx context.Context, namer Namer, oldContainer string, configOverride *config.ServiceConfig, oneOff bool) (*composecontainer.Container, error) {
- serviceConfig := s.serviceConfig
- if configOverride != nil {
- serviceConfig.Command = configOverride.Command
- serviceConfig.Tty = configOverride.Tty
- serviceConfig.StdinOpen = configOverride.StdinOpen
- }
- configWrapper, err := ConvertToAPI(serviceConfig, s.context.Context)
- if err != nil {
- return nil, err
- }
- configWrapper.Config.Image = s.imageName()
-
- containerName, containerNumber := namer.Next()
-
- configWrapper.Config.Labels[labels.SERVICE.Str()] = s.name
- configWrapper.Config.Labels[labels.PROJECT.Str()] = s.project.Name
- configWrapper.Config.Labels[labels.HASH.Str()] = config.GetServiceHash(s.name, serviceConfig)
- configWrapper.Config.Labels[labels.ONEOFF.Str()] = strings.Title(strconv.FormatBool(oneOff))
- configWrapper.Config.Labels[labels.NUMBER.Str()] = fmt.Sprintf("%d", containerNumber)
- configWrapper.Config.Labels[labels.VERSION.Str()] = project.ComposeVersion
-
- err = s.populateAdditionalHostConfig(configWrapper.HostConfig)
- if err != nil {
- return nil, err
- }
-
- // FIXME(vdemeester): oldContainer should be a Container instead of a string
- client := s.clientFactory.Create(s)
- if oldContainer != "" {
- info, err := client.ContainerInspect(ctx, oldContainer)
- if err != nil {
- return nil, err
- }
- configWrapper.HostConfig.Binds = util.Merge(configWrapper.HostConfig.Binds, volumeBinds(configWrapper.Config.Volumes, &info))
- }
-
- logrus.Debugf("Creating container %s %#v", containerName, configWrapper)
- // FIXME(vdemeester): long-term will be container.Create(…)
- container, err := composecontainer.Create(ctx, client, containerName, configWrapper.Config, configWrapper.HostConfig, configWrapper.NetworkingConfig)
- if err != nil {
- return nil, err
- }
- s.project.Notify(events.ContainerCreated, s.name, map[string]string{
- "name": containerName,
- })
- return container, nil
-}
-
-func (s *Service) populateAdditionalHostConfig(hostConfig *containertypes.HostConfig) error {
- links, err := s.getLinks()
- if err != nil {
- return err
- }
-
- for _, link := range s.DependentServices() {
- if !s.project.ServiceConfigs.Has(link.Target) {
- continue
- }
-
- service, err := s.project.CreateService(link.Target)
- if err != nil {
- return err
- }
-
- containers, err := service.Containers(context.Background())
- if err != nil {
- return err
- }
-
- if link.Type == project.RelTypeIpcNamespace {
- hostConfig, err = addIpc(hostConfig, service, containers, s.serviceConfig.Ipc)
- } else if link.Type == project.RelTypeNetNamespace {
- hostConfig, err = addNetNs(hostConfig, service, containers, s.serviceConfig.NetworkMode)
- }
-
- if err != nil {
- return err
- }
- }
-
- hostConfig.Links = []string{}
- for k, v := range links {
- hostConfig.Links = append(hostConfig.Links, strings.Join([]string{v, k}, ":"))
- }
- for _, v := range s.serviceConfig.ExternalLinks {
- hostConfig.Links = append(hostConfig.Links, v)
- }
-
- return nil
-}
-
-// FIXME(vdemeester) this is temporary
-func (s *Service) getLinks() (map[string]string, error) {
- links := map[string]string{}
- for _, link := range s.DependentServices() {
- if !s.project.ServiceConfigs.Has(link.Target) {
- continue
- }
-
- service, err := s.project.CreateService(link.Target)
- if err != nil {
- return nil, err
- }
-
- // FIXME(vdemeester) container should not know service
- containers, err := service.Containers(context.Background())
- if err != nil {
- return nil, err
- }
-
- if link.Type == project.RelTypeLink {
- addLinks(links, service, link, containers)
- }
-
- if err != nil {
- return nil, err
- }
- }
- return links, nil
-}
-
-func addLinks(links map[string]string, service project.Service, rel project.ServiceRelationship, containers []project.Container) {
- for _, container := range containers {
- if _, ok := links[rel.Alias]; !ok {
- links[rel.Alias] = container.Name()
- }
-
- links[container.Name()] = container.Name()
- }
-}
-
-func addIpc(config *containertypes.HostConfig, service project.Service, containers []project.Container, ipc string) (*containertypes.HostConfig, error) {
- if len(containers) == 0 {
- return nil, fmt.Errorf("Failed to find container for IPC %v", ipc)
- }
-
- id, err := containers[0].ID()
- if err != nil {
- return nil, err
- }
-
- config.IpcMode = containertypes.IpcMode("container:" + id)
- return config, nil
-}
-
-func addNetNs(config *containertypes.HostConfig, service project.Service, containers []project.Container, networkMode string) (*containertypes.HostConfig, error) {
- if len(containers) == 0 {
- return nil, fmt.Errorf("Failed to find container for networks ns %v", networkMode)
- }
-
- id, err := containers[0].ID()
- if err != nil {
- return nil, err
- }
-
- config.NetworkMode = containertypes.NetworkMode("container:" + id)
- return config, nil
-}
-
-func volumeBinds(volumes map[string]struct{}, container *types.ContainerJSON) []string {
- result := make([]string, 0, len(container.Mounts))
- for _, mount := range container.Mounts {
- if _, ok := volumes[mount.Destination]; ok {
- result = append(result, fmt.Sprint(mount.Source, ":", mount.Destination))
- }
- }
- return result
-}
diff --git a/vendor/github.com/docker/libcompose/docker/service/service_factory.go b/vendor/github.com/docker/libcompose/docker/service/service_factory.go
deleted file mode 100644
index 2fcaafab1..000000000
--- a/vendor/github.com/docker/libcompose/docker/service/service_factory.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package service
-
-import (
- "github.com/docker/libcompose/config"
- "github.com/docker/libcompose/docker/ctx"
- "github.com/docker/libcompose/project"
-)
-
-// Factory is an implementation of project.ServiceFactory.
-type Factory struct {
- context *ctx.Context
-}
-
-// NewFactory creates a new service factory for the given context
-func NewFactory(context *ctx.Context) *Factory {
- return &Factory{
- context: context,
- }
-}
-
-// Create creates a Service based on the specified project, name and service configuration.
-func (s *Factory) Create(project *project.Project, name string, serviceConfig *config.ServiceConfig) (project.Service, error) {
- return NewService(name, serviceConfig, s.context), nil
-}
diff --git a/vendor/github.com/docker/libcompose/project/container.go b/vendor/github.com/docker/libcompose/project/container.go
deleted file mode 100644
index f822c4000..000000000
--- a/vendor/github.com/docker/libcompose/project/container.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package project
-
-import (
- "golang.org/x/net/context"
-)
-
-// Container defines what a libcompose container provides.
-type Container interface {
- ID() (string, error)
- Name() string
- Port(ctx context.Context, port string) (string, error)
- IsRunning(ctx context.Context) (bool, error)
-}
diff --git a/vendor/github.com/docker/libcompose/project/empty.go b/vendor/github.com/docker/libcompose/project/empty.go
deleted file mode 100644
index 4b31b1dfe..000000000
--- a/vendor/github.com/docker/libcompose/project/empty.go
+++ /dev/null
@@ -1,139 +0,0 @@
-package project
-
-import (
- "golang.org/x/net/context"
-
- "github.com/docker/libcompose/config"
- "github.com/docker/libcompose/project/events"
- "github.com/docker/libcompose/project/options"
-)
-
-// this ensures EmptyService implements Service
-// useful since it's easy to forget adding new functions to EmptyService
-var _ Service = (*EmptyService)(nil)
-
-// EmptyService is a struct that implements Service but does nothing.
-type EmptyService struct {
-}
-
-// Create implements Service.Create but does nothing.
-func (e *EmptyService) Create(ctx context.Context, options options.Create) error {
- return nil
-}
-
-// Build implements Service.Build but does nothing.
-func (e *EmptyService) Build(ctx context.Context, buildOptions options.Build) error {
- return nil
-}
-
-// Up implements Service.Up but does nothing.
-func (e *EmptyService) Up(ctx context.Context, options options.Up) error {
- return nil
-}
-
-// Start implements Service.Start but does nothing.
-func (e *EmptyService) Start(ctx context.Context) error {
- return nil
-}
-
-// Stop implements Service.Stop() but does nothing.
-func (e *EmptyService) Stop(ctx context.Context, timeout int) error {
- return nil
-}
-
-// Delete implements Service.Delete but does nothing.
-func (e *EmptyService) Delete(ctx context.Context, options options.Delete) error {
- return nil
-}
-
-// Restart implements Service.Restart but does nothing.
-func (e *EmptyService) Restart(ctx context.Context, timeout int) error {
- return nil
-}
-
-// Log implements Service.Log but does nothing.
-func (e *EmptyService) Log(ctx context.Context, follow bool) error {
- return nil
-}
-
-// Pull implements Service.Pull but does nothing.
-func (e *EmptyService) Pull(ctx context.Context) error {
- return nil
-}
-
-// Kill implements Service.Kill but does nothing.
-func (e *EmptyService) Kill(ctx context.Context, signal string) error {
- return nil
-}
-
-// Containers implements Service.Containers but does nothing.
-func (e *EmptyService) Containers(ctx context.Context) ([]Container, error) {
- return []Container{}, nil
-}
-
-// Scale implements Service.Scale but does nothing.
-func (e *EmptyService) Scale(ctx context.Context, count int, timeout int) error {
- return nil
-}
-
-// Info implements Service.Info but does nothing.
-func (e *EmptyService) Info(ctx context.Context) (InfoSet, error) {
- return InfoSet{}, nil
-}
-
-// Pause implements Service.Pause but does nothing.
-func (e *EmptyService) Pause(ctx context.Context) error {
- return nil
-}
-
-// Unpause implements Service.Pause but does nothing.
-func (e *EmptyService) Unpause(ctx context.Context) error {
- return nil
-}
-
-// Run implements Service.Run but does nothing.
-func (e *EmptyService) Run(ctx context.Context, commandParts []string, options options.Run) (int, error) {
- return 0, nil
-}
-
-// RemoveImage implements Service.RemoveImage but does nothing.
-func (e *EmptyService) RemoveImage(ctx context.Context, imageType options.ImageType) error {
- return nil
-}
-
-// Events implements Service.Events but does nothing.
-func (e *EmptyService) Events(ctx context.Context, events chan events.ContainerEvent) error {
- return nil
-}
-
-// DependentServices implements Service.DependentServices with empty slice.
-func (e *EmptyService) DependentServices() []ServiceRelationship {
- return []ServiceRelationship{}
-}
-
-// Config implements Service.Config with empty config.
-func (e *EmptyService) Config() *config.ServiceConfig {
- return &config.ServiceConfig{}
-}
-
-// Name implements Service.Name with empty name.
-func (e *EmptyService) Name() string {
- return ""
-}
-
-// this ensures EmptyNetworks implements Networks
-var _ Networks = (*EmptyNetworks)(nil)
-
-// EmptyNetworks is a struct that implements Networks but does nothing.
-type EmptyNetworks struct {
-}
-
-// Initialize implements Networks.Initialize but does nothing.
-func (e *EmptyNetworks) Initialize(ctx context.Context) error {
- return nil
-}
-
-// Remove implements Networks.Remove but does nothing.
-func (e *EmptyNetworks) Remove(ctx context.Context) error {
- return nil
-}
diff --git a/vendor/github.com/docker/libcompose/project/info.go b/vendor/github.com/docker/libcompose/project/info.go
deleted file mode 100644
index c12b04c7d..000000000
--- a/vendor/github.com/docker/libcompose/project/info.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package project
-
-import (
- "bytes"
- "io"
- "text/tabwriter"
-)
-
-// InfoSet holds a list of Info.
-type InfoSet []Info
-
-// Info holds a list of InfoPart.
-type Info map[string]string
-
-func (infos InfoSet) String(columns []string, titleFlag bool) string {
- //no error checking, none of this should fail
- buffer := bytes.NewBuffer(make([]byte, 0, 1024))
- tabwriter := tabwriter.NewWriter(buffer, 4, 4, 2, ' ', 0)
-
- first := true
- for _, info := range infos {
- if first && titleFlag {
- writeLine(tabwriter, columns, true, info)
- }
- first = false
- writeLine(tabwriter, columns, false, info)
- }
-
- tabwriter.Flush()
- return buffer.String()
-}
-
-func writeLine(writer io.Writer, columns []string, key bool, info Info) {
- first := true
- for _, column := range columns {
- if !first {
- writer.Write([]byte{'\t'})
- }
- first = false
- if key {
- writer.Write([]byte(column))
- } else {
- writer.Write([]byte(info[column]))
- }
- }
-
- writer.Write([]byte{'\n'})
-}
diff --git a/vendor/github.com/docker/libcompose/project/interface.go b/vendor/github.com/docker/libcompose/project/interface.go
deleted file mode 100644
index 3356407c2..000000000
--- a/vendor/github.com/docker/libcompose/project/interface.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package project
-
-import (
- "golang.org/x/net/context"
-
- "github.com/docker/libcompose/config"
- "github.com/docker/libcompose/project/events"
- "github.com/docker/libcompose/project/options"
-)
-
-// APIProject defines the methods a libcompose project should implement.
-type APIProject interface {
- events.Notifier
- events.Emitter
-
- Build(ctx context.Context, options options.Build, sevice ...string) error
- Config() (string, error)
- Create(ctx context.Context, options options.Create, services ...string) error
- Delete(ctx context.Context, options options.Delete, services ...string) error
- Down(ctx context.Context, options options.Down, services ...string) error
- Events(ctx context.Context, services ...string) (chan events.ContainerEvent, error)
- Kill(ctx context.Context, signal string, services ...string) error
- Log(ctx context.Context, follow bool, services ...string) error
- Pause(ctx context.Context, services ...string) error
- Ps(ctx context.Context, services ...string) (InfoSet, error)
- // FIXME(vdemeester) we could use nat.Port instead ?
- Port(ctx context.Context, index int, protocol, serviceName, privatePort string) (string, error)
- Pull(ctx context.Context, services ...string) error
- Restart(ctx context.Context, timeout int, services ...string) error
- Run(ctx context.Context, serviceName string, commandParts []string, options options.Run) (int, error)
- Scale(ctx context.Context, timeout int, servicesScale map[string]int) error
- Start(ctx context.Context, services ...string) error
- Stop(ctx context.Context, timeout int, services ...string) error
- Unpause(ctx context.Context, services ...string) error
- Up(ctx context.Context, options options.Up, services ...string) error
-
- Parse() error
- CreateService(name string) (Service, error)
- AddConfig(name string, config *config.ServiceConfig) error
- Load(bytes []byte) error
- Containers(ctx context.Context, filter Filter, services ...string) ([]string, error)
-
- GetServiceConfig(service string) (*config.ServiceConfig, bool)
-}
-
-// Filter holds filter element to filter containers
-type Filter struct {
- State State
-}
-
-// State defines the supported state you can filter on
-type State string
-
-// Definitions of filter states
-const (
- AnyState = State("")
- Running = State("running")
- Stopped = State("stopped")
-)
-
-// RuntimeProject defines runtime-specific methods for a libcompose implementation.
-type RuntimeProject interface {
- RemoveOrphans(ctx context.Context, projectName string, serviceConfigs *config.ServiceConfigs) error
-}
diff --git a/vendor/github.com/docker/libcompose/project/network.go b/vendor/github.com/docker/libcompose/project/network.go
deleted file mode 100644
index af0aa5671..000000000
--- a/vendor/github.com/docker/libcompose/project/network.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package project
-
-import (
- "golang.org/x/net/context"
-
- "github.com/docker/libcompose/config"
-)
-
-// Networks defines the methods a libcompose network aggregate should define.
-type Networks interface {
- Initialize(ctx context.Context) error
- Remove(ctx context.Context) error
-}
-
-// NetworksFactory is an interface factory to create Networks object for the specified
-// configurations (service, networks, …)
-type NetworksFactory interface {
- Create(projectName string, networkConfigs map[string]*config.NetworkConfig, serviceConfigs *config.ServiceConfigs, networkEnabled bool) (Networks, error)
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_config.go b/vendor/github.com/docker/libcompose/project/project_config.go
deleted file mode 100644
index c4ca1a31d..000000000
--- a/vendor/github.com/docker/libcompose/project/project_config.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package project
-
-import (
- "github.com/docker/libcompose/config"
- "gopkg.in/yaml.v2"
-)
-
-// ExportedConfig holds config attribute that will be exported
-type ExportedConfig struct {
- Version string `yaml:"version,omitempty"`
- Services map[string]*config.ServiceConfig `yaml:"services"`
- Volumes map[string]*config.VolumeConfig `yaml:"volumes"`
- Networks map[string]*config.NetworkConfig `yaml:"networks"`
-}
-
-// Config validates and print the compose file.
-func (p *Project) Config() (string, error) {
- cfg := ExportedConfig{
- Version: "2.0",
- Services: p.ServiceConfigs.All(),
- Volumes: p.VolumeConfigs,
- Networks: p.NetworkConfigs,
- }
-
- bytes, err := yaml.Marshal(cfg)
- return string(bytes), err
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_containers.go b/vendor/github.com/docker/libcompose/project/project_containers.go
deleted file mode 100644
index acc2a9a8e..000000000
--- a/vendor/github.com/docker/libcompose/project/project_containers.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package project
-
-import (
- "fmt"
-
- "golang.org/x/net/context"
-
- log "github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/project/events"
-)
-
-// Containers lists the containers for the specified services. Can be filter using
-// the Filter struct.
-func (p *Project) Containers(ctx context.Context, filter Filter, services ...string) ([]string, error) {
- containers := []string{}
- err := p.forEach(services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
- wrapper.Do(nil, events.NoEvent, events.NoEvent, func(service Service) error {
- serviceContainers, innerErr := service.Containers(ctx)
- if innerErr != nil {
- return innerErr
- }
-
- for _, container := range serviceContainers {
- running, innerErr := container.IsRunning(ctx)
- if innerErr != nil {
- log.Error(innerErr)
- }
- switch filter.State {
- case Running:
- if !running {
- continue
- }
- case Stopped:
- if running {
- continue
- }
- case AnyState:
- // Don't do a thing
- default:
- // Invalid state filter
- return fmt.Errorf("Invalid container filter: %s", filter.State)
- }
- containerID, innerErr := container.ID()
- if innerErr != nil {
- log.Error(innerErr)
- }
- containers = append(containers, containerID)
- }
- return nil
- })
- }), nil)
- if err != nil {
- return nil, err
- }
- return containers, nil
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_delete.go b/vendor/github.com/docker/libcompose/project/project_delete.go
deleted file mode 100644
index ab1d35017..000000000
--- a/vendor/github.com/docker/libcompose/project/project_delete.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package project
-
-import (
- "golang.org/x/net/context"
-
- "github.com/docker/libcompose/project/events"
- "github.com/docker/libcompose/project/options"
-)
-
-// Delete removes the specified services (like docker rm).
-func (p *Project) Delete(ctx context.Context, options options.Delete, services ...string) error {
- return p.perform(events.ProjectDeleteStart, events.ProjectDeleteDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
- wrapper.Do(nil, events.ServiceDeleteStart, events.ServiceDelete, func(service Service) error {
- return service.Delete(ctx, options)
- })
- }), nil)
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_down.go b/vendor/github.com/docker/libcompose/project/project_down.go
deleted file mode 100644
index 288ce53dd..000000000
--- a/vendor/github.com/docker/libcompose/project/project_down.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package project
-
-import (
- "fmt"
-
- "golang.org/x/net/context"
-
- "github.com/docker/libcompose/project/events"
- "github.com/docker/libcompose/project/options"
-)
-
-// Down stops the specified services and clean related containers (like docker stop + docker rm).
-func (p *Project) Down(ctx context.Context, opts options.Down, services ...string) error {
- if !opts.RemoveImages.Valid() {
- return fmt.Errorf("--rmi flag must be local, all or empty")
- }
- if err := p.Stop(ctx, 10, services...); err != nil {
- return err
- }
- if opts.RemoveOrphans {
- if err := p.runtime.RemoveOrphans(ctx, p.Name, p.ServiceConfigs); err != nil {
- return err
- }
- }
- if err := p.Delete(ctx, options.Delete{
- RemoveVolume: opts.RemoveVolume,
- }, services...); err != nil {
- return err
- }
-
- networks, err := p.context.NetworksFactory.Create(p.Name, p.NetworkConfigs, p.ServiceConfigs, p.isNetworkEnabled())
- if err != nil {
- return err
- }
- if err := networks.Remove(ctx); err != nil {
- return err
- }
-
- if opts.RemoveVolume {
- volumes, err := p.context.VolumesFactory.Create(p.Name, p.VolumeConfigs, p.ServiceConfigs, p.isVolumeEnabled())
- if err != nil {
- return err
- }
- if err := volumes.Remove(ctx); err != nil {
- return err
- }
- }
-
- return p.forEach([]string{}, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
- wrapper.Do(wrappers, events.NoEvent, events.NoEvent, func(service Service) error {
- return service.RemoveImage(ctx, opts.RemoveImages)
- })
- }), func(service Service) error {
- return service.Create(ctx, options.Create{})
- })
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_events.go b/vendor/github.com/docker/libcompose/project/project_events.go
deleted file mode 100644
index 0b296f30e..000000000
--- a/vendor/github.com/docker/libcompose/project/project_events.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package project
-
-import (
- "golang.org/x/net/context"
-
- "github.com/docker/libcompose/project/events"
-)
-
-// Events listen for real time events from containers (of the project).
-func (p *Project) Events(ctx context.Context, services ...string) (chan events.ContainerEvent, error) {
- events := make(chan events.ContainerEvent)
- if len(services) == 0 {
- services = p.ServiceConfigs.Keys()
- }
- // FIXME(vdemeester) handle errors (chan) here
- for _, service := range services {
- s, err := p.CreateService(service)
- if err != nil {
- return nil, err
- }
- go s.Events(ctx, events)
- }
- return events, nil
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_kill.go b/vendor/github.com/docker/libcompose/project/project_kill.go
deleted file mode 100644
index ac3c87d71..000000000
--- a/vendor/github.com/docker/libcompose/project/project_kill.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package project
-
-import (
- "golang.org/x/net/context"
-
- "github.com/docker/libcompose/project/events"
-)
-
-// Kill kills the specified services (like docker kill).
-func (p *Project) Kill(ctx context.Context, signal string, services ...string) error {
- return p.perform(events.ProjectKillStart, events.ProjectKillDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
- wrapper.Do(nil, events.ServiceKillStart, events.ServiceKill, func(service Service) error {
- return service.Kill(ctx, signal)
- })
- }), nil)
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_pause.go b/vendor/github.com/docker/libcompose/project/project_pause.go
deleted file mode 100644
index c5c4c39b3..000000000
--- a/vendor/github.com/docker/libcompose/project/project_pause.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package project
-
-import (
- "golang.org/x/net/context"
-
- "github.com/docker/libcompose/project/events"
-)
-
-// Pause pauses the specified services containers (like docker pause).
-func (p *Project) Pause(ctx context.Context, services ...string) error {
- return p.perform(events.ProjectPauseStart, events.ProjectPauseDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
- wrapper.Do(nil, events.ServicePauseStart, events.ServicePause, func(service Service) error {
- return service.Pause(ctx)
- })
- }), nil)
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_port.go b/vendor/github.com/docker/libcompose/project/project_port.go
deleted file mode 100644
index 85fa6d8a5..000000000
--- a/vendor/github.com/docker/libcompose/project/project_port.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package project
-
-import (
- "fmt"
-
- "golang.org/x/net/context"
-)
-
-// Port returns the public port for a port binding of the specified service.
-func (p *Project) Port(ctx context.Context, index int, protocol, serviceName, privatePort string) (string, error) {
- service, err := p.CreateService(serviceName)
- if err != nil {
- return "", err
- }
-
- containers, err := service.Containers(ctx)
- if err != nil {
- return "", err
- }
-
- if index < 1 || index > len(containers) {
- return "", fmt.Errorf("Invalid index %d", index)
- }
-
- return containers[index-1].Port(ctx, fmt.Sprintf("%s/%s", privatePort, protocol))
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_ps.go b/vendor/github.com/docker/libcompose/project/project_ps.go
deleted file mode 100644
index f02c3416f..000000000
--- a/vendor/github.com/docker/libcompose/project/project_ps.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package project
-
-import (
- "golang.org/x/net/context"
-)
-
-// Ps list containers for the specified services.
-func (p *Project) Ps(ctx context.Context, services ...string) (InfoSet, error) {
- allInfo := InfoSet{}
- for _, name := range p.ServiceConfigs.Keys() {
- service, err := p.CreateService(name)
- if err != nil {
- return nil, err
- }
-
- info, err := service.Info(ctx)
- if err != nil {
- return nil, err
- }
-
- allInfo = append(allInfo, info...)
- }
- return allInfo, nil
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_pull.go b/vendor/github.com/docker/libcompose/project/project_pull.go
deleted file mode 100644
index 5a7b0eedd..000000000
--- a/vendor/github.com/docker/libcompose/project/project_pull.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package project
-
-import (
- "golang.org/x/net/context"
-
- "github.com/docker/libcompose/project/events"
-)
-
-// Pull pulls the specified services (like docker pull).
-func (p *Project) Pull(ctx context.Context, services ...string) error {
- return p.forEach(services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
- wrapper.Do(nil, events.ServicePullStart, events.ServicePull, func(service Service) error {
- return service.Pull(ctx)
- })
- }), nil)
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_restart.go b/vendor/github.com/docker/libcompose/project/project_restart.go
deleted file mode 100644
index 0cb326523..000000000
--- a/vendor/github.com/docker/libcompose/project/project_restart.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package project
-
-import (
- "golang.org/x/net/context"
-
- "github.com/docker/libcompose/project/events"
-)
-
-// Restart restarts the specified services (like docker restart).
-func (p *Project) Restart(ctx context.Context, timeout int, services ...string) error {
- return p.perform(events.ProjectRestartStart, events.ProjectRestartDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
- wrapper.Do(wrappers, events.ServiceRestartStart, events.ServiceRestart, func(service Service) error {
- return service.Restart(ctx, timeout)
- })
- }), nil)
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_run.go b/vendor/github.com/docker/libcompose/project/project_run.go
deleted file mode 100644
index c5f223fcc..000000000
--- a/vendor/github.com/docker/libcompose/project/project_run.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package project
-
-import (
- "fmt"
-
- "golang.org/x/net/context"
-
- "github.com/docker/libcompose/project/events"
- "github.com/docker/libcompose/project/options"
-)
-
-// Run executes a one off command (like `docker run image command`).
-func (p *Project) Run(ctx context.Context, serviceName string, commandParts []string, opts options.Run) (int, error) {
- if !p.ServiceConfigs.Has(serviceName) {
- return 1, fmt.Errorf("%s is not defined in the template", serviceName)
- }
-
- if err := p.initialize(ctx); err != nil {
- return 1, err
- }
- var exitCode int
- err := p.forEach([]string{}, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
- wrapper.Do(wrappers, events.ServiceRunStart, events.ServiceRun, func(service Service) error {
- if service.Name() == serviceName {
- code, err := service.Run(ctx, commandParts, opts)
- exitCode = code
- return err
- }
- return nil
- })
- }), func(service Service) error {
- return service.Create(ctx, options.Create{})
- })
- return exitCode, err
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_scale.go b/vendor/github.com/docker/libcompose/project/project_scale.go
deleted file mode 100644
index 53d71978b..000000000
--- a/vendor/github.com/docker/libcompose/project/project_scale.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package project
-
-import (
- "fmt"
-
- "golang.org/x/net/context"
-
- log "github.com/Sirupsen/logrus"
-)
-
-// Scale scales the specified services.
-func (p *Project) Scale(ctx context.Context, timeout int, servicesScale map[string]int) error {
- // This code is a bit verbose but I wanted to parse everything up front
- order := make([]string, 0, 0)
- services := make(map[string]Service)
-
- for name := range servicesScale {
- if !p.ServiceConfigs.Has(name) {
- return fmt.Errorf("%s is not defined in the template", name)
- }
-
- service, err := p.CreateService(name)
- if err != nil {
- return fmt.Errorf("Failed to lookup service: %s: %v", service, err)
- }
-
- order = append(order, name)
- services[name] = service
- }
-
- for _, name := range order {
- scale := servicesScale[name]
- log.Infof("Setting scale %s=%d...", name, scale)
- err := services[name].Scale(ctx, scale, timeout)
- if err != nil {
- return fmt.Errorf("Failed to set the scale %s=%d: %v", name, scale, err)
- }
- }
- return nil
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_start.go b/vendor/github.com/docker/libcompose/project/project_start.go
deleted file mode 100644
index 8ffebdd3c..000000000
--- a/vendor/github.com/docker/libcompose/project/project_start.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package project
-
-import (
- "golang.org/x/net/context"
-
- "github.com/docker/libcompose/project/events"
-)
-
-// Start starts the specified services (like docker start).
-func (p *Project) Start(ctx context.Context, services ...string) error {
- return p.perform(events.ProjectStartStart, events.ProjectStartDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
- wrapper.Do(wrappers, events.ServiceStartStart, events.ServiceStart, func(service Service) error {
- return service.Start(ctx)
- })
- }), nil)
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_stop.go b/vendor/github.com/docker/libcompose/project/project_stop.go
deleted file mode 100644
index 16887f5b7..000000000
--- a/vendor/github.com/docker/libcompose/project/project_stop.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package project
-
-import (
- "golang.org/x/net/context"
-
- "github.com/docker/libcompose/project/events"
-)
-
-// Stop stops the specified services (like docker stop).
-func (p *Project) Stop(ctx context.Context, timeout int, services ...string) error {
- return p.perform(events.ProjectStopStart, events.ProjectStopDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
- wrapper.Do(nil, events.ServiceStopStart, events.ServiceStop, func(service Service) error {
- return service.Stop(ctx, timeout)
- })
- }), nil)
-}
diff --git a/vendor/github.com/docker/libcompose/project/project_unpause.go b/vendor/github.com/docker/libcompose/project/project_unpause.go
deleted file mode 100644
index 625129d8b..000000000
--- a/vendor/github.com/docker/libcompose/project/project_unpause.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package project
-
-import (
- "golang.org/x/net/context"
-
- "github.com/docker/libcompose/project/events"
-)
-
-// Unpause pauses the specified services containers (like docker pause).
-func (p *Project) Unpause(ctx context.Context, services ...string) error {
- return p.perform(events.ProjectUnpauseStart, events.ProjectUnpauseDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
- wrapper.Do(nil, events.ServiceUnpauseStart, events.ServiceUnpause, func(service Service) error {
- return service.Unpause(ctx)
- })
- }), nil)
-}
diff --git a/vendor/github.com/docker/libcompose/version/version.go b/vendor/github.com/docker/libcompose/version/version.go
deleted file mode 100644
index 820c98367..000000000
--- a/vendor/github.com/docker/libcompose/version/version.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package version
-
-var (
- // VERSION should be updated by hand at each release
- VERSION = "0.4.0-dev"
-
- // GITCOMMIT will be overwritten automatically by the build system
- GITCOMMIT = "HEAD"
-
- // BUILDTIME will be overwritten automatically by the build system
- BUILDTIME = ""
-
- // SHOWWARNING might be overwritten by the build system to not show the warning
- SHOWWARNING = "true"
-)
-
-// ShowWarning returns wether the warning should be printed or not
-func ShowWarning() bool {
- return SHOWWARNING != "false"
-}
diff --git a/vendor/github.com/rancher/rancher-compose/.dockerignore b/vendor/github.com/rancher/rancher-compose-executor/.dockerignore
similarity index 100%
rename from vendor/github.com/rancher/rancher-compose/.dockerignore
rename to vendor/github.com/rancher/rancher-compose-executor/.dockerignore
diff --git a/vendor/github.com/rancher/rancher-compose/.drone.yml b/vendor/github.com/rancher/rancher-compose-executor/.drone.yml
similarity index 100%
rename from vendor/github.com/rancher/rancher-compose/.drone.yml
rename to vendor/github.com/rancher/rancher-compose-executor/.drone.yml
diff --git a/vendor/github.com/rancher/rancher-compose/.gitignore b/vendor/github.com/rancher/rancher-compose-executor/.gitignore
similarity index 100%
rename from vendor/github.com/rancher/rancher-compose/.gitignore
rename to vendor/github.com/rancher/rancher-compose-executor/.gitignore
diff --git a/vendor/github.com/rancher/rancher-compose/Dockerfile.dapper b/vendor/github.com/rancher/rancher-compose-executor/Dockerfile.dapper
similarity index 89%
rename from vendor/github.com/rancher/rancher-compose/Dockerfile.dapper
rename to vendor/github.com/rancher/rancher-compose-executor/Dockerfile.dapper
index b945c4d5d..0de969bf4 100644
--- a/vendor/github.com/rancher/rancher-compose/Dockerfile.dapper
+++ b/vendor/github.com/rancher/rancher-compose-executor/Dockerfile.dapper
@@ -7,7 +7,7 @@ RUN apt-get update && \
apt-get install -y --no-install-recommends default-jre python-pip zip xz-utils rsync
RUN pip install --upgrade pip==6.0.3 tox==1.8.1 virtualenv==12.0.4
ENV PATH /go/bin:$PATH
-ENV DAPPER_SOURCE /go/src/github.com/rancher/rancher-compose
+ENV DAPPER_SOURCE /go/src/github.com/rancher/rancher-compose-executor
ENV DAPPER_OUTPUT bin dist
ENV DAPPER_DOCKER_SOCKET true
ENV DAPPER_ENV TAG REPO CROSS
diff --git a/vendor/github.com/rancher/rancher-compose/LICENSE b/vendor/github.com/rancher/rancher-compose-executor/LICENSE
similarity index 100%
rename from vendor/github.com/rancher/rancher-compose/LICENSE
rename to vendor/github.com/rancher/rancher-compose-executor/LICENSE
diff --git a/vendor/github.com/rancher/rancher-compose/Makefile b/vendor/github.com/rancher/rancher-compose-executor/Makefile
similarity index 100%
rename from vendor/github.com/rancher/rancher-compose/Makefile
rename to vendor/github.com/rancher/rancher-compose-executor/Makefile
diff --git a/vendor/github.com/rancher/rancher-compose/README.md b/vendor/github.com/rancher/rancher-compose-executor/README.md
similarity index 100%
rename from vendor/github.com/rancher/rancher-compose/README.md
rename to vendor/github.com/rancher/rancher-compose-executor/README.md
diff --git a/vendor/github.com/rancher/rancher-compose/app/app.go b/vendor/github.com/rancher/rancher-compose-executor/app/app.go
similarity index 63%
rename from vendor/github.com/rancher/rancher-compose/app/app.go
rename to vendor/github.com/rancher/rancher-compose-executor/app/app.go
index e8c55ff16..fd8194fdf 100644
--- a/vendor/github.com/rancher/rancher-compose/app/app.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/app/app.go
@@ -1,44 +1,44 @@
package app
import (
+ "os"
+ "strings"
+
"golang.org/x/net/context"
"github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/cli/app"
- "github.com/docker/libcompose/cli/command"
"github.com/docker/libcompose/cli/logger"
- "github.com/docker/libcompose/lookup"
- "github.com/docker/libcompose/project"
- "github.com/docker/libcompose/project/options"
- rLookup "github.com/rancher/rancher-compose/lookup"
- "github.com/rancher/rancher-compose/rancher"
- "github.com/rancher/rancher-compose/upgrade"
+ "github.com/rancher/rancher-compose-executor/lookup"
+ "github.com/rancher/rancher-compose-executor/project"
+ "github.com/rancher/rancher-compose-executor/project/options"
+ "github.com/rancher/rancher-compose-executor/rancher"
+ "github.com/rancher/rancher-compose-executor/upgrade"
"github.com/urfave/cli"
)
-type ProjectFactory struct {
+type RancherProjectFactory struct {
}
-func (p *ProjectFactory) Create(c *cli.Context) (project.APIProject, error) {
+func (p *RancherProjectFactory) Create(c *cli.Context) (*project.Project, error) {
rancherComposeFile, err := rancher.ResolveRancherCompose(c.GlobalString("file"),
c.GlobalString("rancher-file"))
if err != nil {
return nil, err
}
- qLookup, err := rLookup.NewQuestionLookup(rancherComposeFile, &lookup.OsEnvLookup{})
+ qLookup, err := lookup.NewQuestionLookup(rancherComposeFile, &lookup.OsEnvLookup{})
if err != nil {
return nil, err
}
- envLookup, err := rLookup.NewFileEnvLookup(c.GlobalString("env-file"), qLookup)
+ envLookup, err := lookup.NewFileEnvLookup(c.GlobalString("env-file"), qLookup)
if err != nil {
return nil, err
}
context := &rancher.Context{
Context: project.Context{
- ResourceLookup: &rLookup.FileResourceLookup{},
+ ResourceLookup: &lookup.FileResourceLookup{},
EnvironmentLookup: envLookup,
LoggerFactory: logger.NewColorLoggerFactory(),
},
@@ -49,11 +49,11 @@ func (p *ProjectFactory) Create(c *cli.Context) (project.APIProject, error) {
PullCached: c.Bool("cached"),
Uploader: &rancher.S3Uploader{},
Args: c.Args(),
- BindingsFile: c.GlobalString("bindings-file"),
}
- qLookup.Context = context
+ // TODO
+ //qLookup.Context = context
- command.Populate(&context.Context, c)
+ Populate(&context.Context, c)
context.Upgrade = c.Bool("upgrade") || c.Bool("force-upgrade")
context.ForceUpgrade = c.Bool("force-upgrade")
@@ -66,11 +66,43 @@ func (p *ProjectFactory) Create(c *cli.Context) (project.APIProject, error) {
return rancher.NewProject(context)
}
-func UpgradeCommand(factory app.ProjectFactory) cli.Command {
+func Populate(context *project.Context, c *cli.Context) {
+ // urfave/cli does not distinguish whether the first string in the slice comes from the envvar
+ // or is from a flag. Worse off, it appends the flag values to the envvar value instead of
+ // overriding it. To ensure the multifile envvar case is always handled, the first string
+ // must always be split. It gives a more consistent behavior, then, to split each string in
+ // the slice.
+ for _, v := range c.GlobalStringSlice("file") {
+ context.ComposeFiles = append(context.ComposeFiles, strings.Split(v, string(os.PathListSeparator))...)
+ }
+
+ if len(context.ComposeFiles) == 0 {
+ context.ComposeFiles = []string{"docker-compose.yml"}
+ if _, err := os.Stat("docker-compose.override.yml"); err == nil {
+ context.ComposeFiles = append(context.ComposeFiles, "docker-compose.override.yml")
+ }
+ }
+
+ context.ProjectName = c.GlobalString("project-name")
+}
+
+type ProjectAction func(project *project.Project, c *cli.Context) error
+
+func WithProject(factory ProjectFactory, action ProjectAction) func(context *cli.Context) error {
+ return func(context *cli.Context) error {
+ p, err := factory.Create(context)
+ if err != nil {
+ logrus.Fatalf("Failed to read project: %v", err)
+ }
+ return action(p, context)
+ }
+}
+
+func UpgradeCommand(factory ProjectFactory) cli.Command {
return cli.Command{
Name: "upgrade",
Usage: "Perform rolling upgrade between services",
- Action: app.WithProject(factory, Upgrade),
+ Action: WithProject(factory, Upgrade),
Flags: []cli.Flag{
cli.IntFlag{
Name: "batch-size",
@@ -107,31 +139,11 @@ func UpgradeCommand(factory app.ProjectFactory) cli.Command {
}
}
-func RestartCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "restart",
- Usage: "Restart services",
- Action: app.WithProject(factory, app.ProjectRestart),
- Flags: []cli.Flag{
- cli.IntFlag{
- Name: "batch-size",
- Usage: "Number of containers to restart at once",
- Value: 1,
- },
- cli.IntFlag{
- Name: "interval",
- Usage: "Restart interval in milliseconds",
- Value: 0,
- },
- },
- }
-}
-
-func UpCommand(factory app.ProjectFactory) cli.Command {
+func UpCommand(factory ProjectFactory) cli.Command {
return cli.Command{
Name: "up",
Usage: "Bring all services up",
- Action: app.WithProject(factory, ProjectUp),
+ Action: WithProject(factory, ProjectUp),
Flags: []cli.Flag{
cli.BoolFlag{
Name: "pull, p",
@@ -171,29 +183,15 @@ func UpCommand(factory app.ProjectFactory) cli.Command {
}
}
-func PullCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "pull",
- Usage: "Pulls images for services",
- Action: app.WithProject(factory, app.ProjectPull),
- Flags: []cli.Flag{
- cli.BoolFlag{
- Name: "cached, c",
- Usage: "Only update hosts that have the image cached, don't pull new",
- },
- },
- }
-}
-
-func CreateCommand(factory app.ProjectFactory) cli.Command {
+func CreateCommand(factory ProjectFactory) cli.Command {
return cli.Command{
Name: "create",
Usage: "Create all services but do not start",
- Action: app.WithProject(factory, ProjectCreate),
+ Action: WithProject(factory, ProjectCreate),
}
}
-func ProjectCreate(p project.APIProject, c *cli.Context) error {
+func ProjectCreate(p *project.Project, c *cli.Context) error {
if err := p.Create(context.Background(), options.Create{}, c.Args()...); err != nil {
return err
}
@@ -206,7 +204,7 @@ func ProjectCreate(p project.APIProject, c *cli.Context) error {
return nil
}
-func ProjectUp(p project.APIProject, c *cli.Context) error {
+func ProjectUp(p *project.Project, c *cli.Context) error {
if err := p.Create(context.Background(), options.Create{}, c.Args()...); err != nil {
return err
}
@@ -224,7 +222,7 @@ func ProjectUp(p project.APIProject, c *cli.Context) error {
return nil
}
-func Upgrade(p project.APIProject, c *cli.Context) error {
+func Upgrade(p *project.Project, c *cli.Context) error {
args := c.Args()
if len(args) != 2 {
logrus.Fatalf("Please pass arguments in the form: [from service] [to service]")
@@ -245,20 +243,3 @@ func Upgrade(p project.APIProject, c *cli.Context) error {
}
return nil
}
-
-// StopCommand defines the libcompose stop subcommand.
-func StopCommand(factory app.ProjectFactory) cli.Command {
- return cli.Command{
- Name: "stop",
- ShortName: "down",
- Usage: "Stop services",
- Action: app.WithProject(factory, app.ProjectStop),
- Flags: []cli.Flag{
- cli.IntFlag{
- Name: "timeout,t",
- Usage: "Specify a shutdown timeout in seconds.",
- Value: 10,
- },
- },
- }
-}
diff --git a/vendor/github.com/rancher/rancher-compose-executor/app/types.go b/vendor/github.com/rancher/rancher-compose-executor/app/types.go
new file mode 100644
index 000000000..7affe6ba9
--- /dev/null
+++ b/vendor/github.com/rancher/rancher-compose-executor/app/types.go
@@ -0,0 +1,10 @@
+package app
+
+import (
+ "github.com/rancher/rancher-compose-executor/project"
+ "github.com/urfave/cli"
+)
+
+type ProjectFactory interface {
+ Create(c *cli.Context) (*project.Project, error)
+}
diff --git a/vendor/github.com/docker/libcompose/config/convert.go b/vendor/github.com/rancher/rancher-compose-executor/config/convert.go
similarity index 100%
rename from vendor/github.com/docker/libcompose/config/convert.go
rename to vendor/github.com/rancher/rancher-compose-executor/config/convert.go
diff --git a/vendor/github.com/docker/libcompose/config/hash.go b/vendor/github.com/rancher/rancher-compose-executor/config/hash.go
similarity index 100%
rename from vendor/github.com/docker/libcompose/config/hash.go
rename to vendor/github.com/rancher/rancher-compose-executor/config/hash.go
diff --git a/vendor/github.com/docker/libcompose/config/interpolation.go b/vendor/github.com/rancher/rancher-compose-executor/config/interpolation.go
similarity index 100%
rename from vendor/github.com/docker/libcompose/config/interpolation.go
rename to vendor/github.com/rancher/rancher-compose-executor/config/interpolation.go
diff --git a/vendor/github.com/docker/libcompose/config/merge.go b/vendor/github.com/rancher/rancher-compose-executor/config/merge.go
similarity index 87%
rename from vendor/github.com/docker/libcompose/config/merge.go
rename to vendor/github.com/rancher/rancher-compose-executor/config/merge.go
index eb4f229a1..9aaeb6a0a 100644
--- a/vendor/github.com/docker/libcompose/config/merge.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/config/merge.go
@@ -9,6 +9,7 @@ import (
"github.com/docker/docker/pkg/urlutil"
"github.com/docker/libcompose/utils"
composeYaml "github.com/docker/libcompose/yaml"
+ "github.com/rancher/rancher-compose-executor/template"
"gopkg.in/yaml.v2"
)
@@ -23,16 +24,16 @@ var (
}
)
-// CreateConfig unmarshals bytes to config and creates config based on version
-func CreateConfig(bytes []byte) (*Config, error) {
+// CreateConfig unmarshals contents to config and creates config based on version
+func CreateConfig(contents []byte) (*Config, error) {
var config Config
- if err := yaml.Unmarshal(bytes, &config); err != nil {
+ if err := yaml.Unmarshal(contents, &config); err != nil {
return nil, err
}
if config.Version != "2" {
var baseRawServices RawServiceMap
- if err := yaml.Unmarshal(bytes, &baseRawServices); err != nil {
+ if err := yaml.Unmarshal(contents, &baseRawServices); err != nil {
return nil, err
}
config.Services = baseRawServices
@@ -49,12 +50,18 @@ func CreateConfig(bytes []byte) (*Config, error) {
}
// Merge merges a compose file into an existing set of service configs
-func Merge(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, bytes []byte, options *ParseOptions) (string, map[string]*ServiceConfig, map[string]*VolumeConfig, map[string]*NetworkConfig, error) {
+func Merge(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, contents []byte, options *ParseOptions) (string, map[string]*ServiceConfig, map[string]*VolumeConfig, map[string]*NetworkConfig, error) {
if options == nil {
options = &defaultParseOptions
}
- config, err := CreateConfig(bytes)
+ var err error
+ contents, err = template.Apply(contents, environmentLookup.Variables())
+ if err != nil {
+ return "", nil, nil, nil, err
+ }
+
+ config, err := CreateConfig(contents)
if err != nil {
return "", nil, nil, nil, err
}
@@ -121,6 +128,11 @@ func Merge(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup
if err := utils.Convert(config.Volumes, &volumes); err != nil {
return "", nil, nil, nil, err
}
+ for i, volume := range volumes {
+ if volume == nil {
+ volumes[i] = &VolumeConfig{}
+ }
+ }
if err := utils.Convert(config.Networks, &networks); err != nil {
return "", nil, nil, nil, err
}
diff --git a/vendor/github.com/docker/libcompose/config/merge_v1.go b/vendor/github.com/rancher/rancher-compose-executor/config/merge_v1.go
similarity index 100%
rename from vendor/github.com/docker/libcompose/config/merge_v1.go
rename to vendor/github.com/rancher/rancher-compose-executor/config/merge_v1.go
diff --git a/vendor/github.com/docker/libcompose/config/merge_v2.go b/vendor/github.com/rancher/rancher-compose-executor/config/merge_v2.go
similarity index 100%
rename from vendor/github.com/docker/libcompose/config/merge_v2.go
rename to vendor/github.com/rancher/rancher-compose-executor/config/merge_v2.go
diff --git a/vendor/github.com/docker/libcompose/config/schema.go b/vendor/github.com/rancher/rancher-compose-executor/config/schema.go
similarity index 98%
rename from vendor/github.com/docker/libcompose/config/schema.go
rename to vendor/github.com/rancher/rancher-compose-executor/config/schema.go
index 1ef523fbe..ad5c2f3df 100644
--- a/vendor/github.com/docker/libcompose/config/schema.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/config/schema.go
@@ -21,7 +21,7 @@ var schemaDataV1 = `{
"properties": {
"blkio_weight": {"type": ["number", "string"]},
- "blkio_weight_devices": {"$ref": "#/definitions/list_of_strings"},
+ "blkio_weight_device": {"$ref": "#/definitions/list_of_strings"},
"build": {"type": "string"},
"cap_add": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"cap_drop": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
@@ -95,6 +95,7 @@ var schemaDataV1 = `{
"ipc": {"type": "string"},
"isolation": {"type": "string"},
"labels": {"$ref": "#/definitions/list_or_dict"},
+ "lb_config": {"type": "object"},
"links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"load_balancer_config": {"type": "object"},
"log_driver": {"type": "string"},
@@ -163,6 +164,7 @@ var schemaDataV1 = `{
},
"user": {"type": "string"},
"userdata": {"type": "string"},
+ "uts": {"type": "string"},
"vcpu": {"type": ["number", "string"]},
"volumes": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"volume_driver": {"type": "string"},
@@ -247,7 +249,7 @@ var servicesSchemaDataV2 = `{
"properties": {
"blkio_weight": {"type": ["number", "string"]},
- "blkio_weight_devices": {"$ref": "#/definitions/list_of_strings"},
+ "blkio_weight_device": {"$ref": "#/definitions/list_of_strings"},
"build": {
"oneOf": [
{"type": "string"},
@@ -334,6 +336,7 @@ var servicesSchemaDataV2 = `{
"ipc": {"type": "string"},
"isolation": {"type": "string"},
"labels": {"$ref": "#/definitions/list_or_dict"},
+ "lb_config": {"type": "object"},
"links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"load_balancer_config": {"type": "object"},
@@ -438,6 +441,7 @@ var servicesSchemaDataV2 = `{
},
"user": {"type": "string"},
"userdata": {"type": "string"},
+ "uts": {"type": "string"},
"vcpu": {"type": ["number", "string"]},
"volumes": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"volume_driver": {"type": "string"},
diff --git a/vendor/github.com/docker/libcompose/config/schema_helpers.go b/vendor/github.com/rancher/rancher-compose-executor/config/schema_helpers.go
similarity index 100%
rename from vendor/github.com/docker/libcompose/config/schema_helpers.go
rename to vendor/github.com/rancher/rancher-compose-executor/config/schema_helpers.go
diff --git a/vendor/github.com/docker/libcompose/config/types.go b/vendor/github.com/rancher/rancher-compose-executor/config/types.go
similarity index 99%
rename from vendor/github.com/docker/libcompose/config/types.go
rename to vendor/github.com/rancher/rancher-compose-executor/config/types.go
index ac8d156c6..ae0605f19 100644
--- a/vendor/github.com/docker/libcompose/config/types.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/config/types.go
@@ -9,6 +9,7 @@ import (
// EnvironmentLookup defines methods to provides environment variable loading.
type EnvironmentLookup interface {
Lookup(key string, config *ServiceConfig) []string
+ Variables() map[string]string
}
// ResourceLookup defines methods to provides file loading.
diff --git a/vendor/github.com/docker/libcompose/config/utils.go b/vendor/github.com/rancher/rancher-compose-executor/config/utils.go
similarity index 100%
rename from vendor/github.com/docker/libcompose/config/utils.go
rename to vendor/github.com/rancher/rancher-compose-executor/config/utils.go
diff --git a/vendor/github.com/docker/libcompose/config/validation.go b/vendor/github.com/rancher/rancher-compose-executor/config/validation.go
similarity index 100%
rename from vendor/github.com/docker/libcompose/config/validation.go
rename to vendor/github.com/rancher/rancher-compose-executor/config/validation.go
diff --git a/vendor/github.com/docker/libcompose/docker/service/convert.go b/vendor/github.com/rancher/rancher-compose-executor/convert/convert.go
similarity index 98%
rename from vendor/github.com/docker/libcompose/docker/service/convert.go
rename to vendor/github.com/rancher/rancher-compose-executor/convert/convert.go
index 5455977f1..d207c229e 100644
--- a/vendor/github.com/docker/libcompose/docker/service/convert.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/convert/convert.go
@@ -1,4 +1,4 @@
-package service
+package convert
import (
"fmt"
@@ -12,10 +12,10 @@ import (
"github.com/docker/docker/runconfig/opts"
"github.com/docker/go-connections/nat"
"github.com/docker/go-units"
- "github.com/docker/libcompose/config"
- "github.com/docker/libcompose/project"
"github.com/docker/libcompose/utils"
"github.com/docker/libcompose/yaml"
+ "github.com/rancher/rancher-compose-executor/config"
+ "github.com/rancher/rancher-compose-executor/project"
)
// ConfigWrapper wraps Config, HostConfig and NetworkingConfig for a container.
diff --git a/vendor/github.com/rancher/rancher-compose/digest/hash.go b/vendor/github.com/rancher/rancher-compose-executor/digest/hash.go
similarity index 98%
rename from vendor/github.com/rancher/rancher-compose/digest/hash.go
rename to vendor/github.com/rancher/rancher-compose-executor/digest/hash.go
index d156e7cd4..871fba0f2 100644
--- a/vendor/github.com/rancher/rancher-compose/digest/hash.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/digest/hash.go
@@ -10,7 +10,7 @@ import (
"github.com/docker/libcompose/utils"
"github.com/rancher/go-rancher/v2"
- rUtils "github.com/rancher/rancher-compose/utils"
+ rUtils "github.com/rancher/rancher-compose-executor/utils"
)
const (
diff --git a/vendor/github.com/docker/libcompose/docker/service/utils.go b/vendor/github.com/rancher/rancher-compose-executor/docker/service/utils.go
similarity index 96%
rename from vendor/github.com/docker/libcompose/docker/service/utils.go
rename to vendor/github.com/rancher/rancher-compose-executor/docker/service/utils.go
index 5b28c887f..7f9be7e7e 100644
--- a/vendor/github.com/docker/libcompose/docker/service/utils.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/docker/service/utils.go
@@ -2,7 +2,7 @@ package service
import (
"github.com/docker/docker/api/types/container"
- "github.com/docker/libcompose/project"
+ "github.com/rancher/rancher-compose-executor/project"
)
// DefaultDependentServices return the dependent services (as an array of ServiceRelationship)
diff --git a/vendor/github.com/docker/libcompose/lookup/composable.go b/vendor/github.com/rancher/rancher-compose-executor/lookup/composable.go
similarity index 70%
rename from vendor/github.com/docker/libcompose/lookup/composable.go
rename to vendor/github.com/rancher/rancher-compose-executor/lookup/composable.go
index ff76480b3..1eeff7e9c 100644
--- a/vendor/github.com/docker/libcompose/lookup/composable.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/lookup/composable.go
@@ -1,7 +1,8 @@
package lookup
import (
- "github.com/docker/libcompose/config"
+ "github.com/rancher/rancher-compose-executor/config"
+ "github.com/rancher/rancher-compose-executor/utils"
)
// ComposableEnvLookup is a structure that implements the project.EnvironmentLookup interface.
@@ -23,3 +24,11 @@ func (l *ComposableEnvLookup) Lookup(key string, config *config.ServiceConfig) [
}
return result
}
+
+func (l *ComposableEnvLookup) Variables() map[string]string {
+ variables := map[string]string{}
+ for _, lookup := range l.Lookups {
+ variables = utils.MapUnion(variables, lookup.Variables())
+ }
+ return variables
+}
diff --git a/vendor/github.com/rancher/rancher-compose/lookup/env.go b/vendor/github.com/rancher/rancher-compose-executor/lookup/env.go
similarity index 83%
rename from vendor/github.com/rancher/rancher-compose/lookup/env.go
rename to vendor/github.com/rancher/rancher-compose-executor/lookup/env.go
index afde3cae7..74281dd15 100644
--- a/vendor/github.com/rancher/rancher-compose/lookup/env.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/lookup/env.go
@@ -7,7 +7,8 @@ import (
"strings"
"github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/config"
+ "github.com/rancher/rancher-compose-executor/config"
+ "github.com/rancher/rancher-compose-executor/utils"
)
type FileEnvLookup struct {
@@ -57,3 +58,7 @@ func (f *FileEnvLookup) Lookup(key string, config *config.ServiceConfig) []strin
return f.parent.Lookup(key, config)
}
+
+func (f *FileEnvLookup) Variables() map[string]string {
+ return utils.MapUnion(f.variables, f.parent.Variables())
+}
diff --git a/vendor/github.com/docker/libcompose/lookup/envfile.go b/vendor/github.com/rancher/rancher-compose-executor/lookup/envfile.go
similarity index 71%
rename from vendor/github.com/docker/libcompose/lookup/envfile.go
rename to vendor/github.com/rancher/rancher-compose-executor/lookup/envfile.go
index 62241255c..d7ddb0b37 100644
--- a/vendor/github.com/docker/libcompose/lookup/envfile.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/lookup/envfile.go
@@ -4,7 +4,8 @@ import (
"strings"
"github.com/docker/docker/runconfig/opts"
- "github.com/docker/libcompose/config"
+ "github.com/docker/libcompose/yaml"
+ "github.com/rancher/rancher-compose-executor/config"
)
// EnvfileLookup is a structure that implements the project.EnvironmentLookup interface.
@@ -29,3 +30,12 @@ func (l *EnvfileLookup) Lookup(key string, config *config.ServiceConfig) []strin
}
return []string{}
}
+
+func (l *EnvfileLookup) Variables() map[string]string {
+ envs, err := opts.ParseEnvFile(l.Path)
+ if err != nil {
+ return map[string]string{}
+ }
+ environ := yaml.MaporEqualSlice(envs)
+ return environ.ToMap()
+}
diff --git a/vendor/github.com/docker/libcompose/lookup/file.go b/vendor/github.com/rancher/rancher-compose-executor/lookup/file.go
similarity index 100%
rename from vendor/github.com/docker/libcompose/lookup/file.go
rename to vendor/github.com/rancher/rancher-compose-executor/lookup/file.go
diff --git a/vendor/github.com/rancher/rancher-compose/lookup/map_env.go b/vendor/github.com/rancher/rancher-compose-executor/lookup/map_env.go
similarity index 55%
rename from vendor/github.com/rancher/rancher-compose/lookup/map_env.go
rename to vendor/github.com/rancher/rancher-compose-executor/lookup/map_env.go
index 5aa007984..e892ad362 100644
--- a/vendor/github.com/rancher/rancher-compose/lookup/map_env.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/lookup/map_env.go
@@ -3,7 +3,7 @@ package lookup
import (
"fmt"
- "github.com/docker/libcompose/config"
+ "github.com/rancher/rancher-compose-executor/config"
)
type MapEnvLookup struct {
@@ -16,3 +16,11 @@ func (m *MapEnvLookup) Lookup(key string, config *config.ServiceConfig) []string
}
return []string{}
}
+
+func (m *MapEnvLookup) Variables() map[string]string {
+ variables := map[string]string{}
+ for k, v := range m.Env {
+ variables[k] = fmt.Sprint(v)
+ }
+ return variables
+}
diff --git a/vendor/github.com/rancher/rancher-compose/lookup/questions.go b/vendor/github.com/rancher/rancher-compose-executor/lookup/questions.go
similarity index 90%
rename from vendor/github.com/rancher/rancher-compose/lookup/questions.go
rename to vendor/github.com/rancher/rancher-compose-executor/lookup/questions.go
index 2a0fa5061..1e96985d3 100644
--- a/vendor/github.com/rancher/rancher-compose/lookup/questions.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/lookup/questions.go
@@ -7,10 +7,10 @@ import (
"os"
"strings"
- "github.com/docker/libcompose/config"
"github.com/docker/libcompose/utils"
"github.com/rancher/rancher-catalog-service/model"
- "github.com/rancher/rancher-compose/rancher"
+ "github.com/rancher/rancher-compose-executor/config"
+ rUtils "github.com/rancher/rancher-compose-executor/utils"
"gopkg.in/yaml.v2"
)
@@ -22,7 +22,6 @@ type QuestionLookup struct {
parent config.EnvironmentLookup
questions map[string]model.Question
variables map[string]string
- Context *rancher.Context
}
func NewQuestionLookup(file string, parent config.EnvironmentLookup) (*QuestionLookup, error) {
@@ -112,15 +111,6 @@ func (f *QuestionLookup) Lookup(key string, config *config.ServiceConfig) []stri
return join(key, v)
}
- if f.Context != nil {
- stack, err := f.Context.LoadStack()
- if err == nil && stack != nil {
- if v, ok := stack.Environment[key]; ok {
- return join(key, fmt.Sprintf("%v", v))
- }
- }
- }
-
if f.parent != nil {
parentResult := f.parent.Lookup(key, config)
if len(parentResult) > 0 {
@@ -160,3 +150,8 @@ func ask(question model.Question) string {
return answer
}
+
+func (f *QuestionLookup) Variables() map[string]string {
+ // TODO: precedence
+ return rUtils.MapUnion(f.variables, f.parent.Variables())
+}
diff --git a/vendor/github.com/docker/libcompose/lookup/simple_env.go b/vendor/github.com/rancher/rancher-compose-executor/lookup/simple_env.go
similarity index 75%
rename from vendor/github.com/docker/libcompose/lookup/simple_env.go
rename to vendor/github.com/rancher/rancher-compose-executor/lookup/simple_env.go
index 40ce12843..b06036fc4 100644
--- a/vendor/github.com/docker/libcompose/lookup/simple_env.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/lookup/simple_env.go
@@ -4,7 +4,8 @@ import (
"fmt"
"os"
- "github.com/docker/libcompose/config"
+ "github.com/docker/libcompose/yaml"
+ "github.com/rancher/rancher-compose-executor/config"
)
// OsEnvLookup is a "bare" structure that implements the project.EnvironmentLookup interface
@@ -22,3 +23,8 @@ func (o *OsEnvLookup) Lookup(key string, config *config.ServiceConfig) []string
}
return []string{fmt.Sprintf("%s=%s", key, ret)}
}
+
+func (o *OsEnvLookup) Variables() map[string]string {
+ environ := yaml.MaporEqualSlice(os.Environ())
+ return environ.ToMap()
+}
diff --git a/vendor/github.com/rancher/rancher-compose/preprocess/project.go b/vendor/github.com/rancher/rancher-compose-executor/preprocess/preprocess.go
similarity index 56%
rename from vendor/github.com/rancher/rancher-compose/preprocess/project.go
rename to vendor/github.com/rancher/rancher-compose-executor/preprocess/preprocess.go
index cd3a33468..f857c3726 100644
--- a/vendor/github.com/rancher/rancher-compose/preprocess/project.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/preprocess/preprocess.go
@@ -1,69 +1,27 @@
package preprocess
import (
- "encoding/json"
"fmt"
"strconv"
- "github.com/docker/libcompose/config"
- "github.com/rancher/rancher-compose/utils"
+ "github.com/rancher/rancher-compose-executor/config"
)
-type BindingProperty struct {
- Services map[string]Service `json:"services"`
-}
-
-type Service struct {
- Labels map[string]interface{} `json:"labels"`
- Ports []interface{} `json:"ports"`
-}
-
-func PreprocessServiceMap(bindingsBytes []byte) func(serviceMap config.RawServiceMap) (config.RawServiceMap, error) {
- return func(serviceMap config.RawServiceMap) (config.RawServiceMap, error) {
- newServiceMap := make(config.RawServiceMap)
-
- var binding BindingProperty
- var bindingsServices []string
-
- if bindingsBytes != nil {
- err := json.Unmarshal(bindingsBytes, &binding)
- if err != nil {
- return nil, err
- }
-
- for k := range binding.Services {
- bindingsServices = append(bindingsServices, k)
- }
- }
-
- for k, v := range serviceMap {
- newServiceMap[k] = make(config.RawService)
- if bindingsBytes != nil {
- if utils.Contains(bindingsServices, k) == true {
- labelMap := make(map[interface{}]interface{})
- for key, value := range binding.Services[k].Labels {
- labelMap[interface{}(key)] = value
- }
- if len(labelMap) != 0 {
- v["labels"] = labelMap
- }
- if len(binding.Services[k].Ports) > 0 {
- v["ports"] = binding.Services[k].Ports
- }
- }
- }
- for k2, v2 := range v {
- if k2 == "environment" || k2 == "labels" {
- newServiceMap[k][k2] = Preprocess(v2, true)
- } else {
- newServiceMap[k][k2] = Preprocess(v2, false)
- }
+func PreprocessServiceMap(serviceMap config.RawServiceMap) (config.RawServiceMap, error) {
+ newServiceMap := make(config.RawServiceMap)
+ for k, v := range serviceMap {
+ newServiceMap[k] = make(config.RawService)
+ for k2, v2 := range v {
+ if k2 == "environment" || k2 == "labels" {
+ newServiceMap[k][k2] = Preprocess(v2, true)
+ } else {
+ newServiceMap[k][k2] = Preprocess(v2, false)
}
}
-
- return newServiceMap, nil
}
+
+ return newServiceMap, nil
}
func Preprocess(item interface{}, replaceTypes bool) interface{} {
diff --git a/vendor/github.com/docker/libcompose/project/context.go b/vendor/github.com/rancher/rancher-compose-executor/project/context.go
similarity index 97%
rename from vendor/github.com/docker/libcompose/project/context.go
rename to vendor/github.com/rancher/rancher-compose-executor/project/context.go
index 94019306b..e9a2dd027 100644
--- a/vendor/github.com/docker/libcompose/project/context.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/project/context.go
@@ -10,8 +10,8 @@ import (
"strings"
"github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/config"
"github.com/docker/libcompose/logger"
+ "github.com/rancher/rancher-compose-executor/config"
)
var projectRegexp = regexp.MustCompile("[^a-zA-Z0-9_.-]")
@@ -24,7 +24,6 @@ type Context struct {
ProjectName string
isOpen bool
ServiceFactory ServiceFactory
- NetworksFactory NetworksFactory
VolumesFactory VolumesFactory
EnvironmentLookup config.EnvironmentLookup
ResourceLookup config.ResourceLookup
diff --git a/vendor/github.com/rancher/rancher-compose-executor/project/empty.go b/vendor/github.com/rancher/rancher-compose-executor/project/empty.go
new file mode 100644
index 000000000..9bbab1e43
--- /dev/null
+++ b/vendor/github.com/rancher/rancher-compose-executor/project/empty.go
@@ -0,0 +1,51 @@
+package project
+
+import (
+ "golang.org/x/net/context"
+
+ "github.com/rancher/rancher-compose-executor/config"
+ "github.com/rancher/rancher-compose-executor/project/options"
+)
+
+// this ensures EmptyService implements Service
+// useful since it's easy to forget adding new functions to EmptyService
+var _ Service = (*EmptyService)(nil)
+
+// EmptyService is a struct that implements Service but does nothing.
+type EmptyService struct {
+}
+
+// Create implements Service.Create but does nothing.
+func (e *EmptyService) Create(ctx context.Context, options options.Create) error {
+ return nil
+}
+
+// Build implements Service.Build but does nothing.
+func (e *EmptyService) Build(ctx context.Context, buildOptions options.Build) error {
+ return nil
+}
+
+// Up implements Service.Up but does nothing.
+func (e *EmptyService) Up(ctx context.Context, options options.Up) error {
+ return nil
+}
+
+// Log implements Service.Log but does nothing.
+func (e *EmptyService) Log(ctx context.Context, follow bool) error {
+ return nil
+}
+
+// DependentServices implements Service.DependentServices with empty slice.
+func (e *EmptyService) DependentServices() []ServiceRelationship {
+ return []ServiceRelationship{}
+}
+
+// Config implements Service.Config with empty config.
+func (e *EmptyService) Config() *config.ServiceConfig {
+ return &config.ServiceConfig{}
+}
+
+// Name implements Service.Name with empty name.
+func (e *EmptyService) Name() string {
+ return ""
+}
diff --git a/vendor/github.com/docker/libcompose/project/events/events.go b/vendor/github.com/rancher/rancher-compose-executor/project/events/events.go
similarity index 100%
rename from vendor/github.com/docker/libcompose/project/events/events.go
rename to vendor/github.com/rancher/rancher-compose-executor/project/events/events.go
diff --git a/vendor/github.com/docker/libcompose/project/listener.go b/vendor/github.com/rancher/rancher-compose-executor/project/listener.go
similarity index 96%
rename from vendor/github.com/docker/libcompose/project/listener.go
rename to vendor/github.com/rancher/rancher-compose-executor/project/listener.go
index 0110036a0..cc2708067 100644
--- a/vendor/github.com/docker/libcompose/project/listener.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/project/listener.go
@@ -4,7 +4,7 @@ import (
"bytes"
"github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/project/events"
+ "github.com/rancher/rancher-compose-executor/project/events"
)
var (
diff --git a/vendor/github.com/docker/libcompose/project/options/types.go b/vendor/github.com/rancher/rancher-compose-executor/project/options/types.go
similarity index 100%
rename from vendor/github.com/docker/libcompose/project/options/types.go
rename to vendor/github.com/rancher/rancher-compose-executor/project/options/types.go
diff --git a/vendor/github.com/docker/libcompose/project/project.go b/vendor/github.com/rancher/rancher-compose-executor/project/project.go
similarity index 85%
rename from vendor/github.com/docker/libcompose/project/project.go
rename to vendor/github.com/rancher/rancher-compose-executor/project/project.go
index b07de8271..f2c62ef31 100644
--- a/vendor/github.com/docker/libcompose/project/project.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/project/project.go
@@ -10,12 +10,11 @@ import (
"golang.org/x/net/context"
log "github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/config"
"github.com/docker/libcompose/logger"
- "github.com/docker/libcompose/lookup"
- "github.com/docker/libcompose/project/events"
"github.com/docker/libcompose/utils"
- "github.com/docker/libcompose/yaml"
+ "github.com/rancher/rancher-compose-executor/config"
+ "github.com/rancher/rancher-compose-executor/lookup"
+ "github.com/rancher/rancher-compose-executor/project/events"
)
// ComposeVersion is name of docker-compose.yml file syntax supported version
@@ -34,8 +33,6 @@ type Project struct {
ReloadCallback func() error
ParseOptions *config.ParseOptions
- runtime RuntimeProject
- networks Networks
volumes Volumes
configVersion string
context *Context
@@ -46,10 +43,9 @@ type Project struct {
}
// NewProject creates a new project with the specified context.
-func NewProject(context *Context, runtime RuntimeProject, parseOptions *config.ParseOptions) *Project {
+func NewProject(context *Context, parseOptions *config.ParseOptions) *Project {
p := &Project{
context: context,
- runtime: runtime,
ParseOptions: parseOptions,
ServiceConfigs: config.NewServiceConfigs(),
VolumeConfigs: make(map[string]*config.VolumeConfig),
@@ -230,19 +226,6 @@ func (p *Project) load(file string, bytes []byte) error {
}
}
- // Update network configuration a little bit
- p.handleNetworkConfig()
- //p.handleVolumeConfig()
-
- if p.context.NetworksFactory != nil {
- networks, err := p.context.NetworksFactory.Create(p.Name, p.NetworkConfigs, p.ServiceConfigs, p.isNetworkEnabled())
- if err != nil {
- return err
- }
-
- p.networks = networks
- }
-
if p.context.VolumesFactory != nil {
volumes, err := p.context.VolumesFactory.Create(p.Name, p.VolumeConfigs, p.ServiceConfigs, p.isVolumeEnabled())
if err != nil {
@@ -255,46 +238,7 @@ func (p *Project) load(file string, bytes []byte) error {
return nil
}
-func (p *Project) handleNetworkConfig() {
- if p.isNetworkEnabled() {
- for _, serviceName := range p.ServiceConfigs.Keys() {
- serviceConfig, _ := p.ServiceConfigs.Get(serviceName)
- if serviceConfig.NetworkMode != "" {
- continue
- }
- if serviceConfig.Networks == nil || len(serviceConfig.Networks.Networks) == 0 {
- // Add default as network
- serviceConfig.Networks = &yaml.Networks{
- Networks: []*yaml.Network{
- {
- Name: "default",
- },
- },
- }
- }
- // Consolidate the name of the network
- // FIXME(vdemeester) probably shouldn't be there, maybe move that to interface/factory
- for _, network := range serviceConfig.Networks.Networks {
- if net, ok := p.NetworkConfigs[network.Name]; ok {
- if net.External.External {
- network.RealName = network.Name
- if net.External.Name != "" {
- network.RealName = net.External.Name
- }
- } else {
- network.RealName = p.Name + "_" + network.Name
- }
- }
- // Ignoring if we don't find the network, it will be catched later
- }
- }
- }
-}
-
-func (p *Project) isNetworkEnabled() bool {
- return p.configVersion == "2"
-}
-
+// TODO: where is this used?
func (p *Project) handleVolumeConfig() {
if p.isVolumeEnabled() {
for _, serviceName := range p.ServiceConfigs.Keys() {
@@ -330,14 +274,7 @@ func (p *Project) isVolumeEnabled() bool {
return p.configVersion == "2"
}
-// initialize sets up required element for project before any action (on project and service).
-// This means it's not needed to be called on Config for example.
func (p *Project) initialize(ctx context.Context) error {
- if p.networks != nil {
- if err := p.networks.Initialize(ctx); err != nil {
- return err
- }
- }
if p.volumes != nil {
if err := p.volumes.Initialize(ctx); err != nil {
return err
diff --git a/vendor/github.com/docker/libcompose/project/project_build.go b/vendor/github.com/rancher/rancher-compose-executor/project/project_build.go
similarity index 81%
rename from vendor/github.com/docker/libcompose/project/project_build.go
rename to vendor/github.com/rancher/rancher-compose-executor/project/project_build.go
index 506a5c8fe..dbb320017 100644
--- a/vendor/github.com/docker/libcompose/project/project_build.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/project/project_build.go
@@ -3,8 +3,8 @@ package project
import (
"golang.org/x/net/context"
- "github.com/docker/libcompose/project/events"
- "github.com/docker/libcompose/project/options"
+ "github.com/rancher/rancher-compose-executor/project/events"
+ "github.com/rancher/rancher-compose-executor/project/options"
)
// Build builds the specified services (like docker build).
diff --git a/vendor/github.com/docker/libcompose/project/project_create.go b/vendor/github.com/rancher/rancher-compose-executor/project/project_create.go
similarity index 85%
rename from vendor/github.com/docker/libcompose/project/project_create.go
rename to vendor/github.com/rancher/rancher-compose-executor/project/project_create.go
index 9141b719c..0bff71607 100644
--- a/vendor/github.com/docker/libcompose/project/project_create.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/project/project_create.go
@@ -5,8 +5,8 @@ import (
"golang.org/x/net/context"
- "github.com/docker/libcompose/project/events"
- "github.com/docker/libcompose/project/options"
+ "github.com/rancher/rancher-compose-executor/project/events"
+ "github.com/rancher/rancher-compose-executor/project/options"
)
// Create creates the specified services (like docker create).
diff --git a/vendor/github.com/docker/libcompose/project/project_log.go b/vendor/github.com/rancher/rancher-compose-executor/project/project_log.go
similarity index 88%
rename from vendor/github.com/docker/libcompose/project/project_log.go
rename to vendor/github.com/rancher/rancher-compose-executor/project/project_log.go
index 7e576d586..3e9b2738c 100644
--- a/vendor/github.com/docker/libcompose/project/project_log.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/project/project_log.go
@@ -3,7 +3,7 @@ package project
import (
"golang.org/x/net/context"
- "github.com/docker/libcompose/project/events"
+ "github.com/rancher/rancher-compose-executor/project/events"
)
// Log aggregates and prints out the logs for the specified services.
diff --git a/vendor/github.com/docker/libcompose/project/project_up.go b/vendor/github.com/rancher/rancher-compose-executor/project/project_up.go
similarity index 83%
rename from vendor/github.com/docker/libcompose/project/project_up.go
rename to vendor/github.com/rancher/rancher-compose-executor/project/project_up.go
index f5954cd7b..c332178ca 100644
--- a/vendor/github.com/docker/libcompose/project/project_up.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/project/project_up.go
@@ -3,8 +3,8 @@ package project
import (
"golang.org/x/net/context"
- "github.com/docker/libcompose/project/events"
- "github.com/docker/libcompose/project/options"
+ "github.com/rancher/rancher-compose-executor/project/events"
+ "github.com/rancher/rancher-compose-executor/project/options"
)
// Up creates and starts the specified services (kinda like docker run).
diff --git a/vendor/github.com/docker/libcompose/project/service-wrapper.go b/vendor/github.com/rancher/rancher-compose-executor/project/service-wrapper.go
similarity index 97%
rename from vendor/github.com/docker/libcompose/project/service-wrapper.go
rename to vendor/github.com/rancher/rancher-compose-executor/project/service-wrapper.go
index d0654f9f2..d45c3a228 100644
--- a/vendor/github.com/docker/libcompose/project/service-wrapper.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/project/service-wrapper.go
@@ -4,7 +4,7 @@ import (
"sync"
log "github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/project/events"
+ "github.com/rancher/rancher-compose-executor/project/events"
)
type serviceWrapper struct {
diff --git a/vendor/github.com/docker/libcompose/project/service.go b/vendor/github.com/rancher/rancher-compose-executor/project/service.go
similarity index 74%
rename from vendor/github.com/docker/libcompose/project/service.go
rename to vendor/github.com/rancher/rancher-compose-executor/project/service.go
index 581df6740..67ea9b425 100644
--- a/vendor/github.com/docker/libcompose/project/service.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/project/service.go
@@ -5,32 +5,17 @@ import (
"golang.org/x/net/context"
- "github.com/docker/libcompose/config"
- "github.com/docker/libcompose/project/events"
- "github.com/docker/libcompose/project/options"
+ "github.com/rancher/rancher-compose-executor/config"
+ "github.com/rancher/rancher-compose-executor/project/options"
)
// Service defines what a libcompose service provides.
type Service interface {
Build(ctx context.Context, buildOptions options.Build) error
Create(ctx context.Context, options options.Create) error
- Delete(ctx context.Context, options options.Delete) error
- Events(ctx context.Context, messages chan events.ContainerEvent) error
- Info(ctx context.Context) (InfoSet, error)
Log(ctx context.Context, follow bool) error
- Kill(ctx context.Context, signal string) error
- Pause(ctx context.Context) error
- Pull(ctx context.Context) error
- Restart(ctx context.Context, timeout int) error
- Run(ctx context.Context, commandParts []string, options options.Run) (int, error)
- Scale(ctx context.Context, count int, timeout int) error
- Start(ctx context.Context) error
- Stop(ctx context.Context, timeout int) error
- Unpause(ctx context.Context) error
Up(ctx context.Context, options options.Up) error
- RemoveImage(ctx context.Context, imageType options.ImageType) error
- Containers(ctx context.Context) ([]Container, error)
DependentServices() []ServiceRelationship
Config() *config.ServiceConfig
Name() string
diff --git a/vendor/github.com/docker/libcompose/project/utils.go b/vendor/github.com/rancher/rancher-compose-executor/project/utils.go
similarity index 100%
rename from vendor/github.com/docker/libcompose/project/utils.go
rename to vendor/github.com/rancher/rancher-compose-executor/project/utils.go
diff --git a/vendor/github.com/docker/libcompose/project/volume.go b/vendor/github.com/rancher/rancher-compose-executor/project/volume.go
similarity index 91%
rename from vendor/github.com/docker/libcompose/project/volume.go
rename to vendor/github.com/rancher/rancher-compose-executor/project/volume.go
index 08f926e30..0636d169a 100644
--- a/vendor/github.com/docker/libcompose/project/volume.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/project/volume.go
@@ -3,7 +3,7 @@ package project
import (
"golang.org/x/net/context"
- "github.com/docker/libcompose/config"
+ "github.com/rancher/rancher-compose-executor/config"
)
// Volumes defines the methods a libcompose volume aggregate should define.
diff --git a/vendor/github.com/docker/libcompose/docker/builder/builder.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/build.go
similarity index 54%
rename from vendor/github.com/docker/libcompose/docker/builder/builder.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/build.go
index 0df621bde..5e544a49e 100644
--- a/vendor/github.com/docker/libcompose/docker/builder/builder.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/rancher/build.go
@@ -1,123 +1,90 @@
-package builder
+package rancher
import (
+ "crypto/sha256"
+ "encoding/hex"
+ "errors"
"fmt"
"io"
+ "io/ioutil"
"os"
"path"
"path/filepath"
"strings"
- "golang.org/x/net/context"
-
"github.com/Sirupsen/logrus"
- "github.com/docker/docker/api/types"
"github.com/docker/docker/builder"
"github.com/docker/docker/builder/dockerignore"
- "github.com/docker/docker/client"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/fileutils"
- "github.com/docker/docker/pkg/jsonmessage"
- "github.com/docker/docker/pkg/progress"
- "github.com/docker/docker/pkg/streamformatter"
- "github.com/docker/docker/pkg/term"
- "github.com/docker/libcompose/logger"
+ "github.com/rancher/rancher-compose-executor/project"
)
-// DefaultDockerfileName is the default name of a Dockerfile
const DefaultDockerfileName = "Dockerfile"
-// Builder defines methods to provide a docker builder. This makes libcompose
-// not tied up to the docker daemon builder.
-type Builder interface {
- Build(imageName string) error
+type Uploader interface {
+ Upload(p *project.Project, name string, reader io.ReadSeeker, hash string) (string, string, error)
+ Name() string
}
-// DaemonBuilder is the daemon "docker build" Builder implementation.
-type DaemonBuilder struct {
- Client client.ImageAPIClient
- ContextDirectory string
- Dockerfile string
- AuthConfigs map[string]types.AuthConfig
- NoCache bool
- ForceRemove bool
- Pull bool
- BuildArgs map[string]string
- LoggerFactory logger.Factory
-}
+func Upload(c *Context, name string) (string, string, error) {
+ uploader := c.Uploader
+ if uploader == nil {
+ return "", "", errors.New("Build not supported")
+ }
+ p := c.Project
+ logrus.Infof("Uploading build for %s using provider %s", name, uploader.Name())
-// Build implements Builder. It consumes the docker build API endpoint and sends
-// a tar of the specified service build context.
-func (d *DaemonBuilder) Build(ctx context.Context, imageName string) error {
- buildCtx, err := CreateTar(d.ContextDirectory, d.Dockerfile)
+ content, hash, err := createBuildArchive(p, name)
if err != nil {
- return err
- }
- defer buildCtx.Close()
- if d.LoggerFactory == nil {
- d.LoggerFactory = &logger.NullLogger{}
+ return "", "", err
}
- l := d.LoggerFactory.CreateBuildLogger(imageName)
+ return uploader.Upload(p, name, content, hash)
+}
- progBuff := &logger.Wrapper{
- Err: false,
- Logger: l,
+func createBuildArchive(p *project.Project, name string) (io.ReadSeeker, string, error) {
+ service, ok := p.ServiceConfigs.Get(name)
+ if !ok {
+ return nil, "", fmt.Errorf("No such service: %s", name)
}
- buildBuff := &logger.Wrapper{
- Err: false,
- Logger: l,
+ tar, err := createTar(service.Build.Context, service.Build.Dockerfile)
+ if err != nil {
+ return nil, "", err
}
+ defer tar.Close()
- errBuff := &logger.Wrapper{
- Err: true,
- Logger: l,
+ tempFile, err := ioutil.TempFile("", "")
+ if err != nil {
+ return nil, "", err
}
- // Setup an upload progress bar
- progressOutput := streamformatter.NewStreamFormatter().NewProgressOutput(progBuff, true)
-
- var body io.Reader = progress.NewProgressReader(buildCtx, progressOutput, 0, "", "Sending build context to Docker daemon")
-
- logrus.Infof("Building %s...", imageName)
-
- outFd, isTerminalOut := term.GetFdInfo(os.Stdout)
- w := l.OutWriter()
- if w != nil {
- outFd, isTerminalOut = term.GetFdInfo(w)
+ if err := os.Remove(tempFile.Name()); err != nil {
+ tempFile.Close()
+ return nil, "", err
}
- response, err := d.Client.ImageBuild(ctx, body, types.ImageBuildOptions{
- Tags: []string{imageName},
- NoCache: d.NoCache,
- Remove: true,
- ForceRemove: d.ForceRemove,
- PullParent: d.Pull,
- Dockerfile: d.Dockerfile,
- AuthConfigs: d.AuthConfigs,
- BuildArgs: d.BuildArgs,
- })
+ digest := sha256.New()
+ output := io.MultiWriter(tempFile, digest)
+
+ _, err = io.Copy(output, tar)
if err != nil {
- return err
+ tempFile.Close()
+ return nil, "", err
}
- err = jsonmessage.DisplayJSONMessagesStream(response.Body, buildBuff, outFd, isTerminalOut, nil)
+ hexString := hex.EncodeToString(digest.Sum([]byte{}))
+ _, err = tempFile.Seek(0, 0)
if err != nil {
- if jerr, ok := err.(*jsonmessage.JSONError); ok {
- // If no error code is set, default to 1
- if jerr.Code == 0 {
- jerr.Code = 1
- }
- errBuff.Write([]byte(jerr.Error()))
- return fmt.Errorf("Status: %s, Code: %d", jerr.Message, jerr.Code)
- }
+ tempFile.Close()
+ return nil, "", err
}
- return err
+
+ return tempFile, hexString, nil
}
-// CreateTar create a build context tar for the specified project and service name.
-func CreateTar(contextDirectory, dockerfile string) (io.ReadCloser, error) {
+func createTar(contextDirectory, dockerfile string) (io.ReadCloser, error) {
// This code was ripped off from docker/api/client/build.go
dockerfileName := filepath.Join(contextDirectory, dockerfile)
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/certs.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/certs.go
similarity index 100%
rename from vendor/github.com/rancher/rancher-compose/rancher/certs.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/certs.go
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/configs.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/configs.go
similarity index 94%
rename from vendor/github.com/rancher/rancher-compose/rancher/configs.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/configs.go
index 670023dec..9ce077daf 100644
--- a/vendor/github.com/rancher/rancher-compose/rancher/configs.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/rancher/configs.go
@@ -7,11 +7,11 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types/container"
- "github.com/docker/libcompose/config"
- "github.com/docker/libcompose/docker/service"
"github.com/docker/libcompose/utils"
"github.com/docker/libcompose/yaml"
"github.com/rancher/go-rancher/v2"
+ "github.com/rancher/rancher-compose-executor/config"
+ "github.com/rancher/rancher-compose-executor/convert"
)
func createLaunchConfigs(r *RancherService) (client.LaunchConfig, []client.SecondaryLaunchConfig, error) {
@@ -70,14 +70,14 @@ func createLaunchConfig(r *RancherService, name string, serviceConfig *config.Se
// Strip off legacy load balancer labels
for k, v := range serviceConfig.Labels {
- if !strings.HasPrefix(k, "io.rancher.loadbalancer") {
+ if !strings.HasPrefix(k, "io.rancher.loadbalancer") && !strings.HasPrefix(k, "io.rancher.service.selector") {
newLabels[k] = v
}
}
serviceConfig.Labels = newLabels
}
- config, hostConfig, err := service.Convert(serviceConfig, r.context.Context)
+ config, hostConfig, err := convert.Convert(serviceConfig, r.context.Context)
if err != nil {
return result, err
}
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/context.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/context.go
similarity index 92%
rename from vendor/github.com/rancher/rancher-compose/rancher/context.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/context.go
index 18aab0918..58895c99f 100644
--- a/vendor/github.com/rancher/rancher-compose/rancher/context.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/rancher/context.go
@@ -10,16 +10,17 @@ import (
"strings"
"github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/config"
- "github.com/docker/libcompose/project"
"github.com/docker/libcompose/utils"
composeYaml "github.com/docker/libcompose/yaml"
"github.com/fatih/structs"
legacyClient "github.com/rancher/go-rancher/client"
"github.com/rancher/go-rancher/v2"
- "github.com/rancher/rancher-compose/preprocess"
- rUtils "github.com/rancher/rancher-compose/utils"
- rVersion "github.com/rancher/rancher-compose/version"
+ "github.com/rancher/rancher-compose-executor/config"
+ "github.com/rancher/rancher-compose-executor/preprocess"
+ "github.com/rancher/rancher-compose-executor/project"
+ "github.com/rancher/rancher-compose-executor/template"
+ rUtils "github.com/rancher/rancher-compose-executor/utils"
+ rVersion "github.com/rancher/rancher-compose-executor/version"
"github.com/hashicorp/go-version"
)
@@ -32,9 +33,6 @@ type Context struct {
RancherConfig map[string]RancherConfig
RancherComposeFile string
RancherComposeBytes []byte
- BindingsFile string
- Binding *client.Binding
- BindingsBytes []byte
Url string
AccessKey string
SecretKey string
@@ -127,15 +125,6 @@ func getRancherConfigObjects() map[string]bool {
return fields
}
-type BindingProperty struct {
- Services map[string]Service `json:"services"`
-}
-
-type Service struct {
- Labels map[string]interface{} `json:"labels"`
- Ports []interface{} `json:"ports"`
-}
-
func ResolveRancherCompose(composeFile, rancherComposeFile string) (string, error) {
if rancherComposeFile == "" && composeFile != "" {
f, err := filepath.Abs(composeFile)
@@ -173,7 +162,14 @@ func (c *Context) readRancherConfig() error {
return c.unmarshalBytes(c.ComposeBytes[0], c.RancherComposeBytes)
}
-func (c *Context) unmarshalBytes(composeBytes, bytes []byte) error {
+// TODO: try to not duplicate this logic between here and libcompose
+func (c *Context) unmarshalBytes(composeBytes, rancherComposeBytes []byte) error {
+ var err error
+ composeBytes, err = template.Apply(composeBytes, c.EnvironmentLookup.Variables())
+ if err != nil {
+ return err
+ }
+
rawServiceMap := config.RawServiceMap{}
if composeBytes != nil {
config, err := config.CreateConfig(composeBytes)
@@ -185,8 +181,8 @@ func (c *Context) unmarshalBytes(composeBytes, bytes []byte) error {
delete(rawServiceMap[key], "hostname")
}
}
- if bytes != nil && len(bytes) > 0 {
- config, err := config.CreateConfig(bytes)
+ if rancherComposeBytes != nil && len(rancherComposeBytes) > 0 {
+ config, err := config.CreateConfig(rancherComposeBytes)
if err != nil {
return err
}
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/factory.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/factory.go
similarity index 84%
rename from vendor/github.com/rancher/rancher-compose/rancher/factory.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/factory.go
index f4ff57ffd..251316a16 100644
--- a/vendor/github.com/rancher/rancher-compose/rancher/factory.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/rancher/factory.go
@@ -1,6 +1,6 @@
package rancher
-import "github.com/rancher/rancher-compose/digest"
+import "github.com/rancher/rancher-compose-executor/digest"
type Factory interface {
Hash(service *RancherService) (digest.ServiceHash, error)
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/lb_service.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/lb_service.go
similarity index 85%
rename from vendor/github.com/rancher/rancher-compose/rancher/lb_service.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/lb_service.go
index abfa6c072..527cd00b2 100644
--- a/vendor/github.com/rancher/rancher-compose/rancher/lb_service.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/rancher/lb_service.go
@@ -6,10 +6,36 @@ import (
"strconv"
"strings"
+ "github.com/docker/libcompose/utils"
legacyClient "github.com/rancher/go-rancher/client"
"github.com/rancher/go-rancher/v2"
)
+// Links to target services should be automatically added to load balancers
+func (r *RancherService) populateLbLinks() error {
+ links, err := r.getLinks()
+ if err != nil {
+ return err
+ }
+
+ var linkServiceNames []string
+ for link := range links {
+ linkServiceNames = append(linkServiceNames, link.ServiceName)
+ }
+
+ lbConfig := r.RancherConfig().LbConfig
+ serviceType := FindServiceType(r)
+ if lbConfig != nil && (serviceType == LbServiceType || serviceType == LegacyLbServiceType) {
+ for _, portRule := range lbConfig.PortRules {
+ if portRule.Service != "" && !utils.Contains(linkServiceNames, portRule.Service) {
+ r.serviceConfig.Links = append(r.serviceConfig.Links, portRule.Service)
+ }
+ }
+ }
+
+ return nil
+}
+
func populateLbFields(r *RancherService, launchConfig *client.LaunchConfig, service *CompositeService) error {
serviceType := FindServiceType(r)
@@ -65,18 +91,33 @@ func populateLbFields(r *RancherService, launchConfig *client.LaunchConfig, serv
Postonly: legacyStickinessPolicy.Postonly,
}
}
- portRules, err := convertLb(r.serviceConfig.Ports, r.serviceConfig.Links, r.serviceConfig.ExternalLinks)
+ portRules, err := convertLb(r.serviceConfig.Ports, r.serviceConfig.Links, r.serviceConfig.ExternalLinks, "")
if err != nil {
return err
}
- exposeRules, err := convertLb(r.serviceConfig.Expose, r.serviceConfig.Links, r.serviceConfig.ExternalLinks)
+ exposeRules, err := convertLb(r.serviceConfig.Expose, r.serviceConfig.Links, r.serviceConfig.ExternalLinks, "")
portRules = append(portRules, exposeRules...)
+ labelName := "io.rancher.service.selector.link"
+ if label, ok := r.serviceConfig.Labels[labelName]; ok {
+ selectorPortRules, err := convertLb(r.serviceConfig.Ports, nil, nil, label)
+ if err != nil {
+ return err
+ }
+ portRules = append(portRules, selectorPortRules...)
+ selectorExposeRules, err := convertLb(r.serviceConfig.Expose, nil, nil, label)
+ if err != nil {
+ return err
+ }
+ portRules = append(portRules, selectorExposeRules...)
+
+ }
+
links, err := r.getLinks()
if err != nil {
return err
}
for link := range links {
- labelName := "io.rancher.loadbalancer.target." + link.ServiceName
+ labelName = "io.rancher.loadbalancer.target." + link.ServiceName
if label, ok := r.serviceConfig.Labels[labelName]; ok {
newPortRules, err := convertLbLabel(label)
if err != nil {
@@ -88,7 +129,7 @@ func populateLbFields(r *RancherService, launchConfig *client.LaunchConfig, serv
portRules = mergePortRules(portRules, newPortRules)
}
}
- labelName := "io.rancher.loadbalancer.ssl.ports"
+ labelName = "io.rancher.loadbalancer.ssl.ports"
if label, ok := r.serviceConfig.Labels[labelName]; ok {
split := strings.Split(label, ",")
for _, portString := range split {
@@ -113,24 +154,27 @@ frontend %s
}
}
for _, portRule := range portRules {
- targetService, err := r.FindExisting(portRule.Service)
- if err != nil {
- return err
- }
- if targetService == nil {
- return fmt.Errorf("Failed to find existing service: %s", portRule.Service)
- }
- service.RealLbConfig.PortRules = append(service.RealLbConfig.PortRules, client.PortRule{
+ finalPortRule := client.PortRule{
SourcePort: int64(portRule.SourcePort),
Protocol: portRule.Protocol,
Path: portRule.Path,
Hostname: portRule.Hostname,
- ServiceId: targetService.Id,
TargetPort: int64(portRule.TargetPort),
Priority: int64(portRule.Priority),
BackendName: portRule.BackendName,
Selector: portRule.Selector,
- })
+ }
+ if portRule.Service != "" {
+ targetService, err := r.FindExisting(portRule.Service)
+ if err != nil {
+ return err
+ }
+ if targetService == nil {
+ return fmt.Errorf("Failed to find existing service: %s", portRule.Service)
+ }
+ finalPortRule.ServiceId = targetService.Id
+ }
+ service.RealLbConfig.PortRules = append(service.RealLbConfig.PortRules, finalPortRule)
}
// Strip target ports from lb service config
@@ -258,7 +302,7 @@ func rewritePorts(ports []string) ([]string, error) {
return updatedPorts, nil
}
-func convertLb(ports, links, externalLinks []string) ([]PortRule, error) {
+func convertLb(ports, links, externalLinks []string, selector string) ([]PortRule, error) {
portRules := []PortRule{}
for _, port := range ports {
@@ -317,6 +361,14 @@ func convertLb(ports, links, externalLinks []string) ([]PortRule, error) {
Protocol: protocol,
})
}
+ if selector != "" {
+ portRules = append(portRules, PortRule{
+ SourcePort: int(sourcePort),
+ TargetPort: int(targetPort),
+ Selector: selector,
+ Protocol: protocol,
+ })
+ }
}
return portRules, nil
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/normal.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/normal.go
similarity index 97%
rename from vendor/github.com/rancher/rancher-compose/rancher/normal.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/normal.go
index 2b8d92054..8a4fe4ea0 100644
--- a/vendor/github.com/rancher/rancher-compose/rancher/normal.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/rancher/normal.go
@@ -6,7 +6,7 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/libcompose/utils"
"github.com/rancher/go-rancher/v2"
- "github.com/rancher/rancher-compose/digest"
+ "github.com/rancher/rancher-compose-executor/digest"
)
type NormalFactory struct {
@@ -18,6 +18,10 @@ func (f *NormalFactory) Hash(service *RancherService) (digest.ServiceHash, error
}
func (f *NormalFactory) configAndHash(r *RancherService) (digest.ServiceHash, *CompositeService, error) {
+ if err := r.populateLbLinks(); err != nil {
+ return digest.ServiceHash{}, nil, err
+ }
+
rancherService, launchConfig, secondaryLaunchConfigs, err := f.config(r)
if err != nil {
return digest.ServiceHash{}, nil, err
@@ -150,7 +154,7 @@ func (f *NormalFactory) Upgrade(r *RancherService, force bool, selected []string
service := hash.Service != existingHash.Service || isForce(r.Name(), force, selected)
launchConfig := hash.LaunchConfig != existingHash.LaunchConfig || isForce(r.Name(), force, selected)
- for oldSecondary, _ := range existingHash.SecondaryLaunchConfigs {
+ for oldSecondary := range existingHash.SecondaryLaunchConfigs {
if _, ok := hash.SecondaryLaunchConfigs[oldSecondary]; !ok {
removedSecondaryNames = append(removedSecondaryNames, oldSecondary)
}
diff --git a/vendor/github.com/rancher/rancher-compose-executor/rancher/project.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/project.go
new file mode 100644
index 000000000..edbac9681
--- /dev/null
+++ b/vendor/github.com/rancher/rancher-compose-executor/rancher/project.go
@@ -0,0 +1,40 @@
+package rancher
+
+import (
+ "github.com/Sirupsen/logrus"
+ "github.com/rancher/rancher-compose-executor/config"
+ "github.com/rancher/rancher-compose-executor/preprocess"
+ "github.com/rancher/rancher-compose-executor/project"
+)
+
+func NewProject(context *Context) (*project.Project, error) {
+ context.ServiceFactory = &RancherServiceFactory{
+ Context: context,
+ }
+
+ context.VolumesFactory = &RancherVolumesFactory{
+ Context: context,
+ }
+
+ p := project.NewProject(&context.Context, &config.ParseOptions{
+ Interpolate: true,
+ Validate: true,
+ Preprocess: preprocess.PreprocessServiceMap,
+ })
+
+ err := p.Parse()
+ if err != nil {
+ return nil, err
+ }
+
+ if err = context.open(); err != nil {
+ logrus.Errorf("Failed to open project %s: %v", p.Name, err)
+ return nil, err
+ }
+
+ p.Name = context.ProjectName
+
+ context.SidekickInfo = NewSidekickInfo(p)
+
+ return p, err
+}
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/s3_uploader.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/s3_uploader.go
similarity index 97%
rename from vendor/github.com/rancher/rancher-compose/rancher/s3_uploader.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/s3_uploader.go
index e7fe011c6..9ba25e140 100644
--- a/vendor/github.com/rancher/rancher-compose/rancher/s3_uploader.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/rancher/s3_uploader.go
@@ -12,7 +12,7 @@ import (
"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/aws/awserr"
"github.com/awslabs/aws-sdk-go/service/s3"
- "github.com/docker/libcompose/project"
+ "github.com/rancher/rancher-compose-executor/project"
)
type S3Uploader struct {
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/service.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/service.go
similarity index 88%
rename from vendor/github.com/rancher/rancher-compose/rancher/service.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/service.go
index 5ae3ffa9e..c3a7ab0c4 100644
--- a/vendor/github.com/rancher/rancher-compose/rancher/service.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/rancher/service.go
@@ -11,16 +11,15 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types/container"
- "github.com/docker/libcompose/config"
- "github.com/docker/libcompose/docker/service"
"github.com/docker/libcompose/labels"
- "github.com/docker/libcompose/project"
- "github.com/docker/libcompose/project/events"
- "github.com/docker/libcompose/project/options"
"github.com/gorilla/websocket"
"github.com/rancher/go-rancher/hostaccess"
"github.com/rancher/go-rancher/v2"
- rUtils "github.com/rancher/rancher-compose/utils"
+ "github.com/rancher/rancher-compose-executor/config"
+ "github.com/rancher/rancher-compose-executor/docker/service"
+ "github.com/rancher/rancher-compose-executor/project"
+ "github.com/rancher/rancher-compose-executor/project/options"
+ rUtils "github.com/rancher/rancher-compose-executor/utils"
)
type Link struct {
@@ -161,25 +160,6 @@ func (r *RancherService) up(create bool) error {
return err
}
-func (r *RancherService) Stop(ctx context.Context, timeout int) error {
- service, err := r.FindExisting(r.name)
-
- if err == nil && service == nil {
- return nil
- }
-
- if err != nil {
- return err
- }
-
- if service.State == "inactive" {
- return nil
- }
-
- service, err = r.context.Client.Service.ActionDeactivate(service)
- return r.Wait(service)
-}
-
func (r *RancherService) Delete(ctx context.Context, options options.Delete) error {
service, err := r.FindExisting(r.name)
@@ -414,25 +394,6 @@ func (r *RancherService) Scale(ctx context.Context, count int, timeout int) erro
return r.Wait(service)
}
-func (r *RancherService) Containers(ctx context.Context) ([]project.Container, error) {
- result := []project.Container{}
-
- containers, err := r.containers()
- if err != nil {
- return nil, err
- }
-
- for _, c := range containers {
- name := c.Name
- if name == "" {
- name = c.Uuid
- }
- result = append(result, NewContainer(c.Id, name))
- }
-
- return result, nil
-}
-
func (r *RancherService) containers() ([]client.Container, error) {
service, err := r.FindExisting(r.name)
if err != nil {
@@ -568,10 +529,6 @@ func (r *RancherService) Kill(ctx context.Context, signal string) error {
return project.ErrUnsupported
}
-func (r *RancherService) Info(ctx context.Context) (project.InfoSet, error) {
- return project.InfoSet{}, project.ErrUnsupported
-}
-
func (r *RancherService) pullImage(image string, labels map[string]string) error {
taskOpts := &client.PullTask{
Mode: "all",
@@ -650,30 +607,6 @@ func (r *RancherService) Pull(ctx context.Context) (err error) {
return
}
-func (r *RancherService) Pause(ctx context.Context) error {
- return project.ErrUnsupported
-}
-
-func (r *RancherService) Unpause(ctx context.Context) error {
- return project.ErrUnsupported
-}
-
-func (r *RancherService) Down() error {
- return project.ErrUnsupported
-}
-
-func (r *RancherService) Events(ctx context.Context, messages chan events.ContainerEvent) error {
- return project.ErrUnsupported
-}
-
-func (r *RancherService) Run(ctx context.Context, commandParts []string, options options.Run) (int, error) {
- return 0, project.ErrUnsupported
-}
-
-func (r *RancherService) RemoveImage(ctx context.Context, imageType options.ImageType) error {
- return project.ErrUnsupported
-}
-
func appendHash(service *RancherService, existingLabels map[string]interface{}) (map[string]interface{}, error) {
ret := map[string]interface{}{}
for k, v := range existingLabels {
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/service_factory.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/service_factory.go
similarity index 79%
rename from vendor/github.com/rancher/rancher-compose/rancher/service_factory.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/service_factory.go
index c34f686dc..42ba1f3ce 100644
--- a/vendor/github.com/rancher/rancher-compose/rancher/service_factory.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/rancher/service_factory.go
@@ -1,8 +1,8 @@
package rancher
import (
- "github.com/docker/libcompose/config"
- "github.com/docker/libcompose/project"
+ "github.com/rancher/rancher-compose-executor/config"
+ "github.com/rancher/rancher-compose-executor/project"
)
type RancherServiceFactory struct {
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/sidekick.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/sidekick.go
similarity index 91%
rename from vendor/github.com/rancher/rancher-compose/rancher/sidekick.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/sidekick.go
index af4ed9b4b..1baf4b350 100644
--- a/vendor/github.com/rancher/rancher-compose/rancher/sidekick.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/rancher/sidekick.go
@@ -3,8 +3,8 @@ package rancher
import (
"golang.org/x/net/context"
- "github.com/docker/libcompose/config"
- "github.com/docker/libcompose/project"
+ "github.com/rancher/rancher-compose-executor/config"
+ "github.com/rancher/rancher-compose-executor/project"
)
type Sidekick struct {
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/sidekick_info.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/sidekick_info.go
similarity index 95%
rename from vendor/github.com/rancher/rancher-compose/rancher/sidekick_info.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/sidekick_info.go
index 03745ee14..5e8c2cb05 100644
--- a/vendor/github.com/rancher/rancher-compose/rancher/sidekick_info.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/rancher/sidekick_info.go
@@ -3,7 +3,7 @@ package rancher
import (
"strings"
- "github.com/docker/libcompose/project"
+ "github.com/rancher/rancher-compose-executor/project"
)
type SidekickInfo struct {
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/types.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/types.go
similarity index 100%
rename from vendor/github.com/rancher/rancher-compose/rancher/types.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/types.go
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/upgrade.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/upgrade.go
similarity index 97%
rename from vendor/github.com/rancher/rancher-compose/rancher/upgrade.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/upgrade.go
index 9304bc012..b34009022 100644
--- a/vendor/github.com/rancher/rancher-compose/rancher/upgrade.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/rancher/upgrade.go
@@ -3,7 +3,7 @@ package rancher
import (
"github.com/Sirupsen/logrus"
"github.com/rancher/go-rancher/v2"
- "github.com/rancher/rancher-compose/digest"
+ "github.com/rancher/rancher-compose-executor/digest"
)
func (r *RancherService) upgrade(service *client.Service, force bool, selected []string) (*client.Service, error) {
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/volume.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/volume.go
similarity index 97%
rename from vendor/github.com/rancher/rancher-compose/rancher/volume.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/volume.go
index 925ac4484..07b06a356 100644
--- a/vendor/github.com/rancher/rancher-compose/rancher/volume.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/rancher/volume.go
@@ -6,9 +6,9 @@ import (
"golang.org/x/net/context"
"github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/config"
- "github.com/docker/libcompose/project"
"github.com/rancher/go-rancher/v2"
+ "github.com/rancher/rancher-compose-executor/config"
+ "github.com/rancher/rancher-compose-executor/project"
)
type RancherVolumesFactory struct {
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/wait.go b/vendor/github.com/rancher/rancher-compose-executor/rancher/wait.go
similarity index 100%
rename from vendor/github.com/rancher/rancher-compose/rancher/wait.go
rename to vendor/github.com/rancher/rancher-compose-executor/rancher/wait.go
diff --git a/vendor/github.com/rancher/rancher-compose-executor/template/template.go b/vendor/github.com/rancher/rancher-compose-executor/template/template.go
new file mode 100644
index 000000000..a479ba539
--- /dev/null
+++ b/vendor/github.com/rancher/rancher-compose-executor/template/template.go
@@ -0,0 +1,21 @@
+package template
+
+import (
+ "bytes"
+ "text/template"
+
+ "github.com/Masterminds/sprig"
+)
+
+func Apply(contents []byte, variables map[string]string) ([]byte, error) {
+ t, err := template.New("template").Funcs(sprig.TxtFuncMap()).Parse(string(contents))
+ if err != nil {
+ return nil, err
+ }
+
+ buf := bytes.Buffer{}
+ t.Execute(&buf, map[string]map[string]string{
+ "Values": variables,
+ })
+ return buf.Bytes(), nil
+}
diff --git a/vendor/github.com/rancher/rancher-compose/upgrade/upgrade.go b/vendor/github.com/rancher/rancher-compose-executor/upgrade/upgrade.go
similarity index 90%
rename from vendor/github.com/rancher/rancher-compose/upgrade/upgrade.go
rename to vendor/github.com/rancher/rancher-compose-executor/upgrade/upgrade.go
index 8fc158ecd..ade7cf4ac 100644
--- a/vendor/github.com/rancher/rancher-compose/upgrade/upgrade.go
+++ b/vendor/github.com/rancher/rancher-compose-executor/upgrade/upgrade.go
@@ -6,10 +6,10 @@ import (
"golang.org/x/net/context"
"github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/project"
- "github.com/docker/libcompose/project/options"
"github.com/rancher/go-rancher/v2"
- "github.com/rancher/rancher-compose/rancher"
+ "github.com/rancher/rancher-compose-executor/project"
+ "github.com/rancher/rancher-compose-executor/project/options"
+ "github.com/rancher/rancher-compose-executor/rancher"
)
type UpgradeOpts struct {
@@ -22,7 +22,7 @@ type UpgradeOpts struct {
Pull bool
}
-func Upgrade(p project.APIProject, from, to string, opts UpgradeOpts) error {
+func Upgrade(p *project.Project, from, to string, opts UpgradeOpts) error {
fromService, err := p.CreateService(from)
if err != nil {
return err
@@ -139,7 +139,7 @@ func Upgrade(p project.APIProject, from, to string, opts UpgradeOpts) error {
return nil
}
-func upgradeInfo(up bool, p project.APIProject, from, to string, opts UpgradeOpts) (*client.Service, *client.Service, *client.RancherClient, error) {
+func upgradeInfo(up bool, p *project.Project, from, to string, opts UpgradeOpts) (*client.Service, *client.Service, *client.RancherClient, error) {
fromService, err := p.CreateService(from)
if err != nil {
return nil, nil, nil, err
diff --git a/vendor/github.com/rancher/rancher-compose/utils/util.go b/vendor/github.com/rancher/rancher-compose-executor/utils/util.go
similarity index 100%
rename from vendor/github.com/rancher/rancher-compose/utils/util.go
rename to vendor/github.com/rancher/rancher-compose-executor/utils/util.go
diff --git a/vendor/github.com/rancher/rancher-compose/trash.conf b/vendor/github.com/rancher/rancher-compose-executor/vendor.conf
similarity index 91%
rename from vendor/github.com/rancher/rancher-compose/trash.conf
rename to vendor/github.com/rancher/rancher-compose-executor/vendor.conf
index ec68c2d87..642392874 100644
--- a/vendor/github.com/rancher/rancher-compose/trash.conf
+++ b/vendor/github.com/rancher/rancher-compose-executor/vendor.conf
@@ -30,3 +30,6 @@ github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45
github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a
github.com/spf13/pflag cb88ea77998c3f024757528e3305022ab50b43be
github.com/fatih/structs dc3312cb1a4513a366c4c9e622ad55c32df12ed3
+github.com/Masterminds/sprig c974324bb59b465f00b128a055656d44f60e4ffc
+github.com/aokoli/goutils 9c37978a95bd5c709a15883b6242714ea6709e64
+github.com/satori/go.uuid b061729afc07e77a8aa4fad0a2fd840958f1942a
diff --git a/vendor/github.com/rancher/rancher-compose/version/version.go b/vendor/github.com/rancher/rancher-compose-executor/version/version.go
similarity index 100%
rename from vendor/github.com/rancher/rancher-compose/version/version.go
rename to vendor/github.com/rancher/rancher-compose-executor/version/version.go
diff --git a/vendor/github.com/rancher/rancher-compose/lookup/file.go b/vendor/github.com/rancher/rancher-compose/lookup/file.go
deleted file mode 100644
index 24aa0eaba..000000000
--- a/vendor/github.com/rancher/rancher-compose/lookup/file.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package lookup
-
-import (
- "path/filepath"
- "strings"
-
- log "github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/lookup"
-)
-
-type FileResourceLookup struct {
- lookup.FileResourceLookup
-}
-
-// Give a warning rather than resolve relative paths
-func (f *FileResourceLookup) ResolvePath(path, inFile string) string {
- vs := strings.SplitN(path, ":", 2)
- if len(vs) == 2 && !filepath.IsAbs(vs[0]) {
- log.Warnf("Rancher Compose will not resolve relative path %s", vs[0])
- }
- return path
-}
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/build.go b/vendor/github.com/rancher/rancher-compose/rancher/build.go
deleted file mode 100644
index c38b1b1df..000000000
--- a/vendor/github.com/rancher/rancher-compose/rancher/build.go
+++ /dev/null
@@ -1,77 +0,0 @@
-package rancher
-
-import (
- "crypto/sha256"
- "encoding/hex"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "os"
-
- "github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/docker/builder"
- "github.com/docker/libcompose/project"
-)
-
-type Uploader interface {
- Upload(p *project.Project, name string, reader io.ReadSeeker, hash string) (string, string, error)
- Name() string
-}
-
-func Upload(c *Context, name string) (string, string, error) {
- uploader := c.Uploader
- if uploader == nil {
- return "", "", errors.New("Build not supported")
- }
- p := c.Project
- logrus.Infof("Uploading build for %s using provider %s", name, uploader.Name())
-
- content, hash, err := createBuildArchive(p, name)
- if err != nil {
- return "", "", err
- }
-
- return uploader.Upload(p, name, content, hash)
-}
-
-func createBuildArchive(p *project.Project, name string) (io.ReadSeeker, string, error) {
- service, ok := p.ServiceConfigs.Get(name)
- if !ok {
- return nil, "", fmt.Errorf("No such service: %s", name)
- }
-
- tar, err := builder.CreateTar(service.Build.Context, service.Build.Dockerfile)
- if err != nil {
- return nil, "", err
- }
- defer tar.Close()
-
- tempFile, err := ioutil.TempFile("", "")
- if err != nil {
- return nil, "", err
- }
-
- if err := os.Remove(tempFile.Name()); err != nil {
- tempFile.Close()
- return nil, "", err
- }
-
- digest := sha256.New()
- output := io.MultiWriter(tempFile, digest)
-
- _, err = io.Copy(output, tar)
- if err != nil {
- tempFile.Close()
- return nil, "", err
- }
-
- hexString := hex.EncodeToString(digest.Sum([]byte{}))
- _, err = tempFile.Seek(0, 0)
- if err != nil {
- tempFile.Close()
- return nil, "", err
- }
-
- return tempFile, hexString, nil
-}
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/container.go b/vendor/github.com/rancher/rancher-compose/rancher/container.go
deleted file mode 100644
index 7e8a20745..000000000
--- a/vendor/github.com/rancher/rancher-compose/rancher/container.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package rancher
-
-import (
- "github.com/docker/libcompose/project"
- "golang.org/x/net/context"
-)
-
-type Container struct {
- id, name string
-}
-
-func NewContainer(id, name string) *Container {
- return &Container{
- id: id,
- name: name,
- }
-}
-
-func (c *Container) ID() (string, error) {
- return c.id, nil
-}
-
-func (c *Container) Name() string {
- return c.name
-}
-
-// TODO implement
-func (c *Container) Port(ctx context.Context, port string) (string, error) {
- return "", project.ErrUnsupported
-}
-
-// TODO implement
-func (c *Container) IsRunning(ctx context.Context) (bool, error) {
- return false, project.ErrUnsupported
-}
diff --git a/vendor/github.com/rancher/rancher-compose/rancher/project.go b/vendor/github.com/rancher/rancher-compose/rancher/project.go
deleted file mode 100644
index e82edde73..000000000
--- a/vendor/github.com/rancher/rancher-compose/rancher/project.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package rancher
-
-import (
- "encoding/json"
- "github.com/Sirupsen/logrus"
- "github.com/docker/libcompose/config"
- "github.com/docker/libcompose/project"
- "github.com/rancher/rancher-compose/preprocess"
- "io/ioutil"
-)
-
-func NewProject(context *Context) (*project.Project, error) {
- context.ServiceFactory = &RancherServiceFactory{
- Context: context,
- }
-
- context.VolumesFactory = &RancherVolumesFactory{
- Context: context,
- }
-
- if context.Binding != nil {
- bindingBytes, err := json.Marshal(context.Binding)
- if err != nil {
- return nil, err
- }
- context.BindingsBytes = bindingBytes
- }
-
- if context.BindingsBytes == nil {
- if context.BindingsFile != "" {
- bindingsContent, err := ioutil.ReadFile(context.BindingsFile)
- if err != nil {
- return nil, err
- }
- context.BindingsBytes = bindingsContent
- }
- }
-
- preProcessServiceMap := preprocess.PreprocessServiceMap(context.BindingsBytes)
- p := project.NewProject(&context.Context, nil, &config.ParseOptions{
- Interpolate: true,
- Validate: true,
- Preprocess: preProcessServiceMap,
- })
-
- err := p.Parse()
- if err != nil {
- return nil, err
- }
-
- if err = context.open(); err != nil {
- logrus.Errorf("Failed to open project %s: %v", p.Name, err)
- return nil, err
- }
-
- p.Name = context.ProjectName
-
- context.SidekickInfo = NewSidekickInfo(p)
-
- return p, err
-}
diff --git a/vendor/github.com/satori/go.uuid/.travis.yml b/vendor/github.com/satori/go.uuid/.travis.yml
new file mode 100644
index 000000000..bf90ad530
--- /dev/null
+++ b/vendor/github.com/satori/go.uuid/.travis.yml
@@ -0,0 +1,21 @@
+language: go
+sudo: false
+go:
+ - 1.2
+ - 1.3
+ - 1.4
+ - 1.5
+ - 1.6
+ - 1.7
+ - tip
+matrix:
+ allow_failures:
+ - go: tip
+ fast_finish: true
+before_install:
+ - go get github.com/mattn/goveralls
+ - go get golang.org/x/tools/cmd/cover
+script:
+ - $HOME/gopath/bin/goveralls -service=travis-ci
+notifications:
+ email: false
diff --git a/vendor/github.com/satori/go.uuid/LICENSE b/vendor/github.com/satori/go.uuid/LICENSE
new file mode 100644
index 000000000..488357b8a
--- /dev/null
+++ b/vendor/github.com/satori/go.uuid/LICENSE
@@ -0,0 +1,20 @@
+Copyright (C) 2013-2016 by Maxim Bublis
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/satori/go.uuid/README.md b/vendor/github.com/satori/go.uuid/README.md
new file mode 100644
index 000000000..b6aad1c81
--- /dev/null
+++ b/vendor/github.com/satori/go.uuid/README.md
@@ -0,0 +1,65 @@
+# UUID package for Go language
+
+[](https://travis-ci.org/satori/go.uuid)
+[](https://coveralls.io/github/satori/go.uuid)
+[](http://godoc.org/github.com/satori/go.uuid)
+
+This package provides pure Go implementation of Universally Unique Identifier (UUID). Supported both creation and parsing of UUIDs.
+
+With 100% test coverage and benchmarks out of box.
+
+Supported versions:
+* Version 1, based on timestamp and MAC address (RFC 4122)
+* Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1)
+* Version 3, based on MD5 hashing (RFC 4122)
+* Version 4, based on random numbers (RFC 4122)
+* Version 5, based on SHA-1 hashing (RFC 4122)
+
+## Installation
+
+Use the `go` command:
+
+ $ go get github.com/satori/go.uuid
+
+## Requirements
+
+UUID package requires Go >= 1.2.
+
+## Example
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/satori/go.uuid"
+)
+
+func main() {
+ // Creating UUID Version 4
+ u1 := uuid.NewV4()
+ fmt.Printf("UUIDv4: %s\n", u1)
+
+ // Parsing UUID from string input
+ u2, err := uuid.FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
+ if err != nil {
+ fmt.Printf("Something gone wrong: %s", err)
+ }
+ fmt.Printf("Successfully parsed: %s", u2)
+}
+```
+
+## Documentation
+
+[Documentation](http://godoc.org/github.com/satori/go.uuid) is hosted at GoDoc project.
+
+## Links
+* [RFC 4122](http://tools.ietf.org/html/rfc4122)
+* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01)
+
+## Copyright
+
+Copyright (C) 2013-2016 by Maxim Bublis .
+
+UUID package released under MIT License.
+See [LICENSE](https://github.com/satori/go.uuid/blob/master/LICENSE) for details.
diff --git a/vendor/github.com/satori/go.uuid/uuid.go b/vendor/github.com/satori/go.uuid/uuid.go
new file mode 100644
index 000000000..295f3fc2c
--- /dev/null
+++ b/vendor/github.com/satori/go.uuid/uuid.go
@@ -0,0 +1,481 @@
+// Copyright (C) 2013-2015 by Maxim Bublis
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// Package uuid provides implementation of Universally Unique Identifier (UUID).
+// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and
+// version 2 (as specified in DCE 1.1).
+package uuid
+
+import (
+ "bytes"
+ "crypto/md5"
+ "crypto/rand"
+ "crypto/sha1"
+ "database/sql/driver"
+ "encoding/binary"
+ "encoding/hex"
+ "fmt"
+ "hash"
+ "net"
+ "os"
+ "sync"
+ "time"
+)
+
+// UUID layout variants.
+const (
+ VariantNCS = iota
+ VariantRFC4122
+ VariantMicrosoft
+ VariantFuture
+)
+
+// UUID DCE domains.
+const (
+ DomainPerson = iota
+ DomainGroup
+ DomainOrg
+)
+
+// Difference in 100-nanosecond intervals between
+// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
+const epochStart = 122192928000000000
+
+// Used in string method conversion
+const dash byte = '-'
+
+// UUID v1/v2 storage.
+var (
+ storageMutex sync.Mutex
+ storageOnce sync.Once
+ epochFunc = unixTimeFunc
+ clockSequence uint16
+ lastTime uint64
+ hardwareAddr [6]byte
+ posixUID = uint32(os.Getuid())
+ posixGID = uint32(os.Getgid())
+)
+
+// String parse helpers.
+var (
+ urnPrefix = []byte("urn:uuid:")
+ byteGroups = []int{8, 4, 4, 4, 12}
+)
+
+func initClockSequence() {
+ buf := make([]byte, 2)
+ safeRandom(buf)
+ clockSequence = binary.BigEndian.Uint16(buf)
+}
+
+func initHardwareAddr() {
+ interfaces, err := net.Interfaces()
+ if err == nil {
+ for _, iface := range interfaces {
+ if len(iface.HardwareAddr) >= 6 {
+ copy(hardwareAddr[:], iface.HardwareAddr)
+ return
+ }
+ }
+ }
+
+ // Initialize hardwareAddr randomly in case
+ // of real network interfaces absence
+ safeRandom(hardwareAddr[:])
+
+ // Set multicast bit as recommended in RFC 4122
+ hardwareAddr[0] |= 0x01
+}
+
+func initStorage() {
+ initClockSequence()
+ initHardwareAddr()
+}
+
+func safeRandom(dest []byte) {
+ if _, err := rand.Read(dest); err != nil {
+ panic(err)
+ }
+}
+
+// Returns difference in 100-nanosecond intervals between
+// UUID epoch (October 15, 1582) and current time.
+// This is default epoch calculation function.
+func unixTimeFunc() uint64 {
+ return epochStart + uint64(time.Now().UnixNano()/100)
+}
+
+// UUID representation compliant with specification
+// described in RFC 4122.
+type UUID [16]byte
+
+// NullUUID can be used with the standard sql package to represent a
+// UUID value that can be NULL in the database
+type NullUUID struct {
+ UUID UUID
+ Valid bool
+}
+
+// The nil UUID is special form of UUID that is specified to have all
+// 128 bits set to zero.
+var Nil = UUID{}
+
+// Predefined namespace UUIDs.
+var (
+ NamespaceDNS, _ = FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
+ NamespaceURL, _ = FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
+ NamespaceOID, _ = FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
+ NamespaceX500, _ = FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
+)
+
+// And returns result of binary AND of two UUIDs.
+func And(u1 UUID, u2 UUID) UUID {
+ u := UUID{}
+ for i := 0; i < 16; i++ {
+ u[i] = u1[i] & u2[i]
+ }
+ return u
+}
+
+// Or returns result of binary OR of two UUIDs.
+func Or(u1 UUID, u2 UUID) UUID {
+ u := UUID{}
+ for i := 0; i < 16; i++ {
+ u[i] = u1[i] | u2[i]
+ }
+ return u
+}
+
+// Equal returns true if u1 and u2 equals, otherwise returns false.
+func Equal(u1 UUID, u2 UUID) bool {
+ return bytes.Equal(u1[:], u2[:])
+}
+
+// Version returns algorithm version used to generate UUID.
+func (u UUID) Version() uint {
+ return uint(u[6] >> 4)
+}
+
+// Variant returns UUID layout variant.
+func (u UUID) Variant() uint {
+ switch {
+ case (u[8] & 0x80) == 0x00:
+ return VariantNCS
+ case (u[8]&0xc0)|0x80 == 0x80:
+ return VariantRFC4122
+ case (u[8]&0xe0)|0xc0 == 0xc0:
+ return VariantMicrosoft
+ }
+ return VariantFuture
+}
+
+// Bytes returns bytes slice representation of UUID.
+func (u UUID) Bytes() []byte {
+ return u[:]
+}
+
+// Returns canonical string representation of UUID:
+// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
+func (u UUID) String() string {
+ buf := make([]byte, 36)
+
+ hex.Encode(buf[0:8], u[0:4])
+ buf[8] = dash
+ hex.Encode(buf[9:13], u[4:6])
+ buf[13] = dash
+ hex.Encode(buf[14:18], u[6:8])
+ buf[18] = dash
+ hex.Encode(buf[19:23], u[8:10])
+ buf[23] = dash
+ hex.Encode(buf[24:], u[10:])
+
+ return string(buf)
+}
+
+// SetVersion sets version bits.
+func (u *UUID) SetVersion(v byte) {
+ u[6] = (u[6] & 0x0f) | (v << 4)
+}
+
+// SetVariant sets variant bits as described in RFC 4122.
+func (u *UUID) SetVariant() {
+ u[8] = (u[8] & 0xbf) | 0x80
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+// The encoding is the same as returned by String.
+func (u UUID) MarshalText() (text []byte, err error) {
+ text = []byte(u.String())
+ return
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+// Following formats are supported:
+// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
+// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
+// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
+func (u *UUID) UnmarshalText(text []byte) (err error) {
+ if len(text) < 32 {
+ err = fmt.Errorf("uuid: UUID string too short: %s", text)
+ return
+ }
+
+ t := text[:]
+ braced := false
+
+ if bytes.Equal(t[:9], urnPrefix) {
+ t = t[9:]
+ } else if t[0] == '{' {
+ braced = true
+ t = t[1:]
+ }
+
+ b := u[:]
+
+ for i, byteGroup := range byteGroups {
+ if i > 0 {
+ if t[0] != '-' {
+ err = fmt.Errorf("uuid: invalid string format")
+ return
+ }
+ t = t[1:]
+ }
+
+ if len(t) < byteGroup {
+ err = fmt.Errorf("uuid: UUID string too short: %s", text)
+ return
+ }
+
+ if i == 4 && len(t) > byteGroup &&
+ ((braced && t[byteGroup] != '}') || len(t[byteGroup:]) > 1 || !braced) {
+ err = fmt.Errorf("uuid: UUID string too long: %s", text)
+ return
+ }
+
+ _, err = hex.Decode(b[:byteGroup/2], t[:byteGroup])
+ if err != nil {
+ return
+ }
+
+ t = t[byteGroup:]
+ b = b[byteGroup/2:]
+ }
+
+ return
+}
+
+// MarshalBinary implements the encoding.BinaryMarshaler interface.
+func (u UUID) MarshalBinary() (data []byte, err error) {
+ data = u.Bytes()
+ return
+}
+
+// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
+// It will return error if the slice isn't 16 bytes long.
+func (u *UUID) UnmarshalBinary(data []byte) (err error) {
+ if len(data) != 16 {
+ err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data))
+ return
+ }
+ copy(u[:], data)
+
+ return
+}
+
+// Value implements the driver.Valuer interface.
+func (u UUID) Value() (driver.Value, error) {
+ return u.String(), nil
+}
+
+// Scan implements the sql.Scanner interface.
+// A 16-byte slice is handled by UnmarshalBinary, while
+// a longer byte slice or a string is handled by UnmarshalText.
+func (u *UUID) Scan(src interface{}) error {
+ switch src := src.(type) {
+ case []byte:
+ if len(src) == 16 {
+ return u.UnmarshalBinary(src)
+ }
+ return u.UnmarshalText(src)
+
+ case string:
+ return u.UnmarshalText([]byte(src))
+ }
+
+ return fmt.Errorf("uuid: cannot convert %T to UUID", src)
+}
+
+// Value implements the driver.Valuer interface.
+func (u NullUUID) Value() (driver.Value, error) {
+ if !u.Valid {
+ return nil, nil
+ }
+ // Delegate to UUID Value function
+ return u.UUID.Value()
+}
+
+// Scan implements the sql.Scanner interface.
+func (u *NullUUID) Scan(src interface{}) error {
+ if src == nil {
+ u.UUID, u.Valid = Nil, false
+ return nil
+ }
+
+ // Delegate to UUID Scan function
+ u.Valid = true
+ return u.UUID.Scan(src)
+}
+
+// FromBytes returns UUID converted from raw byte slice input.
+// It will return error if the slice isn't 16 bytes long.
+func FromBytes(input []byte) (u UUID, err error) {
+ err = u.UnmarshalBinary(input)
+ return
+}
+
+// FromBytesOrNil returns UUID converted from raw byte slice input.
+// Same behavior as FromBytes, but returns a Nil UUID on error.
+func FromBytesOrNil(input []byte) UUID {
+ uuid, err := FromBytes(input)
+ if err != nil {
+ return Nil
+ }
+ return uuid
+}
+
+// FromString returns UUID parsed from string input.
+// Input is expected in a form accepted by UnmarshalText.
+func FromString(input string) (u UUID, err error) {
+ err = u.UnmarshalText([]byte(input))
+ return
+}
+
+// FromStringOrNil returns UUID parsed from string input.
+// Same behavior as FromString, but returns a Nil UUID on error.
+func FromStringOrNil(input string) UUID {
+ uuid, err := FromString(input)
+ if err != nil {
+ return Nil
+ }
+ return uuid
+}
+
+// Returns UUID v1/v2 storage state.
+// Returns epoch timestamp, clock sequence, and hardware address.
+func getStorage() (uint64, uint16, []byte) {
+ storageOnce.Do(initStorage)
+
+ storageMutex.Lock()
+ defer storageMutex.Unlock()
+
+ timeNow := epochFunc()
+ // Clock changed backwards since last UUID generation.
+ // Should increase clock sequence.
+ if timeNow <= lastTime {
+ clockSequence++
+ }
+ lastTime = timeNow
+
+ return timeNow, clockSequence, hardwareAddr[:]
+}
+
+// NewV1 returns UUID based on current timestamp and MAC address.
+func NewV1() UUID {
+ u := UUID{}
+
+ timeNow, clockSeq, hardwareAddr := getStorage()
+
+ binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
+ binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
+ binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
+ binary.BigEndian.PutUint16(u[8:], clockSeq)
+
+ copy(u[10:], hardwareAddr)
+
+ u.SetVersion(1)
+ u.SetVariant()
+
+ return u
+}
+
+// NewV2 returns DCE Security UUID based on POSIX UID/GID.
+func NewV2(domain byte) UUID {
+ u := UUID{}
+
+ timeNow, clockSeq, hardwareAddr := getStorage()
+
+ switch domain {
+ case DomainPerson:
+ binary.BigEndian.PutUint32(u[0:], posixUID)
+ case DomainGroup:
+ binary.BigEndian.PutUint32(u[0:], posixGID)
+ }
+
+ binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
+ binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
+ binary.BigEndian.PutUint16(u[8:], clockSeq)
+ u[9] = domain
+
+ copy(u[10:], hardwareAddr)
+
+ u.SetVersion(2)
+ u.SetVariant()
+
+ return u
+}
+
+// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
+func NewV3(ns UUID, name string) UUID {
+ u := newFromHash(md5.New(), ns, name)
+ u.SetVersion(3)
+ u.SetVariant()
+
+ return u
+}
+
+// NewV4 returns random generated UUID.
+func NewV4() UUID {
+ u := UUID{}
+ safeRandom(u[:])
+ u.SetVersion(4)
+ u.SetVariant()
+
+ return u
+}
+
+// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
+func NewV5(ns UUID, name string) UUID {
+ u := newFromHash(sha1.New(), ns, name)
+ u.SetVersion(5)
+ u.SetVariant()
+
+ return u
+}
+
+// Returns UUID based on hashing of namespace UUID and name.
+func newFromHash(h hash.Hash, ns UUID, name string) UUID {
+ u := UUID{}
+ h.Write(ns[:])
+ h.Write([]byte(name))
+ copy(u[:], h.Sum(nil))
+
+ return u
+}