VMware vSphere Integrated Containers provider (#206)
* Add Virtual Kubelet provider for VIC Initial virtual kubelet provider for VMware VIC. This provider currently handles creating and starting of a pod VM via the VIC portlayer and persona server. Image store handling via the VIC persona server. This provider currently requires the feature/wolfpack branch of VIC. * Added pod stop and delete. Also added node capacity. Added the ability to stop and delete pod VMs via VIC. Also retrieve node capacity information from the VCH. * Cleanup and readme file Some file clean up and added a Readme.md markdown file for the VIC provider. * Cleaned up errors, added function comments, moved operation code 1. Cleaned up error handling. Set standard for creating errors. 2. Added method prototype comments for all interface functions. 3. Moved PodCreator, PodStarter, PodStopper, and PodDeleter to a new folder. * Add mocking code and unit tests for podcache, podcreator, and podstarter Used the unit test framework used in VIC to handle assertions in the provider's unit test. Mocking code generated using OSS project mockery, which is compatible with the testify assertion framework. * Vendored packages for the VIC provider Requires feature/wolfpack branch of VIC and a few specific commit sha of projects used within VIC. * Implementation of POD Stopper and Deleter unit tests (#4) * Updated files for initial PR
This commit is contained in:
292
Gopkg.lock
generated
292
Gopkg.lock
generated
@@ -37,6 +37,12 @@
|
||||
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
|
||||
version = "v1.0.5"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/asaskevich/govalidator"
|
||||
packages = ["."]
|
||||
revision = "ccb8e960c48f04d6935e72476ae4a51028f9e22f"
|
||||
version = "v9"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/aws/aws-sdk-go"
|
||||
packages = [
|
||||
@@ -129,9 +135,58 @@
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/docker"
|
||||
packages = ["api/types/strslice"]
|
||||
revision = "092cba3727bb9b4a2f0e922cd6c0f93ea270e363"
|
||||
version = "v1.13.1"
|
||||
packages = [
|
||||
"api/errors",
|
||||
"api/types",
|
||||
"api/types/backend",
|
||||
"api/types/blkiodev",
|
||||
"api/types/container",
|
||||
"api/types/filters",
|
||||
"api/types/mount",
|
||||
"api/types/network",
|
||||
"api/types/registry",
|
||||
"api/types/strslice",
|
||||
"api/types/swarm",
|
||||
"api/types/versions",
|
||||
"daemon/graphdriver",
|
||||
"image",
|
||||
"image/v1",
|
||||
"layer",
|
||||
"oci",
|
||||
"pkg/archive",
|
||||
"pkg/chrootarchive",
|
||||
"pkg/fileutils",
|
||||
"pkg/idtools",
|
||||
"pkg/ioutils",
|
||||
"pkg/jsonlog",
|
||||
"pkg/jsonmessage",
|
||||
"pkg/longpath",
|
||||
"pkg/mount",
|
||||
"pkg/plugingetter",
|
||||
"pkg/plugins",
|
||||
"pkg/plugins/transport",
|
||||
"pkg/pools",
|
||||
"pkg/progress",
|
||||
"pkg/promise",
|
||||
"pkg/pubsub",
|
||||
"pkg/random",
|
||||
"pkg/reexec",
|
||||
"pkg/streamformatter",
|
||||
"pkg/stringid",
|
||||
"pkg/system",
|
||||
"pkg/term",
|
||||
"pkg/term/windows",
|
||||
"pkg/truncindex",
|
||||
"plugin/v2",
|
||||
"reference"
|
||||
]
|
||||
revision = "49bf474f9ed7ce7143a59d1964ff7b7fd9b52178"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/engine-api"
|
||||
packages = ["types/strslice"]
|
||||
revision = "3d1601b9d2436a70b0dfc045a23f6503d19195df"
|
||||
version = "v0.4.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/go-connections"
|
||||
@@ -158,6 +213,15 @@
|
||||
revision = "7c59e343cd9d1f3f5577b5bfb71f6486beb4c006"
|
||||
version = "v0.4.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/libnetwork"
|
||||
packages = [
|
||||
"iptables",
|
||||
"portallocator"
|
||||
]
|
||||
revision = "1ee720e18fe98dceda6039bdd005ffbcb359d343"
|
||||
version = "v0.5.6"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/flynn/go-shlex"
|
||||
@@ -182,6 +246,72 @@
|
||||
revision = "6529cf7c58879c08d927016dde4477f18a0634cb"
|
||||
version = "v1.36.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-openapi/analysis"
|
||||
packages = ["."]
|
||||
revision = "d5a75b7d751ca3f11ad5d93cfe97405f2c3f6a47"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-openapi/errors"
|
||||
packages = ["."]
|
||||
revision = "fc3f73a224499b047eda7191e5d22e1e9631e86f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/go-openapi/jsonpointer"
|
||||
packages = ["."]
|
||||
revision = "779f45308c19820f1a69e9a4cd965f496e0da10f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/go-openapi/jsonreference"
|
||||
packages = ["."]
|
||||
revision = "36d33bfe519efae5632669801b180bf1a245da3b"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-openapi/loads"
|
||||
packages = [
|
||||
".",
|
||||
"fmts"
|
||||
]
|
||||
revision = "6bb6486231e079ea125c0f39994ed3d0c53399ed"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-openapi/runtime"
|
||||
packages = [
|
||||
".",
|
||||
"client"
|
||||
]
|
||||
revision = "3b13ebb46790d871d74a6c2450fa4b1280f90854"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/go-openapi/spec"
|
||||
packages = ["."]
|
||||
revision = "bfb48d37839bcacb52be3f539ffac5abcda7e195"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-openapi/strfmt"
|
||||
packages = ["."]
|
||||
revision = "0cb3db44c13bad3b3f567b762a66751972a310cc"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/go-openapi/swag"
|
||||
packages = ["."]
|
||||
revision = "cf0bdb963811675a4d7e74901cefc7411a1df939"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-openapi/validate"
|
||||
packages = ["."]
|
||||
revision = "035dcd74f1f61e83debe1c22950dc53556e7e4b2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/godbus/dbus"
|
||||
packages = ["."]
|
||||
revision = "a389bdde4dd695d414e47b755e95e72b7826432c"
|
||||
version = "v4.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gogo/protobuf"
|
||||
packages = [
|
||||
@@ -353,6 +483,18 @@
|
||||
revision = "ca39e5af3ece67bbcda3d0f4f56a8e24d9f2dad4"
|
||||
version = "1.1.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/kr/pretty"
|
||||
packages = ["."]
|
||||
revision = "cfb55aafdaf3ec08f0db22699ab822c50091b1c4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/kr/text"
|
||||
packages = ["."]
|
||||
revision = "7cafcd837844e784b526369c9bce262804aebc60"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/magiconair/properties"
|
||||
packages = ["."]
|
||||
@@ -385,10 +527,20 @@
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/opencontainers/runc"
|
||||
packages = ["libcontainer/user"]
|
||||
packages = [
|
||||
"libcontainer/configs",
|
||||
"libcontainer/devices",
|
||||
"libcontainer/system",
|
||||
"libcontainer/user"
|
||||
]
|
||||
revision = "baf6536d6259209c3edfa2b22237af82942d3dfa"
|
||||
version = "v0.1.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/opencontainers/runtime-spec"
|
||||
packages = ["specs-go"]
|
||||
revision = "1c7c27d043c2a5e513a44084d2b10d77d1402b8c"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pelletier/go-toml"
|
||||
packages = ["."]
|
||||
@@ -446,15 +598,28 @@
|
||||
revision = "b5e8006cbee93ec955a89ab31e0e3ce3204f3736"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/stretchr/objx"
|
||||
packages = ["."]
|
||||
revision = "facf9a85c22f48d2f52f2380e4efce1768749a89"
|
||||
version = "v0.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = [
|
||||
"assert",
|
||||
"mock",
|
||||
"require"
|
||||
]
|
||||
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
|
||||
version = "v1.2.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/tchap/go-patricia"
|
||||
packages = ["patricia"]
|
||||
revision = "666120de432aea38ab06bd5c818f04f4129882c9"
|
||||
version = "v2.2.6"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/vbatts/tar-split"
|
||||
packages = [
|
||||
@@ -465,6 +630,107 @@
|
||||
revision = "38ec4ddb06dedbea0a895c4848b248eb38af221b"
|
||||
version = "v0.10.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/vishvananda/netlink"
|
||||
packages = [
|
||||
".",
|
||||
"nl"
|
||||
]
|
||||
revision = "482f7a52b758233521878cb6c5904b6bd63f3457"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/vishvananda/netns"
|
||||
packages = ["."]
|
||||
revision = "be1fbeda19366dea804f00efff2dd73a1642fdcc"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/vmware/govmomi"
|
||||
packages = [
|
||||
".",
|
||||
"find",
|
||||
"list",
|
||||
"nfc",
|
||||
"object",
|
||||
"performance",
|
||||
"property",
|
||||
"session",
|
||||
"task",
|
||||
"vim25",
|
||||
"vim25/debug",
|
||||
"vim25/methods",
|
||||
"vim25/mo",
|
||||
"vim25/progress",
|
||||
"vim25/soap",
|
||||
"vim25/types",
|
||||
"vim25/xml"
|
||||
]
|
||||
revision = "123ed177021588bac57b5c87c1a84270ddf2eca8"
|
||||
version = "v0.17.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "feature/wolfpack"
|
||||
name = "github.com/vmware/vic"
|
||||
packages = [
|
||||
"lib/apiservers/engine/backends/cache",
|
||||
"lib/apiservers/engine/backends/container",
|
||||
"lib/apiservers/engine/backends/convert",
|
||||
"lib/apiservers/engine/backends/endpoint",
|
||||
"lib/apiservers/engine/backends/filter",
|
||||
"lib/apiservers/engine/backends/kv",
|
||||
"lib/apiservers/engine/backends/portmap",
|
||||
"lib/apiservers/engine/constants",
|
||||
"lib/apiservers/engine/errors",
|
||||
"lib/apiservers/engine/network",
|
||||
"lib/apiservers/engine/proxy",
|
||||
"lib/apiservers/portlayer/client",
|
||||
"lib/apiservers/portlayer/client/containers",
|
||||
"lib/apiservers/portlayer/client/events",
|
||||
"lib/apiservers/portlayer/client/interaction",
|
||||
"lib/apiservers/portlayer/client/kv",
|
||||
"lib/apiservers/portlayer/client/logging",
|
||||
"lib/apiservers/portlayer/client/misc",
|
||||
"lib/apiservers/portlayer/client/scopes",
|
||||
"lib/apiservers/portlayer/client/storage",
|
||||
"lib/apiservers/portlayer/client/tasks",
|
||||
"lib/apiservers/portlayer/models",
|
||||
"lib/archive",
|
||||
"lib/config",
|
||||
"lib/config/executor",
|
||||
"lib/constants",
|
||||
"lib/metadata",
|
||||
"lib/migration/feature",
|
||||
"pkg/certificate",
|
||||
"pkg/dio",
|
||||
"pkg/errors",
|
||||
"pkg/ip",
|
||||
"pkg/log",
|
||||
"pkg/log/syslog",
|
||||
"pkg/retry",
|
||||
"pkg/trace",
|
||||
"pkg/version",
|
||||
"pkg/vsphere/extraconfig",
|
||||
"pkg/vsphere/extraconfig/vmomi",
|
||||
"pkg/vsphere/performance",
|
||||
"pkg/vsphere/session",
|
||||
"pkg/vsphere/sys",
|
||||
"pkg/vsphere/tasks",
|
||||
"pkg/vsphere/vm"
|
||||
]
|
||||
revision = "aaff393e268f9ba7a70f55455174e671ce27f3ef"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/vmware/vmw-guestinfo"
|
||||
packages = [
|
||||
"bdoor",
|
||||
"message",
|
||||
"rpcout",
|
||||
"rpcvmx",
|
||||
"vmcheck"
|
||||
]
|
||||
revision = "25eff159a728be87e103a0b8045e08273f4dbec4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/xeipuuv/gojsonpointer"
|
||||
@@ -486,8 +752,13 @@
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["ssh/terminal"]
|
||||
revision = "2d027ae1dddd4694d54f7a8b6cbe78dca8720226"
|
||||
packages = [
|
||||
"nacl/secretbox",
|
||||
"poly1305",
|
||||
"salsa20/salsa",
|
||||
"ssh/terminal"
|
||||
]
|
||||
revision = "94eea52f7b742c7cbe0b03b22f0c4c8631ece122"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -495,6 +766,7 @@
|
||||
packages = [
|
||||
"context",
|
||||
"http/httpguts",
|
||||
"context/ctxhttp",
|
||||
"http2",
|
||||
"http2/hpack",
|
||||
"idna",
|
||||
@@ -578,6 +850,12 @@
|
||||
packages = ["rate"]
|
||||
revision = "fbb02b2291d28baffd63558aa44b4b56f178d650"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/time"
|
||||
packages = ["rate"]
|
||||
revision = "fbb02b2291d28baffd63558aa44b4b56f178d650"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/inf.v0"
|
||||
packages = ["."]
|
||||
@@ -762,6 +1040,6 @@
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "574b1551c18b46c07b8d4a67c305c335c6001f6e9a07b41b15067a0f2aa9352e"
|
||||
inputs-digest = "78bbfe28d4d9a3dc7f506a80b31c877133e9db027e30e1b006e0d6f6aaf5c73e"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
39
Gopkg.toml
39
Gopkg.toml
@@ -77,3 +77,42 @@
|
||||
name = "k8s.io/kubernetes"
|
||||
version = "1.10.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "feature/wolfpack"
|
||||
name = "github.com/vmware/vic"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/docker/docker"
|
||||
revision = "49bf474f9ed7ce7143a59d1964ff7b7fd9b52178"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/vishvananda/netlink"
|
||||
revision = "482f7a52b758233521878cb6c5904b6bd63f3457"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/opencontainers/runtime-spec"
|
||||
revision = "1c7c27d043c2a5e513a44084d2b10d77d1402b8c"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/go-openapi/analysis"
|
||||
revision = "d5a75b7d751ca3f11ad5d93cfe97405f2c3f6a47"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/go-openapi/errors"
|
||||
revision = "fc3f73a224499b047eda7191e5d22e1e9631e86f"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/go-openapi/loads"
|
||||
revision = "6bb6486231e079ea125c0f39994ed3d0c53399ed"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/go-openapi/runtime"
|
||||
revision = "3b13ebb46790d871d74a6c2450fa4b1280f90854"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/go-openapi/strfmt"
|
||||
revision = "0cb3db44c13bad3b3f567b762a66751972a310cc"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/go-openapi/validate"
|
||||
revision = "035dcd74f1f61e83debe1c22950dc53556e7e4b2"
|
||||
|
||||
2
Makefile
2
Makefile
@@ -54,7 +54,7 @@ docker:
|
||||
@echo "Docker Build..."
|
||||
$Q docker build -t $(DOCKER_IMAGE) .
|
||||
|
||||
clean:
|
||||
clean: clean-build
|
||||
@echo "Clean..."
|
||||
$Q rm -rf bin
|
||||
|
||||
|
||||
80
providers/vic/README.md
Normal file
80
providers/vic/README.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# vSphere Integrated Containers virtual kubelet provider
|
||||
|
||||
This is a very early preview of the [VMware vSphere Integrated Containers](https://github.com/vmware/vic) virtual kubelet provider.
|
||||
|
||||
## Introduction to vSphere Integrated Containers
|
||||
|
||||
For those who are unfamiliar with vSphere Integrated Containers, it is a open source project that enables users to create a CaaS (container as a service) endpoint on a vSphere cluster. There are a few advantages of using vSphere Integrated Containers over using standard Docker in a VM:
|
||||
|
||||
1. Containers are wrapped in VMs and provides stronger isolation than a standard OS containers.
|
||||
1. Use of vSphere Integrated Containers removes the need to deploy a host VM, OS, and docker software. It also removes the requirement to maintain that stack. An administrator can simply deploy a VCH (virtual container host) and get back a docker endpoint. With this endpoint, users can deploy containers. vSphere manages the endpoint.
|
||||
1. The VCH can span a vCenter cluster, providing a much larger virtual host than any VM or physical machine on which users can deploy their containers. Users can deploy containers across the entire vCenter cluster using this single virtual host.
|
||||
|
||||
## Virtual Kubelet in vSphere Integrated Containers
|
||||
|
||||
Within a deployed VCH, there is a daemon that provides a Docker compatible endpoint. We refer to this daemon as a Docker personality server. With the vSphere integrated Container virtual kubelet provider, we are introducing a second personality server that provides a Kubelet compatible endpoint for the VCH. With this endpoint, the VCH can join a kubernetes cluster, providing a robust virtual node for pods. Just as the VCH provides a CaaS endpoint for Docker users, it will now provide a Pod-as-a-Service endpoint for kubernetes users. vSphere manages the availability of the pods and remove the need for administrators to maintain the uptime of a normal node, it's software, and the pods running on it. For the user, it provides a much larger virtual node than any single VM or physical machine.
|
||||
|
||||

|
||||
|
||||
## Pod VM in vSphere Integrated Containers
|
||||
|
||||
With the vSphere integrated Container virtual kubelet provider, we are also introducing a new isolation concept called the pod vm. With the original vSphere Integrated Containers, we introduced stronger container isolation through our container vm concept. Interested parties may go to the vSphere Integrated Containers github project page to read all about it. A standard pod in a standard kubernetes node is just a collection of containers with a parent container. The containers are isolated by the OS, but the pod is not. With vSphere Integrated Containers, pods are strongly isolated within a pod vm. Each pod runs within it's own pod vm.
|
||||
|
||||

|
||||
|
||||
## Project Status
|
||||
|
||||
This is an early preview. The project relies on a feature branch within the vSphere Integrated Containers project. Currently, pods can be created and removed. Some node statuses can be queried. This provider reuses vSphere Integrated Containers to provision pods. As such, there is a dependency between this provider and the vSphere Integrated Containers project. All changes to that project are currently being done on a feature branch, named wolfpack.
|
||||
|
||||
There are a lot of kubelet features still undefined in the virtual-kubelet project, such as networking, volumes, exec, logging, etc. As these are defined, we will add this support into our provider and into vSphere Integrated Containers.
|
||||
|
||||
## Building vSphere Integrated Containers with virtual kubelet support
|
||||
|
||||
This project and the associated vSphere Integrated Containers project are in active development. The simplest way to utilize this virtual kubelet provider, is to build the kubelet project and the wolfpack feature branch of vSphere Integrated Containers. The following is a step by step instructions on building both. There is an asciinema playback of this process below. The current instructions assumes your development environment is Linux.
|
||||
|
||||
First, ensure golang 1.8.x and git are installed on your machine. The vSphere Integrated Containers project checks for go 1.8. Next, perform the following steps
|
||||
|
||||
1. make sure you have go 1.8.x and prepare your GOPATH
|
||||
* $> `go version`
|
||||
* $> `mkdir -p go/src/github.com/virtual-kubelet`
|
||||
1. get and build the virtual kubelet
|
||||
* $> `cd go/src/github.com/virtual-kubelet`
|
||||
* $> `git clone https://github.com/virtual-kubelet/virtual-kubelet.git`
|
||||
* $> `cd virtual-kubelet`
|
||||
* $> `go build .`
|
||||
1. get wolfpack feature branch of vSphere Integrated Containers
|
||||
* $> `cd`
|
||||
* $> `mkdir -p go/src/github.com/vmware`
|
||||
* $> `cd $GOPATH/src/github.com/vmware`
|
||||
* $> `git clone https://github.com/vmware/vic`
|
||||
* $> `cd vic`
|
||||
* $> `git checkout feature/wolfpack`
|
||||
1. build vSphere Integrated Containers **as root**
|
||||
* $> `cd $GOPATH/src/github.com/vmware/vic`
|
||||
* $> `sudo su`
|
||||
* $> `export GOPATH=/home/[user]/go`
|
||||
* $> `export PATH=$PATH:/usr/local/go/bin:/home/[user]/go/bin`
|
||||
* $> `export VIRTUAL_KUBELET_PATH=$GOPATH/src/github.com/virtual-kubelet/virtual-kubelet/virtual-kubelet`
|
||||
* $> `make most-vkubelet`
|
||||
* $> `chown -R user:user *`
|
||||
* $> `exit` (exit root)
|
||||
|
||||
You should now have a **bin** folder in the vic folder. This contains all the necessary assets to deploy a VCH using the vic-machine CLI.
|
||||
|
||||
[Asciinema recording of the build steps](https://asciinema.org/a/oeGbhPmKWqVgWeQxCOPLHCcYN)
|
||||
|
||||
## Usage
|
||||
|
||||
To get started with the vSphere Integrated Containers' virtual kubelet, users should first familiarize themselves with deploying vSphere Integrated Containers and using the VCH as a docker endpoint. We're leveraging the same deployment model with the virtual kubelet. Administrators deploy a VCH, using the vic-machine CLI or [VIC Appliance](https://github.com/vmware/vic-product), specifying the kubernetes cluster that the VCH should join.
|
||||
|
||||
Virtual Container Hosts should be deployed with the proper CLI flags to enable virtual kubelet, including both `--k8s-server-address` and `--k8s-config`.
|
||||
|
||||
Once the VCH is fully started, it automatically joins the cluster. Administrators can then apply taints or labels to the virtual node to create node affinity. Pods created with the right toleration or nodeSelector will then be deployed onto the VCH.
|
||||
|
||||
1. Get IP or FQDN of your kubernetes master node
|
||||
2. Get location of your kube config you use for kubectl (usually in $HOME/.kube/config)
|
||||
3. Deploy a virtual container host with vic-machine.
|
||||
4. $> `kubectl get nodes`
|
||||
5. Deploy a pod
|
||||
|
||||
[Asciinema recording of an example usage](https://asciinema.org/a/nArPOJSKWJwx09UsJVUFiI2y7)
|
||||
162
providers/vic/cache/pod_cache.go
vendored
Normal file
162
providers/vic/cache/pod_cache.go
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
|
||||
vicpod "github.com/virtual-kubelet/virtual-kubelet/providers/vic/pod"
|
||||
)
|
||||
|
||||
type PodCache interface {
|
||||
Rehydrate(op trace.Operation) error
|
||||
Get(op trace.Operation, namespace, name string) (*vicpod.VicPod, error)
|
||||
GetAll(op trace.Operation) []*vicpod.VicPod
|
||||
Add(op trace.Operation, namespace, name string, pod *vicpod.VicPod) error
|
||||
Delete(op trace.Operation, namespace, name string) error
|
||||
}
|
||||
|
||||
type VicPodCache struct {
|
||||
cache map[string]*vicpod.VicPod
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
type CacheError string
|
||||
|
||||
func (c CacheError) Error() string {return string(c)}
|
||||
|
||||
const (
|
||||
PodCachePodNameError = CacheError("PodCache called with empty pod name")
|
||||
PodCacheNilPodError = CacheError("PodCache called with nil pod")
|
||||
)
|
||||
|
||||
func NewVicPodCache() PodCache {
|
||||
v := &VicPodCache{}
|
||||
|
||||
v.cache = make(map[string]*vicpod.VicPod, 0)
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// Rehydrate replenishes the cache in the event of a virtual kubelet restart.
|
||||
// NOT YET IMPLEMENTED
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// returns:
|
||||
// error
|
||||
func (v *VicPodCache) Rehydrate(op trace.Operation) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the pod definition for a running pod
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// namespace namespace of the pod. Empty namespace assumes default.
|
||||
// name name of the pod
|
||||
// returns:
|
||||
// error
|
||||
func (v *VicPodCache) Get(op trace.Operation, namespace, name string) (*vicpod.VicPod, error) {
|
||||
defer trace.End(trace.Begin(name, op))
|
||||
|
||||
if name == "" {
|
||||
op.Errorf(PodCachePodNameError.Error())
|
||||
return nil, PodCachePodNameError
|
||||
}
|
||||
|
||||
//TODO: handle namespaces
|
||||
|
||||
pod, ok := v.cache[name]
|
||||
if !ok {
|
||||
err := fmt.Errorf("Pod %s not found in cache", name)
|
||||
|
||||
op.Info(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pod, nil
|
||||
}
|
||||
|
||||
// GetAll returns the pod definitions for all running pods
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// returns:
|
||||
// error
|
||||
func (v *VicPodCache) GetAll(op trace.Operation) []*vicpod.VicPod {
|
||||
defer trace.End(trace.Begin("", op))
|
||||
defer v.lock.Unlock()
|
||||
v.lock.Lock()
|
||||
|
||||
list := make([]*vicpod.VicPod, 0)
|
||||
|
||||
for _, vp := range v.cache {
|
||||
list = append(list, vp)
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
// Add saves the pod definition of a running pod
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// namespace namespace of the pod. Empty namespace assumes default.
|
||||
// name name of the pod
|
||||
// pod pod definition
|
||||
// returns:
|
||||
// error
|
||||
func (v *VicPodCache) Add(op trace.Operation, namespace, name string, pod *vicpod.VicPod) error {
|
||||
defer trace.End(trace.Begin(name, op))
|
||||
defer v.lock.Unlock()
|
||||
v.lock.Lock()
|
||||
|
||||
if name == "" {
|
||||
op.Errorf(PodCachePodNameError.Error())
|
||||
return PodCachePodNameError
|
||||
}
|
||||
if pod == nil {
|
||||
op.Errorf(PodCacheNilPodError.Error())
|
||||
return PodCacheNilPodError
|
||||
}
|
||||
|
||||
//TODO: handle namespaces
|
||||
|
||||
_, ok := v.cache[name]
|
||||
if ok {
|
||||
err := fmt.Errorf("Pod %s already cached. Duplicate pod.", name)
|
||||
|
||||
op.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
v.cache[name] = pod
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete removes a pod definition from the cache. It does not stop/delete the
|
||||
// actual pod.
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// namespace namespace of the pod. Empty namespace assumes default.
|
||||
// name name of the pod
|
||||
// returns:
|
||||
// error
|
||||
func (v *VicPodCache) Delete(op trace.Operation, namespace, name string) error {
|
||||
defer trace.End(trace.Begin(name, op))
|
||||
defer v.lock.Unlock()
|
||||
v.lock.Lock()
|
||||
|
||||
if name == "" {
|
||||
op.Errorf(PodCachePodNameError.Error())
|
||||
return PodCachePodNameError
|
||||
}
|
||||
|
||||
//TODO: handle namespaces
|
||||
delete(v.cache, name)
|
||||
|
||||
return nil
|
||||
}
|
||||
139
providers/vic/cache/pod_cache_test.go
vendored
Normal file
139
providers/vic/cache/pod_cache_test.go
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/pod"
|
||||
"k8s.io/api/core/v1"
|
||||
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
)
|
||||
|
||||
var (
|
||||
testpod *v1.Pod
|
||||
)
|
||||
|
||||
func init() {
|
||||
testpod = &v1.Pod{}
|
||||
}
|
||||
|
||||
func setup(t *testing.T, op trace.Operation) PodCache {
|
||||
c := NewVicPodCache()
|
||||
assert.NotNil(t, c, "NewPod did not return a valid cache")
|
||||
|
||||
//populate with dummy data
|
||||
vp := pod.VicPod{
|
||||
ID: "123",
|
||||
Pod: testpod,
|
||||
}
|
||||
c.Add(op, "namespace1", "testpod1a", &vp)
|
||||
c.Add(op, "namespace1", "testpod1b", &vp)
|
||||
c.Add(op, "namespace2", "testpod2a", &vp)
|
||||
c.Add(op, "namespace2", "testpod2b", &vp)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func TestRehydrate(t *testing.T) {
|
||||
op := trace.NewOperation(context.Background(), "")
|
||||
|
||||
c := NewVicPodCache()
|
||||
assert.NotNil(t, c, "NewPod did not return a valid cache")
|
||||
|
||||
err := c.Rehydrate(op)
|
||||
assert.Nil(t, err, "PodCache.Rehydrate failed with error: %s", err)
|
||||
}
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
var err error
|
||||
op := trace.NewOperation(context.Background(), "")
|
||||
|
||||
c := NewVicPodCache()
|
||||
assert.NotNil(t, c, "NewPod did not return a valid cache")
|
||||
|
||||
//populate with dummy data
|
||||
vp := pod.VicPod{
|
||||
ID: "123",
|
||||
Pod: testpod,
|
||||
}
|
||||
|
||||
// Positive cases
|
||||
err = c.Add(op, "namespace1", "testpod1a", &vp)
|
||||
assert.Nil(t, err, "PodCache.Add failed with error: %s", err)
|
||||
|
||||
// Negative cases
|
||||
err = c.Add(op, "namespace1", "", &vp)
|
||||
assert.NotNil(t, err, "PodCache.Add expected error for empty name")
|
||||
assert.Equal(t, err, PodCachePodNameError)
|
||||
|
||||
err = c.Add(op, "namespace1", "test2", nil)
|
||||
assert.NotNil(t, err, "PodCache.Add expected error for nil pod")
|
||||
assert.Equal(t, err, PodCacheNilPodError)
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
var err error
|
||||
var vpod *pod.VicPod
|
||||
op := trace.NewOperation(context.Background(), "")
|
||||
|
||||
c := setup(t, op)
|
||||
|
||||
// Positive cases
|
||||
vpod, err = c.Get(op, "namespace1", "testpod1a")
|
||||
assert.Nil(t, err, "PodCache.Get failed with error: %s", err)
|
||||
assert.NotNil(t, vpod, "PodCache.Get expected to return non-nil pod but received nil")
|
||||
|
||||
vpod, err = c.Get(op, "namespace2", "testpod2a")
|
||||
assert.Nil(t, err, "PodCache.Get failed with error: %s", err)
|
||||
assert.NotNil(t, vpod, "PodCache.Get expected to return non-nil pod but received nil")
|
||||
|
||||
// Negative cases
|
||||
vpod, err = c.Get(op, "namespace1", "")
|
||||
assert.Equal(t, err, PodCachePodNameError)
|
||||
assert.Nil(t, vpod, "PodCache.Get expected to return nil pod but received non-nil")
|
||||
|
||||
//TODO: uncomment out once namespace support added to cache
|
||||
//vpod, err = c.Get(op, "namespace1", "testpod2a")
|
||||
//assert.NotNil(t, err, "PodCache.Get did not respect namespace: %s", err)
|
||||
|
||||
//vpod, err = c.Get(op, "", "testpod1a")
|
||||
//assert.NotNil(t, err, "PodCache.Get did not respect namespace: %s", err)
|
||||
}
|
||||
|
||||
func TestGetAll(t *testing.T) {
|
||||
op := trace.NewOperation(context.Background(), "")
|
||||
|
||||
c := setup(t, op)
|
||||
|
||||
vps := c.GetAll(op)
|
||||
assert.NotNil(t, vps, "PodCache.GetAll returned nil slice")
|
||||
assert.Len(t, vps, 4, "PodCache.Get did not return all pod definitions. Returned %d pods.", len(vps))
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
var err error
|
||||
op := trace.NewOperation(context.Background(), "")
|
||||
|
||||
c := setup(t, op)
|
||||
|
||||
// Positive cases
|
||||
err = c.Delete(op, "namespace1", "testpod1a")
|
||||
assert.Nil(t, err, "PodCache.Delete failed with error: %s", err)
|
||||
vps := c.GetAll(op)
|
||||
assert.Len(t, vps, 3, "PodCache.Delete did not delete pod.")
|
||||
|
||||
// Negative cases
|
||||
err = c.Delete(op, "namespace2", "")
|
||||
assert.Equal(t, err, PodCachePodNameError)
|
||||
|
||||
//TODO: uncomment the tests below once namespace support added to cache
|
||||
//vps = c.GetAll(op)
|
||||
//currCount := len(vps)
|
||||
//err = c.Delete(op, "", "testpod1b")
|
||||
//assert.NotNil(t, err, "PodCache.Delete expected to return error but received nil")
|
||||
//vps = c.GetAll(op)
|
||||
//assert.Len(t, vps, currCount, "PodCache.Delete ignored namespace")
|
||||
}
|
||||
|
||||
77
providers/vic/config.go
Normal file
77
providers/vic/config.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package vic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
)
|
||||
|
||||
type VicConfig struct {
|
||||
PersonaAddr string `yaml:"persona-server"`
|
||||
PortlayerAddr string `yaml:"portlayer-server"`
|
||||
HostUUID string `yaml:"host-uuid"`
|
||||
}
|
||||
|
||||
const (
|
||||
personaAddrEnv = "PERSONA_ADDR"
|
||||
portlayerAddrEnv = "PORTLAYER_ADDR"
|
||||
hostUUIDEnv = "HOST_UUID"
|
||||
localVirtualKubelet = "LOCAL_VIRTUAL_KUBELET"
|
||||
)
|
||||
|
||||
func LocalInstance() bool {
|
||||
value := strings.ToLower(os.Getenv(localVirtualKubelet))
|
||||
|
||||
if value == "1" || value == "t" || value == "true" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func NewVicConfig(op trace.Operation, configFile string) VicConfig {
|
||||
var config VicConfig
|
||||
|
||||
if configFile == "" {
|
||||
config.loadConfigFromEnv()
|
||||
} else {
|
||||
config.loadConfigFile(configFile)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
func (v *VicConfig) loadConfigFile(configFile string) error {
|
||||
op := trace.NewOperation(context.Background(), "LoadConfigFile - %s", configFile)
|
||||
defer trace.End(trace.Begin("", op))
|
||||
|
||||
contents, err := ioutil.ReadFile(configFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var config VicConfig
|
||||
err = yaml.Unmarshal(contents, &config)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Unable to unmarshal vic virtual kubelet configfile: %s", err.Error())
|
||||
op.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
*v = config
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *VicConfig) loadConfigFromEnv() {
|
||||
v.PersonaAddr = os.Getenv(personaAddrEnv)
|
||||
v.PortlayerAddr = os.Getenv(portlayerAddrEnv)
|
||||
v.HostUUID = os.Getenv(hostUUIDEnv)
|
||||
}
|
||||
13
providers/vic/constants/constants.go
Normal file
13
providers/vic/constants/constants.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
// DefaultCPUs - the default number of container VM CPUs
|
||||
DefaultCPUs = 2
|
||||
DefaultMemory = 512
|
||||
|
||||
DummyImage = "f6e427c148a766d2d6c117d67359a0aa7d133b5bc05830a7ff6e8b64ff6b1d1d" //busybox
|
||||
DummyLayerID = "02d3847f0b0fb7acd4419040cc53febf91cb112db2451d9b27a245dee5b227c0" //busybox
|
||||
DummyRepoName = "busybox"
|
||||
|
||||
HostName = "test-kubelet"
|
||||
)
|
||||
113
providers/vic/docker_client.go
Normal file
113
providers/vic/docker_client.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package vic
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
)
|
||||
|
||||
type CreateResponse struct {
|
||||
Id string `json:"Id"`
|
||||
Warnings string `json:"Warnings"`
|
||||
}
|
||||
|
||||
// Super simplistic docker client for the virtual kubelet to perform some operations
|
||||
type DockerClient interface {
|
||||
Ping(op trace.Operation) error
|
||||
CreateContainer(op trace.Operation, config string) error
|
||||
PullImage(op trace.Operation, image string) error
|
||||
}
|
||||
|
||||
type VicDockerClient struct {
|
||||
serverAddr string
|
||||
}
|
||||
|
||||
func NewVicDockerClient(personaAddr string) DockerClient {
|
||||
return &VicDockerClient{
|
||||
serverAddr: personaAddr,
|
||||
}
|
||||
}
|
||||
|
||||
func (v *VicDockerClient) Ping(op trace.Operation) error {
|
||||
personaServer := fmt.Sprintf("http://%s/v1.35/info", v.serverAddr)
|
||||
resp, err := http.Get(personaServer)
|
||||
if err != nil {
|
||||
op.Errorf("Ping failed: error = %s", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
op.Errorf("Ping failed: status = %d", resp.StatusCode)
|
||||
return fmt.Errorf("Server Error")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *VicDockerClient) CreateContainer(op trace.Operation, config string) error {
|
||||
personaServer := fmt.Sprintf("http://%s/v1.35/containers/create", v.serverAddr)
|
||||
reader := bytes.NewBuffer([]byte(config))
|
||||
resp, err := http.Post(personaServer, "application/json", reader)
|
||||
if err != nil {
|
||||
op.Errorf("Error from from docker create: error = %s", err.Error())
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode >= 300 {
|
||||
op.Errorf("Error from from docker create: status = %d", resp.StatusCode)
|
||||
return fmt.Errorf("Image not found")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
|
||||
op.Infof("Response from docker create: status = %d", resp.StatusCode)
|
||||
op.Infof("Response from docker create: body = %s", string(body))
|
||||
var createResp CreateResponse
|
||||
err = json.Unmarshal(body, &createResp)
|
||||
if err != nil {
|
||||
op.Errorf("Failed to unmarshal response from container create post")
|
||||
return err
|
||||
}
|
||||
startContainerUrl := fmt.Sprintf("http://%s/v1.35/containers/%s/start", v.serverAddr, createResp.Id)
|
||||
op.Infof("Starting container with request - %s", startContainerUrl)
|
||||
_, err = http.Post(startContainerUrl, "", nil)
|
||||
if err != nil {
|
||||
op.Errorf("Failed to start container %s", createResp.Id)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *VicDockerClient) PullImage(op trace.Operation, image string) error {
|
||||
pullClient := &http.Client{Timeout: 60 * time.Second}
|
||||
personaServer := fmt.Sprintf("http://%s/v1.35/images/create?fromImage=%s", v.serverAddr, image)
|
||||
op.Infof("POST %s", personaServer)
|
||||
reader := bytes.NewBuffer([]byte(""))
|
||||
resp, err := pullClient.Post(personaServer, "application/json", reader)
|
||||
if err != nil {
|
||||
op.Errorf("Error from docker pull: error = %s", err.Error())
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
msg := fmt.Sprintf("Error from docker pull: status = %d", resp.StatusCode)
|
||||
op.Errorf(msg)
|
||||
return fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Error reading docker pull response: error = %s", err.Error())
|
||||
op.Errorf(msg)
|
||||
return fmt.Errorf(msg)
|
||||
}
|
||||
op.Infof("Response from docker pull: body = %s", string(body))
|
||||
|
||||
return nil
|
||||
}
|
||||
261
providers/vic/operations/common_test.go
Normal file
261
providers/vic/operations/common_test.go
Normal file
@@ -0,0 +1,261 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
vicpod "github.com/virtual-kubelet/virtual-kubelet/providers/vic/pod"
|
||||
|
||||
"github.com/vmware/vic/lib/metadata"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"fmt"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/cache"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/proxy"
|
||||
proxymocks "github.com/virtual-kubelet/virtual-kubelet/providers/vic/proxy/mocks"
|
||||
)
|
||||
|
||||
var (
|
||||
pod v1.Pod
|
||||
imgConfig metadata.ImageConfig
|
||||
busyboxIsoConfig proxy.IsolationContainerConfig
|
||||
alpineIsoConfig proxy.IsolationContainerConfig
|
||||
vicPod vicpod.VicPod
|
||||
)
|
||||
|
||||
const (
|
||||
podID = "123"
|
||||
podName = "busybox-sleep"
|
||||
podHandle = "fakehandle"
|
||||
|
||||
fakeEP = "fake-endpoint"
|
||||
)
|
||||
|
||||
func createMocks(t *testing.T) (*proxymocks.ImageStore, *proxymocks.IsolationProxy, cache.PodCache, trace.Operation) {
|
||||
store := &proxymocks.ImageStore{}
|
||||
ip := &proxymocks.IsolationProxy{}
|
||||
cache := cache.NewVicPodCache()
|
||||
op := trace.NewOperation(context.Background(), "tests")
|
||||
|
||||
return store, ip, cache, op
|
||||
}
|
||||
|
||||
func fakeError(myErr string) error {
|
||||
return fmt.Errorf("fake error: %s", myErr)
|
||||
}
|
||||
|
||||
func initPod() {
|
||||
pod = v1.Pod{
|
||||
//TypeMeta: v1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: podName,
|
||||
GenerateName: "",
|
||||
Namespace: "default",
|
||||
SelfLink: "/api/v1/namespaces/default/pods/busybox-sleep",
|
||||
UID: "b1fc6e1b-499b-11e8-946c-000c29479092",
|
||||
ResourceVersion: "10338145",
|
||||
Generation: 0,
|
||||
DeletionTimestamp: nil,
|
||||
DeletionGracePeriodSeconds: nil,
|
||||
Labels: map[string]string{},
|
||||
Annotations: map[string]string{},
|
||||
OwnerReferences: nil,
|
||||
Initializers: nil,
|
||||
Finalizers: nil,
|
||||
ClusterName: "",
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: "default-token-9q9lr",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: nil,
|
||||
EmptyDir: nil,
|
||||
GCEPersistentDisk: nil,
|
||||
AWSElasticBlockStore: nil,
|
||||
GitRepo: nil,
|
||||
Secret: &v1.SecretVolumeSource{
|
||||
SecretName: "default-token-9q9lr",
|
||||
Items: nil,
|
||||
Optional: nil,
|
||||
},
|
||||
NFS: nil,
|
||||
ISCSI: nil,
|
||||
Glusterfs: nil,
|
||||
PersistentVolumeClaim: nil,
|
||||
RBD: nil,
|
||||
FlexVolume: nil,
|
||||
Cinder: nil,
|
||||
CephFS: nil,
|
||||
Flocker: nil,
|
||||
DownwardAPI: nil,
|
||||
FC: nil,
|
||||
AzureFile: nil,
|
||||
ConfigMap: nil,
|
||||
VsphereVolume: nil,
|
||||
Quobyte: nil,
|
||||
AzureDisk: nil,
|
||||
PhotonPersistentDisk: nil,
|
||||
Projected: nil,
|
||||
PortworxVolume: nil,
|
||||
ScaleIO: nil,
|
||||
StorageOS: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
InitContainers: nil,
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "busybox-container",
|
||||
Image: "busybox",
|
||||
Command: []string{"/bin/sleep"},
|
||||
Args: []string{"2m"},
|
||||
WorkingDir: "",
|
||||
Ports: nil,
|
||||
EnvFrom: nil,
|
||||
Env: nil,
|
||||
Resources: v1.ResourceRequirements{},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: "default-token-9q9lr",
|
||||
ReadOnly: true,
|
||||
MountPath: "/var/run/secrets/kubernetes.io/serviceaccount",
|
||||
SubPath: "",
|
||||
MountPropagation: nil,
|
||||
},
|
||||
},
|
||||
LivenessProbe: nil,
|
||||
ReadinessProbe: nil,
|
||||
Lifecycle: nil,
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
TerminationMessagePolicy: "File",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
SecurityContext: nil,
|
||||
Stdin: false,
|
||||
StdinOnce: false,
|
||||
TTY: false,
|
||||
},
|
||||
{
|
||||
Name: "alpine-container",
|
||||
Image: "alpine",
|
||||
Command: nil,
|
||||
Args: nil,
|
||||
WorkingDir: "",
|
||||
Ports: nil,
|
||||
EnvFrom: nil,
|
||||
Env: nil,
|
||||
Resources: v1.ResourceRequirements{},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: "default-token-9q9lr",
|
||||
ReadOnly: true,
|
||||
MountPath: "/var/run/secrets/kubernetes.io/serviceaccount",
|
||||
SubPath: "",
|
||||
MountPropagation: nil,
|
||||
},
|
||||
},
|
||||
LivenessProbe: nil,
|
||||
ReadinessProbe: nil,
|
||||
Lifecycle: nil,
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
TerminationMessagePolicy: "File",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
SecurityContext: nil,
|
||||
Stdin: false,
|
||||
StdinOnce: false,
|
||||
TTY: false,
|
||||
},
|
||||
},
|
||||
RestartPolicy: "Always",
|
||||
TerminationGracePeriodSeconds: new(int64),
|
||||
ActiveDeadlineSeconds: nil,
|
||||
DNSPolicy: "ClusterFirst",
|
||||
NodeSelector: map[string]string{"affinity": "vmware"},
|
||||
ServiceAccountName: "default",
|
||||
DeprecatedServiceAccount: "default",
|
||||
AutomountServiceAccountToken: nil,
|
||||
NodeName: "vic-kubelet",
|
||||
HostNetwork: false,
|
||||
HostPID: false,
|
||||
HostIPC: false,
|
||||
SecurityContext: &v1.PodSecurityContext{},
|
||||
ImagePullSecrets: nil,
|
||||
Hostname: "",
|
||||
Subdomain: "",
|
||||
Affinity: nil,
|
||||
SchedulerName: "default-scheduler",
|
||||
Tolerations: []v1.Toleration{
|
||||
{
|
||||
Key: "node.kubernetes.io/not-ready",
|
||||
Operator: "Exists",
|
||||
Value: "",
|
||||
Effect: "NoExecute",
|
||||
TolerationSeconds: new(int64),
|
||||
},
|
||||
{
|
||||
Key: "node.kubernetes.io/unreachable",
|
||||
Operator: "Exists",
|
||||
Value: "",
|
||||
Effect: "NoExecute",
|
||||
TolerationSeconds: new(int64),
|
||||
},
|
||||
},
|
||||
HostAliases: nil,
|
||||
PriorityClassName: "",
|
||||
Priority: nil,
|
||||
},
|
||||
}
|
||||
|
||||
busyboxIsoConfig = proxy.IsolationContainerConfig{
|
||||
ID: "",
|
||||
ImageID: "",
|
||||
LayerID: "",
|
||||
ImageName: "busybox",
|
||||
Name: "busybox-container",
|
||||
Namespace: "",
|
||||
Cmd: []string{"/bin/sleep", "2m"},
|
||||
Path: "",
|
||||
Entrypoint: nil,
|
||||
Env: nil,
|
||||
WorkingDir: "",
|
||||
User: "",
|
||||
StopSignal: "",
|
||||
Attach: false,
|
||||
StdinOnce: false,
|
||||
OpenStdin: false,
|
||||
Tty: false,
|
||||
CPUCount: 2,
|
||||
Memory: 2048,
|
||||
PortMap: map[string]proxy.PortBinding{},
|
||||
}
|
||||
|
||||
alpineIsoConfig = proxy.IsolationContainerConfig{
|
||||
ID: "",
|
||||
ImageID: "",
|
||||
LayerID: "",
|
||||
ImageName: "alpine",
|
||||
Name: "alpine-container",
|
||||
Namespace: "",
|
||||
Cmd: nil,
|
||||
Path: "",
|
||||
Entrypoint: nil,
|
||||
Env: nil,
|
||||
WorkingDir: "",
|
||||
User: "",
|
||||
StopSignal: "",
|
||||
Attach: false,
|
||||
StdinOnce: false,
|
||||
OpenStdin: false,
|
||||
Tty: false,
|
||||
CPUCount: 2,
|
||||
Memory: 2048,
|
||||
PortMap: map[string]proxy.PortBinding{},
|
||||
}
|
||||
|
||||
vicPod = vicpod.VicPod{
|
||||
ID: podID,
|
||||
Pod: &pod,
|
||||
}
|
||||
}
|
||||
451
providers/vic/operations/pod_creator.go
Normal file
451
providers/vic/operations/pod_creator.go
Normal file
@@ -0,0 +1,451 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/kr/pretty"
|
||||
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/cache"
|
||||
vicpod "github.com/virtual-kubelet/virtual-kubelet/providers/vic/pod"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/proxy"
|
||||
|
||||
vicerrors "github.com/vmware/vic/lib/apiservers/engine/errors"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client"
|
||||
"github.com/vmware/vic/lib/metadata"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
type PodCreator interface {
|
||||
CreatePod(op trace.Operation, pod *v1.Pod, start bool) error
|
||||
}
|
||||
|
||||
type VicPodCreator struct {
|
||||
client *client.PortLayer
|
||||
imageStore proxy.ImageStore
|
||||
isolationProxy proxy.IsolationProxy
|
||||
podCache cache.PodCache
|
||||
personaAddr string
|
||||
portlayerAddr string
|
||||
}
|
||||
|
||||
type VicPodCreatorError string
|
||||
|
||||
func (e VicPodCreatorError) Error() string { return string(e) }
|
||||
func NewPodCreatorPullError(image, msg string) VicPodCreatorError {
|
||||
return VicPodCreatorError(fmt.Sprintf("VicPodCreator failed to get image %s's config from the image store: %s", image, msg))
|
||||
}
|
||||
func NewPodCreatorNilImgConfigError(image string) VicPodCreatorError {
|
||||
return VicPodCreatorError(fmt.Sprintf("VicPodCreator failed to get image %s's config from the image store", image))
|
||||
}
|
||||
|
||||
const (
|
||||
// MemoryAlignMB is the value to which container VM memory must align in order for hotadd to work
|
||||
MemoryAlignMB = 128
|
||||
// MemoryMinMB - the minimum allowable container memory size
|
||||
MemoryMinMB = 512
|
||||
// MemoryDefaultMB - the default container VM memory size
|
||||
MemoryDefaultMB = 2048
|
||||
// MinCPUs - the minimum number of allowable CPUs the container can use
|
||||
MinCPUs = 1
|
||||
// DefaultCPUs - the default number of container VM CPUs
|
||||
DefaultCPUs = 2
|
||||
DefaultMemory = 512
|
||||
MiBytesUnit = 1024 * 1024
|
||||
|
||||
defaultEnvPath = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
|
||||
// Errors
|
||||
PodCreatorPortlayerClientError = VicPodCreatorError("PodCreator called with an invalid portlayer client")
|
||||
PodCreatorImageStoreError = VicPodCreatorError("PodCreator called with an invalid image store")
|
||||
PodCreatorIsolationProxyError = VicPodCreatorError("PodCreator called with an invalid isolation proxy")
|
||||
PodCreatorPodCacheError = VicPodCreatorError("PodCreator called with an invalid pod cache")
|
||||
PodCreatorPersonaAddrError = VicPodCreatorError("PodCreator called with an invalid VIC persona addr")
|
||||
PodCreatorPortlayerAddrError = VicPodCreatorError("PodCreator called with an invalid VIC portlayer addr")
|
||||
PodCreatorInvalidPodSpecError = VicPodCreatorError("CreatePod called with nil pod")
|
||||
PodCreatorInvalidArgsError = VicPodCreatorError("Invalid arguments")
|
||||
)
|
||||
|
||||
func NewPodCreator(client *client.PortLayer, imageStore proxy.ImageStore, isolationProxy proxy.IsolationProxy, podCache cache.PodCache, personaAddr string, portlayerAddr string) (PodCreator, error) {
|
||||
if client == nil {
|
||||
return nil, PodCreatorPortlayerClientError
|
||||
} else if imageStore == nil {
|
||||
return nil, PodCreatorImageStoreError
|
||||
} else if isolationProxy == nil {
|
||||
return nil, PodCreatorIsolationProxyError
|
||||
} else if podCache == nil {
|
||||
return nil, PodCreatorPodCacheError
|
||||
}
|
||||
|
||||
return &VicPodCreator{
|
||||
client: client,
|
||||
imageStore: imageStore,
|
||||
podCache: podCache,
|
||||
personaAddr: personaAddr,
|
||||
portlayerAddr: portlayerAddr,
|
||||
isolationProxy: isolationProxy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreatePod creates the pod and potentially start it
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// pod pod spec
|
||||
// start start the pod after creation
|
||||
// returns:
|
||||
// error
|
||||
func (v *VicPodCreator) CreatePod(op trace.Operation, pod *v1.Pod, start bool) error {
|
||||
defer trace.End(trace.Begin("", op))
|
||||
|
||||
if pod == nil {
|
||||
op.Errorf(PodCreatorInvalidPodSpecError.Error())
|
||||
return PodCreatorInvalidPodSpecError
|
||||
}
|
||||
|
||||
defer trace.End(trace.Begin(pod.Name, op))
|
||||
|
||||
// Pull all containers simultaneously
|
||||
err := v.pullPodContainers(op, pod)
|
||||
if err != nil {
|
||||
op.Errorf("PodCreator failed to pull containers: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
// Transform kube container config to docker create config
|
||||
id, err := v.createPod(op, pod, start)
|
||||
if err != nil {
|
||||
op.Errorf("pod_creator failed to create pod: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
vp := &vicpod.VicPod{
|
||||
ID: id,
|
||||
Pod: pod.DeepCopy(),
|
||||
}
|
||||
|
||||
err = v.podCache.Add(op, "", pod.Name, vp)
|
||||
if err != nil {
|
||||
//TODO: What should we do if pod already exist?
|
||||
}
|
||||
|
||||
if start {
|
||||
ps, err := NewPodStarter(v.client, v.isolationProxy)
|
||||
if err != nil {
|
||||
op.Errorf("Error creating pod starter: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
err = ps.Start(op, id, pod.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// pullPodContainers simultaneously pulls all containers in a pod
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// pod pod spec
|
||||
// returns:
|
||||
// error
|
||||
func (v *VicPodCreator) pullPodContainers(op trace.Operation, pod *v1.Pod) error {
|
||||
defer trace.End(trace.Begin("", op))
|
||||
|
||||
if pod == nil || pod.Spec.Containers == nil {
|
||||
return PodCreatorInvalidPodSpecError
|
||||
}
|
||||
|
||||
var pullGroup sync.WaitGroup
|
||||
|
||||
errChan := make(chan error, 2)
|
||||
|
||||
for _, c := range pod.Spec.Containers {
|
||||
pullGroup.Add(1)
|
||||
|
||||
go func(img string, policy v1.PullPolicy) {
|
||||
defer pullGroup.Done()
|
||||
|
||||
// Pull image config from VIC's image store if policy allows
|
||||
var realize bool
|
||||
if policy == v1.PullIfNotPresent {
|
||||
realize = true
|
||||
} else {
|
||||
realize = false
|
||||
}
|
||||
|
||||
_, err := v.imageStore.Get(op, img, "", realize)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("VicPodCreator failed to get image %s's config from the image store: %s", img, err.Error())
|
||||
op.Error(err)
|
||||
errChan <- err
|
||||
}
|
||||
}(c.Image, c.ImagePullPolicy)
|
||||
}
|
||||
|
||||
pullGroup.Wait()
|
||||
close(errChan)
|
||||
|
||||
for err := range errChan {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// createPod creates a pod using the VIC portlayer. Images can be pulled serially if not already present.
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// pod pod spec
|
||||
// start start the pod after creation
|
||||
// returns:
|
||||
// (pod id, error)
|
||||
func (v *VicPodCreator) createPod(op trace.Operation, pod *v1.Pod, start bool) (string, error) {
|
||||
defer trace.End(trace.Begin("", op))
|
||||
|
||||
if pod == nil || pod.Spec.Containers == nil {
|
||||
op.Errorf(PodCreatorInvalidPodSpecError.Error())
|
||||
return "", PodCreatorInvalidPodSpecError
|
||||
}
|
||||
|
||||
id, h, err := v.isolationProxy.CreateHandle(op)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for idx, c := range pod.Spec.Containers {
|
||||
// Pull image config from VIC's image store if policy allows
|
||||
var realize bool
|
||||
if c.ImagePullPolicy == v1.PullIfNotPresent {
|
||||
realize = true
|
||||
} else {
|
||||
realize = false
|
||||
}
|
||||
|
||||
imgConfig, err := v.imageStore.Get(op, c.Image, "", realize)
|
||||
if err != nil {
|
||||
err = NewPodCreatorPullError(c.Image, err.Error())
|
||||
op.Error(err)
|
||||
return "", err
|
||||
}
|
||||
if imgConfig == nil {
|
||||
err = NewPodCreatorNilImgConfigError(c.Image)
|
||||
op.Error(err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
op.Debugf("Receive image config from imagestore = %# v", pretty.Formatter(imgConfig))
|
||||
|
||||
// Create the initial config
|
||||
ic, err := IsolationContainerConfigFromKubeContainer(op, &c, imgConfig, pod)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
op.Debugf("isolation config %# v", pretty.Formatter(ic))
|
||||
|
||||
h, err = v.isolationProxy.AddImageToHandle(op, h, c.Name, imgConfig.V1Image.ID, imgConfig.ImageID, imgConfig.Name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
//TODO: We need one task with the container ID as the portlayer uses this to track session. Longer term, we should figure out
|
||||
// a way to fix this in the portlayer?
|
||||
if idx == 0 {
|
||||
h, err = v.isolationProxy.CreateHandleTask(op, h, id, imgConfig.V1Image.ID, ic)
|
||||
} else {
|
||||
h, err = v.isolationProxy.CreateHandleTask(op, h, fmt.Sprintf("Container-%d-task", idx), imgConfig.V1Image.ID, ic)
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
h, err = v.isolationProxy.AddHandleToScope(op, h, ic)
|
||||
if err != nil {
|
||||
return id, err
|
||||
}
|
||||
}
|
||||
|
||||
// Need both interaction and logging added or we will not be able to retrieve output.log or tether.debug
|
||||
h, err = v.isolationProxy.AddInteractionToHandle(op, h)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
h, err = v.isolationProxy.AddLoggingToHandle(op, h)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = v.isolationProxy.CommitHandle(op, h, id, -1)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
op.Debugf("Created Pod: %s, Handle: %s, ID: %s", pod.Name, h, id)
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
//------------------------------------
|
||||
// Utility Functions
|
||||
//------------------------------------
|
||||
|
||||
func IsolationContainerConfigFromKubeContainer(op trace.Operation, cSpec *v1.Container, imgConfig *metadata.ImageConfig, pod *v1.Pod) (proxy.IsolationContainerConfig, error) {
|
||||
defer trace.End(trace.Begin("", op))
|
||||
|
||||
if cSpec == nil || imgConfig == nil || pod == nil {
|
||||
op.Errorf("Invalid args to IsolationContainerConfigFromKubeContainer: cSpec(%#v), imgConfig(%#v), pod(%#v)", cSpec, imgConfig, pod)
|
||||
return proxy.IsolationContainerConfig{}, PodCreatorInvalidArgsError
|
||||
}
|
||||
|
||||
op.Debugf("** IsolationContainerConfig... imgConfig = %#v", imgConfig)
|
||||
config := proxy.IsolationContainerConfig{
|
||||
Name: cSpec.Name,
|
||||
WorkingDir: cSpec.WorkingDir,
|
||||
ImageName: cSpec.Image,
|
||||
Tty: cSpec.TTY,
|
||||
StdinOnce: cSpec.StdinOnce,
|
||||
OpenStdin: cSpec.Stdin,
|
||||
PortMap: make(map[string]proxy.PortBinding, 0),
|
||||
}
|
||||
|
||||
setResourceFromKubeSpec(op, &config, cSpec)
|
||||
|
||||
// Overwrite or append the image's config from the CLI with the metadata from the image's
|
||||
// layer metadata where appropriate
|
||||
if len(cSpec.Command) > 0 {
|
||||
config.Cmd = make([]string, len(cSpec.Command))
|
||||
copy(config.Cmd, cSpec.Command)
|
||||
|
||||
config.Cmd = append(config.Cmd, cSpec.Args...)
|
||||
} else if imgConfig.Config != nil {
|
||||
config.Cmd = make([]string, len(imgConfig.Config.Cmd))
|
||||
copy(config.Cmd, imgConfig.Config.Cmd)
|
||||
}
|
||||
|
||||
config.User = ""
|
||||
if imgConfig.Config != nil {
|
||||
if imgConfig.Config.User != "" {
|
||||
config.User = imgConfig.Config.User
|
||||
}
|
||||
|
||||
// set up environment
|
||||
config.Env = setEnvFromImageConfig(config.Tty, config.Env, imgConfig.Config.Env)
|
||||
}
|
||||
|
||||
op.Debugf("config = %#v", config)
|
||||
|
||||
// TODO: Cache the container (so that they are shared with the persona)
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func setEnvFromImageConfig(tty bool, env []string, imgEnv []string) []string {
|
||||
// Set PATH in ENV if needed
|
||||
env = setPathFromImageConfig(env, imgEnv)
|
||||
|
||||
containerEnv := make(map[string]string, len(env))
|
||||
for _, e := range env {
|
||||
kv := strings.SplitN(e, "=", 2)
|
||||
var val string
|
||||
if len(kv) == 2 {
|
||||
val = kv[1]
|
||||
}
|
||||
containerEnv[kv[0]] = val
|
||||
}
|
||||
|
||||
// Set TERM to xterm if tty is set, unless user supplied a different TERM
|
||||
if tty {
|
||||
if _, ok := containerEnv["TERM"]; !ok {
|
||||
env = append(env, "TERM=xterm")
|
||||
}
|
||||
}
|
||||
|
||||
// add remaining environment variables from the image config to the container
|
||||
// config, taking care not to overwrite anything
|
||||
for _, imageEnv := range imgEnv {
|
||||
key := strings.SplitN(imageEnv, "=", 2)[0]
|
||||
// is environment variable already set in container config?
|
||||
if _, ok := containerEnv[key]; !ok {
|
||||
// no? let's copy it from the image config
|
||||
env = append(env, imageEnv)
|
||||
}
|
||||
}
|
||||
|
||||
return env
|
||||
}
|
||||
|
||||
func setPathFromImageConfig(env []string, imgEnv []string) []string {
|
||||
// check if user supplied PATH environment variable at creation time
|
||||
for _, v := range env {
|
||||
if strings.HasPrefix(v, "PATH=") {
|
||||
// a PATH is set, bail
|
||||
return env
|
||||
}
|
||||
}
|
||||
|
||||
// check to see if the image this container is created from supplies a PATH
|
||||
for _, v := range imgEnv {
|
||||
if strings.HasPrefix(v, "PATH=") {
|
||||
// a PATH was found, add it to the config
|
||||
env = append(env, v)
|
||||
return env
|
||||
}
|
||||
}
|
||||
|
||||
// no PATH set, use the default
|
||||
env = append(env, fmt.Sprintf("PATH=%s", defaultEnvPath))
|
||||
|
||||
return env
|
||||
}
|
||||
|
||||
func setResourceFromKubeSpec(op trace.Operation, config *proxy.IsolationContainerConfig, cSpec *v1.Container) error {
|
||||
if config == nil {
|
||||
return vicerrors.BadRequestError("invalid config")
|
||||
}
|
||||
|
||||
// Get resource request. If not specified, use the limits. If that's not set, use default VIC values.
|
||||
config.CPUCount = cSpec.Resources.Requests.Cpu().Value()
|
||||
if config.CPUCount == 0 {
|
||||
config.CPUCount = cSpec.Resources.Limits.Cpu().Value()
|
||||
if config.CPUCount == 0 {
|
||||
config.CPUCount = DefaultCPUs
|
||||
}
|
||||
}
|
||||
config.Memory = cSpec.Resources.Requests.Memory().Value()
|
||||
if config.Memory == 0 {
|
||||
config.Memory = cSpec.Resources.Limits.Memory().Value()
|
||||
if config.Memory == 0 {
|
||||
config.Memory = DefaultMemory
|
||||
}
|
||||
}
|
||||
|
||||
// convert from bytes to MiB for vsphere
|
||||
memoryMB := config.Memory / MiBytesUnit
|
||||
if memoryMB == 0 {
|
||||
memoryMB = MemoryDefaultMB
|
||||
} else if memoryMB < MemoryMinMB {
|
||||
memoryMB = MemoryMinMB
|
||||
}
|
||||
|
||||
// check that memory is aligned
|
||||
if remainder := memoryMB % MemoryAlignMB; remainder != 0 {
|
||||
op.Warnf("Default container VM memory must be %d aligned for hotadd, rounding up.", MemoryAlignMB)
|
||||
memoryMB += MemoryAlignMB - remainder
|
||||
}
|
||||
|
||||
config.Memory = memoryMB
|
||||
op.Debugf("Container memory: %d MB", config.Memory)
|
||||
|
||||
return nil
|
||||
}
|
||||
466
providers/vic/operations/pod_creator_test.go
Normal file
466
providers/vic/operations/pod_creator_test.go
Normal file
@@ -0,0 +1,466 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client"
|
||||
"github.com/vmware/vic/lib/metadata"
|
||||
)
|
||||
|
||||
func init() {
|
||||
initPod()
|
||||
}
|
||||
|
||||
func TestNewPodCreator(t *testing.T) {
|
||||
var c PodCreator
|
||||
var err error
|
||||
|
||||
store, proxy, cache, _ := createMocks(t)
|
||||
client := client.Default
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
// Positive cases
|
||||
c, err = NewPodCreator(client, store, proxy, cache, persona, portlayer)
|
||||
assert.NotNil(t, c, "Expected not-nil creating a pod creator but received nil")
|
||||
|
||||
// Negative cases
|
||||
c, err = NewPodCreator(nil, store, proxy, cache, persona, portlayer)
|
||||
assert.Nil(t, c, "Expected nil")
|
||||
assert.Equal(t, err, PodCreatorPortlayerClientError)
|
||||
|
||||
c, err = NewPodCreator(client, nil, proxy, cache, persona, portlayer)
|
||||
assert.Nil(t, c, "Expected nil")
|
||||
assert.Equal(t, err, PodCreatorImageStoreError)
|
||||
|
||||
c, err = NewPodCreator(client, store, nil, cache, persona, portlayer)
|
||||
assert.Nil(t, c, "Expected nil")
|
||||
assert.Equal(t, err, PodCreatorIsolationProxyError)
|
||||
|
||||
c, err = NewPodCreator(client, store, proxy, nil, persona, portlayer)
|
||||
assert.Nil(t, c, "Expected nil")
|
||||
assert.Equal(t, err, PodCreatorPodCacheError)
|
||||
}
|
||||
|
||||
func TestCreatePod_NilPod(t *testing.T) {
|
||||
store, ip, cache, op := createMocks(t)
|
||||
client := client.Default
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
// Create nil pod
|
||||
c, err := NewPodCreator(client, store, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, c, "Expected not-nil creating a pod creator but received nil")
|
||||
|
||||
err = c.CreatePod(op, nil, true)
|
||||
assert.NotNil(t, err, "Expected error from createPod but received '%s'", err)
|
||||
}
|
||||
|
||||
func TestCreatePod_Success(t *testing.T) {
|
||||
store, ip, cache, op := createMocks(t)
|
||||
client := client.Default
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
// Setup mocks
|
||||
ip.On("CreateHandle", op).Return(podID, podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "busybox-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "alpine-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, podID, "", busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, "Container-1-task", "", alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddInteractionToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("AddLoggingToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("BindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "RUNNING").Return(podHandle, nil)
|
||||
|
||||
store.On("Get", op, "busybox", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
store.On("Get", op, "alpine", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
|
||||
// The test
|
||||
c, err := NewPodCreator(client, store, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, c, "Expected not-nil creating a pod creator but received nil")
|
||||
|
||||
err = c.CreatePod(op, &pod, true)
|
||||
assert.Nil(t, err, "Expected error from createPod but received '%s'", err)
|
||||
}
|
||||
|
||||
func TestCreatePod_ImageStoreError(t *testing.T) {
|
||||
store, ip, cache, op := createMocks(t)
|
||||
client := client.Default
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
// Setup mocks
|
||||
ip.On("CreateHandle", op).Return(podID, podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "busybox-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "alpine-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, podID, "", busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, "Container-1-task", "", alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddInteractionToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("AddLoggingToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("BindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "RUNNING").Return(podHandle, nil)
|
||||
|
||||
fakeErr := fmt.Errorf("Error getting pod containers")
|
||||
store.On("Get", op, "alpine", "", true).Return(nil, fakeErr)
|
||||
store.On("Get", op, "busybox", "", true).Return(nil, fakeErr)
|
||||
|
||||
// The test
|
||||
c, err := NewPodCreator(client, store, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, c, "Expected not-nil creating a pod creator but received nil")
|
||||
|
||||
err = c.CreatePod(op, &pod, true)
|
||||
assert.NotNil(t, err, "Expected nil error from createPod")
|
||||
}
|
||||
|
||||
func TestCreatePod_CreateHandleError(t *testing.T) {
|
||||
store, ip, cache, op := createMocks(t)
|
||||
client := client.Default
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
// Setup mocks
|
||||
fakeErr := fmt.Errorf("fake create handle error")
|
||||
ip.On("CreateHandle", op).Return(podID, podHandle, fakeErr)
|
||||
ip.On("AddImageToHandle", op, podHandle, "busybox-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "alpine-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, podID, "", busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, "Container-1-task", "", alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddInteractionToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("AddLoggingToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("BindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "RUNNING").Return(podHandle, nil)
|
||||
|
||||
store.On("Get", op, "busybox", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
store.On("Get", op, "alpine", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
|
||||
// The test
|
||||
c, err := NewPodCreator(client, store, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, c, "Expected not-nil creating a pod creator but received nil")
|
||||
|
||||
err = c.CreatePod(op, &pod, true)
|
||||
assert.NotNil(t, err, "Expected nil error from createPod")
|
||||
assert.Equal(t, err.Error(), fakeErr.Error())
|
||||
}
|
||||
|
||||
func TestCreatePod_AddImageError(t *testing.T) {
|
||||
store, ip, cache, op := createMocks(t)
|
||||
client := client.Default
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
// Setup mocks
|
||||
fakeErr := fmt.Errorf("fake add image error")
|
||||
ip.On("CreateHandle", op).Return(podID, podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "busybox-container", "", "", "").Return(podHandle, fakeErr)
|
||||
ip.On("AddImageToHandle", op, podHandle, "alpine-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, podID, "", busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, "Container-1-task", "", alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddInteractionToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("AddLoggingToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("BindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "RUNNING").Return(podHandle, nil)
|
||||
|
||||
store.On("Get", op, "busybox", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
store.On("Get", op, "alpine", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
|
||||
// The test
|
||||
c, err := NewPodCreator(client, store, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, c, "Expected not-nil creating a pod creator but received nil")
|
||||
|
||||
err = c.CreatePod(op, &pod, true)
|
||||
assert.NotNil(t, err, "Expected nil error from createPod")
|
||||
assert.Equal(t, err.Error(), fakeErr.Error())
|
||||
}
|
||||
|
||||
func TestCreatePod_CreateHandleTaskError(t *testing.T) {
|
||||
store, ip, cache, op := createMocks(t)
|
||||
client := client.Default
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
// Setup mocks
|
||||
fakeErr := fmt.Errorf("fake create handle task error")
|
||||
ip.On("CreateHandle", op).Return(podID, podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "busybox-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "alpine-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, podID, "", busyboxIsoConfig).Return(podHandle, fakeErr)
|
||||
ip.On("CreateHandleTask", op, podHandle, "Container-1-task", "", alpineIsoConfig).Return(podHandle, fakeErr)
|
||||
ip.On("AddHandleToScope", op, podHandle, busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddInteractionToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("AddLoggingToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("BindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "RUNNING").Return(podHandle, nil)
|
||||
|
||||
store.On("Get", op, "busybox", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
store.On("Get", op, "alpine", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
|
||||
// The test
|
||||
c, err := NewPodCreator(client, store, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, c, "Expected not-nil creating a pod creator but received nil")
|
||||
|
||||
err = c.CreatePod(op, &pod, true)
|
||||
assert.NotNil(t, err, "Expected nil error from createPod")
|
||||
assert.Equal(t, err.Error(), fakeErr.Error())
|
||||
}
|
||||
|
||||
func TestCreatePod_AddHandleToScopeError(t *testing.T) {
|
||||
store, ip, cache, op := createMocks(t)
|
||||
client := client.Default
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
// Setup mocks
|
||||
fakeErr := fmt.Errorf("fake add handle to scope error")
|
||||
ip.On("CreateHandle", op).Return(podID, podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "busybox-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "alpine-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, podID, "", busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, "Container-1-task", "", alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, busyboxIsoConfig).Return(podHandle, fakeErr)
|
||||
ip.On("AddHandleToScope", op, podHandle, alpineIsoConfig).Return(podHandle, fakeErr)
|
||||
ip.On("AddInteractionToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("AddLoggingToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("BindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "RUNNING").Return(podHandle, nil)
|
||||
|
||||
store.On("Get", op, "busybox", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
store.On("Get", op, "alpine", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
|
||||
// The test
|
||||
c, err := NewPodCreator(client, store, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, c, "Expected not-nil creating a pod creator but received nil")
|
||||
|
||||
err = c.CreatePod(op, &pod, true)
|
||||
assert.NotNil(t, err, "Expected nil error from createPod")
|
||||
assert.Equal(t, err.Error(), fakeErr.Error())
|
||||
}
|
||||
|
||||
func TestCreatePod_AddInteractionError(t *testing.T) {
|
||||
store, ip, cache, op := createMocks(t)
|
||||
client := client.Default
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
// Setup mocks
|
||||
fakeErr := fmt.Errorf("fake add interaction error")
|
||||
ip.On("CreateHandle", op).Return(podID, podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "busybox-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "alpine-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, podID, "", busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, "Container-1-task", "", alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddInteractionToHandle", op, podHandle).Return(podHandle, fakeErr)
|
||||
ip.On("AddLoggingToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("BindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "RUNNING").Return(podHandle, nil)
|
||||
|
||||
store.On("Get", op, "busybox", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
store.On("Get", op, "alpine", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
|
||||
// The test
|
||||
c, err := NewPodCreator(client, store, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, c, "Expected not-nil creating a pod creator but received nil")
|
||||
|
||||
err = c.CreatePod(op, &pod, true)
|
||||
assert.NotNil(t, err, "Expected nil error from createPod")
|
||||
assert.Equal(t, err.Error(), fakeErr.Error())
|
||||
}
|
||||
|
||||
func TestCreatePod_AddLoggingError(t *testing.T) {
|
||||
store, ip, cache, op := createMocks(t)
|
||||
client := client.Default
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
// Setup mocks
|
||||
fakeErr := fmt.Errorf("fake add logging error")
|
||||
ip.On("CreateHandle", op).Return(podID, podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "busybox-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "alpine-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, podID, "", busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, "Container-1-task", "", alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddInteractionToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("AddLoggingToHandle", op, podHandle).Return(podHandle, fakeErr)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("BindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "RUNNING").Return(podHandle, nil)
|
||||
|
||||
store.On("Get", op, "busybox", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
store.On("Get", op, "alpine", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
|
||||
// The test
|
||||
c, err := NewPodCreator(client, store, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, c, "Expected not-nil creating a pod creator but received nil")
|
||||
|
||||
err = c.CreatePod(op, &pod, true)
|
||||
assert.NotNil(t, err, "Expected nil error from createPod")
|
||||
assert.Equal(t, err.Error(), fakeErr.Error())
|
||||
}
|
||||
|
||||
func TestCreatePod_CommitError(t *testing.T) {
|
||||
store, ip, cache, op := createMocks(t)
|
||||
client := client.Default
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
// Setup mocks
|
||||
fakeErr := fmt.Errorf("fake commit error")
|
||||
ip.On("CreateHandle", op).Return(podID, podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "busybox-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "alpine-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, podID, "", busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, "Container-1-task", "", alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddInteractionToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("AddLoggingToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(fakeErr)
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("BindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "RUNNING").Return(podHandle, nil)
|
||||
|
||||
store.On("Get", op, "busybox", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
store.On("Get", op, "alpine", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
|
||||
// The test
|
||||
c, err := NewPodCreator(client, store, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, c, "Expected not-nil creating a pod creator but received nil")
|
||||
|
||||
err = c.CreatePod(op, &pod, true)
|
||||
assert.NotNil(t, err, "Expected nil error from createPod")
|
||||
assert.Equal(t, err.Error(), fakeErr.Error())
|
||||
}
|
||||
|
||||
func TestCreatePod_HandleError(t *testing.T) {
|
||||
store, ip, cache, op := createMocks(t)
|
||||
client := client.Default
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
// Setup mocks
|
||||
fakeErr := fmt.Errorf("fake handle error")
|
||||
ip.On("CreateHandle", op).Return(podID, podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "busybox-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "alpine-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, podID, "", busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, "Container-1-task", "", alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddInteractionToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("AddLoggingToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, fakeErr)
|
||||
ip.On("BindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "RUNNING").Return(podHandle, nil)
|
||||
|
||||
store.On("Get", op, "busybox", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
store.On("Get", op, "alpine", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
|
||||
// The test
|
||||
c, err := NewPodCreator(client, store, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, c, "Expected not-nil creating a pod creator but received nil")
|
||||
|
||||
err = c.CreatePod(op, &pod, true)
|
||||
assert.NotNil(t, err, "Expected nil error from createPod")
|
||||
assert.Equal(t, err.Error(), fakeErr.Error())
|
||||
}
|
||||
|
||||
func TestCreatePod_BindScopeError(t *testing.T) {
|
||||
store, ip, cache, op := createMocks(t)
|
||||
client := client.Default
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
// Setup mocks
|
||||
fakeErr := fmt.Errorf("fake bind scope error")
|
||||
ip.On("CreateHandle", op).Return(podID, podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "busybox-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "alpine-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, podID, "", busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, "Container-1-task", "", alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddInteractionToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("AddLoggingToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("BindScope", op, podHandle, podName).Return(podHandle, fakeEP, fakeErr)
|
||||
ip.On("UnbindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "RUNNING").Return(podHandle, nil)
|
||||
|
||||
store.On("Get", op, "busybox", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
store.On("Get", op, "alpine", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
|
||||
// The test
|
||||
c, err := NewPodCreator(client, store, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, c, "Expected not-nil creating a pod creator but received nil")
|
||||
|
||||
err = c.CreatePod(op, &pod, true)
|
||||
assert.NotNil(t, err, "Expected nil error from createPod")
|
||||
assert.Equal(t, err.Error(), fakeErr.Error())
|
||||
}
|
||||
|
||||
func TestCreatePod_SetStateError(t *testing.T) {
|
||||
store, ip, cache, op := createMocks(t)
|
||||
client := client.Default
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
// Setup mocks
|
||||
fakeErr := fmt.Errorf("fake set state error")
|
||||
ip.On("CreateHandle", op).Return(podID, podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "busybox-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("AddImageToHandle", op, podHandle, "alpine-container", "", "", "").Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, podID, "", busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("CreateHandleTask", op, podHandle, "Container-1-task", "", alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, busyboxIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddHandleToScope", op, podHandle, alpineIsoConfig).Return(podHandle, nil)
|
||||
ip.On("AddInteractionToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("AddLoggingToHandle", op, podHandle).Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("BindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("UnbindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "RUNNING").Return(podHandle, fakeErr)
|
||||
|
||||
store.On("Get", op, "busybox", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
store.On("Get", op, "alpine", "", true).Return(&metadata.ImageConfig{}, nil)
|
||||
|
||||
// The test
|
||||
c, err := NewPodCreator(client, store, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, c, "Expected not-nil creating a pod creator but received nil")
|
||||
|
||||
err = c.CreatePod(op, &pod, true)
|
||||
assert.NotNil(t, err, "Expected nil error from createPod")
|
||||
assert.Equal(t, err.Error(), fakeErr.Error())
|
||||
}
|
||||
174
providers/vic/operations/pod_deleter.go
Normal file
174
providers/vic/operations/pod_deleter.go
Normal file
@@ -0,0 +1,174 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/cache"
|
||||
vicpod "github.com/virtual-kubelet/virtual-kubelet/providers/vic/pod"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/proxy"
|
||||
|
||||
vicerrors "github.com/vmware/vic/lib/apiservers/engine/errors"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client"
|
||||
"github.com/vmware/vic/pkg/retry"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
type PodDeleter interface {
|
||||
DeletePod(op trace.Operation, pod *v1.Pod) error
|
||||
}
|
||||
|
||||
type VicPodDeleter struct {
|
||||
client *client.PortLayer
|
||||
imageStore proxy.ImageStore
|
||||
isolationProxy proxy.IsolationProxy
|
||||
podCache cache.PodCache
|
||||
personaAddr string
|
||||
portlayerAddr string
|
||||
}
|
||||
|
||||
type VicPodDeleterError string
|
||||
|
||||
func (e VicPodDeleterError) Error() string { return string(e) }
|
||||
|
||||
const (
|
||||
PodDeleterPortlayerClientError = VicPodDeleterError("PodDeleter called with an invalid portlayer client")
|
||||
PodDeleterIsolationProxyError = VicPodDeleterError("PodDeleter called with an invalid isolation proxy")
|
||||
PodDeleterPodCacheError = VicPodDeleterError("PodDeleter called with an invalid pod cache")
|
||||
PodDeleterPersonaAddrError = VicPodDeleterError("PodDeleter called with an invalid VIC persona addr")
|
||||
PodDeleterPortlayerAddrError = VicPodDeleterError("PodDeleter called with an invalid VIC portlayer addr")
|
||||
PodDeleterInvalidPodSpecError = VicPodDeleterError("PodDeleter called with nil pod")
|
||||
)
|
||||
|
||||
type DeleteResponse struct {
|
||||
Id string `json:"Id"`
|
||||
Warnings string `json:"Warnings"`
|
||||
}
|
||||
|
||||
func NewPodDeleter(client *client.PortLayer, isolationProxy proxy.IsolationProxy, podCache cache.PodCache, personaAddr string, portlayerAddr string) (PodDeleter, error) {
|
||||
if client == nil {
|
||||
return nil, PodDeleterPortlayerClientError
|
||||
} else if isolationProxy == nil {
|
||||
return nil, PodDeleterIsolationProxyError
|
||||
} else if podCache == nil {
|
||||
return nil, PodDeleterPodCacheError
|
||||
}
|
||||
|
||||
return &VicPodDeleter{
|
||||
client: client,
|
||||
podCache: podCache,
|
||||
personaAddr: personaAddr,
|
||||
portlayerAddr: portlayerAddr,
|
||||
isolationProxy: isolationProxy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeletePod deletes a pod
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// pod pod spec
|
||||
// returns:
|
||||
// error
|
||||
func (v *VicPodDeleter) DeletePod(op trace.Operation, pod *v1.Pod) error {
|
||||
if pod == nil {
|
||||
return PodDeleterInvalidPodSpecError
|
||||
}
|
||||
defer trace.End(trace.Begin(pod.Name, op))
|
||||
|
||||
// Get pod from cache
|
||||
vp, err := v.podCache.Get(op, "", pod.Name)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Stop pod if not already stopped
|
||||
|
||||
// Transform kube container config to docker create config
|
||||
err = v.deletePod(op, vp, true)
|
||||
if err != nil {
|
||||
op.Errorf("PodDeleter failed to delete pod: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
op.Infof("PodDeleter deleting from cache, name: %s, ID: %s", pod.Name, vp.ID)
|
||||
v.podCache.Delete(op, "", pod.Name)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// deletePod deletes a pod
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// vp VIC pod struct
|
||||
// force if set to true, the pod will be deleted even if it's still running
|
||||
// returns:
|
||||
// error
|
||||
func (v *VicPodDeleter) deletePod(op trace.Operation, vp *vicpod.VicPod, force bool) error {
|
||||
defer trace.End(trace.Begin("", op))
|
||||
|
||||
if vp == nil {
|
||||
return PodDeleterInvalidPodSpecError
|
||||
}
|
||||
|
||||
id := vp.ID
|
||||
name := vp.Pod.Name
|
||||
running := false
|
||||
|
||||
stopper, err := NewPodStopper(v.client, v.isolationProxy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Use the force and stop the container first
|
||||
if force {
|
||||
if err := stopper.Stop(op, id, name); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
state, err := v.isolationProxy.State(op, id, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch state {
|
||||
case "Error":
|
||||
// force stop if container state is error to make sure container is deletable later
|
||||
stopper.Stop(op, id, name)
|
||||
case "Starting":
|
||||
// if we are starting let the user know they must use the force
|
||||
return fmt.Errorf("The container is starting. To remove use -f")
|
||||
case "Running":
|
||||
running = true
|
||||
}
|
||||
|
||||
handle, err := v.isolationProxy.Handle(op, id, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Unbind the container to the scope
|
||||
_, ep, err := v.isolationProxy.UnbindScope(op, handle, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
op.Infof("Scope Unbind returned endpoints %# +v", ep)
|
||||
}
|
||||
|
||||
// Retry remove operation if container is not in running state. If in running state, we only try
|
||||
// once to prevent retries from degrading performance.
|
||||
if !running {
|
||||
operation := func() error {
|
||||
return v.isolationProxy.Remove(op, id, true)
|
||||
}
|
||||
op.Infof("Delete Pod, ID: %s, running: %v", vp.ID, running)
|
||||
return retry.Do(operation, vicerrors.IsConflictError)
|
||||
}
|
||||
|
||||
err = v.isolationProxy.Remove(op, id, true)
|
||||
op.Infof("Delete Pod, ID: %s, running: %v err: %v", vp.ID, running, err)
|
||||
return err
|
||||
}
|
||||
212
providers/vic/operations/pod_deleter_test.go
Normal file
212
providers/vic/operations/pod_deleter_test.go
Normal file
@@ -0,0 +1,212 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client"
|
||||
)
|
||||
|
||||
func init() {
|
||||
initPod()
|
||||
}
|
||||
|
||||
func TestNewPodDeleter(t *testing.T) {
|
||||
_, ip, cache, _ := createMocks(t)
|
||||
client := client.Default
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
// Positive Cases
|
||||
d, err := NewPodDeleter(client, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, d, "Expected non-nil creating a pod Deleter but received nil")
|
||||
|
||||
// Negative Cases
|
||||
d, err = NewPodDeleter(nil, ip, cache, persona, portlayer)
|
||||
assert.Nil(t, d, "Expected nil")
|
||||
assert.Equal(t, err, PodDeleterPortlayerClientError)
|
||||
|
||||
d, err = NewPodDeleter(client, nil, cache, persona, portlayer)
|
||||
assert.Nil(t, d, "Expected nil")
|
||||
assert.Equal(t, err, PodDeleterIsolationProxyError)
|
||||
|
||||
d, err = NewPodDeleter(client, ip, nil, persona, portlayer)
|
||||
assert.Nil(t, d, "Expected nil")
|
||||
assert.Equal(t, err, PodDeleterPodCacheError)
|
||||
}
|
||||
|
||||
func TestDeletePod(t *testing.T) {
|
||||
client := client.Default
|
||||
_, ip, cache, op := createMocks(t)
|
||||
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
d, err := NewPodDeleter(client, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, d, "Expected non-nil creating a pod Deleter but received nil")
|
||||
assert.Nil(t, err, "Expected nil")
|
||||
|
||||
// Set up the mocks for this test
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("UnbindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "STOPPED").Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
ip.On("Remove", op, podID, true).Return(nil)
|
||||
|
||||
// Add vicPod to the cache
|
||||
cache.Add(op, "", pod.Name, &vicPod)
|
||||
|
||||
// Positive case
|
||||
err = d.DeletePod(op, &pod)
|
||||
assert.Nil(t, err, "Expected nil")
|
||||
}
|
||||
|
||||
func TestDeletePodErrorHandle(t *testing.T) {
|
||||
client := client.Default
|
||||
_, ip, cache, op := createMocks(t)
|
||||
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
d, err := NewPodDeleter(client, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, d, "Expected non-nil creating a pod Deleter but received nil")
|
||||
assert.Nil(t, err, "Expected nil")
|
||||
|
||||
// Set up the mocks for this test
|
||||
ip.On("UnbindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "STOPPED").Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
ip.On("Remove", op, podID, true).Return(nil)
|
||||
|
||||
// Add vicPod to the cache
|
||||
cache.Add(op, "", pod.Name, &vicPod)
|
||||
|
||||
// Failed Handle
|
||||
fakeErr := fakeError("invalid handle")
|
||||
ip.On("Handle", op, podID, podName).Return("", fakeErr)
|
||||
|
||||
err = d.DeletePod(op, &pod)
|
||||
assert.Equal(t, err, fakeErr, "Expected invalid handle error")
|
||||
}
|
||||
|
||||
func TestDeletePodErrorUnbindScope(t *testing.T) {
|
||||
client := client.Default
|
||||
_, ip, cache, op := createMocks(t)
|
||||
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
d, err := NewPodDeleter(client, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, d, "Expected non-nil creating a pod Deleter but received nil")
|
||||
assert.Nil(t, err, "Expected nil")
|
||||
|
||||
// Set up the mocks for this test
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "STOPPED").Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
ip.On("Remove", op, podID, true).Return(nil)
|
||||
|
||||
// Add vicPod to the cache
|
||||
cache.Add(op, "", pod.Name, &vicPod)
|
||||
// Failed UnbindScope
|
||||
fakeErr := fakeError("failed UnbindScope")
|
||||
ip.On("UnbindScope", op, podHandle, podName).Return("", nil, fakeErr)
|
||||
|
||||
err = d.DeletePod(op, &pod)
|
||||
assert.Equal(t, err, fakeErr, "Expected failed UnbindScope error")
|
||||
}
|
||||
|
||||
func TestDeletePodErrorSetState(t *testing.T) {
|
||||
client := client.Default
|
||||
_, ip, cache, op := createMocks(t)
|
||||
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
d, err := NewPodDeleter(client, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, d, "Expected non-nil creating a pod Deleter but received nil")
|
||||
assert.Nil(t, err, "Expected nil")
|
||||
|
||||
// Set up the mocks for this test
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("UnbindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
ip.On("Remove", op, podID, true).Return(nil)
|
||||
|
||||
// Add vicPod to the cache
|
||||
cache.Add(op, "", pod.Name, &vicPod)
|
||||
|
||||
// Failed SetState
|
||||
fakeErr := fakeError("failed SetState")
|
||||
ip.On("SetState", op, podHandle, podName, "STOPPED").Return("", fakeErr)
|
||||
err = d.DeletePod(op, &pod)
|
||||
assert.Equal(t, err, fakeErr, "Expected failed SetState error")
|
||||
}
|
||||
|
||||
func TestDeletePodErrorCommitHandle(t *testing.T) {
|
||||
client := client.Default
|
||||
_, ip, cache, op := createMocks(t)
|
||||
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
d, err := NewPodDeleter(client, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, d, "Expected non-nil creating a pod Deleter but received nil")
|
||||
assert.Nil(t, err, "Expected nil")
|
||||
|
||||
// Set up the mocks for this test
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("UnbindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "STOPPED").Return(podHandle, nil)
|
||||
ip.On("Remove", op, podID, true).Return(nil)
|
||||
|
||||
// Add vicPod to the cache
|
||||
cache.Add(op, "", pod.Name, &vicPod)
|
||||
// Failed Commit
|
||||
fakeErr := fakeError("failed Commit")
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(fakeErr)
|
||||
err = d.DeletePod(op, &pod)
|
||||
assert.Equal(t, err, fakeErr, "Expected failed Commit error")
|
||||
}
|
||||
|
||||
func TestDeletePodErrorRemove(t *testing.T) {
|
||||
client := client.Default
|
||||
_, ip, cache, op := createMocks(t)
|
||||
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
d, err := NewPodDeleter(client, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, d, "Expected non-nil creating a pod Deleter but received nil")
|
||||
assert.Nil(t, err, "Expected nil")
|
||||
|
||||
// Set up the mocks for this test
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("UnbindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "STOPPED").Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
|
||||
// Add vicPod to the cache
|
||||
cache.Add(op, "", pod.Name, &vicPod)
|
||||
|
||||
// Failed Remove
|
||||
fakeErr := fakeError("failed Remove")
|
||||
ip.On("Remove", op, podID, true).Return(fakeErr)
|
||||
err = d.DeletePod(op, &pod)
|
||||
assert.Equal(t, err, fakeErr, "Expected failed Remove error")
|
||||
}
|
||||
|
||||
func TestDeletePodErrorBadArgs(t *testing.T) {
|
||||
client := client.Default
|
||||
_, ip, cache, op := createMocks(t)
|
||||
persona := "1.2.3.4"
|
||||
portlayer := "1.2.3.4"
|
||||
|
||||
d, err := NewPodDeleter(client, ip, cache, persona, portlayer)
|
||||
assert.NotNil(t, d, "Expected non-nil creating a pod Deleter but received nil")
|
||||
|
||||
// Negative Cases
|
||||
err = d.DeletePod(op, nil)
|
||||
assert.Equal(t, err, PodDeleterInvalidPodSpecError)
|
||||
}
|
||||
91
providers/vic/operations/pod_starter.go
Normal file
91
providers/vic/operations/pod_starter.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/proxy"
|
||||
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
)
|
||||
|
||||
type PodStarter interface {
|
||||
Start(op trace.Operation, id, name string) error
|
||||
}
|
||||
|
||||
type VicPodStarter struct {
|
||||
client *client.PortLayer
|
||||
isolationProxy proxy.IsolationProxy
|
||||
imageStore proxy.ImageStore
|
||||
}
|
||||
|
||||
type VicPodStarterError string
|
||||
|
||||
func (e VicPodStarterError) Error() string { return string(e) }
|
||||
|
||||
const (
|
||||
PodStarterPortlayerClientError = VicPodStarterError("PodStarter called with an invalid portlayer client")
|
||||
PodStarterIsolationProxyError = VicPodStarterError("PodStarter called with an invalid isolation proxy")
|
||||
PodStarterInvalidPodIDError = VicPodStarterError("PodStarter called with invalid Pod ID")
|
||||
PodStarterInvalidPodNameError = VicPodStarterError("PodStarter called with invalid Pod name")
|
||||
)
|
||||
|
||||
func NewPodStarter(client *client.PortLayer, isolationProxy proxy.IsolationProxy) (PodStarter, error) {
|
||||
defer trace.End(trace.Begin("", context.Background()))
|
||||
|
||||
if client == nil {
|
||||
return nil, PodStarterPortlayerClientError
|
||||
}
|
||||
if isolationProxy == nil {
|
||||
return nil, PodStarterIsolationProxyError
|
||||
}
|
||||
|
||||
return &VicPodStarter{
|
||||
client: client,
|
||||
isolationProxy: isolationProxy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Start starts up the pod vm
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// id pod id
|
||||
// name pod name
|
||||
// returns:
|
||||
// error
|
||||
func (v *VicPodStarter) Start(op trace.Operation, id, name string) error {
|
||||
defer trace.End(trace.Begin(fmt.Sprintf("id(%s), name(%s)", id, name), op))
|
||||
|
||||
h, err := v.isolationProxy.Handle(op, id, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Bind the container to the scope
|
||||
h, ep, err := v.isolationProxy.BindScope(op, h, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op.Debugf("*** Scope bind returned endpoints %#v", ep)
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
op.Debugf("Unbinding %s due to error - %s", id, err.Error())
|
||||
v.isolationProxy.UnbindScope(op, h, name)
|
||||
}
|
||||
}()
|
||||
|
||||
h, err = v.isolationProxy.SetState(op, h, name, "RUNNING")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// map ports
|
||||
|
||||
err = v.isolationProxy.CommitHandle(op, h, id, -1)
|
||||
|
||||
return nil
|
||||
}
|
||||
33
providers/vic/operations/pod_starter_test.go
Normal file
33
providers/vic/operations/pod_starter_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/proxy/mocks"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client"
|
||||
)
|
||||
|
||||
func TestNewPodStarter(t *testing.T) {
|
||||
var s PodStarter
|
||||
var err error
|
||||
|
||||
client := client.Default
|
||||
ip := &mocks.IsolationProxy{}
|
||||
|
||||
// Positive Cases
|
||||
s, err = NewPodStarter(client, ip)
|
||||
assert.NotNil(t, s, "Expected non-nil creating a pod starter but received nil")
|
||||
|
||||
// Negative Cases
|
||||
s, err = NewPodStarter(nil, ip)
|
||||
assert.Nil(t, s, "Expected nil")
|
||||
assert.Equal(t, err, PodStarterPortlayerClientError)
|
||||
|
||||
s, err = NewPodStarter(client, nil)
|
||||
assert.Nil(t, s, "Expected nil")
|
||||
assert.Equal(t, err, PodStarterIsolationProxyError)
|
||||
}
|
||||
|
||||
//NOTE: The rest of PodStarter tests were handled in PodCreator's tests so there's no need for further tests.
|
||||
95
providers/vic/operations/pod_stopper.go
Normal file
95
providers/vic/operations/pod_stopper.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/proxy"
|
||||
|
||||
vicerrors "github.com/vmware/vic/lib/apiservers/engine/errors"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client"
|
||||
"github.com/vmware/vic/pkg/retry"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
)
|
||||
|
||||
type PodStopper interface {
|
||||
Stop(op trace.Operation, id, name string) error
|
||||
}
|
||||
|
||||
type VicPodStopper struct {
|
||||
client *client.PortLayer
|
||||
isolationProxy proxy.IsolationProxy
|
||||
}
|
||||
|
||||
type VicPodStopperError string
|
||||
|
||||
func (e VicPodStopperError) Error() string { return string(e) }
|
||||
|
||||
const (
|
||||
PodStopperPortlayerClientError = VicPodStopperError("PodStopper called with an invalid portlayer client")
|
||||
PodStopperIsolationProxyError = VicPodStopperError("PodStopper called with an invalid isolation proxy")
|
||||
PodStopperInvalidPodIDError = VicPodStopperError("PodStopper called with invalid PodID")
|
||||
PodStopperInvalidPodNameError = VicPodStopperError("PodStopper called with invalid PodName")
|
||||
)
|
||||
|
||||
func NewPodStopper(client *client.PortLayer, isolationProxy proxy.IsolationProxy) (PodStopper, error) {
|
||||
if client == nil {
|
||||
return nil, PodStopperPortlayerClientError
|
||||
} else if isolationProxy == nil {
|
||||
return nil, PodStopperIsolationProxyError
|
||||
}
|
||||
|
||||
return &VicPodStopper{
|
||||
client: client,
|
||||
isolationProxy: isolationProxy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Stop stops a pod but does not delete it
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// id pod id
|
||||
// name pod name
|
||||
// returns:
|
||||
// error
|
||||
func (v *VicPodStopper) Stop(op trace.Operation, id, name string) error {
|
||||
defer trace.End(trace.Begin(fmt.Sprintf("id(%s), name(%s)", id, name), op))
|
||||
|
||||
operation := func() error {
|
||||
return v.stop(op, id, name)
|
||||
}
|
||||
|
||||
config := retry.NewBackoffConfig()
|
||||
config.MaxElapsedTime = 10 * time.Minute
|
||||
if err := retry.DoWithConfig(operation, vicerrors.IsConflictError, config); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *VicPodStopper) stop(op trace.Operation, id, name string) error {
|
||||
defer trace.End(trace.Begin(fmt.Sprintf("id(%s), name(%s)", id, name), op))
|
||||
|
||||
h, err := v.isolationProxy.Handle(op, id, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Unbind the container to the scope
|
||||
h, ep, err := v.isolationProxy.UnbindScope(op, h, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op.Infof("Scope Unbind returned endpoints %# +v", ep)
|
||||
|
||||
h, err = v.isolationProxy.SetState(op, h, name, "STOPPED")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = v.isolationProxy.CommitHandle(op, h, id, -1)
|
||||
op.Infof("Commit handler returned %v", err)
|
||||
return err
|
||||
}
|
||||
133
providers/vic/operations/pod_stopper_test.go
Normal file
133
providers/vic/operations/pod_stopper_test.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client"
|
||||
)
|
||||
|
||||
func TestNewPodStopper(t *testing.T) {
|
||||
_, ip, _, _ := createMocks(t)
|
||||
client := client.Default
|
||||
|
||||
// Positive Cases
|
||||
s, err := NewPodStopper(client, ip)
|
||||
assert.NotNil(t, s, "Expected non-nil creating a pod Stopper but received nil")
|
||||
|
||||
// Negative Cases
|
||||
s, err = NewPodStopper(nil, ip)
|
||||
assert.Nil(t, s, "Expected nil")
|
||||
assert.Equal(t, err, PodStopperPortlayerClientError)
|
||||
|
||||
s, err = NewPodStopper(client, nil)
|
||||
assert.Nil(t, s, "Expected nil")
|
||||
assert.Equal(t, err, PodStopperIsolationProxyError)
|
||||
}
|
||||
|
||||
func TestStopPod(t *testing.T) {
|
||||
client := client.Default
|
||||
_, ip, _, op := createMocks(t)
|
||||
|
||||
// Start with arguments
|
||||
s, err := NewPodStopper(client, ip)
|
||||
assert.NotNil(t, s, "Expected non-nil creating a pod Stopper but received nil")
|
||||
assert.Nil(t, err, "Expected nil")
|
||||
|
||||
// Set up the mocks for this test
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("UnbindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "STOPPED").Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
|
||||
// Positive case
|
||||
err = s.Stop(op, podID, podName)
|
||||
assert.Nil(t, err, "Expected nil")
|
||||
}
|
||||
|
||||
func TestStopPodErrorHandle(t *testing.T) {
|
||||
client := client.Default
|
||||
_, ip, _, op := createMocks(t)
|
||||
|
||||
// Start with arguments
|
||||
s, err := NewPodStopper(client, ip)
|
||||
assert.NotNil(t, s, "Expected non-nil creating a pod Stopper but received nil")
|
||||
assert.Nil(t, err, "Expected nil")
|
||||
|
||||
// Set up the mocks for this test
|
||||
ip.On("UnbindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "STOPPED").Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
|
||||
// Failed Handle
|
||||
fakeErr := fakeError("invalid handle")
|
||||
ip.On("Handle", op, podID, podName).Return("", fakeErr)
|
||||
|
||||
err = s.Stop(op, podID, podName)
|
||||
assert.Equal(t, err, fakeErr, "Expected invalid handle error")
|
||||
}
|
||||
|
||||
func TestStopPodErrorUnbindScope(t *testing.T) {
|
||||
client := client.Default
|
||||
_, ip, _, op := createMocks(t)
|
||||
|
||||
// Start with arguments
|
||||
s, err := NewPodStopper(client, ip)
|
||||
assert.NotNil(t, s, "Expected non-nil creating a pod Stopper but received nil")
|
||||
assert.Nil(t, err, "Expected nil")
|
||||
|
||||
// Set up the mocks for this test
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "STOPPED").Return(podHandle, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
|
||||
// Failed UnbindScope
|
||||
fakeErr := fakeError("failed UnbindScope")
|
||||
ip.On("UnbindScope", op, podHandle, podName).Return("", nil, fakeErr)
|
||||
|
||||
err = s.Stop(op, podID, podName)
|
||||
assert.Equal(t, err, fakeErr, "Expected failed UnbindScope error")
|
||||
}
|
||||
|
||||
func TestStopPodErrorSetState(t *testing.T) {
|
||||
client := client.Default
|
||||
_, ip, _, op := createMocks(t)
|
||||
|
||||
// Start with arguments
|
||||
s, err := NewPodStopper(client, ip)
|
||||
assert.NotNil(t, s, "Expected non-nil creating a pod Stopper but received nil")
|
||||
assert.Nil(t, err, "Expected nil")
|
||||
|
||||
// Set up the mocks for this test
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("UnbindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(nil)
|
||||
|
||||
// Failed SetState
|
||||
fakeErr := fakeError("failed SetState")
|
||||
ip.On("SetState", op, podHandle, podName, "STOPPED").Return("", fakeErr)
|
||||
err = s.Stop(op, podID, podName)
|
||||
assert.Equal(t, err, fakeErr, "Expected failed SetState error")
|
||||
}
|
||||
|
||||
func TestStopPodErrorCommit(t *testing.T) {
|
||||
client := client.Default
|
||||
_, ip, _, op := createMocks(t)
|
||||
|
||||
// Start with arguments
|
||||
s, err := NewPodStopper(client, ip)
|
||||
assert.NotNil(t, s, "Expected non-nil creating a pod Stopper but received nil")
|
||||
assert.Nil(t, err, "Expected nil")
|
||||
|
||||
// Set up the mocks for this test
|
||||
ip.On("Handle", op, podID, podName).Return(podHandle, nil)
|
||||
ip.On("UnbindScope", op, podHandle, podName).Return(podHandle, fakeEP, nil)
|
||||
ip.On("SetState", op, podHandle, podName, "STOPPED").Return(podHandle, nil)
|
||||
|
||||
// Failed Commit
|
||||
fakeErr := fakeError("failed Commit")
|
||||
ip.On("CommitHandle", op, podHandle, podID, int32(-1)).Return(fakeErr)
|
||||
err = s.Stop(op, podID, podName)
|
||||
assert.Equal(t, err, fakeErr ,"Expected failed Commit error")
|
||||
}
|
||||
10
providers/vic/pod/vicpod.go
Normal file
10
providers/vic/pod/vicpod.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package pod
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
type VicPod struct {
|
||||
ID string
|
||||
Pod *v1.Pod
|
||||
}
|
||||
BIN
providers/vic/podvm_basic_design.png
Normal file
BIN
providers/vic/podvm_basic_design.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
167
providers/vic/proxy/image_store.go
Normal file
167
providers/vic/proxy/image_store.go
Normal file
@@ -0,0 +1,167 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/vic/lib/apiservers/engine/backends/cache"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client"
|
||||
"github.com/vmware/vic/lib/metadata"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
)
|
||||
|
||||
//TODO: This image cache needs to hook into the VIC persona to receive an event when users pulled images
|
||||
// via docker.
|
||||
|
||||
type ImageStore interface {
|
||||
Get(op trace.Operation, idOrRef, tag string, actuate bool) (*metadata.ImageConfig, error)
|
||||
GetImages(op trace.Operation) []*metadata.ImageConfig
|
||||
PullImage(op trace.Operation, image, tag, username, password string) error
|
||||
}
|
||||
|
||||
type VicImageStore struct {
|
||||
client *client.PortLayer
|
||||
personaAddr string
|
||||
portlayerAddr string
|
||||
}
|
||||
|
||||
type ImageStoreError string
|
||||
|
||||
func (e ImageStoreError) Error() string { return string(e) }
|
||||
|
||||
const (
|
||||
ImageStorePortlayerClientError = ImageStoreError("ImageStore cannot be created without a valid portlayer client")
|
||||
ImageStorePersonaAddrError = ImageStoreError("ImageStore cannot be created without a valid VIC persona addr")
|
||||
ImageStorePortlayerAddrError = ImageStoreError("ImageStore cannot be created without a valid VIC portlayer addr")
|
||||
ImageStoreContainerIDError = ImageStoreError("ImageStore called with empty container ID")
|
||||
ImageStoreEmptyUserNameError = ImageStoreError("ImageStore called with empty username")
|
||||
ImageStoreEmptyPasswordError = ImageStoreError("ImageStore called with empty password")
|
||||
)
|
||||
|
||||
func NewImageStore(plClient *client.PortLayer, personaAddr, portlayerAddr string) (ImageStore, error) {
|
||||
if plClient == nil {
|
||||
return nil, ImageStorePortlayerClientError
|
||||
}
|
||||
if personaAddr == "" {
|
||||
return nil, ImageStorePersonaAddrError
|
||||
}
|
||||
if portlayerAddr == "" {
|
||||
return nil, ImageStorePortlayerAddrError
|
||||
}
|
||||
|
||||
err := cache.InitializeImageCache(plClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vs := &VicImageStore{
|
||||
client: plClient,
|
||||
personaAddr: personaAddr,
|
||||
portlayerAddr: portlayerAddr,
|
||||
}
|
||||
|
||||
return vs, nil
|
||||
}
|
||||
|
||||
// Get retrieves the VIC ImageConfig data structure. If the config is not cached,
|
||||
// VicImageStore can request imagec to pull the image if actuate is set to true.
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// idOrRef docker image id or reference
|
||||
// tag docker image tag
|
||||
// realize determines whether the image is pulled if not in the cache
|
||||
// returns:
|
||||
// error
|
||||
func (v *VicImageStore) Get(op trace.Operation, idOrRef, tag string, realize bool) (*metadata.ImageConfig, error) {
|
||||
defer trace.End(trace.Begin(fmt.Sprintf("Get - %s:%s", idOrRef, tag), op))
|
||||
|
||||
if idOrRef == "" {
|
||||
op.Errorf(ImageStoreContainerIDError.Error())
|
||||
return nil, ImageStoreContainerIDError
|
||||
}
|
||||
|
||||
c, err := cache.ImageCache().Get(idOrRef)
|
||||
if err != nil && realize {
|
||||
err = v.PullImage(op, idOrRef, tag, "", "")
|
||||
if err == nil {
|
||||
//TODO: Find a better way to get update imageconfig instead of this hammer
|
||||
err := cache.InitializeImageCache(v.client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c, err = cache.ImageCache().Get(idOrRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Get retrieves all the VIC ImageConfig data structure.
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// returns:
|
||||
// array of ImageConfig
|
||||
func (v *VicImageStore) GetImages(op trace.Operation) []*metadata.ImageConfig {
|
||||
defer trace.End(trace.Begin("", op))
|
||||
|
||||
return cache.ImageCache().GetImages()
|
||||
}
|
||||
|
||||
// PullImage makes a request to the VIC persona server (imageC component) to retrieve a container image.
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// idOrRef docker image id or reference
|
||||
// tag docker image tag
|
||||
// username user name for the registry server
|
||||
// password password for the registry server
|
||||
// returns:
|
||||
// array of ImageConfig
|
||||
func (v *VicImageStore) PullImage(op trace.Operation, image, tag, username, password string) error {
|
||||
defer trace.End(trace.Begin(fmt.Sprintf("Get - %s:%s", image, tag), op))
|
||||
|
||||
if image == "" {
|
||||
op.Errorf(ImageStoreContainerIDError.Error())
|
||||
return ImageStoreContainerIDError
|
||||
}
|
||||
|
||||
pullClient := &http.Client{Timeout: 60 * time.Second}
|
||||
var personaServer string
|
||||
if tag == "" {
|
||||
personaServer = fmt.Sprintf("http://%s/v1.35/images/create?fromImage=%s", v.personaAddr, image)
|
||||
} else {
|
||||
personaServer = fmt.Sprintf("http://%s/v1.35/images/create?fromImage=%s&tag=%s", v.personaAddr, image, tag)
|
||||
}
|
||||
op.Infof("POST %s", personaServer)
|
||||
reader := bytes.NewBuffer([]byte(""))
|
||||
resp, err := pullClient.Post(personaServer, "application/json", reader)
|
||||
if err != nil {
|
||||
op.Errorf("Error from docker pull: error = %s", err.Error())
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
msg := fmt.Sprintf("Error from docker pull: status = %d", resp.StatusCode)
|
||||
op.Errorf(msg)
|
||||
return fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Error reading docker pull response: error = %s", err.Error())
|
||||
op.Errorf(msg)
|
||||
return fmt.Errorf(msg)
|
||||
}
|
||||
op.Infof("Response from docker pull: body = %s", string(body))
|
||||
|
||||
return nil
|
||||
}
|
||||
589
providers/vic/proxy/isolation_proxy.go
Normal file
589
providers/vic/proxy/isolation_proxy.go
Normal file
@@ -0,0 +1,589 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
vicerrors "github.com/vmware/vic/lib/apiservers/engine/errors"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client/containers"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client/interaction"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client/logging"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client/scopes"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client/storage"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client/tasks"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/models"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
"github.com/vmware/vic/pkg/vsphere/sys"
|
||||
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/cache"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/constants"
|
||||
)
|
||||
|
||||
type IsolationProxy interface {
|
||||
CreateHandle(op trace.Operation) (string, string, error)
|
||||
AddImageToHandle(op trace.Operation, handle, deltaID, layerID, imageID, imageName string) (string, error)
|
||||
CreateHandleTask(op trace.Operation, handle, id, layerID string, config IsolationContainerConfig) (string, error)
|
||||
AddHandleToScope(op trace.Operation, handle string, config IsolationContainerConfig) (string, error)
|
||||
AddInteractionToHandle(op trace.Operation, handle string) (string, error)
|
||||
AddLoggingToHandle(op trace.Operation, handle string) (string, error)
|
||||
CommitHandle(op trace.Operation, handle, containerID string, waitTime int32) error
|
||||
SetState(op trace.Operation, handle, name, state string) (string, error)
|
||||
|
||||
BindScope(op trace.Operation, handle string, name string) (string, interface{}, error)
|
||||
UnbindScope(op trace.Operation, handle string, name string) (string, interface{}, error)
|
||||
|
||||
Handle(op trace.Operation, id, name string) (string, error)
|
||||
State(op trace.Operation, id, name string) (string, error)
|
||||
Remove(op trace.Operation, id string, force bool) error
|
||||
}
|
||||
|
||||
type VicIsolationProxy struct {
|
||||
client *client.PortLayer
|
||||
imageStore ImageStore
|
||||
podCache cache.PodCache
|
||||
portlayerAddr string
|
||||
hostUUID string
|
||||
}
|
||||
|
||||
type PortBinding struct {
|
||||
HostIP string
|
||||
HostPort string
|
||||
}
|
||||
|
||||
type IsolationContainerConfig struct {
|
||||
ID string
|
||||
ImageID string
|
||||
LayerID string
|
||||
ImageName string
|
||||
Name string
|
||||
Namespace string
|
||||
|
||||
Cmd []string
|
||||
Path string
|
||||
Entrypoint []string
|
||||
//Args []string
|
||||
Env []string
|
||||
WorkingDir string
|
||||
User string
|
||||
StopSignal string
|
||||
|
||||
Attach bool
|
||||
StdinOnce bool
|
||||
OpenStdin bool
|
||||
Tty bool
|
||||
|
||||
CPUCount int64
|
||||
Memory int64
|
||||
|
||||
PortMap map[string]PortBinding
|
||||
}
|
||||
|
||||
func NewIsolationProxy(plClient *client.PortLayer, portlayerAddr string, hostUUID string, imageStore ImageStore, podCache cache.PodCache) IsolationProxy {
|
||||
if plClient == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &VicIsolationProxy{
|
||||
client: plClient,
|
||||
imageStore: imageStore,
|
||||
podCache: podCache,
|
||||
portlayerAddr: portlayerAddr,
|
||||
hostUUID: hostUUID,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateHandle creates a "manifest" that will be used by Commit() to create the actual
|
||||
// isolation vm.
|
||||
//
|
||||
// returns:
|
||||
// (container/pod id, handle, error)
|
||||
func (v *VicIsolationProxy) CreateHandle(op trace.Operation) (string, string, error) {
|
||||
defer trace.End(trace.Begin("CreateHandle", op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", "", vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
// Call the Exec port layer to create the container
|
||||
var err error
|
||||
var hostUUID string
|
||||
if v.hostUUID != "" {
|
||||
hostUUID = v.hostUUID
|
||||
} else {
|
||||
hostUUID, err = sys.UUID()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return "", "", vicerrors.InternalServerError("IsolationProxy.CreateContainerHandle got unexpected error getting VCH UUID")
|
||||
}
|
||||
|
||||
plCreateParams := initIsolationConfig(op, "", constants.DummyRepoName, constants.DummyImage, constants.DummyLayerID, hostUUID)
|
||||
createResults, err := v.client.Containers.Create(plCreateParams)
|
||||
if err != nil {
|
||||
if _, ok := err.(*containers.CreateNotFound); ok {
|
||||
cerr := fmt.Errorf("No such image: %s", constants.DummyImage)
|
||||
op.Errorf("%s (%s)", cerr, err)
|
||||
return "", "", vicerrors.NotFoundError(cerr.Error())
|
||||
}
|
||||
|
||||
// If we get here, most likely something went wrong with the port layer API server
|
||||
return "", "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
id := createResults.Payload.ID
|
||||
h := createResults.Payload.Handle
|
||||
|
||||
return id, h, nil
|
||||
}
|
||||
|
||||
// Handle retrieves a handle to a VIC container. Handles should be treated as opaque strings.
|
||||
//
|
||||
// returns:
|
||||
// (handle string, error)
|
||||
func (v *VicIsolationProxy) Handle(op trace.Operation, id, name string) (string, error) {
|
||||
if v.client == nil {
|
||||
return "", vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
resp, err := v.client.Containers.Get(containers.NewGetParamsWithContext(op).WithID(id))
|
||||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case *containers.GetNotFound:
|
||||
return "", vicerrors.NotFoundError(name)
|
||||
case *containers.GetDefault:
|
||||
return "", vicerrors.InternalServerError(err.Payload.Message)
|
||||
default:
|
||||
return "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
}
|
||||
return resp.Payload, nil
|
||||
}
|
||||
|
||||
func (v *VicIsolationProxy) AddImageToHandle(op trace.Operation, handle, deltaID, layerID, imageID, imageName string) (string, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", vicerrors.InternalServerError("IsolationProxy.AddImageToContainer failed to get the portlayer client")
|
||||
}
|
||||
|
||||
var err error
|
||||
var hostUUID string
|
||||
if v.hostUUID != "" {
|
||||
hostUUID = v.hostUUID
|
||||
} else {
|
||||
hostUUID, err = sys.UUID()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return "", vicerrors.InternalServerError("IsolationProxy.AddImageToContainer got unexpected error getting VCH UUID")
|
||||
}
|
||||
|
||||
response, err := v.client.Storage.ImageJoin(storage.NewImageJoinParamsWithContext(op).WithStoreName(hostUUID).WithID(layerID).
|
||||
WithConfig(&models.ImageJoinConfig{
|
||||
Handle: handle,
|
||||
DeltaID: deltaID,
|
||||
ImageID: imageID,
|
||||
RepoName: imageName,
|
||||
}))
|
||||
if err != nil {
|
||||
return "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
handle, ok := response.Payload.Handle.(string)
|
||||
if !ok {
|
||||
return "", vicerrors.InternalServerError(fmt.Sprintf("Type assertion failed for %#+v", handle))
|
||||
}
|
||||
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
func (v *VicIsolationProxy) CreateHandleTask(op trace.Operation, handle, id, layerID string, config IsolationContainerConfig) (string, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", vicerrors.InternalServerError("IsolationProxy.CreateContainerTask failed to create a portlayer client")
|
||||
}
|
||||
|
||||
op.Debugf("CreateHandleTask - %#v", config)
|
||||
|
||||
plTaskParams := IsolationContainerConfigToTask(op, id, layerID, config)
|
||||
plTaskParams.Config.Handle = handle
|
||||
|
||||
op.Debugf("*** CreateContainerTask - params = %#v", *plTaskParams.Config)
|
||||
responseJoin, err := v.client.Tasks.Join(plTaskParams)
|
||||
if err != nil {
|
||||
op.Errorf("Unable to join primary task to container: %+v", err)
|
||||
return "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
handle, ok := responseJoin.Payload.Handle.(string)
|
||||
if !ok {
|
||||
return "", vicerrors.InternalServerError(fmt.Sprintf("Type assertion failed on handle from task join: %#+v", handle))
|
||||
}
|
||||
|
||||
plBindParams := tasks.NewBindParamsWithContext(op).WithConfig(&models.TaskBindConfig{Handle: handle, ID: id})
|
||||
responseBind, err := v.client.Tasks.Bind(plBindParams)
|
||||
if err != nil {
|
||||
op.Errorf("Unable to bind primary task to container: %+v", err)
|
||||
return "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
handle, ok = responseBind.Payload.Handle.(string)
|
||||
if !ok {
|
||||
return "", vicerrors.InternalServerError(fmt.Sprintf("Type assertion failed on handle from task bind %#+v", handle))
|
||||
}
|
||||
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
// AddHandleToScope adds a container, referenced by handle, to a scope.
|
||||
// If an error is return, the returned handle should not be used.
|
||||
//
|
||||
// returns:
|
||||
// modified handle
|
||||
func (v *VicIsolationProxy) AddHandleToScope(op trace.Operation, handle string, config IsolationContainerConfig) (string, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
// configure network
|
||||
netConf := networkConfigFromIsolationConfig(config)
|
||||
if netConf != nil {
|
||||
addContRes, err := v.client.Scopes.AddContainer(scopes.NewAddContainerParamsWithContext(op).
|
||||
WithScope(netConf.NetworkName).
|
||||
WithConfig(&models.ScopesAddContainerConfig{
|
||||
Handle: handle,
|
||||
NetworkConfig: netConf,
|
||||
}))
|
||||
|
||||
if err != nil {
|
||||
op.Errorf("IsolationProxy.AddContainerToScope: Scopes error: %s", err.Error())
|
||||
return handle, vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
// roll back the AddContainer call
|
||||
if _, err2 := v.client.Scopes.RemoveContainer(scopes.NewRemoveContainerParamsWithContext(op).WithHandle(handle).WithScope(netConf.NetworkName)); err2 != nil {
|
||||
op.Warnf("could not roll back container add: %s", err2)
|
||||
}
|
||||
}()
|
||||
|
||||
handle = addContRes.Payload
|
||||
}
|
||||
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
// AddLoggingToHandle adds logging capability to the isolation vm, referenced by handle.
|
||||
// If an error is return, the returned handle should not be used.
|
||||
//
|
||||
// returns:
|
||||
// modified handle
|
||||
func (v *VicIsolationProxy) AddLoggingToHandle(op trace.Operation, handle string) (string, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
response, err := v.client.Logging.LoggingJoin(logging.NewLoggingJoinParamsWithContext(op).
|
||||
WithConfig(&models.LoggingJoinConfig{
|
||||
Handle: handle,
|
||||
}))
|
||||
if err != nil {
|
||||
return "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
handle, ok := response.Payload.Handle.(string)
|
||||
if !ok {
|
||||
return "", vicerrors.InternalServerError(fmt.Sprintf("Type assertion failed for %#+v", handle))
|
||||
}
|
||||
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
// AddInteractionToContainer adds interaction capabilities to a container, referenced by handle.
|
||||
// If an error is return, the returned handle should not be used.
|
||||
//
|
||||
// returns:
|
||||
// modified handle
|
||||
func (v *VicIsolationProxy) AddInteractionToHandle(op trace.Operation, handle string) (string, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
response, err := v.client.Interaction.InteractionJoin(interaction.NewInteractionJoinParamsWithContext(op).
|
||||
WithConfig(&models.InteractionJoinConfig{
|
||||
Handle: handle,
|
||||
}))
|
||||
if err != nil {
|
||||
return "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
handle, ok := response.Payload.Handle.(string)
|
||||
if !ok {
|
||||
return "", vicerrors.InternalServerError(fmt.Sprintf("Type assertion failed for %#+v", handle))
|
||||
}
|
||||
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
func (v *VicIsolationProxy) CommitHandle(op trace.Operation, handle, containerID string, waitTime int32) error {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
var commitParams *containers.CommitParams
|
||||
if waitTime > 0 {
|
||||
commitParams = containers.NewCommitParamsWithContext(op).WithHandle(handle).WithWaitTime(&waitTime)
|
||||
} else {
|
||||
commitParams = containers.NewCommitParamsWithContext(op).WithHandle(handle)
|
||||
}
|
||||
|
||||
_, err := v.client.Containers.Commit(commitParams)
|
||||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case *containers.CommitNotFound:
|
||||
return vicerrors.NotFoundError(containerID)
|
||||
case *containers.CommitConflict:
|
||||
return vicerrors.ConflictError(err.Error())
|
||||
case *containers.CommitDefault:
|
||||
return vicerrors.InternalServerError(err.Payload.Message)
|
||||
default:
|
||||
return vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//TODO: I don't think this function should be in here.
|
||||
// BindNetwork binds the handle to the scope and returns endpoints. Caller of the function does not need
|
||||
// to interpret the return value. In the event the caller want to unbind,
|
||||
func (v *VicIsolationProxy) BindScope(op trace.Operation, handle string, name string) (string, interface{}, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", nil, vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
bindParams := scopes.NewBindContainerParamsWithContext(op).WithHandle(handle)
|
||||
bindRes, err := v.client.Scopes.BindContainer(bindParams)
|
||||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case *scopes.BindContainerNotFound:
|
||||
return "", nil, vicerrors.NotFoundError(name)
|
||||
case *scopes.BindContainerInternalServerError:
|
||||
return "", nil, vicerrors.InternalServerError(err.Payload.Message)
|
||||
default:
|
||||
return "", nil, vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return bindRes.Payload.Handle, bindRes.Payload.Endpoints, nil
|
||||
}
|
||||
|
||||
func (v *VicIsolationProxy) UnbindScope(op trace.Operation, handle string, name string) (string, interface{}, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", nil, vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
unbindParams := scopes.NewUnbindContainerParamsWithContext(op).WithHandle(handle)
|
||||
resp, err := v.client.Scopes.UnbindContainer(unbindParams)
|
||||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case *scopes.UnbindContainerNotFound:
|
||||
return "", nil, vicerrors.NotFoundError(name)
|
||||
case *scopes.UnbindContainerInternalServerError:
|
||||
return "", nil, vicerrors.InternalServerError(err.Payload.Message)
|
||||
default:
|
||||
return "", nil, vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return resp.Payload.Handle, resp.Payload.Endpoints, nil
|
||||
}
|
||||
|
||||
// SetState adds the desire state of the isolation unit once the handle is commited.
|
||||
//
|
||||
// returns handle string and error
|
||||
func (v *VicIsolationProxy) SetState(op trace.Operation, handle, name, state string) (string, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
resp, err := v.client.Containers.StateChange(containers.NewStateChangeParamsWithContext(op).WithHandle(handle).WithState(state))
|
||||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case *containers.StateChangeNotFound:
|
||||
return "", vicerrors.NotFoundError(name)
|
||||
case *containers.StateChangeDefault:
|
||||
return "", vicerrors.InternalServerError(err.Payload.Message)
|
||||
default:
|
||||
return "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return resp.Payload, nil
|
||||
}
|
||||
|
||||
func (v *VicIsolationProxy) State(op trace.Operation, id, name string) (string, error) {
|
||||
defer trace.End(trace.Begin(id, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
results, err := v.client.Containers.GetContainerInfo(containers.NewGetContainerInfoParamsWithContext(op).WithID(id))
|
||||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case *containers.GetContainerInfoNotFound:
|
||||
return "", vicerrors.NotFoundError(name)
|
||||
case *containers.GetContainerInfoInternalServerError:
|
||||
return "", vicerrors.InternalServerError(err.Payload.Message)
|
||||
default:
|
||||
return "", vicerrors.InternalServerError(fmt.Sprintf("Unknown error from the interaction port layer: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
state := results.Payload.ContainerConfig.State
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func (v *VicIsolationProxy) Remove(op trace.Operation, id string, force bool) error {
|
||||
defer trace.End(trace.Begin(id, op))
|
||||
|
||||
if v.client == nil {
|
||||
return vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
pForce := force
|
||||
params := containers.NewContainerRemoveParamsWithContext(op).
|
||||
WithID(id).
|
||||
WithForce(&pForce).
|
||||
WithTimeout(120 * time.Second)
|
||||
|
||||
removeOK, err := v.client.Containers.ContainerRemove(params)
|
||||
op.Debugf("ContainerRemove returned %# +v", removeOK)
|
||||
return err
|
||||
}
|
||||
|
||||
//------------------------------------
|
||||
// Utility Functions
|
||||
//------------------------------------
|
||||
|
||||
// Convert isolation container config to portlayer task param
|
||||
func IsolationContainerConfigToTask(op trace.Operation, id, layerID string, ic IsolationContainerConfig) *tasks.JoinParams {
|
||||
config := &models.TaskJoinConfig{}
|
||||
|
||||
var path string
|
||||
var args []string
|
||||
|
||||
// we explicitly specify the ID for the primary task so that it's the same as the containerID
|
||||
config.ID = id
|
||||
|
||||
// Set the filesystem namespace this task expects to run in
|
||||
config.Namespace = layerID
|
||||
|
||||
// Expand cmd into entrypoint and args
|
||||
cmd := strslice.StrSlice(ic.Cmd)
|
||||
if len(ic.Entrypoint) != 0 {
|
||||
path, args = ic.Entrypoint[0], append(ic.Entrypoint[1:], cmd...)
|
||||
} else {
|
||||
path, args = cmd[0], cmd[1:]
|
||||
}
|
||||
|
||||
// copy the path
|
||||
config.Path = path
|
||||
|
||||
// copy the args
|
||||
config.Args = make([]string, len(args))
|
||||
copy(config.Args, args)
|
||||
|
||||
// copy the env array
|
||||
config.Env = make([]string, len(ic.Env))
|
||||
copy(config.Env, ic.Env)
|
||||
|
||||
// working dir
|
||||
config.WorkingDir = ic.WorkingDir
|
||||
|
||||
// user
|
||||
config.User = ic.User
|
||||
|
||||
// attach. Always set to true otherwise we cannot attach later.
|
||||
// this tells portlayer container is attachable.
|
||||
config.Attach = true
|
||||
|
||||
// openstdin
|
||||
config.OpenStdin = ic.OpenStdin
|
||||
|
||||
// tty
|
||||
config.Tty = ic.Tty
|
||||
|
||||
// container stop signal
|
||||
config.StopSignal = ic.StopSignal
|
||||
|
||||
op.Debugf("dockerContainerCreateParamsToTask = %+v", config)
|
||||
|
||||
return tasks.NewJoinParamsWithContext(op).WithConfig(config)
|
||||
}
|
||||
|
||||
// initIsolationConfig returns a default config used to create the isolation unit handle
|
||||
func initIsolationConfig(op trace.Operation, name, repoName, imageID, layerID, imageStore string) *containers.CreateParams {
|
||||
config := &models.ContainerCreateConfig{}
|
||||
|
||||
config.NumCpus = constants.DefaultCPUs
|
||||
config.MemoryMB = constants.DefaultMemory
|
||||
|
||||
// Layer/vmdk to use
|
||||
config.Layer = layerID
|
||||
|
||||
// Image ID
|
||||
config.Image = imageID
|
||||
|
||||
// Repo Requested
|
||||
config.RepoName = repoName
|
||||
|
||||
//copy friendly name
|
||||
config.Name = name
|
||||
|
||||
// image store
|
||||
config.ImageStore = &models.ImageStore{Name: imageStore}
|
||||
|
||||
// network
|
||||
config.NetworkDisabled = true
|
||||
|
||||
// hostname
|
||||
config.Hostname = constants.HostName
|
||||
//// domainname - https://github.com/moby/moby/issues/27067
|
||||
//config.Domainname = cc.Config.Domainname
|
||||
|
||||
op.Debugf("dockerContainerCreateParamsToPortlayer = %+v", config)
|
||||
|
||||
return containers.NewCreateParamsWithContext(op).WithCreateConfig(config)
|
||||
}
|
||||
|
||||
func networkConfigFromIsolationConfig(config IsolationContainerConfig) *models.NetworkConfig {
|
||||
nc := &models.NetworkConfig{
|
||||
NetworkName: "default",
|
||||
}
|
||||
|
||||
for key, val := range config.PortMap {
|
||||
nc.Ports = append(nc.Ports, fmt.Sprintf("%s:%s", val.HostPort, key))
|
||||
}
|
||||
|
||||
return nc
|
||||
}
|
||||
65
providers/vic/proxy/mocks/ImageStore.go
Normal file
65
providers/vic/proxy/mocks/ImageStore.go
Normal file
@@ -0,0 +1,65 @@
|
||||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
package mocks
|
||||
|
||||
import metadata "github.com/vmware/vic/lib/metadata"
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
|
||||
import trace "github.com/vmware/vic/pkg/trace"
|
||||
|
||||
// ImageStore is an autogenerated mock type for the ImageStore type
|
||||
type ImageStore struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Get provides a mock function with given fields: op, idOrRef, tag, actuate
|
||||
func (_m *ImageStore) Get(op trace.Operation, idOrRef string, tag string, actuate bool) (*metadata.ImageConfig, error) {
|
||||
ret := _m.Called(op, idOrRef, tag, actuate)
|
||||
|
||||
var r0 *metadata.ImageConfig
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string, bool) *metadata.ImageConfig); ok {
|
||||
r0 = rf(op, idOrRef, tag, actuate)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*metadata.ImageConfig)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string, bool) error); ok {
|
||||
r1 = rf(op, idOrRef, tag, actuate)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetImages provides a mock function with given fields: op
|
||||
func (_m *ImageStore) GetImages(op trace.Operation) []*metadata.ImageConfig {
|
||||
ret := _m.Called(op)
|
||||
|
||||
var r0 []*metadata.ImageConfig
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation) []*metadata.ImageConfig); ok {
|
||||
r0 = rf(op)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*metadata.ImageConfig)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// PullImage provides a mock function with given fields: op, image, tag, username, password
|
||||
func (_m *ImageStore) PullImage(op trace.Operation, image string, tag string, username string, password string) error {
|
||||
ret := _m.Called(op, image, tag, username, password)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string, string, string) error); ok {
|
||||
r0 = rf(op, image, tag, username, password)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
295
providers/vic/proxy/mocks/IsolationProxy.go
Normal file
295
providers/vic/proxy/mocks/IsolationProxy.go
Normal file
@@ -0,0 +1,295 @@
|
||||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
package mocks
|
||||
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
import proxy "github.com/virtual-kubelet/virtual-kubelet/providers/vic/proxy"
|
||||
import trace "github.com/vmware/vic/pkg/trace"
|
||||
|
||||
// IsolationProxy is an autogenerated mock type for the IsolationProxy type
|
||||
type IsolationProxy struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// AddHandleToScope provides a mock function with given fields: op, handle, config
|
||||
func (_m *IsolationProxy) AddHandleToScope(op trace.Operation, handle string, config proxy.IsolationContainerConfig) (string, error) {
|
||||
ret := _m.Called(op, handle, config)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, proxy.IsolationContainerConfig) string); ok {
|
||||
r0 = rf(op, handle, config)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, proxy.IsolationContainerConfig) error); ok {
|
||||
r1 = rf(op, handle, config)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// AddImageToHandle provides a mock function with given fields: op, handle, deltaID, layerID, imageID, imageName
|
||||
func (_m *IsolationProxy) AddImageToHandle(op trace.Operation, handle string, deltaID string, layerID string, imageID string, imageName string) (string, error) {
|
||||
ret := _m.Called(op, handle, deltaID, layerID, imageID, imageName)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string, string, string, string) string); ok {
|
||||
r0 = rf(op, handle, deltaID, layerID, imageID, imageName)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string, string, string, string) error); ok {
|
||||
r1 = rf(op, handle, deltaID, layerID, imageID, imageName)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// AddInteractionToHandle provides a mock function with given fields: op, handle
|
||||
func (_m *IsolationProxy) AddInteractionToHandle(op trace.Operation, handle string) (string, error) {
|
||||
ret := _m.Called(op, handle)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string) string); ok {
|
||||
r0 = rf(op, handle)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string) error); ok {
|
||||
r1 = rf(op, handle)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// AddLoggingToHandle provides a mock function with given fields: op, handle
|
||||
func (_m *IsolationProxy) AddLoggingToHandle(op trace.Operation, handle string) (string, error) {
|
||||
ret := _m.Called(op, handle)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string) string); ok {
|
||||
r0 = rf(op, handle)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string) error); ok {
|
||||
r1 = rf(op, handle)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// BindScope provides a mock function with given fields: op, handle, name
|
||||
func (_m *IsolationProxy) BindScope(op trace.Operation, handle string, name string) (string, interface{}, error) {
|
||||
ret := _m.Called(op, handle, name)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string) string); ok {
|
||||
r0 = rf(op, handle, name)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 interface{}
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string) interface{}); ok {
|
||||
r1 = rf(op, handle, name)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(interface{})
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(trace.Operation, string, string) error); ok {
|
||||
r2 = rf(op, handle, name)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// CommitHandle provides a mock function with given fields: op, handle, containerID, waitTime
|
||||
func (_m *IsolationProxy) CommitHandle(op trace.Operation, handle string, containerID string, waitTime int32) error {
|
||||
ret := _m.Called(op, handle, containerID, waitTime)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string, int32) error); ok {
|
||||
r0 = rf(op, handle, containerID, waitTime)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// CreateHandle provides a mock function with given fields: op
|
||||
func (_m *IsolationProxy) CreateHandle(op trace.Operation) (string, string, error) {
|
||||
ret := _m.Called(op)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation) string); ok {
|
||||
r0 = rf(op)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 string
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation) string); ok {
|
||||
r1 = rf(op)
|
||||
} else {
|
||||
r1 = ret.Get(1).(string)
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(trace.Operation) error); ok {
|
||||
r2 = rf(op)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// CreateHandleTask provides a mock function with given fields: op, handle, id, layerID, config
|
||||
func (_m *IsolationProxy) CreateHandleTask(op trace.Operation, handle string, id string, layerID string, config proxy.IsolationContainerConfig) (string, error) {
|
||||
ret := _m.Called(op, handle, id, layerID, config)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string, string, proxy.IsolationContainerConfig) string); ok {
|
||||
r0 = rf(op, handle, id, layerID, config)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string, string, proxy.IsolationContainerConfig) error); ok {
|
||||
r1 = rf(op, handle, id, layerID, config)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Handle provides a mock function with given fields: op, id, name
|
||||
func (_m *IsolationProxy) Handle(op trace.Operation, id string, name string) (string, error) {
|
||||
ret := _m.Called(op, id, name)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string) string); ok {
|
||||
r0 = rf(op, id, name)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string) error); ok {
|
||||
r1 = rf(op, id, name)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Remove provides a mock function with given fields: op, id, force
|
||||
func (_m *IsolationProxy) Remove(op trace.Operation, id string, force bool) error {
|
||||
ret := _m.Called(op, id, force)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, bool) error); ok {
|
||||
r0 = rf(op, id, force)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// SetState provides a mock function with given fields: op, handle, name, state
|
||||
func (_m *IsolationProxy) SetState(op trace.Operation, handle string, name string, state string) (string, error) {
|
||||
ret := _m.Called(op, handle, name, state)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string, string) string); ok {
|
||||
r0 = rf(op, handle, name, state)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string, string) error); ok {
|
||||
r1 = rf(op, handle, name, state)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// State provides a mock function with given fields: op, id, name
|
||||
func (_m *IsolationProxy) State(op trace.Operation, id string, name string) (string, error) {
|
||||
ret := _m.Called(op, id, name)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string) string); ok {
|
||||
r0 = rf(op, id, name)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string) error); ok {
|
||||
r1 = rf(op, id, name)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UnbindScope provides a mock function with given fields: op, handle, name
|
||||
func (_m *IsolationProxy) UnbindScope(op trace.Operation, handle string, name string) (string, interface{}, error) {
|
||||
ret := _m.Called(op, handle, name)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string) string); ok {
|
||||
r0 = rf(op, handle, name)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 interface{}
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string) interface{}); ok {
|
||||
r1 = rf(op, handle, name)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(interface{})
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(trace.Operation, string, string) error); ok {
|
||||
r2 = rf(op, handle, name)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
179
providers/vic/utils/units.go
Normal file
179
providers/vic/utils/units.go
Normal file
@@ -0,0 +1,179 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
BYTE = 1.0 << (10 * iota)
|
||||
KILOBYTE
|
||||
MEGABYTE
|
||||
GIGABYTE
|
||||
TERABYTE
|
||||
PETABYTE
|
||||
)
|
||||
|
||||
const (
|
||||
KILOBYTESUFFIX = "Ki"
|
||||
MEGABYTESUFFIX = "Mi"
|
||||
GIGABYTESUFFIX = "Gi"
|
||||
TERABYTESUFFIX = "Ti"
|
||||
PETABYTESUFFIX = "Pi"
|
||||
)
|
||||
|
||||
const (
|
||||
ONE = 1.0
|
||||
KILO = 1000.0
|
||||
MEGA = KILO * KILO
|
||||
GIGA = MEGA * KILO
|
||||
TERA = GIGA * KILO
|
||||
PETA = TERA * KILO
|
||||
)
|
||||
|
||||
const (
|
||||
KILOSUFFIX = "K"
|
||||
MEGASUFFIX = "M"
|
||||
GIGASUFFIX = "G"
|
||||
TERASUFFIX = "T"
|
||||
PETASUFFIX = "P"
|
||||
)
|
||||
|
||||
const (
|
||||
MEMORYCUTOVER = 100
|
||||
FREQUENCYCUTOVER = 10
|
||||
)
|
||||
|
||||
const (
|
||||
MINPODSIZE = 2 * GIGABYTE
|
||||
)
|
||||
|
||||
func MemsizeToBytesize(size int64, unit string) int64 {
|
||||
u := strings.ToLower(unit)
|
||||
var sizeInBytes int64
|
||||
switch u {
|
||||
case "b":
|
||||
sizeInBytes = size
|
||||
break
|
||||
case "k":
|
||||
case "kb":
|
||||
sizeInBytes = size * KILOBYTE
|
||||
break
|
||||
case "m":
|
||||
case "mb":
|
||||
sizeInBytes = size * MEGABYTE
|
||||
break
|
||||
case "g":
|
||||
case "gb":
|
||||
sizeInBytes = size * GIGABYTE
|
||||
break
|
||||
case "t":
|
||||
case "tb":
|
||||
sizeInBytes = size * TERABYTE
|
||||
break
|
||||
case "p":
|
||||
case "pb":
|
||||
sizeInBytes = size * PETABYTE
|
||||
break
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
|
||||
return sizeInBytes
|
||||
}
|
||||
|
||||
func MemsizeToDecimalString(size int64, unit string) string {
|
||||
sizeInBytes := MemsizeToBytesize(size, unit)
|
||||
|
||||
var res string
|
||||
if sizeInBytes >= PETA*MEMORYCUTOVER {
|
||||
res = fmt.Sprintf("%d%s", sizeInBytes/PETA, PETASUFFIX)
|
||||
} else if sizeInBytes >= TERA*MEMORYCUTOVER {
|
||||
res = fmt.Sprintf("%d%s", sizeInBytes/TERA, TERASUFFIX)
|
||||
} else if sizeInBytes >= GIGA*MEMORYCUTOVER {
|
||||
res = fmt.Sprintf("%d%s", sizeInBytes/GIGA, GIGASUFFIX)
|
||||
} else if sizeInBytes >= MEGA*MEMORYCUTOVER {
|
||||
res = fmt.Sprintf("%d%s", sizeInBytes/MEGA, MEGASUFFIX)
|
||||
} else if sizeInBytes >= KILO*MEMORYCUTOVER {
|
||||
res = fmt.Sprintf("%d%s", sizeInBytes/KILO, KILOSUFFIX)
|
||||
} else {
|
||||
res = fmt.Sprintf("%d", sizeInBytes)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func MemsizeToBinaryString(size int64, unit string) string {
|
||||
sizeInBytes := MemsizeToBytesize(size, unit)
|
||||
|
||||
var res string
|
||||
if sizeInBytes >= PETABYTE*MEMORYCUTOVER {
|
||||
res = fmt.Sprintf("%d%s", sizeInBytes/PETABYTE, PETABYTESUFFIX)
|
||||
} else if sizeInBytes >= TERABYTE*MEMORYCUTOVER {
|
||||
res = fmt.Sprintf("%d%s", sizeInBytes/TERABYTE, TERABYTESUFFIX)
|
||||
} else if sizeInBytes >= GIGABYTE*MEMORYCUTOVER {
|
||||
res = fmt.Sprintf("%d%s", sizeInBytes/GIGABYTE, GIGABYTESUFFIX)
|
||||
} else if sizeInBytes >= MEGABYTE*MEMORYCUTOVER {
|
||||
res = fmt.Sprintf("%d%s", sizeInBytes/MEGABYTE, MEGABYTESUFFIX)
|
||||
} else if sizeInBytes >= KILOBYTE*MEMORYCUTOVER {
|
||||
res = fmt.Sprintf("%d%s", sizeInBytes/KILOBYTE, KILOBYTESUFFIX)
|
||||
} else {
|
||||
res = fmt.Sprintf("%d", sizeInBytes)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func MemsizeToMaxPodCount(size int64, unit string) int64 {
|
||||
sizeInBytes := MemsizeToBytesize(size, unit)
|
||||
|
||||
// Divide by minimum pod size
|
||||
return sizeInBytes / MINPODSIZE
|
||||
}
|
||||
|
||||
func FrequencyToHertzFrequency(size int64, unit string) int64 {
|
||||
u := strings.ToLower(unit)
|
||||
var sizeInBytes int64
|
||||
switch u {
|
||||
case "k":
|
||||
case "khz":
|
||||
sizeInBytes = size * KILO
|
||||
break
|
||||
case "m":
|
||||
case "mhz":
|
||||
sizeInBytes = size * MEGA
|
||||
break
|
||||
case "g":
|
||||
case "ghz":
|
||||
sizeInBytes = size * GIGA
|
||||
break
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
|
||||
return sizeInBytes
|
||||
}
|
||||
|
||||
func CpuFrequencyToString(size int64, unit string) string {
|
||||
var res string
|
||||
|
||||
hertz := FrequencyToHertzFrequency(size, unit)
|
||||
if hertz >= GIGA*10 {
|
||||
res = fmt.Sprintf("%d%s", hertz/GIGA, GIGASUFFIX)
|
||||
} else if hertz >= MEGA*FREQUENCYCUTOVER {
|
||||
res = fmt.Sprintf("%d%s", hertz/MEGA, MEGASUFFIX)
|
||||
} else if hertz >= KILO*FREQUENCYCUTOVER {
|
||||
res = fmt.Sprintf("%d%s", hertz/KILO, KILOSUFFIX)
|
||||
} else {
|
||||
res = fmt.Sprintf("%d", hertz)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func CpuFrequencyToCores(size int64, unit string) int64 {
|
||||
hertz := FrequencyToHertzFrequency(size, unit)
|
||||
// Assume 1G per Core
|
||||
cores := hertz / GIGA
|
||||
return cores
|
||||
}
|
||||
53
providers/vic/utils/units_test.go
Normal file
53
providers/vic/utils/units_test.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func TestMemoryConversion(t *testing.T) {
|
||||
memSize := MemsizeToBinaryString(2, "Gb")
|
||||
require.True(t, memSize == "2048Mi")
|
||||
|
||||
memSize = MemsizeToDecimalString(2, "Gb")
|
||||
require.True(t, memSize == "2147M")
|
||||
|
||||
memSize = MemsizeToBinaryString(2048, "Mb")
|
||||
require.True(t, memSize == "2048Mi")
|
||||
|
||||
memSize = MemsizeToDecimalString(2048, "Mb")
|
||||
require.True(t, memSize == "2147M")
|
||||
|
||||
memSize = MemsizeToBinaryString(2048*1024, "Kb")
|
||||
require.True(t, memSize == "2048Mi")
|
||||
|
||||
memSize = MemsizeToDecimalString(2048*1024, "Kb")
|
||||
require.True(t, memSize == "2147M")
|
||||
|
||||
memSize = MemsizeToBinaryString(MEMORYCUTOVER, "Gb")
|
||||
require.True(t, memSize == "100Gi")
|
||||
|
||||
memSize = MemsizeToBinaryString(MEMORYCUTOVER-1, "Gb")
|
||||
strings.HasSuffix(memSize, "Mi")
|
||||
require.True(t, strings.HasSuffix(memSize, "Mi"))
|
||||
|
||||
memSize = MemsizeToBinaryString((MEMORYCUTOVER-1)*1024, "Mb")
|
||||
require.True(t, strings.HasSuffix(memSize, "Mi"))
|
||||
|
||||
memSize = MemsizeToDecimalString(MEMORYCUTOVER*1000000000, "b")
|
||||
require.True(t, memSize == "100G")
|
||||
|
||||
memSize = MemsizeToDecimalString((MEMORYCUTOVER-1)*1000000000, "b")
|
||||
require.True(t, strings.HasSuffix(memSize, "M"))
|
||||
}
|
||||
|
||||
func TestFrequencyConversion(t *testing.T) {
|
||||
feq := CpuFrequencyToString(FREQUENCYCUTOVER, "Ghz")
|
||||
require.True(t, feq == "10G")
|
||||
feq = CpuFrequencyToString(FREQUENCYCUTOVER-1, "Ghz")
|
||||
require.True(t, feq == "9000M")
|
||||
feq = CpuFrequencyToString((FREQUENCYCUTOVER-1)*1000, "Mhz")
|
||||
require.True(t, feq == "9000M")
|
||||
}
|
||||
BIN
providers/vic/vic_kubelet_design.png
Normal file
BIN
providers/vic/vic_kubelet_design.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
450
providers/vic/vic_provider.go
Normal file
450
providers/vic/vic_provider.go
Normal file
@@ -0,0 +1,450 @@
|
||||
package vic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/kr/pretty"
|
||||
|
||||
vicerrors "github.com/vmware/vic/lib/apiservers/engine/errors"
|
||||
vicproxy "github.com/vmware/vic/lib/apiservers/engine/proxy"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/models"
|
||||
vicconst "github.com/vmware/vic/lib/constants"
|
||||
"github.com/vmware/vic/pkg/dio"
|
||||
viclog "github.com/vmware/vic/pkg/log"
|
||||
"github.com/vmware/vic/pkg/retry"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
|
||||
"github.com/virtual-kubelet/virtual-kubelet/manager"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/cache"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/operations"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/proxy"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/utils"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type VicProvider struct {
|
||||
resourceManager *manager.ResourceManager
|
||||
nodeName string
|
||||
os string
|
||||
podCount int
|
||||
config VicConfig
|
||||
podCache cache.PodCache
|
||||
|
||||
client *client.PortLayer
|
||||
imageStore proxy.ImageStore
|
||||
isolationProxy proxy.IsolationProxy
|
||||
systemProxy vicproxy.VicSystemProxy
|
||||
}
|
||||
|
||||
const (
|
||||
// Name of filename used in the endpoint vm
|
||||
LogFilename = "virtual-kubelet"
|
||||
|
||||
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
||||
// message passed to Debug, Info, ...
|
||||
PanicLevel uint8 = iota
|
||||
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
|
||||
// logging level is set to Panic.
|
||||
FatalLevel
|
||||
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||
// Commonly used for hooks to send errors to an error tracking service.
|
||||
ErrorLevel
|
||||
// WarnLevel level. Non-critical entries that deserve eyes.
|
||||
WarnLevel
|
||||
// InfoLevel level. General operational entries about what's going on inside the
|
||||
// application.
|
||||
InfoLevel
|
||||
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||
DebugLevel
|
||||
)
|
||||
|
||||
var (
|
||||
portlayerUp chan struct{}
|
||||
)
|
||||
|
||||
func NewVicProvider(configFile string, rm *manager.ResourceManager, nodeName, operatingSystem string) (*VicProvider, error) {
|
||||
initLogger()
|
||||
|
||||
op := trace.NewOperation(context.Background(), "VicProvider creation: config - %s", configFile)
|
||||
defer trace.End(trace.Begin("", op))
|
||||
|
||||
config := NewVicConfig(op, configFile)
|
||||
op.Infof("Provider config = %#v", config)
|
||||
|
||||
plClient := vicproxy.NewPortLayerClient(config.PortlayerAddr)
|
||||
|
||||
op.Infof("** Wait for VCH servers to start")
|
||||
if !waitForVCH(op, plClient, config.PersonaAddr) {
|
||||
msg := "VicProvider timed out waiting for VCH's persona and portlayer servers"
|
||||
op.Errorf(msg)
|
||||
return nil, fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
i, err := proxy.NewImageStore(plClient, config.PersonaAddr, config.PortlayerAddr)
|
||||
if err != nil {
|
||||
msg := "Couldn't initialize the image store"
|
||||
op.Error(msg)
|
||||
return nil, fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
op.Infof("** creating proxy")
|
||||
p := VicProvider{
|
||||
config: config,
|
||||
nodeName: nodeName,
|
||||
os: operatingSystem,
|
||||
podCache: cache.NewVicPodCache(),
|
||||
client: plClient,
|
||||
resourceManager: rm,
|
||||
systemProxy: vicproxy.NewSystemProxy(plClient),
|
||||
}
|
||||
|
||||
p.imageStore = i
|
||||
p.isolationProxy = proxy.NewIsolationProxy(plClient, config.PortlayerAddr, config.HostUUID, i, p.podCache)
|
||||
op.Infof("** ready to go")
|
||||
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func waitForVCH(op trace.Operation, plClient *client.PortLayer, personaAddr string) bool {
|
||||
backoffConf := retry.NewBackoffConfig()
|
||||
backoffConf.MaxInterval = 2 * time.Second
|
||||
backoffConf.InitialInterval = 500 * time.Millisecond
|
||||
|
||||
// Wait for portlayer to start up
|
||||
systemProxy := vicproxy.NewSystemProxy(plClient)
|
||||
|
||||
opWaitForPortlayer := func() error {
|
||||
op.Infof("** Checking portlayer server is running")
|
||||
if !systemProxy.PingPortlayer(context.Background()) {
|
||||
return vicerrors.ServerNotReadyError{Name: "Portlayer"}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := retry.DoWithConfig(opWaitForPortlayer, vicerrors.IsServerNotReady, backoffConf); err != nil {
|
||||
op.Errorf("Wait for portlayer to be ready failed")
|
||||
return false
|
||||
}
|
||||
|
||||
// Wait for persona to start up
|
||||
dockerClient := NewVicDockerClient(personaAddr)
|
||||
opWaitForPersona := func() error {
|
||||
op.Infof("** Checking persona server is running")
|
||||
if err := dockerClient.Ping(op); err != nil {
|
||||
return vicerrors.ServerNotReadyError{Name: "Persona"}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := retry.DoWithConfig(opWaitForPersona, vicerrors.IsServerNotReady, backoffConf); err != nil {
|
||||
op.Errorf("Wait for VIC docker server to be ready failed")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func initLogger() {
|
||||
var logPath string
|
||||
if LocalInstance() {
|
||||
logPath = path.Join("", ".", LogFilename+".log")
|
||||
} else {
|
||||
logPath = path.Join("", vicconst.DefaultLogDir, LogFilename+".log")
|
||||
}
|
||||
|
||||
os.MkdirAll(vicconst.DefaultLogDir, 0755)
|
||||
// #nosec: Expect file permissions to be 0600 or less
|
||||
f, err := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND|os.O_SYNC|syscall.O_NOCTTY, 0644)
|
||||
if err != nil {
|
||||
detail := fmt.Sprintf("failed to open file for VIC's virtual kubelet provider log: %s", err)
|
||||
log.Error(detail)
|
||||
}
|
||||
|
||||
// use multi-writer so it goes to both screen and session log
|
||||
writer := dio.MultiWriter(f, os.Stdout)
|
||||
|
||||
logcfg := viclog.NewLoggingConfig()
|
||||
|
||||
logcfg.SetLogLevel(DebugLevel)
|
||||
trace.SetLogLevel(DebugLevel)
|
||||
trace.Logger.Out = writer
|
||||
|
||||
err = viclog.Init(logcfg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
trace.InitLogger(logcfg)
|
||||
}
|
||||
|
||||
// CreatePod takes a Kubernetes Pod and deploys it within the provider.
|
||||
func (v *VicProvider) CreatePod(pod *v1.Pod) error {
|
||||
op := trace.NewOperation(context.Background(), "CreatePod - %s", pod.Name)
|
||||
defer trace.End(trace.Begin(pod.Name, op))
|
||||
|
||||
op.Debugf("Creating %s's pod = %# +v", pod.Name, pretty.Formatter(pod))
|
||||
|
||||
pc, err := operations.NewPodCreator(v.client, v.imageStore, v.isolationProxy, v.podCache, v.config.PersonaAddr, v.config.PortlayerAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = pc.CreatePod(op, pod, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//v.resourceManager.AddPod()
|
||||
|
||||
op.Debugf("** pod created ok")
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdatePod takes a Kubernetes Pod and updates it within the provider.
|
||||
func (v *VicProvider) UpdatePod(pod *v1.Pod) error {
|
||||
op := trace.NewOperation(context.Background(), "UpdatePod - %s", pod.Name)
|
||||
defer trace.End(trace.Begin(pod.Name, op))
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeletePod takes a Kubernetes Pod and deletes it from the provider.
|
||||
func (v *VicProvider) DeletePod(pod *v1.Pod) error {
|
||||
op := trace.NewOperation(context.Background(), "DeletePod - %s", pod.Name)
|
||||
defer trace.End(trace.Begin(pod.Name, op))
|
||||
|
||||
op.Infof("Deleting %s's pod spec = %#v", pod.Name, pod.Spec)
|
||||
|
||||
pd, err := operations.NewPodDeleter(v.client, v.isolationProxy, v.podCache, v.config.PersonaAddr, v.config.PortlayerAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = pd.DeletePod(op, pod)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// GetPod retrieves a pod by name from the provider (can be cached).
|
||||
func (v *VicProvider) GetPod(namespace, name string) (*v1.Pod, error) {
|
||||
op := trace.NewOperation(context.Background(), "GetPod - %s", name)
|
||||
defer trace.End(trace.Begin(name, op))
|
||||
|
||||
// Look for the pod in our cache of running pods
|
||||
vp, err := v.podCache.Get(op, namespace, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return vp.Pod, nil
|
||||
}
|
||||
|
||||
// GetContainerLogs retrieves the logs of a container by name from the provider.
|
||||
func (v *VicProvider) GetContainerLogs(namespace, podName, containerName string, tail int) (string, error) {
|
||||
op := trace.NewOperation(context.Background(), "GetContainerLogs - pod[%s], container[%s]", podName, containerName)
|
||||
defer trace.End(trace.Begin("", op))
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// GetPodStatus retrieves the status of a pod by name from the provider.
|
||||
// This function needs to return a status or the reconcile loop will stop running.
|
||||
func (v *VicProvider) GetPodStatus(namespace, name string) (*v1.PodStatus, error) {
|
||||
op := trace.NewOperation(context.Background(), "GetPodStatus - pod[%s], namespace", name, namespace)
|
||||
defer trace.End(trace.Begin("GetPodStatus", op))
|
||||
|
||||
now := metav1.NewTime(time.Now())
|
||||
|
||||
status := &v1.PodStatus{
|
||||
Phase: v1.PodRunning,
|
||||
HostIP: "1.2.3.4",
|
||||
PodIP: "5.6.7.8",
|
||||
StartTime: &now,
|
||||
Conditions: []v1.PodCondition{
|
||||
{
|
||||
Type: v1.PodInitialized,
|
||||
Status: v1.ConditionTrue,
|
||||
},
|
||||
{
|
||||
Type: v1.PodReady,
|
||||
Status: v1.ConditionTrue,
|
||||
},
|
||||
{
|
||||
Type: v1.PodScheduled,
|
||||
Status: v1.ConditionTrue,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
pod, err := v.GetPod(namespace, name)
|
||||
if err != nil {
|
||||
return status, err
|
||||
}
|
||||
|
||||
for _, container := range pod.Spec.Containers {
|
||||
status.ContainerStatuses = append(status.ContainerStatuses, v1.ContainerStatus{
|
||||
Name: container.Name,
|
||||
Image: container.Image,
|
||||
Ready: true,
|
||||
RestartCount: 0,
|
||||
State: v1.ContainerState{
|
||||
Running: &v1.ContainerStateRunning{
|
||||
StartedAt: now,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return status, nil
|
||||
}
|
||||
|
||||
// GetPods retrieves a list of all pods running on the provider (can be cached).
|
||||
func (v *VicProvider) GetPods() ([]*v1.Pod, error) {
|
||||
op := trace.NewOperation(context.Background(), "GetPods")
|
||||
defer trace.End(trace.Begin("GetPods", op))
|
||||
|
||||
vps := v.podCache.GetAll(op)
|
||||
allPods := make([]*v1.Pod, 0)
|
||||
for _, vp := range vps {
|
||||
allPods = append(allPods, vp.Pod)
|
||||
}
|
||||
|
||||
return allPods, nil
|
||||
}
|
||||
|
||||
// Capacity returns a resource list with the capacity constraints of the provider.
|
||||
func (v *VicProvider) Capacity() v1.ResourceList {
|
||||
op := trace.NewOperation(context.Background(), "VicProvider.Capacity")
|
||||
defer trace.End(trace.Begin("", op))
|
||||
|
||||
if v.systemProxy == nil {
|
||||
err := NilProxy("VicProvider.Capacity", "SystemProxy")
|
||||
op.Error(err)
|
||||
return v1.ResourceList{}
|
||||
}
|
||||
info, err := v.systemProxy.VCHInfo(context.Background())
|
||||
if err != nil {
|
||||
op.Errorf("VicProvider.Capacity failed to get VCHInfo: %s", err.Error())
|
||||
}
|
||||
op.Infof("VCH Config: %# +v\n", pretty.Formatter(info))
|
||||
|
||||
return KubeResourcesFromVchInfo(op, info)
|
||||
}
|
||||
|
||||
// NodeConditions returns a list of conditions (Ready, OutOfDisk, etc), which is polled periodically to update the node status
|
||||
// within Kubernetes.
|
||||
func (v *VicProvider) NodeConditions() []v1.NodeCondition {
|
||||
// TODO: Make these dynamic and augment with custom ACI specific conditions of interest
|
||||
return []v1.NodeCondition{
|
||||
{
|
||||
Type: "Ready",
|
||||
Status: v1.ConditionTrue,
|
||||
LastHeartbeatTime: metav1.Now(),
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: "KubeletReady",
|
||||
Message: "kubelet is ready.",
|
||||
},
|
||||
{
|
||||
Type: "OutOfDisk",
|
||||
Status: v1.ConditionFalse,
|
||||
LastHeartbeatTime: metav1.Now(),
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: "KubeletHasSufficientDisk",
|
||||
Message: "kubelet has sufficient disk space available",
|
||||
},
|
||||
{
|
||||
Type: "MemoryPressure",
|
||||
Status: v1.ConditionFalse,
|
||||
LastHeartbeatTime: metav1.Now(),
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: "KubeletHasSufficientMemory",
|
||||
Message: "kubelet has sufficient memory available",
|
||||
},
|
||||
{
|
||||
Type: "DiskPressure",
|
||||
Status: v1.ConditionFalse,
|
||||
LastHeartbeatTime: metav1.Now(),
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: "KubeletHasNoDiskPressure",
|
||||
Message: "kubelet has no disk pressure",
|
||||
},
|
||||
{
|
||||
Type: "NetworkUnavailable",
|
||||
Status: v1.ConditionFalse,
|
||||
LastHeartbeatTime: metav1.Now(),
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: "RouteCreated",
|
||||
Message: "RouteController created a route",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NodeAddresses returns a list of addresses for the node status
|
||||
// within Kubernetes.
|
||||
func (v *VicProvider) NodeAddresses() []v1.NodeAddress {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NodeDaemonEndpoints returns NodeDaemonEndpoints for the node status
|
||||
// within Kubernetes.
|
||||
func (v *VicProvider) NodeDaemonEndpoints() *v1.NodeDaemonEndpoints {
|
||||
return &v1.NodeDaemonEndpoints{
|
||||
KubeletEndpoint: v1.DaemonEndpoint{
|
||||
Port: 80,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// OperatingSystem returns the operating system the provider is for.
|
||||
func (v *VicProvider) OperatingSystem() string {
|
||||
return v.os
|
||||
}
|
||||
|
||||
//------------------------------------
|
||||
// Utility Functions
|
||||
//------------------------------------
|
||||
|
||||
// KubeResourcesFromVchInfo returns a K8s node resource list, given the VCHInfo
|
||||
func KubeResourcesFromVchInfo(op trace.Operation, info *models.VCHInfo) v1.ResourceList {
|
||||
nr := make(v1.ResourceList)
|
||||
|
||||
if info != nil {
|
||||
cores := utils.CpuFrequencyToCores(info.CPUMhz, "Mhz")
|
||||
// translate CPU resources. K8s wants cores. We have virtual cores based on mhz.
|
||||
cpuQ := resource.Quantity{}
|
||||
cpuQ.Set(cores)
|
||||
nr[v1.ResourceCPU] = cpuQ
|
||||
|
||||
memQstr := utils.MemsizeToBinaryString(info.Memory, "Mb")
|
||||
// translate memory resources. K8s wants bytes.
|
||||
memQ, err := resource.ParseQuantity(memQstr)
|
||||
if err == nil {
|
||||
nr[v1.ResourceMemory] = memQ
|
||||
} else {
|
||||
op.Errorf("KubeResourcesFromVchInfo, cannot parse MEM quantity: %s, err: %s", memQstr, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Estimate the available pod count, based on memory
|
||||
podCount := utils.MemsizeToMaxPodCount(info.Memory, "Mb")
|
||||
|
||||
containerCountQ := resource.Quantity{}
|
||||
containerCountQ.Set(podCount)
|
||||
nr[v1.ResourcePods] = containerCountQ
|
||||
|
||||
op.Infof("Capacity Resource Config: %# +v\n", pretty.Formatter(nr))
|
||||
return nr
|
||||
}
|
||||
|
||||
func NilProxy(caller, proxyName string) error {
|
||||
|
||||
return fmt.Errorf("%s: %s not valid", caller, proxyName)
|
||||
}
|
||||
2
vendor/github.com/asaskevich/govalidator/.github/ISSUE_TEMPLATE.md
generated
vendored
Normal file
2
vendor/github.com/asaskevich/govalidator/.github/ISSUE_TEMPLATE.md
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<!-- Love govalidator? Please consider supporting our collective:
|
||||
👉 https://opencollective.com/govalidator/donate -->
|
||||
14
vendor/github.com/asaskevich/govalidator/.travis.yml
generated
vendored
Normal file
14
vendor/github.com/asaskevich/govalidator/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- tip
|
||||
|
||||
notifications:
|
||||
email:
|
||||
- bwatas@gmail.com
|
||||
63
vendor/github.com/asaskevich/govalidator/CONTRIBUTING.md
generated
vendored
Normal file
63
vendor/github.com/asaskevich/govalidator/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
#### Support
|
||||
If you do have a contribution to the package, feel free to create a Pull Request or an Issue.
|
||||
|
||||
#### What to contribute
|
||||
If you don't know what to do, there are some features and functions that need to be done
|
||||
|
||||
- [ ] Refactor code
|
||||
- [ ] Edit docs and [README](https://github.com/asaskevich/govalidator/README.md): spellcheck, grammar and typo check
|
||||
- [ ] Create actual list of contributors and projects that currently using this package
|
||||
- [ ] Resolve [issues and bugs](https://github.com/asaskevich/govalidator/issues)
|
||||
- [ ] Update actual [list of functions](https://github.com/asaskevich/govalidator#list-of-functions)
|
||||
- [ ] Update [list of validators](https://github.com/asaskevich/govalidator#validatestruct-2) that available for `ValidateStruct` and add new
|
||||
- [ ] Implement new validators: `IsFQDN`, `IsIMEI`, `IsPostalCode`, `IsISIN`, `IsISRC` etc
|
||||
- [ ] Implement [validation by maps](https://github.com/asaskevich/govalidator/issues/224)
|
||||
- [ ] Implement fuzzing testing
|
||||
- [ ] Implement some struct/map/array utilities
|
||||
- [ ] Implement map/array validation
|
||||
- [ ] Implement benchmarking
|
||||
- [ ] Implement batch of examples
|
||||
- [ ] Look at forks for new features and fixes
|
||||
|
||||
#### Advice
|
||||
Feel free to create what you want, but keep in mind when you implement new features:
|
||||
- Code must be clear and readable, names of variables/constants clearly describes what they are doing
|
||||
- Public functions must be documented and described in source file and added to README.md to the list of available functions
|
||||
- There are must be unit-tests for any new functions and improvements
|
||||
|
||||
## Financial contributions
|
||||
|
||||
We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/govalidator).
|
||||
Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed.
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
|
||||
### Contributors
|
||||
|
||||
Thank you to all the people who have already contributed to govalidator!
|
||||
<a href="graphs/contributors"><img src="https://opencollective.com/govalidator/contributors.svg?width=890" /></a>
|
||||
|
||||
|
||||
### Backers
|
||||
|
||||
Thank you to all our backers! [[Become a backer](https://opencollective.com/govalidator#backer)]
|
||||
|
||||
<a href="https://opencollective.com/govalidator#backers" target="_blank"><img src="https://opencollective.com/govalidator/backers.svg?width=890"></a>
|
||||
|
||||
|
||||
### Sponsors
|
||||
|
||||
Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/govalidator#sponsor))
|
||||
|
||||
<a href="https://opencollective.com/govalidator/sponsor/0/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/1/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/2/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/3/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/4/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/5/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/6/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/7/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/8/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/9/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/9/avatar.svg"></a>
|
||||
21
vendor/github.com/asaskevich/govalidator/LICENSE
generated
vendored
Normal file
21
vendor/github.com/asaskevich/govalidator/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Alex Saskevich
|
||||
|
||||
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.
|
||||
490
vendor/github.com/asaskevich/govalidator/README.md
generated
vendored
Normal file
490
vendor/github.com/asaskevich/govalidator/README.md
generated
vendored
Normal file
@@ -0,0 +1,490 @@
|
||||
govalidator
|
||||
===========
|
||||
[](https://gitter.im/asaskevich/govalidator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [](https://godoc.org/github.com/asaskevich/govalidator) [](https://coveralls.io/r/asaskevich/govalidator?branch=master) [](https://app.wercker.com/project/bykey/1ec990b09ea86c910d5f08b0e02c6043)
|
||||
[](https://travis-ci.org/asaskevich/govalidator) [](https://goreportcard.com/report/github.com/asaskevich/govalidator) [](http://go-search.org/view?id=github.com%2Fasaskevich%2Fgovalidator) [](#backers) [](#sponsors)
|
||||
|
||||
A package of validators and sanitizers for strings, structs and collections. Based on [validator.js](https://github.com/chriso/validator.js).
|
||||
|
||||
#### Installation
|
||||
Make sure that Go is installed on your computer.
|
||||
Type the following command in your terminal:
|
||||
|
||||
go get github.com/asaskevich/govalidator
|
||||
|
||||
or you can get specified release of the package with `gopkg.in`:
|
||||
|
||||
go get gopkg.in/asaskevich/govalidator.v4
|
||||
|
||||
After it the package is ready to use.
|
||||
|
||||
|
||||
#### Import package in your project
|
||||
Add following line in your `*.go` file:
|
||||
```go
|
||||
import "github.com/asaskevich/govalidator"
|
||||
```
|
||||
If you are unhappy to use long `govalidator`, you can do something like this:
|
||||
```go
|
||||
import (
|
||||
valid "github.com/asaskevich/govalidator"
|
||||
)
|
||||
```
|
||||
|
||||
#### Activate behavior to require all fields have a validation tag by default
|
||||
`SetFieldsRequiredByDefault` causes validation to fail when struct fields do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`). A good place to activate this is a package init function or the main() function.
|
||||
|
||||
```go
|
||||
import "github.com/asaskevich/govalidator"
|
||||
|
||||
func init() {
|
||||
govalidator.SetFieldsRequiredByDefault(true)
|
||||
}
|
||||
```
|
||||
|
||||
Here's some code to explain it:
|
||||
```go
|
||||
// this struct definition will fail govalidator.ValidateStruct() (and the field values do not matter):
|
||||
type exampleStruct struct {
|
||||
Name string ``
|
||||
Email string `valid:"email"`
|
||||
}
|
||||
|
||||
// this, however, will only fail when Email is empty or an invalid email address:
|
||||
type exampleStruct2 struct {
|
||||
Name string `valid:"-"`
|
||||
Email string `valid:"email"`
|
||||
}
|
||||
|
||||
// lastly, this will only fail when Email is an invalid email address but not when it's empty:
|
||||
type exampleStruct2 struct {
|
||||
Name string `valid:"-"`
|
||||
Email string `valid:"email,optional"`
|
||||
}
|
||||
```
|
||||
|
||||
#### Recent breaking changes (see [#123](https://github.com/asaskevich/govalidator/pull/123))
|
||||
##### Custom validator function signature
|
||||
A context was added as the second parameter, for structs this is the object being validated – this makes dependent validation possible.
|
||||
```go
|
||||
import "github.com/asaskevich/govalidator"
|
||||
|
||||
// old signature
|
||||
func(i interface{}) bool
|
||||
|
||||
// new signature
|
||||
func(i interface{}, o interface{}) bool
|
||||
```
|
||||
|
||||
##### Adding a custom validator
|
||||
This was changed to prevent data races when accessing custom validators.
|
||||
```go
|
||||
import "github.com/asaskevich/govalidator"
|
||||
|
||||
// before
|
||||
govalidator.CustomTypeTagMap["customByteArrayValidator"] = CustomTypeValidator(func(i interface{}, o interface{}) bool {
|
||||
// ...
|
||||
})
|
||||
|
||||
// after
|
||||
govalidator.CustomTypeTagMap.Set("customByteArrayValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool {
|
||||
// ...
|
||||
}))
|
||||
```
|
||||
|
||||
#### List of functions:
|
||||
```go
|
||||
func Abs(value float64) float64
|
||||
func BlackList(str, chars string) string
|
||||
func ByteLength(str string, params ...string) bool
|
||||
func CamelCaseToUnderscore(str string) string
|
||||
func Contains(str, substring string) bool
|
||||
func Count(array []interface{}, iterator ConditionIterator) int
|
||||
func Each(array []interface{}, iterator Iterator)
|
||||
func ErrorByField(e error, field string) string
|
||||
func ErrorsByField(e error) map[string]string
|
||||
func Filter(array []interface{}, iterator ConditionIterator) []interface{}
|
||||
func Find(array []interface{}, iterator ConditionIterator) interface{}
|
||||
func GetLine(s string, index int) (string, error)
|
||||
func GetLines(s string) []string
|
||||
func InRange(value, left, right float64) bool
|
||||
func IsASCII(str string) bool
|
||||
func IsAlpha(str string) bool
|
||||
func IsAlphanumeric(str string) bool
|
||||
func IsBase64(str string) bool
|
||||
func IsByteLength(str string, min, max int) bool
|
||||
func IsCIDR(str string) bool
|
||||
func IsCreditCard(str string) bool
|
||||
func IsDNSName(str string) bool
|
||||
func IsDataURI(str string) bool
|
||||
func IsDialString(str string) bool
|
||||
func IsDivisibleBy(str, num string) bool
|
||||
func IsEmail(str string) bool
|
||||
func IsFilePath(str string) (bool, int)
|
||||
func IsFloat(str string) bool
|
||||
func IsFullWidth(str string) bool
|
||||
func IsHalfWidth(str string) bool
|
||||
func IsHexadecimal(str string) bool
|
||||
func IsHexcolor(str string) bool
|
||||
func IsHost(str string) bool
|
||||
func IsIP(str string) bool
|
||||
func IsIPv4(str string) bool
|
||||
func IsIPv6(str string) bool
|
||||
func IsISBN(str string, version int) bool
|
||||
func IsISBN10(str string) bool
|
||||
func IsISBN13(str string) bool
|
||||
func IsISO3166Alpha2(str string) bool
|
||||
func IsISO3166Alpha3(str string) bool
|
||||
func IsISO693Alpha2(str string) bool
|
||||
func IsISO693Alpha3b(str string) bool
|
||||
func IsISO4217(str string) bool
|
||||
func IsIn(str string, params ...string) bool
|
||||
func IsInt(str string) bool
|
||||
func IsJSON(str string) bool
|
||||
func IsLatitude(str string) bool
|
||||
func IsLongitude(str string) bool
|
||||
func IsLowerCase(str string) bool
|
||||
func IsMAC(str string) bool
|
||||
func IsMongoID(str string) bool
|
||||
func IsMultibyte(str string) bool
|
||||
func IsNatural(value float64) bool
|
||||
func IsNegative(value float64) bool
|
||||
func IsNonNegative(value float64) bool
|
||||
func IsNonPositive(value float64) bool
|
||||
func IsNull(str string) bool
|
||||
func IsNumeric(str string) bool
|
||||
func IsPort(str string) bool
|
||||
func IsPositive(value float64) bool
|
||||
func IsPrintableASCII(str string) bool
|
||||
func IsRFC3339(str string) bool
|
||||
func IsRFC3339WithoutZone(str string) bool
|
||||
func IsRGBcolor(str string) bool
|
||||
func IsRequestURI(rawurl string) bool
|
||||
func IsRequestURL(rawurl string) bool
|
||||
func IsSSN(str string) bool
|
||||
func IsSemver(str string) bool
|
||||
func IsTime(str string, format string) bool
|
||||
func IsURL(str string) bool
|
||||
func IsUTFDigit(str string) bool
|
||||
func IsUTFLetter(str string) bool
|
||||
func IsUTFLetterNumeric(str string) bool
|
||||
func IsUTFNumeric(str string) bool
|
||||
func IsUUID(str string) bool
|
||||
func IsUUIDv3(str string) bool
|
||||
func IsUUIDv4(str string) bool
|
||||
func IsUUIDv5(str string) bool
|
||||
func IsUpperCase(str string) bool
|
||||
func IsVariableWidth(str string) bool
|
||||
func IsWhole(value float64) bool
|
||||
func LeftTrim(str, chars string) string
|
||||
func Map(array []interface{}, iterator ResultIterator) []interface{}
|
||||
func Matches(str, pattern string) bool
|
||||
func NormalizeEmail(str string) (string, error)
|
||||
func PadBoth(str string, padStr string, padLen int) string
|
||||
func PadLeft(str string, padStr string, padLen int) string
|
||||
func PadRight(str string, padStr string, padLen int) string
|
||||
func Range(str string, params ...string) bool
|
||||
func RemoveTags(s string) string
|
||||
func ReplacePattern(str, pattern, replace string) string
|
||||
func Reverse(s string) string
|
||||
func RightTrim(str, chars string) string
|
||||
func RuneLength(str string, params ...string) bool
|
||||
func SafeFileName(str string) string
|
||||
func SetFieldsRequiredByDefault(value bool)
|
||||
func Sign(value float64) float64
|
||||
func StringLength(str string, params ...string) bool
|
||||
func StringMatches(s string, params ...string) bool
|
||||
func StripLow(str string, keepNewLines bool) string
|
||||
func ToBoolean(str string) (bool, error)
|
||||
func ToFloat(str string) (float64, error)
|
||||
func ToInt(str string) (int64, error)
|
||||
func ToJSON(obj interface{}) (string, error)
|
||||
func ToString(obj interface{}) string
|
||||
func Trim(str, chars string) string
|
||||
func Truncate(str string, length int, ending string) string
|
||||
func UnderscoreToCamelCase(s string) string
|
||||
func ValidateStruct(s interface{}) (bool, error)
|
||||
func WhiteList(str, chars string) string
|
||||
type ConditionIterator
|
||||
type CustomTypeValidator
|
||||
type Error
|
||||
func (e Error) Error() string
|
||||
type Errors
|
||||
func (es Errors) Error() string
|
||||
func (es Errors) Errors() []error
|
||||
type ISO3166Entry
|
||||
type Iterator
|
||||
type ParamValidator
|
||||
type ResultIterator
|
||||
type UnsupportedTypeError
|
||||
func (e *UnsupportedTypeError) Error() string
|
||||
type Validator
|
||||
```
|
||||
|
||||
#### Examples
|
||||
###### IsURL
|
||||
```go
|
||||
println(govalidator.IsURL(`http://user@pass:domain.com/path/page`))
|
||||
```
|
||||
###### ToString
|
||||
```go
|
||||
type User struct {
|
||||
FirstName string
|
||||
LastName string
|
||||
}
|
||||
|
||||
str := govalidator.ToString(&User{"John", "Juan"})
|
||||
println(str)
|
||||
```
|
||||
###### Each, Map, Filter, Count for slices
|
||||
Each iterates over the slice/array and calls Iterator for every item
|
||||
```go
|
||||
data := []interface{}{1, 2, 3, 4, 5}
|
||||
var fn govalidator.Iterator = func(value interface{}, index int) {
|
||||
println(value.(int))
|
||||
}
|
||||
govalidator.Each(data, fn)
|
||||
```
|
||||
```go
|
||||
data := []interface{}{1, 2, 3, 4, 5}
|
||||
var fn govalidator.ResultIterator = func(value interface{}, index int) interface{} {
|
||||
return value.(int) * 3
|
||||
}
|
||||
_ = govalidator.Map(data, fn) // result = []interface{}{1, 6, 9, 12, 15}
|
||||
```
|
||||
```go
|
||||
data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
var fn govalidator.ConditionIterator = func(value interface{}, index int) bool {
|
||||
return value.(int)%2 == 0
|
||||
}
|
||||
_ = govalidator.Filter(data, fn) // result = []interface{}{2, 4, 6, 8, 10}
|
||||
_ = govalidator.Count(data, fn) // result = 5
|
||||
```
|
||||
###### ValidateStruct [#2](https://github.com/asaskevich/govalidator/pull/2)
|
||||
If you want to validate structs, you can use tag `valid` for any field in your structure. All validators used with this field in one tag are separated by comma. If you want to skip validation, place `-` in your tag. If you need a validator that is not on the list below, you can add it like this:
|
||||
```go
|
||||
govalidator.TagMap["duck"] = govalidator.Validator(func(str string) bool {
|
||||
return str == "duck"
|
||||
})
|
||||
```
|
||||
For completely custom validators (interface-based), see below.
|
||||
|
||||
Here is a list of available validators for struct fields (validator - used function):
|
||||
```go
|
||||
"email": IsEmail,
|
||||
"url": IsURL,
|
||||
"dialstring": IsDialString,
|
||||
"requrl": IsRequestURL,
|
||||
"requri": IsRequestURI,
|
||||
"alpha": IsAlpha,
|
||||
"utfletter": IsUTFLetter,
|
||||
"alphanum": IsAlphanumeric,
|
||||
"utfletternum": IsUTFLetterNumeric,
|
||||
"numeric": IsNumeric,
|
||||
"utfnumeric": IsUTFNumeric,
|
||||
"utfdigit": IsUTFDigit,
|
||||
"hexadecimal": IsHexadecimal,
|
||||
"hexcolor": IsHexcolor,
|
||||
"rgbcolor": IsRGBcolor,
|
||||
"lowercase": IsLowerCase,
|
||||
"uppercase": IsUpperCase,
|
||||
"int": IsInt,
|
||||
"float": IsFloat,
|
||||
"null": IsNull,
|
||||
"uuid": IsUUID,
|
||||
"uuidv3": IsUUIDv3,
|
||||
"uuidv4": IsUUIDv4,
|
||||
"uuidv5": IsUUIDv5,
|
||||
"creditcard": IsCreditCard,
|
||||
"isbn10": IsISBN10,
|
||||
"isbn13": IsISBN13,
|
||||
"json": IsJSON,
|
||||
"multibyte": IsMultibyte,
|
||||
"ascii": IsASCII,
|
||||
"printableascii": IsPrintableASCII,
|
||||
"fullwidth": IsFullWidth,
|
||||
"halfwidth": IsHalfWidth,
|
||||
"variablewidth": IsVariableWidth,
|
||||
"base64": IsBase64,
|
||||
"datauri": IsDataURI,
|
||||
"ip": IsIP,
|
||||
"port": IsPort,
|
||||
"ipv4": IsIPv4,
|
||||
"ipv6": IsIPv6,
|
||||
"dns": IsDNSName,
|
||||
"host": IsHost,
|
||||
"mac": IsMAC,
|
||||
"latitude": IsLatitude,
|
||||
"longitude": IsLongitude,
|
||||
"ssn": IsSSN,
|
||||
"semver": IsSemver,
|
||||
"rfc3339": IsRFC3339,
|
||||
"rfc3339WithoutZone": IsRFC3339WithoutZone,
|
||||
"ISO3166Alpha2": IsISO3166Alpha2,
|
||||
"ISO3166Alpha3": IsISO3166Alpha3,
|
||||
```
|
||||
Validators with parameters
|
||||
|
||||
```go
|
||||
"range(min|max)": Range,
|
||||
"length(min|max)": ByteLength,
|
||||
"runelength(min|max)": RuneLength,
|
||||
"matches(pattern)": StringMatches,
|
||||
"in(string1|string2|...|stringN)": IsIn,
|
||||
```
|
||||
|
||||
And here is small example of usage:
|
||||
```go
|
||||
type Post struct {
|
||||
Title string `valid:"alphanum,required"`
|
||||
Message string `valid:"duck,ascii"`
|
||||
AuthorIP string `valid:"ipv4"`
|
||||
Date string `valid:"-"`
|
||||
}
|
||||
post := &Post{
|
||||
Title: "My Example Post",
|
||||
Message: "duck",
|
||||
AuthorIP: "123.234.54.3",
|
||||
}
|
||||
|
||||
// Add your own struct validation tags
|
||||
govalidator.TagMap["duck"] = govalidator.Validator(func(str string) bool {
|
||||
return str == "duck"
|
||||
})
|
||||
|
||||
result, err := govalidator.ValidateStruct(post)
|
||||
if err != nil {
|
||||
println("error: " + err.Error())
|
||||
}
|
||||
println(result)
|
||||
```
|
||||
###### WhiteList
|
||||
```go
|
||||
// Remove all characters from string ignoring characters between "a" and "z"
|
||||
println(govalidator.WhiteList("a3a43a5a4a3a2a23a4a5a4a3a4", "a-z") == "aaaaaaaaaaaa")
|
||||
```
|
||||
|
||||
###### Custom validation functions
|
||||
Custom validation using your own domain specific validators is also available - here's an example of how to use it:
|
||||
```go
|
||||
import "github.com/asaskevich/govalidator"
|
||||
|
||||
type CustomByteArray [6]byte // custom types are supported and can be validated
|
||||
|
||||
type StructWithCustomByteArray struct {
|
||||
ID CustomByteArray `valid:"customByteArrayValidator,customMinLengthValidator"` // multiple custom validators are possible as well and will be evaluated in sequence
|
||||
Email string `valid:"email"`
|
||||
CustomMinLength int `valid:"-"`
|
||||
}
|
||||
|
||||
govalidator.CustomTypeTagMap.Set("customByteArrayValidator", CustomTypeValidator(func(i interface{}, context interface{}) bool {
|
||||
switch v := context.(type) { // you can type switch on the context interface being validated
|
||||
case StructWithCustomByteArray:
|
||||
// you can check and validate against some other field in the context,
|
||||
// return early or not validate against the context at all – your choice
|
||||
case SomeOtherType:
|
||||
// ...
|
||||
default:
|
||||
// expecting some other type? Throw/panic here or continue
|
||||
}
|
||||
|
||||
switch v := i.(type) { // type switch on the struct field being validated
|
||||
case CustomByteArray:
|
||||
for _, e := range v { // this validator checks that the byte array is not empty, i.e. not all zeroes
|
||||
if e != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}))
|
||||
govalidator.CustomTypeTagMap.Set("customMinLengthValidator", CustomTypeValidator(func(i interface{}, context interface{}) bool {
|
||||
switch v := context.(type) { // this validates a field against the value in another field, i.e. dependent validation
|
||||
case StructWithCustomByteArray:
|
||||
return len(v.ID) >= v.CustomMinLength
|
||||
}
|
||||
return false
|
||||
}))
|
||||
```
|
||||
|
||||
###### Custom error messages
|
||||
Custom error messages are supported via annotations by adding the `~` separator - here's an example of how to use it:
|
||||
```go
|
||||
type Ticket struct {
|
||||
Id int64 `json:"id"`
|
||||
FirstName string `json:"firstname" valid:"required~First name is blank"`
|
||||
}
|
||||
```
|
||||
|
||||
#### Notes
|
||||
Documentation is available here: [godoc.org](https://godoc.org/github.com/asaskevich/govalidator).
|
||||
Full information about code coverage is also available here: [govalidator on gocover.io](http://gocover.io/github.com/asaskevich/govalidator).
|
||||
|
||||
#### Support
|
||||
If you do have a contribution to the package, feel free to create a Pull Request or an Issue.
|
||||
|
||||
#### What to contribute
|
||||
If you don't know what to do, there are some features and functions that need to be done
|
||||
|
||||
- [ ] Refactor code
|
||||
- [ ] Edit docs and [README](https://github.com/asaskevich/govalidator/README.md): spellcheck, grammar and typo check
|
||||
- [ ] Create actual list of contributors and projects that currently using this package
|
||||
- [ ] Resolve [issues and bugs](https://github.com/asaskevich/govalidator/issues)
|
||||
- [ ] Update actual [list of functions](https://github.com/asaskevich/govalidator#list-of-functions)
|
||||
- [ ] Update [list of validators](https://github.com/asaskevich/govalidator#validatestruct-2) that available for `ValidateStruct` and add new
|
||||
- [ ] Implement new validators: `IsFQDN`, `IsIMEI`, `IsPostalCode`, `IsISIN`, `IsISRC` etc
|
||||
- [ ] Implement [validation by maps](https://github.com/asaskevich/govalidator/issues/224)
|
||||
- [ ] Implement fuzzing testing
|
||||
- [ ] Implement some struct/map/array utilities
|
||||
- [ ] Implement map/array validation
|
||||
- [ ] Implement benchmarking
|
||||
- [ ] Implement batch of examples
|
||||
- [ ] Look at forks for new features and fixes
|
||||
|
||||
#### Advice
|
||||
Feel free to create what you want, but keep in mind when you implement new features:
|
||||
- Code must be clear and readable, names of variables/constants clearly describes what they are doing
|
||||
- Public functions must be documented and described in source file and added to README.md to the list of available functions
|
||||
- There are must be unit-tests for any new functions and improvements
|
||||
|
||||
## Credits
|
||||
### Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||
|
||||
#### Special thanks to [contributors](https://github.com/asaskevich/govalidator/graphs/contributors)
|
||||
* [Daniel Lohse](https://github.com/annismckenzie)
|
||||
* [Attila Oláh](https://github.com/attilaolah)
|
||||
* [Daniel Korner](https://github.com/Dadie)
|
||||
* [Steven Wilkin](https://github.com/stevenwilkin)
|
||||
* [Deiwin Sarjas](https://github.com/deiwin)
|
||||
* [Noah Shibley](https://github.com/slugmobile)
|
||||
* [Nathan Davies](https://github.com/nathj07)
|
||||
* [Matt Sanford](https://github.com/mzsanford)
|
||||
* [Simon ccl1115](https://github.com/ccl1115)
|
||||
|
||||
<a href="graphs/contributors"><img src="https://opencollective.com/govalidator/contributors.svg?width=890" /></a>
|
||||
|
||||
|
||||
### Backers
|
||||
|
||||
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/govalidator#backer)]
|
||||
|
||||
<a href="https://opencollective.com/govalidator#backers" target="_blank"><img src="https://opencollective.com/govalidator/backers.svg?width=890"></a>
|
||||
|
||||
|
||||
### Sponsors
|
||||
|
||||
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/govalidator#sponsor)]
|
||||
|
||||
<a href="https://opencollective.com/govalidator/sponsor/0/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/1/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/2/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/3/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/4/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/5/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/6/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/7/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/8/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/govalidator/sponsor/9/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/9/avatar.svg"></a>
|
||||
|
||||
|
||||
58
vendor/github.com/asaskevich/govalidator/arrays.go
generated
vendored
Normal file
58
vendor/github.com/asaskevich/govalidator/arrays.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
package govalidator
|
||||
|
||||
// Iterator is the function that accepts element of slice/array and its index
|
||||
type Iterator func(interface{}, int)
|
||||
|
||||
// ResultIterator is the function that accepts element of slice/array and its index and returns any result
|
||||
type ResultIterator func(interface{}, int) interface{}
|
||||
|
||||
// ConditionIterator is the function that accepts element of slice/array and its index and returns boolean
|
||||
type ConditionIterator func(interface{}, int) bool
|
||||
|
||||
// Each iterates over the slice and apply Iterator to every item
|
||||
func Each(array []interface{}, iterator Iterator) {
|
||||
for index, data := range array {
|
||||
iterator(data, index)
|
||||
}
|
||||
}
|
||||
|
||||
// Map iterates over the slice and apply ResultIterator to every item. Returns new slice as a result.
|
||||
func Map(array []interface{}, iterator ResultIterator) []interface{} {
|
||||
var result = make([]interface{}, len(array))
|
||||
for index, data := range array {
|
||||
result[index] = iterator(data, index)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Find iterates over the slice and apply ConditionIterator to every item. Returns first item that meet ConditionIterator or nil otherwise.
|
||||
func Find(array []interface{}, iterator ConditionIterator) interface{} {
|
||||
for index, data := range array {
|
||||
if iterator(data, index) {
|
||||
return data
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Filter iterates over the slice and apply ConditionIterator to every item. Returns new slice.
|
||||
func Filter(array []interface{}, iterator ConditionIterator) []interface{} {
|
||||
var result = make([]interface{}, 0)
|
||||
for index, data := range array {
|
||||
if iterator(data, index) {
|
||||
result = append(result, data)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Count iterates over the slice and apply ConditionIterator to every item. Returns count of items that meets ConditionIterator.
|
||||
func Count(array []interface{}, iterator ConditionIterator) int {
|
||||
count := 0
|
||||
for index, data := range array {
|
||||
if iterator(data, index) {
|
||||
count = count + 1
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
116
vendor/github.com/asaskevich/govalidator/arrays_test.go
generated
vendored
Normal file
116
vendor/github.com/asaskevich/govalidator/arrays_test.go
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
package govalidator
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEach(t *testing.T) {
|
||||
// TODO Maybe refactor?
|
||||
t.Parallel()
|
||||
acc := 0
|
||||
data := []interface{}{1, 2, 3, 4, 5}
|
||||
var fn Iterator = func(value interface{}, index int) {
|
||||
acc = acc + value.(int)
|
||||
}
|
||||
Each(data, fn)
|
||||
if acc != 15 {
|
||||
t.Errorf("Expected Each(..) to be %v, got %v", 15, acc)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleEach() {
|
||||
data := []interface{}{1, 2, 3, 4, 5}
|
||||
var fn Iterator = func(value interface{}, index int) {
|
||||
println(value.(int))
|
||||
}
|
||||
Each(data, fn)
|
||||
}
|
||||
|
||||
func TestMap(t *testing.T) {
|
||||
// TODO Maybe refactor?
|
||||
t.Parallel()
|
||||
data := []interface{}{1, 2, 3, 4, 5}
|
||||
var fn ResultIterator = func(value interface{}, index int) interface{} {
|
||||
return value.(int) * 3
|
||||
}
|
||||
result := Map(data, fn)
|
||||
for i, d := range result {
|
||||
if d != fn(data[i], i) {
|
||||
t.Errorf("Expected Map(..) to be %v, got %v", fn(data[i], i), d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleMap() {
|
||||
data := []interface{}{1, 2, 3, 4, 5}
|
||||
var fn ResultIterator = func(value interface{}, index int) interface{} {
|
||||
return value.(int) * 3
|
||||
}
|
||||
_ = Map(data, fn) // result = []interface{}{1, 6, 9, 12, 15}
|
||||
}
|
||||
|
||||
func TestFind(t *testing.T) {
|
||||
// TODO Maybe refactor?
|
||||
t.Parallel()
|
||||
findElement := 96
|
||||
data := []interface{}{1, 2, 3, 4, findElement, 5}
|
||||
var fn1 ConditionIterator = func(value interface{}, index int) bool {
|
||||
return value.(int) == findElement
|
||||
}
|
||||
var fn2 ConditionIterator = func(value interface{}, index int) bool {
|
||||
value, _ = value.(string)
|
||||
return value == "govalidator"
|
||||
}
|
||||
val1 := Find(data, fn1)
|
||||
val2 := Find(data, fn2)
|
||||
if val1 != findElement {
|
||||
t.Errorf("Expected Find(..) to be %v, got %v", findElement, val1)
|
||||
}
|
||||
if val2 != nil {
|
||||
t.Errorf("Expected Find(..) to be %v, got %v", nil, val2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
// TODO Maybe refactor?
|
||||
t.Parallel()
|
||||
data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
answer := []interface{}{2, 4, 6, 8, 10}
|
||||
var fn ConditionIterator = func(value interface{}, index int) bool {
|
||||
return value.(int)%2 == 0
|
||||
}
|
||||
result := Filter(data, fn)
|
||||
for i := range result {
|
||||
if result[i] != answer[i] {
|
||||
t.Errorf("Expected Filter(..) to be %v, got %v", answer[i], result[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleFilter() {
|
||||
data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
var fn ConditionIterator = func(value interface{}, index int) bool {
|
||||
return value.(int)%2 == 0
|
||||
}
|
||||
_ = Filter(data, fn) // result = []interface{}{2, 4, 6, 8, 10}
|
||||
}
|
||||
|
||||
func TestCount(t *testing.T) {
|
||||
// TODO Maybe refactor?
|
||||
t.Parallel()
|
||||
data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
count := 5
|
||||
var fn ConditionIterator = func(value interface{}, index int) bool {
|
||||
return value.(int)%2 == 0
|
||||
}
|
||||
result := Count(data, fn)
|
||||
if result != count {
|
||||
t.Errorf("Expected Count(..) to be %v, got %v", count, result)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleCount() {
|
||||
data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
var fn ConditionIterator = func(value interface{}, index int) bool {
|
||||
return value.(int)%2 == 0
|
||||
}
|
||||
_ = Count(data, fn) // result = 5
|
||||
}
|
||||
64
vendor/github.com/asaskevich/govalidator/converter.go
generated
vendored
Normal file
64
vendor/github.com/asaskevich/govalidator/converter.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
package govalidator
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// ToString convert the input to a string.
|
||||
func ToString(obj interface{}) string {
|
||||
res := fmt.Sprintf("%v", obj)
|
||||
return string(res)
|
||||
}
|
||||
|
||||
// ToJSON convert the input to a valid JSON string
|
||||
func ToJSON(obj interface{}) (string, error) {
|
||||
res, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
res = []byte("")
|
||||
}
|
||||
return string(res), err
|
||||
}
|
||||
|
||||
// ToFloat convert the input string to a float, or 0.0 if the input is not a float.
|
||||
func ToFloat(str string) (float64, error) {
|
||||
res, err := strconv.ParseFloat(str, 64)
|
||||
if err != nil {
|
||||
res = 0.0
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
// ToInt convert the input string or any int type to an integer type 64, or 0 if the input is not an integer.
|
||||
func ToInt(value interface{}) (res int64, err error) {
|
||||
val := reflect.ValueOf(value)
|
||||
|
||||
switch value.(type) {
|
||||
case int, int8, int16, int32, int64:
|
||||
res = val.Int()
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
res = int64(val.Uint())
|
||||
case string:
|
||||
if IsInt(val.String()) {
|
||||
res, err = strconv.ParseInt(val.String(), 0, 64)
|
||||
if err != nil {
|
||||
res = 0
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("math: square root of negative number %g", value)
|
||||
res = 0
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("math: square root of negative number %g", value)
|
||||
res = 0
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ToBoolean convert the input string to a boolean.
|
||||
func ToBoolean(str string) (bool, error) {
|
||||
return strconv.ParseBool(str)
|
||||
}
|
||||
78
vendor/github.com/asaskevich/govalidator/converter_test.go
generated
vendored
Normal file
78
vendor/github.com/asaskevich/govalidator/converter_test.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
package govalidator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestToInt(t *testing.T) {
|
||||
tests := []string{"1000", "-123", "abcdef", "100000000000000000000000000000000000000000000"}
|
||||
expected := []int64{1000, -123, 0, 0}
|
||||
for i := 0; i < len(tests); i++ {
|
||||
result, _ := ToInt(tests[i])
|
||||
if result != expected[i] {
|
||||
t.Log("Case ", i, ": expected ", expected[i], " when result is ", result)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToBoolean(t *testing.T) {
|
||||
tests := []string{"true", "1", "True", "false", "0", "abcdef"}
|
||||
expected := []bool{true, true, true, false, false, false}
|
||||
for i := 0; i < len(tests); i++ {
|
||||
res, _ := ToBoolean(tests[i])
|
||||
if res != expected[i] {
|
||||
t.Log("Case ", i, ": expected ", expected[i], " when result is ", res)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toString(t *testing.T, test interface{}, expected string) {
|
||||
res := ToString(test)
|
||||
if res != expected {
|
||||
t.Log("Case ToString: expected ", expected, " when result is ", res)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestToString(t *testing.T) {
|
||||
toString(t, "str123", "str123")
|
||||
toString(t, 123, "123")
|
||||
toString(t, 12.3, "12.3")
|
||||
toString(t, true, "true")
|
||||
toString(t, 1.5+10i, "(1.5+10i)")
|
||||
// Sprintf function not guarantee that maps with equal keys always will be equal in string representation
|
||||
//toString(t, struct{ Keys map[int]int }{Keys: map[int]int{1: 2, 3: 4}}, "{map[1:2 3:4]}")
|
||||
}
|
||||
|
||||
func TestToFloat(t *testing.T) {
|
||||
tests := []string{"", "123", "-.01", "10.", "string", "1.23e3", ".23e10"}
|
||||
expected := []float64{0, 123, -0.01, 10.0, 0, 1230, 0.23e10}
|
||||
for i := 0; i < len(tests); i++ {
|
||||
res, _ := ToFloat(tests[i])
|
||||
if res != expected[i] {
|
||||
t.Log("Case ", i, ": expected ", expected[i], " when result is ", res)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToJSON(t *testing.T) {
|
||||
tests := []interface{}{"test", map[string]string{"a": "b", "b": "c"}, func() error { return fmt.Errorf("Error") }}
|
||||
expected := [][]string{
|
||||
{"\"test\"", "<nil>"},
|
||||
{"{\"a\":\"b\",\"b\":\"c\"}", "<nil>"},
|
||||
{"", "json: unsupported type: func() error"},
|
||||
}
|
||||
for i, test := range tests {
|
||||
actual, err := ToJSON(test)
|
||||
if actual != expected[i][0] {
|
||||
t.Errorf("Expected toJSON(%v) to return '%v', got '%v'", test, expected[i][0], actual)
|
||||
}
|
||||
if fmt.Sprintf("%v", err) != expected[i][1] {
|
||||
t.Errorf("Expected error returned from toJSON(%v) to return '%v', got '%v'", test, expected[i][1], fmt.Sprintf("%v", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
36
vendor/github.com/asaskevich/govalidator/error.go
generated
vendored
Normal file
36
vendor/github.com/asaskevich/govalidator/error.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package govalidator
|
||||
|
||||
import "strings"
|
||||
|
||||
// Errors is an array of multiple errors and conforms to the error interface.
|
||||
type Errors []error
|
||||
|
||||
// Errors returns itself.
|
||||
func (es Errors) Errors() []error {
|
||||
return es
|
||||
}
|
||||
|
||||
func (es Errors) Error() string {
|
||||
var errs []string
|
||||
for _, e := range es {
|
||||
errs = append(errs, e.Error())
|
||||
}
|
||||
return strings.Join(errs, ";")
|
||||
}
|
||||
|
||||
// Error encapsulates a name, an error and whether there's a custom error message or not.
|
||||
type Error struct {
|
||||
Name string
|
||||
Err error
|
||||
CustomErrorMessageExists bool
|
||||
|
||||
// Validator indicates the name of the validator that failed
|
||||
Validator string
|
||||
}
|
||||
|
||||
func (e Error) Error() string {
|
||||
if e.CustomErrorMessageExists {
|
||||
return e.Err.Error()
|
||||
}
|
||||
return e.Name + ": " + e.Err.Error()
|
||||
}
|
||||
29
vendor/github.com/asaskevich/govalidator/error_test.go
generated
vendored
Normal file
29
vendor/github.com/asaskevich/govalidator/error_test.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
package govalidator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestErrorsToString(t *testing.T) {
|
||||
t.Parallel()
|
||||
customErr := &Error{Name: "Custom Error Name", Err: fmt.Errorf("stdlib error")}
|
||||
customErrWithCustomErrorMessage := &Error{Name: "Custom Error Name 2", Err: fmt.Errorf("Bad stuff happened"), CustomErrorMessageExists: true}
|
||||
|
||||
var tests = []struct {
|
||||
param1 Errors
|
||||
expected string
|
||||
}{
|
||||
{Errors{}, ""},
|
||||
{Errors{fmt.Errorf("Error 1")}, "Error 1"},
|
||||
{Errors{fmt.Errorf("Error 1"), fmt.Errorf("Error 2")}, "Error 1;Error 2"},
|
||||
{Errors{customErr, fmt.Errorf("Error 2")}, "Custom Error Name: stdlib error;Error 2"},
|
||||
{Errors{fmt.Errorf("Error 123"), customErrWithCustomErrorMessage}, "Error 123;Bad stuff happened"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := test.param1.Error()
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected Error() to return '%v', got '%v'", test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
97
vendor/github.com/asaskevich/govalidator/numerics.go
generated
vendored
Normal file
97
vendor/github.com/asaskevich/govalidator/numerics.go
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
package govalidator
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Abs returns absolute value of number
|
||||
func Abs(value float64) float64 {
|
||||
return math.Abs(value)
|
||||
}
|
||||
|
||||
// Sign returns signum of number: 1 in case of value > 0, -1 in case of value < 0, 0 otherwise
|
||||
func Sign(value float64) float64 {
|
||||
if value > 0 {
|
||||
return 1
|
||||
} else if value < 0 {
|
||||
return -1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// IsNegative returns true if value < 0
|
||||
func IsNegative(value float64) bool {
|
||||
return value < 0
|
||||
}
|
||||
|
||||
// IsPositive returns true if value > 0
|
||||
func IsPositive(value float64) bool {
|
||||
return value > 0
|
||||
}
|
||||
|
||||
// IsNonNegative returns true if value >= 0
|
||||
func IsNonNegative(value float64) bool {
|
||||
return value >= 0
|
||||
}
|
||||
|
||||
// IsNonPositive returns true if value <= 0
|
||||
func IsNonPositive(value float64) bool {
|
||||
return value <= 0
|
||||
}
|
||||
|
||||
// InRange returns true if value lies between left and right border
|
||||
func InRangeInt(value, left, right interface{}) bool {
|
||||
value64, _ := ToInt(value)
|
||||
left64, _ := ToInt(left)
|
||||
right64, _ := ToInt(right)
|
||||
if left64 > right64 {
|
||||
left64, right64 = right64, left64
|
||||
}
|
||||
return value64 >= left64 && value64 <= right64
|
||||
}
|
||||
|
||||
// InRange returns true if value lies between left and right border
|
||||
func InRangeFloat32(value, left, right float32) bool {
|
||||
if left > right {
|
||||
left, right = right, left
|
||||
}
|
||||
return value >= left && value <= right
|
||||
}
|
||||
|
||||
// InRange returns true if value lies between left and right border
|
||||
func InRangeFloat64(value, left, right float64) bool {
|
||||
if left > right {
|
||||
left, right = right, left
|
||||
}
|
||||
return value >= left && value <= right
|
||||
}
|
||||
|
||||
// InRange returns true if value lies between left and right border, generic type to handle int, float32 or float64, all types must the same type
|
||||
func InRange(value interface{}, left interface{}, right interface{}) bool {
|
||||
|
||||
reflectValue := reflect.TypeOf(value).Kind()
|
||||
reflectLeft := reflect.TypeOf(left).Kind()
|
||||
reflectRight := reflect.TypeOf(right).Kind()
|
||||
|
||||
if reflectValue == reflect.Int && reflectLeft == reflect.Int && reflectRight == reflect.Int {
|
||||
return InRangeInt(value.(int), left.(int), right.(int))
|
||||
} else if reflectValue == reflect.Float32 && reflectLeft == reflect.Float32 && reflectRight == reflect.Float32 {
|
||||
return InRangeFloat32(value.(float32), left.(float32), right.(float32))
|
||||
} else if reflectValue == reflect.Float64 && reflectLeft == reflect.Float64 && reflectRight == reflect.Float64 {
|
||||
return InRangeFloat64(value.(float64), left.(float64), right.(float64))
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// IsWhole returns true if value is whole number
|
||||
func IsWhole(value float64) bool {
|
||||
return math.Remainder(value, 1) == 0
|
||||
}
|
||||
|
||||
// IsNatural returns true if value is natural number (positive and whole)
|
||||
func IsNatural(value float64) bool {
|
||||
return IsWhole(value) && IsPositive(value)
|
||||
}
|
||||
549
vendor/github.com/asaskevich/govalidator/numerics_test.go
generated
vendored
Normal file
549
vendor/github.com/asaskevich/govalidator/numerics_test.go
generated
vendored
Normal file
@@ -0,0 +1,549 @@
|
||||
package govalidator
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestAbs(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param float64
|
||||
expected float64
|
||||
}{
|
||||
{0, 0},
|
||||
{-1, 1},
|
||||
{10, 10},
|
||||
{3.14, 3.14},
|
||||
{-96, 96},
|
||||
{-10e-12, 10e-12},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := Abs(test.param)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected Abs(%v) to be %v, got %v", test.param, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param float64
|
||||
expected float64
|
||||
}{
|
||||
{0, 0},
|
||||
{-1, -1},
|
||||
{10, 1},
|
||||
{3.14, 1},
|
||||
{-96, -1},
|
||||
{-10e-12, -1},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := Sign(test.param)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected Sign(%v) to be %v, got %v", test.param, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsNegative(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param float64
|
||||
expected bool
|
||||
}{
|
||||
{0, false},
|
||||
{-1, true},
|
||||
{10, false},
|
||||
{3.14, false},
|
||||
{-96, true},
|
||||
{-10e-12, true},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := IsNegative(test.param)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected IsNegative(%v) to be %v, got %v", test.param, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsNonNegative(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param float64
|
||||
expected bool
|
||||
}{
|
||||
{0, true},
|
||||
{-1, false},
|
||||
{10, true},
|
||||
{3.14, true},
|
||||
{-96, false},
|
||||
{-10e-12, false},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := IsNonNegative(test.param)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected IsNonNegative(%v) to be %v, got %v", test.param, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsPositive(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param float64
|
||||
expected bool
|
||||
}{
|
||||
{0, false},
|
||||
{-1, false},
|
||||
{10, true},
|
||||
{3.14, true},
|
||||
{-96, false},
|
||||
{-10e-12, false},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := IsPositive(test.param)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected IsPositive(%v) to be %v, got %v", test.param, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsNonPositive(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param float64
|
||||
expected bool
|
||||
}{
|
||||
{0, true},
|
||||
{-1, true},
|
||||
{10, false},
|
||||
{3.14, false},
|
||||
{-96, true},
|
||||
{-10e-12, true},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := IsNonPositive(test.param)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected IsNonPositive(%v) to be %v, got %v", test.param, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsWhole(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param float64
|
||||
expected bool
|
||||
}{
|
||||
{0, true},
|
||||
{-1, true},
|
||||
{10, true},
|
||||
{3.14, false},
|
||||
{-96, true},
|
||||
{-10e-12, false},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := IsWhole(test.param)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected IsWhole(%v) to be %v, got %v", test.param, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsNatural(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param float64
|
||||
expected bool
|
||||
}{
|
||||
{0, false},
|
||||
{-1, false},
|
||||
{10, true},
|
||||
{3.14, false},
|
||||
{96, true},
|
||||
{-10e-12, false},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := IsNatural(test.param)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected IsNatural(%v) to be %v, got %v", test.param, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInRangeInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var testAsInts = []struct {
|
||||
param int
|
||||
left int
|
||||
right int
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{1, 0, 0, false},
|
||||
{-1, 0, 0, false},
|
||||
{0, -1, 1, true},
|
||||
{0, 0, 1, true},
|
||||
{0, -1, 0, true},
|
||||
{0, 0, -1, true},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range testAsInts {
|
||||
actual := InRangeInt(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type int", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
var testAsInt8s = []struct {
|
||||
param int8
|
||||
left int8
|
||||
right int8
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{1, 0, 0, false},
|
||||
{-1, 0, 0, false},
|
||||
{0, -1, 1, true},
|
||||
{0, 0, 1, true},
|
||||
{0, -1, 0, true},
|
||||
{0, 0, -1, true},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range testAsInt8s {
|
||||
actual := InRangeInt(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type int8", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
var testAsInt16s = []struct {
|
||||
param int16
|
||||
left int16
|
||||
right int16
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{1, 0, 0, false},
|
||||
{-1, 0, 0, false},
|
||||
{0, -1, 1, true},
|
||||
{0, 0, 1, true},
|
||||
{0, -1, 0, true},
|
||||
{0, 0, -1, true},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range testAsInt16s {
|
||||
actual := InRangeInt(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type int16", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
var testAsInt32s = []struct {
|
||||
param int32
|
||||
left int32
|
||||
right int32
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{1, 0, 0, false},
|
||||
{-1, 0, 0, false},
|
||||
{0, -1, 1, true},
|
||||
{0, 0, 1, true},
|
||||
{0, -1, 0, true},
|
||||
{0, 0, -1, true},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range testAsInt32s {
|
||||
actual := InRangeInt(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type int32", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
var testAsInt64s = []struct {
|
||||
param int64
|
||||
left int64
|
||||
right int64
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{1, 0, 0, false},
|
||||
{-1, 0, 0, false},
|
||||
{0, -1, 1, true},
|
||||
{0, 0, 1, true},
|
||||
{0, -1, 0, true},
|
||||
{0, 0, -1, true},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range testAsInt64s {
|
||||
actual := InRangeInt(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type int64", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
var testAsUInts = []struct {
|
||||
param uint
|
||||
left uint
|
||||
right uint
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{1, 0, 0, false},
|
||||
{0, 0, 1, true},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range testAsUInts {
|
||||
actual := InRangeInt(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type uint", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
var testAsUInt8s = []struct {
|
||||
param uint8
|
||||
left uint8
|
||||
right uint8
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{1, 0, 0, false},
|
||||
{0, 0, 1, true},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range testAsUInt8s {
|
||||
actual := InRangeInt(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type uint", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
var testAsUInt16s = []struct {
|
||||
param uint16
|
||||
left uint16
|
||||
right uint16
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{1, 0, 0, false},
|
||||
{0, 0, 1, true},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range testAsUInt16s {
|
||||
actual := InRangeInt(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type uint", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
var testAsUInt32s = []struct {
|
||||
param uint32
|
||||
left uint32
|
||||
right uint32
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{1, 0, 0, false},
|
||||
{0, 0, 1, true},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range testAsUInt32s {
|
||||
actual := InRangeInt(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type uint", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
var testAsUInt64s = []struct {
|
||||
param uint64
|
||||
left uint64
|
||||
right uint64
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{1, 0, 0, false},
|
||||
{0, 0, 1, true},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range testAsUInt64s {
|
||||
actual := InRangeInt(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type uint", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
var testAsStrings = []struct {
|
||||
param string
|
||||
left string
|
||||
right string
|
||||
expected bool
|
||||
}{
|
||||
{"0", "0", "0", true},
|
||||
{"1", "0", "0", false},
|
||||
{"-1", "0", "0", false},
|
||||
{"0", "-1", "1", true},
|
||||
{"0", "0", "1", true},
|
||||
{"0", "-1", "0", true},
|
||||
{"0", "0", "-1", true},
|
||||
{"0", "10", "5", false},
|
||||
}
|
||||
for _, test := range testAsStrings {
|
||||
actual := InRangeInt(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRangeInt(%v, %v, %v) to be %v, got %v using type string", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInRangeFloat32(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param float32
|
||||
left float32
|
||||
right float32
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{1, 0, 0, false},
|
||||
{-1, 0, 0, false},
|
||||
{0, -1, 1, true},
|
||||
{0, 0, 1, true},
|
||||
{0, -1, 0, true},
|
||||
{0, 0, -1, true},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := InRangeFloat32(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRangeFloat32(%v, %v, %v) to be %v, got %v", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInRangeFloat64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param float64
|
||||
left float64
|
||||
right float64
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{1, 0, 0, false},
|
||||
{-1, 0, 0, false},
|
||||
{0, -1, 1, true},
|
||||
{0, 0, 1, true},
|
||||
{0, -1, 0, true},
|
||||
{0, 0, -1, true},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := InRangeFloat64(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRangeFloat64(%v, %v, %v) to be %v, got %v", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInRange(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var testsInt = []struct {
|
||||
param int
|
||||
left int
|
||||
right int
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{1, 0, 0, false},
|
||||
{-1, 0, 0, false},
|
||||
{0, -1, 1, true},
|
||||
{0, 0, 1, true},
|
||||
{0, -1, 0, true},
|
||||
{0, 0, -1, true},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range testsInt {
|
||||
actual := InRange(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRange(%v, %v, %v) to be %v, got %v", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
var testsFloat32 = []struct {
|
||||
param float32
|
||||
left float32
|
||||
right float32
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{1, 0, 0, false},
|
||||
{-1, 0, 0, false},
|
||||
{0, -1, 1, true},
|
||||
{0, 0, 1, true},
|
||||
{0, -1, 0, true},
|
||||
{0, 0, -1, true},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range testsFloat32 {
|
||||
actual := InRange(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRange(%v, %v, %v) to be %v, got %v", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
var testsFloat64 = []struct {
|
||||
param float64
|
||||
left float64
|
||||
right float64
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{1, 0, 0, false},
|
||||
{-1, 0, 0, false},
|
||||
{0, -1, 1, true},
|
||||
{0, 0, 1, true},
|
||||
{0, -1, 0, true},
|
||||
{0, 0, -1, true},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range testsFloat64 {
|
||||
actual := InRange(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRange(%v, %v, %v) to be %v, got %v", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
var testsTypeMix = []struct {
|
||||
param int
|
||||
left float64
|
||||
right float64
|
||||
expected bool
|
||||
}{
|
||||
{0, 0, 0, false},
|
||||
{1, 0, 0, false},
|
||||
{-1, 0, 0, false},
|
||||
{0, -1, 1, false},
|
||||
{0, 0, 1, false},
|
||||
{0, -1, 0, false},
|
||||
{0, 0, -1, false},
|
||||
{0, 10, 5, false},
|
||||
}
|
||||
for _, test := range testsTypeMix {
|
||||
actual := InRange(test.param, test.left, test.right)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected InRange(%v, %v, %v) to be %v, got %v", test.param, test.left, test.right, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
97
vendor/github.com/asaskevich/govalidator/patterns.go
generated
vendored
Normal file
97
vendor/github.com/asaskevich/govalidator/patterns.go
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
package govalidator
|
||||
|
||||
import "regexp"
|
||||
|
||||
// Basic regular expressions for validating strings
|
||||
const (
|
||||
//Email string = "^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$"
|
||||
CreditCard string = "^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$"
|
||||
ISBN10 string = "^(?:[0-9]{9}X|[0-9]{10})$"
|
||||
ISBN13 string = "^(?:[0-9]{13})$"
|
||||
UUID3 string = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$"
|
||||
UUID4 string = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
|
||||
UUID5 string = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
|
||||
UUID string = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
|
||||
Alpha string = "^[a-zA-Z]+$"
|
||||
Alphanumeric string = "^[a-zA-Z0-9]+$"
|
||||
Numeric string = "^[0-9]+$"
|
||||
Int string = "^(?:[-+]?(?:0|[1-9][0-9]*))$"
|
||||
Float string = "^(?:[-+]?(?:[0-9]+))?(?:\\.[0-9]*)?(?:[eE][\\+\\-]?(?:[0-9]+))?$"
|
||||
Hexadecimal string = "^[0-9a-fA-F]+$"
|
||||
Hexcolor string = "^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
|
||||
RGBcolor string = "^rgb\\(\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*\\)$"
|
||||
ASCII string = "^[\x00-\x7F]+$"
|
||||
Multibyte string = "[^\x00-\x7F]"
|
||||
FullWidth string = "[^\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]"
|
||||
HalfWidth string = "[\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]"
|
||||
Base64 string = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$"
|
||||
PrintableASCII string = "^[\x20-\x7E]+$"
|
||||
DataURI string = "^data:.+\\/(.+);base64$"
|
||||
Latitude string = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$"
|
||||
Longitude string = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$"
|
||||
DNSName string = `^([a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*[\._]?$`
|
||||
IP string = `(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))`
|
||||
URLSchema string = `((ftp|tcp|udp|wss?|https?):\/\/)`
|
||||
URLUsername string = `(\S+(:\S*)?@)`
|
||||
URLPath string = `((\/|\?|#)[^\s]*)`
|
||||
URLPort string = `(:(\d{1,5}))`
|
||||
URLIP string = `([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))`
|
||||
URLSubdomain string = `((www\.)|([a-zA-Z0-9]([-\.][-\._a-zA-Z0-9]+)*))`
|
||||
URL string = `^` + URLSchema + `?` + URLUsername + `?` + `((` + URLIP + `|(\[` + IP + `\])|(([a-zA-Z0-9]([a-zA-Z0-9-_]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|(` + URLSubdomain + `?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))\.?` + URLPort + `?` + URLPath + `?$`
|
||||
SSN string = `^\d{3}[- ]?\d{2}[- ]?\d{4}$`
|
||||
WinPath string = `^[a-zA-Z]:\\(?:[^\\/:*?"<>|\r\n]+\\)*[^\\/:*?"<>|\r\n]*$`
|
||||
UnixPath string = `^(/[^/\x00]*)+/?$`
|
||||
Semver string = "^v?(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(-(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\+[0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)?$"
|
||||
tagName string = "valid"
|
||||
hasLowerCase string = ".*[[:lower:]]"
|
||||
hasUpperCase string = ".*[[:upper:]]"
|
||||
)
|
||||
|
||||
// Used by IsFilePath func
|
||||
const (
|
||||
// Unknown is unresolved OS type
|
||||
Unknown = iota
|
||||
// Win is Windows type
|
||||
Win
|
||||
// Unix is *nix OS types
|
||||
Unix
|
||||
)
|
||||
|
||||
var (
|
||||
userRegexp = regexp.MustCompile("^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+$")
|
||||
hostRegexp = regexp.MustCompile("^[^\\s]+\\.[^\\s]+$")
|
||||
userDotRegexp = regexp.MustCompile("(^[.]{1})|([.]{1}$)|([.]{2,})")
|
||||
//rxEmail = regexp.MustCompile(Email)
|
||||
rxCreditCard = regexp.MustCompile(CreditCard)
|
||||
rxISBN10 = regexp.MustCompile(ISBN10)
|
||||
rxISBN13 = regexp.MustCompile(ISBN13)
|
||||
rxUUID3 = regexp.MustCompile(UUID3)
|
||||
rxUUID4 = regexp.MustCompile(UUID4)
|
||||
rxUUID5 = regexp.MustCompile(UUID5)
|
||||
rxUUID = regexp.MustCompile(UUID)
|
||||
rxAlpha = regexp.MustCompile(Alpha)
|
||||
rxAlphanumeric = regexp.MustCompile(Alphanumeric)
|
||||
rxNumeric = regexp.MustCompile(Numeric)
|
||||
rxInt = regexp.MustCompile(Int)
|
||||
rxFloat = regexp.MustCompile(Float)
|
||||
rxHexadecimal = regexp.MustCompile(Hexadecimal)
|
||||
rxHexcolor = regexp.MustCompile(Hexcolor)
|
||||
rxRGBcolor = regexp.MustCompile(RGBcolor)
|
||||
rxASCII = regexp.MustCompile(ASCII)
|
||||
rxPrintableASCII = regexp.MustCompile(PrintableASCII)
|
||||
rxMultibyte = regexp.MustCompile(Multibyte)
|
||||
rxFullWidth = regexp.MustCompile(FullWidth)
|
||||
rxHalfWidth = regexp.MustCompile(HalfWidth)
|
||||
rxBase64 = regexp.MustCompile(Base64)
|
||||
rxDataURI = regexp.MustCompile(DataURI)
|
||||
rxLatitude = regexp.MustCompile(Latitude)
|
||||
rxLongitude = regexp.MustCompile(Longitude)
|
||||
rxDNSName = regexp.MustCompile(DNSName)
|
||||
rxURL = regexp.MustCompile(URL)
|
||||
rxSSN = regexp.MustCompile(SSN)
|
||||
rxWinPath = regexp.MustCompile(WinPath)
|
||||
rxUnixPath = regexp.MustCompile(UnixPath)
|
||||
rxSemver = regexp.MustCompile(Semver)
|
||||
rxHasLowerCase = regexp.MustCompile(hasLowerCase)
|
||||
rxHasUpperCase = regexp.MustCompile(hasUpperCase)
|
||||
)
|
||||
616
vendor/github.com/asaskevich/govalidator/types.go
generated
vendored
Normal file
616
vendor/github.com/asaskevich/govalidator/types.go
generated
vendored
Normal file
@@ -0,0 +1,616 @@
|
||||
package govalidator
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Validator is a wrapper for a validator function that returns bool and accepts string.
|
||||
type Validator func(str string) bool
|
||||
|
||||
// CustomTypeValidator is a wrapper for validator functions that returns bool and accepts any type.
|
||||
// The second parameter should be the context (in the case of validating a struct: the whole object being validated).
|
||||
type CustomTypeValidator func(i interface{}, o interface{}) bool
|
||||
|
||||
// ParamValidator is a wrapper for validator functions that accepts additional parameters.
|
||||
type ParamValidator func(str string, params ...string) bool
|
||||
type tagOptionsMap map[string]string
|
||||
|
||||
// UnsupportedTypeError is a wrapper for reflect.Type
|
||||
type UnsupportedTypeError struct {
|
||||
Type reflect.Type
|
||||
}
|
||||
|
||||
// stringValues is a slice of reflect.Value holding *reflect.StringValue.
|
||||
// It implements the methods to sort by string.
|
||||
type stringValues []reflect.Value
|
||||
|
||||
// ParamTagMap is a map of functions accept variants parameters
|
||||
var ParamTagMap = map[string]ParamValidator{
|
||||
"length": ByteLength,
|
||||
"range": Range,
|
||||
"runelength": RuneLength,
|
||||
"stringlength": StringLength,
|
||||
"matches": StringMatches,
|
||||
"in": isInRaw,
|
||||
"rsapub": IsRsaPub,
|
||||
}
|
||||
|
||||
// ParamTagRegexMap maps param tags to their respective regexes.
|
||||
var ParamTagRegexMap = map[string]*regexp.Regexp{
|
||||
"range": regexp.MustCompile("^range\\((\\d+)\\|(\\d+)\\)$"),
|
||||
"length": regexp.MustCompile("^length\\((\\d+)\\|(\\d+)\\)$"),
|
||||
"runelength": regexp.MustCompile("^runelength\\((\\d+)\\|(\\d+)\\)$"),
|
||||
"stringlength": regexp.MustCompile("^stringlength\\((\\d+)\\|(\\d+)\\)$"),
|
||||
"in": regexp.MustCompile(`^in\((.*)\)`),
|
||||
"matches": regexp.MustCompile(`^matches\((.+)\)$`),
|
||||
"rsapub": regexp.MustCompile("^rsapub\\((\\d+)\\)$"),
|
||||
}
|
||||
|
||||
type customTypeTagMap struct {
|
||||
validators map[string]CustomTypeValidator
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func (tm *customTypeTagMap) Get(name string) (CustomTypeValidator, bool) {
|
||||
tm.RLock()
|
||||
defer tm.RUnlock()
|
||||
v, ok := tm.validators[name]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
func (tm *customTypeTagMap) Set(name string, ctv CustomTypeValidator) {
|
||||
tm.Lock()
|
||||
defer tm.Unlock()
|
||||
tm.validators[name] = ctv
|
||||
}
|
||||
|
||||
// CustomTypeTagMap is a map of functions that can be used as tags for ValidateStruct function.
|
||||
// Use this to validate compound or custom types that need to be handled as a whole, e.g.
|
||||
// `type UUID [16]byte` (this would be handled as an array of bytes).
|
||||
var CustomTypeTagMap = &customTypeTagMap{validators: make(map[string]CustomTypeValidator)}
|
||||
|
||||
// TagMap is a map of functions, that can be used as tags for ValidateStruct function.
|
||||
var TagMap = map[string]Validator{
|
||||
"email": IsEmail,
|
||||
"url": IsURL,
|
||||
"dialstring": IsDialString,
|
||||
"requrl": IsRequestURL,
|
||||
"requri": IsRequestURI,
|
||||
"alpha": IsAlpha,
|
||||
"utfletter": IsUTFLetter,
|
||||
"alphanum": IsAlphanumeric,
|
||||
"utfletternum": IsUTFLetterNumeric,
|
||||
"numeric": IsNumeric,
|
||||
"utfnumeric": IsUTFNumeric,
|
||||
"utfdigit": IsUTFDigit,
|
||||
"hexadecimal": IsHexadecimal,
|
||||
"hexcolor": IsHexcolor,
|
||||
"rgbcolor": IsRGBcolor,
|
||||
"lowercase": IsLowerCase,
|
||||
"uppercase": IsUpperCase,
|
||||
"int": IsInt,
|
||||
"float": IsFloat,
|
||||
"null": IsNull,
|
||||
"uuid": IsUUID,
|
||||
"uuidv3": IsUUIDv3,
|
||||
"uuidv4": IsUUIDv4,
|
||||
"uuidv5": IsUUIDv5,
|
||||
"creditcard": IsCreditCard,
|
||||
"isbn10": IsISBN10,
|
||||
"isbn13": IsISBN13,
|
||||
"json": IsJSON,
|
||||
"multibyte": IsMultibyte,
|
||||
"ascii": IsASCII,
|
||||
"printableascii": IsPrintableASCII,
|
||||
"fullwidth": IsFullWidth,
|
||||
"halfwidth": IsHalfWidth,
|
||||
"variablewidth": IsVariableWidth,
|
||||
"base64": IsBase64,
|
||||
"datauri": IsDataURI,
|
||||
"ip": IsIP,
|
||||
"port": IsPort,
|
||||
"ipv4": IsIPv4,
|
||||
"ipv6": IsIPv6,
|
||||
"dns": IsDNSName,
|
||||
"host": IsHost,
|
||||
"mac": IsMAC,
|
||||
"latitude": IsLatitude,
|
||||
"longitude": IsLongitude,
|
||||
"ssn": IsSSN,
|
||||
"semver": IsSemver,
|
||||
"rfc3339": IsRFC3339,
|
||||
"rfc3339WithoutZone": IsRFC3339WithoutZone,
|
||||
"ISO3166Alpha2": IsISO3166Alpha2,
|
||||
"ISO3166Alpha3": IsISO3166Alpha3,
|
||||
"ISO4217": IsISO4217,
|
||||
}
|
||||
|
||||
// ISO3166Entry stores country codes
|
||||
type ISO3166Entry struct {
|
||||
EnglishShortName string
|
||||
FrenchShortName string
|
||||
Alpha2Code string
|
||||
Alpha3Code string
|
||||
Numeric string
|
||||
}
|
||||
|
||||
//ISO3166List based on https://www.iso.org/obp/ui/#search/code/ Code Type "Officially Assigned Codes"
|
||||
var ISO3166List = []ISO3166Entry{
|
||||
{"Afghanistan", "Afghanistan (l')", "AF", "AFG", "004"},
|
||||
{"Albania", "Albanie (l')", "AL", "ALB", "008"},
|
||||
{"Antarctica", "Antarctique (l')", "AQ", "ATA", "010"},
|
||||
{"Algeria", "Algérie (l')", "DZ", "DZA", "012"},
|
||||
{"American Samoa", "Samoa américaines (les)", "AS", "ASM", "016"},
|
||||
{"Andorra", "Andorre (l')", "AD", "AND", "020"},
|
||||
{"Angola", "Angola (l')", "AO", "AGO", "024"},
|
||||
{"Antigua and Barbuda", "Antigua-et-Barbuda", "AG", "ATG", "028"},
|
||||
{"Azerbaijan", "Azerbaïdjan (l')", "AZ", "AZE", "031"},
|
||||
{"Argentina", "Argentine (l')", "AR", "ARG", "032"},
|
||||
{"Australia", "Australie (l')", "AU", "AUS", "036"},
|
||||
{"Austria", "Autriche (l')", "AT", "AUT", "040"},
|
||||
{"Bahamas (the)", "Bahamas (les)", "BS", "BHS", "044"},
|
||||
{"Bahrain", "Bahreïn", "BH", "BHR", "048"},
|
||||
{"Bangladesh", "Bangladesh (le)", "BD", "BGD", "050"},
|
||||
{"Armenia", "Arménie (l')", "AM", "ARM", "051"},
|
||||
{"Barbados", "Barbade (la)", "BB", "BRB", "052"},
|
||||
{"Belgium", "Belgique (la)", "BE", "BEL", "056"},
|
||||
{"Bermuda", "Bermudes (les)", "BM", "BMU", "060"},
|
||||
{"Bhutan", "Bhoutan (le)", "BT", "BTN", "064"},
|
||||
{"Bolivia (Plurinational State of)", "Bolivie (État plurinational de)", "BO", "BOL", "068"},
|
||||
{"Bosnia and Herzegovina", "Bosnie-Herzégovine (la)", "BA", "BIH", "070"},
|
||||
{"Botswana", "Botswana (le)", "BW", "BWA", "072"},
|
||||
{"Bouvet Island", "Bouvet (l'Île)", "BV", "BVT", "074"},
|
||||
{"Brazil", "Brésil (le)", "BR", "BRA", "076"},
|
||||
{"Belize", "Belize (le)", "BZ", "BLZ", "084"},
|
||||
{"British Indian Ocean Territory (the)", "Indien (le Territoire britannique de l'océan)", "IO", "IOT", "086"},
|
||||
{"Solomon Islands", "Salomon (Îles)", "SB", "SLB", "090"},
|
||||
{"Virgin Islands (British)", "Vierges britanniques (les Îles)", "VG", "VGB", "092"},
|
||||
{"Brunei Darussalam", "Brunéi Darussalam (le)", "BN", "BRN", "096"},
|
||||
{"Bulgaria", "Bulgarie (la)", "BG", "BGR", "100"},
|
||||
{"Myanmar", "Myanmar (le)", "MM", "MMR", "104"},
|
||||
{"Burundi", "Burundi (le)", "BI", "BDI", "108"},
|
||||
{"Belarus", "Bélarus (le)", "BY", "BLR", "112"},
|
||||
{"Cambodia", "Cambodge (le)", "KH", "KHM", "116"},
|
||||
{"Cameroon", "Cameroun (le)", "CM", "CMR", "120"},
|
||||
{"Canada", "Canada (le)", "CA", "CAN", "124"},
|
||||
{"Cabo Verde", "Cabo Verde", "CV", "CPV", "132"},
|
||||
{"Cayman Islands (the)", "Caïmans (les Îles)", "KY", "CYM", "136"},
|
||||
{"Central African Republic (the)", "République centrafricaine (la)", "CF", "CAF", "140"},
|
||||
{"Sri Lanka", "Sri Lanka", "LK", "LKA", "144"},
|
||||
{"Chad", "Tchad (le)", "TD", "TCD", "148"},
|
||||
{"Chile", "Chili (le)", "CL", "CHL", "152"},
|
||||
{"China", "Chine (la)", "CN", "CHN", "156"},
|
||||
{"Taiwan (Province of China)", "Taïwan (Province de Chine)", "TW", "TWN", "158"},
|
||||
{"Christmas Island", "Christmas (l'Île)", "CX", "CXR", "162"},
|
||||
{"Cocos (Keeling) Islands (the)", "Cocos (les Îles)/ Keeling (les Îles)", "CC", "CCK", "166"},
|
||||
{"Colombia", "Colombie (la)", "CO", "COL", "170"},
|
||||
{"Comoros (the)", "Comores (les)", "KM", "COM", "174"},
|
||||
{"Mayotte", "Mayotte", "YT", "MYT", "175"},
|
||||
{"Congo (the)", "Congo (le)", "CG", "COG", "178"},
|
||||
{"Congo (the Democratic Republic of the)", "Congo (la République démocratique du)", "CD", "COD", "180"},
|
||||
{"Cook Islands (the)", "Cook (les Îles)", "CK", "COK", "184"},
|
||||
{"Costa Rica", "Costa Rica (le)", "CR", "CRI", "188"},
|
||||
{"Croatia", "Croatie (la)", "HR", "HRV", "191"},
|
||||
{"Cuba", "Cuba", "CU", "CUB", "192"},
|
||||
{"Cyprus", "Chypre", "CY", "CYP", "196"},
|
||||
{"Czech Republic (the)", "tchèque (la République)", "CZ", "CZE", "203"},
|
||||
{"Benin", "Bénin (le)", "BJ", "BEN", "204"},
|
||||
{"Denmark", "Danemark (le)", "DK", "DNK", "208"},
|
||||
{"Dominica", "Dominique (la)", "DM", "DMA", "212"},
|
||||
{"Dominican Republic (the)", "dominicaine (la République)", "DO", "DOM", "214"},
|
||||
{"Ecuador", "Équateur (l')", "EC", "ECU", "218"},
|
||||
{"El Salvador", "El Salvador", "SV", "SLV", "222"},
|
||||
{"Equatorial Guinea", "Guinée équatoriale (la)", "GQ", "GNQ", "226"},
|
||||
{"Ethiopia", "Éthiopie (l')", "ET", "ETH", "231"},
|
||||
{"Eritrea", "Érythrée (l')", "ER", "ERI", "232"},
|
||||
{"Estonia", "Estonie (l')", "EE", "EST", "233"},
|
||||
{"Faroe Islands (the)", "Féroé (les Îles)", "FO", "FRO", "234"},
|
||||
{"Falkland Islands (the) [Malvinas]", "Falkland (les Îles)/Malouines (les Îles)", "FK", "FLK", "238"},
|
||||
{"South Georgia and the South Sandwich Islands", "Géorgie du Sud-et-les Îles Sandwich du Sud (la)", "GS", "SGS", "239"},
|
||||
{"Fiji", "Fidji (les)", "FJ", "FJI", "242"},
|
||||
{"Finland", "Finlande (la)", "FI", "FIN", "246"},
|
||||
{"Åland Islands", "Åland(les Îles)", "AX", "ALA", "248"},
|
||||
{"France", "France (la)", "FR", "FRA", "250"},
|
||||
{"French Guiana", "Guyane française (la )", "GF", "GUF", "254"},
|
||||
{"French Polynesia", "Polynésie française (la)", "PF", "PYF", "258"},
|
||||
{"French Southern Territories (the)", "Terres australes françaises (les)", "TF", "ATF", "260"},
|
||||
{"Djibouti", "Djibouti", "DJ", "DJI", "262"},
|
||||
{"Gabon", "Gabon (le)", "GA", "GAB", "266"},
|
||||
{"Georgia", "Géorgie (la)", "GE", "GEO", "268"},
|
||||
{"Gambia (the)", "Gambie (la)", "GM", "GMB", "270"},
|
||||
{"Palestine, State of", "Palestine, État de", "PS", "PSE", "275"},
|
||||
{"Germany", "Allemagne (l')", "DE", "DEU", "276"},
|
||||
{"Ghana", "Ghana (le)", "GH", "GHA", "288"},
|
||||
{"Gibraltar", "Gibraltar", "GI", "GIB", "292"},
|
||||
{"Kiribati", "Kiribati", "KI", "KIR", "296"},
|
||||
{"Greece", "Grèce (la)", "GR", "GRC", "300"},
|
||||
{"Greenland", "Groenland (le)", "GL", "GRL", "304"},
|
||||
{"Grenada", "Grenade (la)", "GD", "GRD", "308"},
|
||||
{"Guadeloupe", "Guadeloupe (la)", "GP", "GLP", "312"},
|
||||
{"Guam", "Guam", "GU", "GUM", "316"},
|
||||
{"Guatemala", "Guatemala (le)", "GT", "GTM", "320"},
|
||||
{"Guinea", "Guinée (la)", "GN", "GIN", "324"},
|
||||
{"Guyana", "Guyana (le)", "GY", "GUY", "328"},
|
||||
{"Haiti", "Haïti", "HT", "HTI", "332"},
|
||||
{"Heard Island and McDonald Islands", "Heard-et-Îles MacDonald (l'Île)", "HM", "HMD", "334"},
|
||||
{"Holy See (the)", "Saint-Siège (le)", "VA", "VAT", "336"},
|
||||
{"Honduras", "Honduras (le)", "HN", "HND", "340"},
|
||||
{"Hong Kong", "Hong Kong", "HK", "HKG", "344"},
|
||||
{"Hungary", "Hongrie (la)", "HU", "HUN", "348"},
|
||||
{"Iceland", "Islande (l')", "IS", "ISL", "352"},
|
||||
{"India", "Inde (l')", "IN", "IND", "356"},
|
||||
{"Indonesia", "Indonésie (l')", "ID", "IDN", "360"},
|
||||
{"Iran (Islamic Republic of)", "Iran (République Islamique d')", "IR", "IRN", "364"},
|
||||
{"Iraq", "Iraq (l')", "IQ", "IRQ", "368"},
|
||||
{"Ireland", "Irlande (l')", "IE", "IRL", "372"},
|
||||
{"Israel", "Israël", "IL", "ISR", "376"},
|
||||
{"Italy", "Italie (l')", "IT", "ITA", "380"},
|
||||
{"Côte d'Ivoire", "Côte d'Ivoire (la)", "CI", "CIV", "384"},
|
||||
{"Jamaica", "Jamaïque (la)", "JM", "JAM", "388"},
|
||||
{"Japan", "Japon (le)", "JP", "JPN", "392"},
|
||||
{"Kazakhstan", "Kazakhstan (le)", "KZ", "KAZ", "398"},
|
||||
{"Jordan", "Jordanie (la)", "JO", "JOR", "400"},
|
||||
{"Kenya", "Kenya (le)", "KE", "KEN", "404"},
|
||||
{"Korea (the Democratic People's Republic of)", "Corée (la République populaire démocratique de)", "KP", "PRK", "408"},
|
||||
{"Korea (the Republic of)", "Corée (la République de)", "KR", "KOR", "410"},
|
||||
{"Kuwait", "Koweït (le)", "KW", "KWT", "414"},
|
||||
{"Kyrgyzstan", "Kirghizistan (le)", "KG", "KGZ", "417"},
|
||||
{"Lao People's Democratic Republic (the)", "Lao, République démocratique populaire", "LA", "LAO", "418"},
|
||||
{"Lebanon", "Liban (le)", "LB", "LBN", "422"},
|
||||
{"Lesotho", "Lesotho (le)", "LS", "LSO", "426"},
|
||||
{"Latvia", "Lettonie (la)", "LV", "LVA", "428"},
|
||||
{"Liberia", "Libéria (le)", "LR", "LBR", "430"},
|
||||
{"Libya", "Libye (la)", "LY", "LBY", "434"},
|
||||
{"Liechtenstein", "Liechtenstein (le)", "LI", "LIE", "438"},
|
||||
{"Lithuania", "Lituanie (la)", "LT", "LTU", "440"},
|
||||
{"Luxembourg", "Luxembourg (le)", "LU", "LUX", "442"},
|
||||
{"Macao", "Macao", "MO", "MAC", "446"},
|
||||
{"Madagascar", "Madagascar", "MG", "MDG", "450"},
|
||||
{"Malawi", "Malawi (le)", "MW", "MWI", "454"},
|
||||
{"Malaysia", "Malaisie (la)", "MY", "MYS", "458"},
|
||||
{"Maldives", "Maldives (les)", "MV", "MDV", "462"},
|
||||
{"Mali", "Mali (le)", "ML", "MLI", "466"},
|
||||
{"Malta", "Malte", "MT", "MLT", "470"},
|
||||
{"Martinique", "Martinique (la)", "MQ", "MTQ", "474"},
|
||||
{"Mauritania", "Mauritanie (la)", "MR", "MRT", "478"},
|
||||
{"Mauritius", "Maurice", "MU", "MUS", "480"},
|
||||
{"Mexico", "Mexique (le)", "MX", "MEX", "484"},
|
||||
{"Monaco", "Monaco", "MC", "MCO", "492"},
|
||||
{"Mongolia", "Mongolie (la)", "MN", "MNG", "496"},
|
||||
{"Moldova (the Republic of)", "Moldova , République de", "MD", "MDA", "498"},
|
||||
{"Montenegro", "Monténégro (le)", "ME", "MNE", "499"},
|
||||
{"Montserrat", "Montserrat", "MS", "MSR", "500"},
|
||||
{"Morocco", "Maroc (le)", "MA", "MAR", "504"},
|
||||
{"Mozambique", "Mozambique (le)", "MZ", "MOZ", "508"},
|
||||
{"Oman", "Oman", "OM", "OMN", "512"},
|
||||
{"Namibia", "Namibie (la)", "NA", "NAM", "516"},
|
||||
{"Nauru", "Nauru", "NR", "NRU", "520"},
|
||||
{"Nepal", "Népal (le)", "NP", "NPL", "524"},
|
||||
{"Netherlands (the)", "Pays-Bas (les)", "NL", "NLD", "528"},
|
||||
{"Curaçao", "Curaçao", "CW", "CUW", "531"},
|
||||
{"Aruba", "Aruba", "AW", "ABW", "533"},
|
||||
{"Sint Maarten (Dutch part)", "Saint-Martin (partie néerlandaise)", "SX", "SXM", "534"},
|
||||
{"Bonaire, Sint Eustatius and Saba", "Bonaire, Saint-Eustache et Saba", "BQ", "BES", "535"},
|
||||
{"New Caledonia", "Nouvelle-Calédonie (la)", "NC", "NCL", "540"},
|
||||
{"Vanuatu", "Vanuatu (le)", "VU", "VUT", "548"},
|
||||
{"New Zealand", "Nouvelle-Zélande (la)", "NZ", "NZL", "554"},
|
||||
{"Nicaragua", "Nicaragua (le)", "NI", "NIC", "558"},
|
||||
{"Niger (the)", "Niger (le)", "NE", "NER", "562"},
|
||||
{"Nigeria", "Nigéria (le)", "NG", "NGA", "566"},
|
||||
{"Niue", "Niue", "NU", "NIU", "570"},
|
||||
{"Norfolk Island", "Norfolk (l'Île)", "NF", "NFK", "574"},
|
||||
{"Norway", "Norvège (la)", "NO", "NOR", "578"},
|
||||
{"Northern Mariana Islands (the)", "Mariannes du Nord (les Îles)", "MP", "MNP", "580"},
|
||||
{"United States Minor Outlying Islands (the)", "Îles mineures éloignées des États-Unis (les)", "UM", "UMI", "581"},
|
||||
{"Micronesia (Federated States of)", "Micronésie (États fédérés de)", "FM", "FSM", "583"},
|
||||
{"Marshall Islands (the)", "Marshall (Îles)", "MH", "MHL", "584"},
|
||||
{"Palau", "Palaos (les)", "PW", "PLW", "585"},
|
||||
{"Pakistan", "Pakistan (le)", "PK", "PAK", "586"},
|
||||
{"Panama", "Panama (le)", "PA", "PAN", "591"},
|
||||
{"Papua New Guinea", "Papouasie-Nouvelle-Guinée (la)", "PG", "PNG", "598"},
|
||||
{"Paraguay", "Paraguay (le)", "PY", "PRY", "600"},
|
||||
{"Peru", "Pérou (le)", "PE", "PER", "604"},
|
||||
{"Philippines (the)", "Philippines (les)", "PH", "PHL", "608"},
|
||||
{"Pitcairn", "Pitcairn", "PN", "PCN", "612"},
|
||||
{"Poland", "Pologne (la)", "PL", "POL", "616"},
|
||||
{"Portugal", "Portugal (le)", "PT", "PRT", "620"},
|
||||
{"Guinea-Bissau", "Guinée-Bissau (la)", "GW", "GNB", "624"},
|
||||
{"Timor-Leste", "Timor-Leste (le)", "TL", "TLS", "626"},
|
||||
{"Puerto Rico", "Porto Rico", "PR", "PRI", "630"},
|
||||
{"Qatar", "Qatar (le)", "QA", "QAT", "634"},
|
||||
{"Réunion", "Réunion (La)", "RE", "REU", "638"},
|
||||
{"Romania", "Roumanie (la)", "RO", "ROU", "642"},
|
||||
{"Russian Federation (the)", "Russie (la Fédération de)", "RU", "RUS", "643"},
|
||||
{"Rwanda", "Rwanda (le)", "RW", "RWA", "646"},
|
||||
{"Saint Barthélemy", "Saint-Barthélemy", "BL", "BLM", "652"},
|
||||
{"Saint Helena, Ascension and Tristan da Cunha", "Sainte-Hélène, Ascension et Tristan da Cunha", "SH", "SHN", "654"},
|
||||
{"Saint Kitts and Nevis", "Saint-Kitts-et-Nevis", "KN", "KNA", "659"},
|
||||
{"Anguilla", "Anguilla", "AI", "AIA", "660"},
|
||||
{"Saint Lucia", "Sainte-Lucie", "LC", "LCA", "662"},
|
||||
{"Saint Martin (French part)", "Saint-Martin (partie française)", "MF", "MAF", "663"},
|
||||
{"Saint Pierre and Miquelon", "Saint-Pierre-et-Miquelon", "PM", "SPM", "666"},
|
||||
{"Saint Vincent and the Grenadines", "Saint-Vincent-et-les Grenadines", "VC", "VCT", "670"},
|
||||
{"San Marino", "Saint-Marin", "SM", "SMR", "674"},
|
||||
{"Sao Tome and Principe", "Sao Tomé-et-Principe", "ST", "STP", "678"},
|
||||
{"Saudi Arabia", "Arabie saoudite (l')", "SA", "SAU", "682"},
|
||||
{"Senegal", "Sénégal (le)", "SN", "SEN", "686"},
|
||||
{"Serbia", "Serbie (la)", "RS", "SRB", "688"},
|
||||
{"Seychelles", "Seychelles (les)", "SC", "SYC", "690"},
|
||||
{"Sierra Leone", "Sierra Leone (la)", "SL", "SLE", "694"},
|
||||
{"Singapore", "Singapour", "SG", "SGP", "702"},
|
||||
{"Slovakia", "Slovaquie (la)", "SK", "SVK", "703"},
|
||||
{"Viet Nam", "Viet Nam (le)", "VN", "VNM", "704"},
|
||||
{"Slovenia", "Slovénie (la)", "SI", "SVN", "705"},
|
||||
{"Somalia", "Somalie (la)", "SO", "SOM", "706"},
|
||||
{"South Africa", "Afrique du Sud (l')", "ZA", "ZAF", "710"},
|
||||
{"Zimbabwe", "Zimbabwe (le)", "ZW", "ZWE", "716"},
|
||||
{"Spain", "Espagne (l')", "ES", "ESP", "724"},
|
||||
{"South Sudan", "Soudan du Sud (le)", "SS", "SSD", "728"},
|
||||
{"Sudan (the)", "Soudan (le)", "SD", "SDN", "729"},
|
||||
{"Western Sahara*", "Sahara occidental (le)*", "EH", "ESH", "732"},
|
||||
{"Suriname", "Suriname (le)", "SR", "SUR", "740"},
|
||||
{"Svalbard and Jan Mayen", "Svalbard et l'Île Jan Mayen (le)", "SJ", "SJM", "744"},
|
||||
{"Swaziland", "Swaziland (le)", "SZ", "SWZ", "748"},
|
||||
{"Sweden", "Suède (la)", "SE", "SWE", "752"},
|
||||
{"Switzerland", "Suisse (la)", "CH", "CHE", "756"},
|
||||
{"Syrian Arab Republic", "République arabe syrienne (la)", "SY", "SYR", "760"},
|
||||
{"Tajikistan", "Tadjikistan (le)", "TJ", "TJK", "762"},
|
||||
{"Thailand", "Thaïlande (la)", "TH", "THA", "764"},
|
||||
{"Togo", "Togo (le)", "TG", "TGO", "768"},
|
||||
{"Tokelau", "Tokelau (les)", "TK", "TKL", "772"},
|
||||
{"Tonga", "Tonga (les)", "TO", "TON", "776"},
|
||||
{"Trinidad and Tobago", "Trinité-et-Tobago (la)", "TT", "TTO", "780"},
|
||||
{"United Arab Emirates (the)", "Émirats arabes unis (les)", "AE", "ARE", "784"},
|
||||
{"Tunisia", "Tunisie (la)", "TN", "TUN", "788"},
|
||||
{"Turkey", "Turquie (la)", "TR", "TUR", "792"},
|
||||
{"Turkmenistan", "Turkménistan (le)", "TM", "TKM", "795"},
|
||||
{"Turks and Caicos Islands (the)", "Turks-et-Caïcos (les Îles)", "TC", "TCA", "796"},
|
||||
{"Tuvalu", "Tuvalu (les)", "TV", "TUV", "798"},
|
||||
{"Uganda", "Ouganda (l')", "UG", "UGA", "800"},
|
||||
{"Ukraine", "Ukraine (l')", "UA", "UKR", "804"},
|
||||
{"Macedonia (the former Yugoslav Republic of)", "Macédoine (l'ex‑République yougoslave de)", "MK", "MKD", "807"},
|
||||
{"Egypt", "Égypte (l')", "EG", "EGY", "818"},
|
||||
{"United Kingdom of Great Britain and Northern Ireland (the)", "Royaume-Uni de Grande-Bretagne et d'Irlande du Nord (le)", "GB", "GBR", "826"},
|
||||
{"Guernsey", "Guernesey", "GG", "GGY", "831"},
|
||||
{"Jersey", "Jersey", "JE", "JEY", "832"},
|
||||
{"Isle of Man", "Île de Man", "IM", "IMN", "833"},
|
||||
{"Tanzania, United Republic of", "Tanzanie, République-Unie de", "TZ", "TZA", "834"},
|
||||
{"United States of America (the)", "États-Unis d'Amérique (les)", "US", "USA", "840"},
|
||||
{"Virgin Islands (U.S.)", "Vierges des États-Unis (les Îles)", "VI", "VIR", "850"},
|
||||
{"Burkina Faso", "Burkina Faso (le)", "BF", "BFA", "854"},
|
||||
{"Uruguay", "Uruguay (l')", "UY", "URY", "858"},
|
||||
{"Uzbekistan", "Ouzbékistan (l')", "UZ", "UZB", "860"},
|
||||
{"Venezuela (Bolivarian Republic of)", "Venezuela (République bolivarienne du)", "VE", "VEN", "862"},
|
||||
{"Wallis and Futuna", "Wallis-et-Futuna", "WF", "WLF", "876"},
|
||||
{"Samoa", "Samoa (le)", "WS", "WSM", "882"},
|
||||
{"Yemen", "Yémen (le)", "YE", "YEM", "887"},
|
||||
{"Zambia", "Zambie (la)", "ZM", "ZMB", "894"},
|
||||
}
|
||||
|
||||
// ISO4217List is the list of ISO currency codes
|
||||
var ISO4217List = []string{
|
||||
"AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN",
|
||||
"BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BOV", "BRL", "BSD", "BTN", "BWP", "BYN", "BZD",
|
||||
"CAD", "CDF", "CHE", "CHF", "CHW", "CLF", "CLP", "CNY", "COP", "COU", "CRC", "CUC", "CUP", "CVE", "CZK",
|
||||
"DJF", "DKK", "DOP", "DZD",
|
||||
"EGP", "ERN", "ETB", "EUR",
|
||||
"FJD", "FKP",
|
||||
"GBP", "GEL", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD",
|
||||
"HKD", "HNL", "HRK", "HTG", "HUF",
|
||||
"IDR", "ILS", "INR", "IQD", "IRR", "ISK",
|
||||
"JMD", "JOD", "JPY",
|
||||
"KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT",
|
||||
"LAK", "LBP", "LKR", "LRD", "LSL", "LYD",
|
||||
"MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRO", "MUR", "MVR", "MWK", "MXN", "MXV", "MYR", "MZN",
|
||||
"NAD", "NGN", "NIO", "NOK", "NPR", "NZD",
|
||||
"OMR",
|
||||
"PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG",
|
||||
"QAR",
|
||||
"RON", "RSD", "RUB", "RWF",
|
||||
"SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLL", "SOS", "SRD", "SSP", "STD", "SVC", "SYP", "SZL",
|
||||
"THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TWD", "TZS",
|
||||
"UAH", "UGX", "USD", "USN", "UYI", "UYU", "UZS",
|
||||
"VEF", "VND", "VUV",
|
||||
"WST",
|
||||
"XAF", "XAG", "XAU", "XBA", "XBB", "XBC", "XBD", "XCD", "XDR", "XOF", "XPD", "XPF", "XPT", "XSU", "XTS", "XUA", "XXX",
|
||||
"YER",
|
||||
"ZAR", "ZMW", "ZWL",
|
||||
}
|
||||
|
||||
// ISO693Entry stores ISO language codes
|
||||
type ISO693Entry struct {
|
||||
Alpha3bCode string
|
||||
Alpha2Code string
|
||||
English string
|
||||
}
|
||||
|
||||
//ISO693List based on http://data.okfn.org/data/core/language-codes/r/language-codes-3b2.json
|
||||
var ISO693List = []ISO693Entry{
|
||||
{Alpha3bCode: "aar", Alpha2Code: "aa", English: "Afar"},
|
||||
{Alpha3bCode: "abk", Alpha2Code: "ab", English: "Abkhazian"},
|
||||
{Alpha3bCode: "afr", Alpha2Code: "af", English: "Afrikaans"},
|
||||
{Alpha3bCode: "aka", Alpha2Code: "ak", English: "Akan"},
|
||||
{Alpha3bCode: "alb", Alpha2Code: "sq", English: "Albanian"},
|
||||
{Alpha3bCode: "amh", Alpha2Code: "am", English: "Amharic"},
|
||||
{Alpha3bCode: "ara", Alpha2Code: "ar", English: "Arabic"},
|
||||
{Alpha3bCode: "arg", Alpha2Code: "an", English: "Aragonese"},
|
||||
{Alpha3bCode: "arm", Alpha2Code: "hy", English: "Armenian"},
|
||||
{Alpha3bCode: "asm", Alpha2Code: "as", English: "Assamese"},
|
||||
{Alpha3bCode: "ava", Alpha2Code: "av", English: "Avaric"},
|
||||
{Alpha3bCode: "ave", Alpha2Code: "ae", English: "Avestan"},
|
||||
{Alpha3bCode: "aym", Alpha2Code: "ay", English: "Aymara"},
|
||||
{Alpha3bCode: "aze", Alpha2Code: "az", English: "Azerbaijani"},
|
||||
{Alpha3bCode: "bak", Alpha2Code: "ba", English: "Bashkir"},
|
||||
{Alpha3bCode: "bam", Alpha2Code: "bm", English: "Bambara"},
|
||||
{Alpha3bCode: "baq", Alpha2Code: "eu", English: "Basque"},
|
||||
{Alpha3bCode: "bel", Alpha2Code: "be", English: "Belarusian"},
|
||||
{Alpha3bCode: "ben", Alpha2Code: "bn", English: "Bengali"},
|
||||
{Alpha3bCode: "bih", Alpha2Code: "bh", English: "Bihari languages"},
|
||||
{Alpha3bCode: "bis", Alpha2Code: "bi", English: "Bislama"},
|
||||
{Alpha3bCode: "bos", Alpha2Code: "bs", English: "Bosnian"},
|
||||
{Alpha3bCode: "bre", Alpha2Code: "br", English: "Breton"},
|
||||
{Alpha3bCode: "bul", Alpha2Code: "bg", English: "Bulgarian"},
|
||||
{Alpha3bCode: "bur", Alpha2Code: "my", English: "Burmese"},
|
||||
{Alpha3bCode: "cat", Alpha2Code: "ca", English: "Catalan; Valencian"},
|
||||
{Alpha3bCode: "cha", Alpha2Code: "ch", English: "Chamorro"},
|
||||
{Alpha3bCode: "che", Alpha2Code: "ce", English: "Chechen"},
|
||||
{Alpha3bCode: "chi", Alpha2Code: "zh", English: "Chinese"},
|
||||
{Alpha3bCode: "chu", Alpha2Code: "cu", English: "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic"},
|
||||
{Alpha3bCode: "chv", Alpha2Code: "cv", English: "Chuvash"},
|
||||
{Alpha3bCode: "cor", Alpha2Code: "kw", English: "Cornish"},
|
||||
{Alpha3bCode: "cos", Alpha2Code: "co", English: "Corsican"},
|
||||
{Alpha3bCode: "cre", Alpha2Code: "cr", English: "Cree"},
|
||||
{Alpha3bCode: "cze", Alpha2Code: "cs", English: "Czech"},
|
||||
{Alpha3bCode: "dan", Alpha2Code: "da", English: "Danish"},
|
||||
{Alpha3bCode: "div", Alpha2Code: "dv", English: "Divehi; Dhivehi; Maldivian"},
|
||||
{Alpha3bCode: "dut", Alpha2Code: "nl", English: "Dutch; Flemish"},
|
||||
{Alpha3bCode: "dzo", Alpha2Code: "dz", English: "Dzongkha"},
|
||||
{Alpha3bCode: "eng", Alpha2Code: "en", English: "English"},
|
||||
{Alpha3bCode: "epo", Alpha2Code: "eo", English: "Esperanto"},
|
||||
{Alpha3bCode: "est", Alpha2Code: "et", English: "Estonian"},
|
||||
{Alpha3bCode: "ewe", Alpha2Code: "ee", English: "Ewe"},
|
||||
{Alpha3bCode: "fao", Alpha2Code: "fo", English: "Faroese"},
|
||||
{Alpha3bCode: "fij", Alpha2Code: "fj", English: "Fijian"},
|
||||
{Alpha3bCode: "fin", Alpha2Code: "fi", English: "Finnish"},
|
||||
{Alpha3bCode: "fre", Alpha2Code: "fr", English: "French"},
|
||||
{Alpha3bCode: "fry", Alpha2Code: "fy", English: "Western Frisian"},
|
||||
{Alpha3bCode: "ful", Alpha2Code: "ff", English: "Fulah"},
|
||||
{Alpha3bCode: "geo", Alpha2Code: "ka", English: "Georgian"},
|
||||
{Alpha3bCode: "ger", Alpha2Code: "de", English: "German"},
|
||||
{Alpha3bCode: "gla", Alpha2Code: "gd", English: "Gaelic; Scottish Gaelic"},
|
||||
{Alpha3bCode: "gle", Alpha2Code: "ga", English: "Irish"},
|
||||
{Alpha3bCode: "glg", Alpha2Code: "gl", English: "Galician"},
|
||||
{Alpha3bCode: "glv", Alpha2Code: "gv", English: "Manx"},
|
||||
{Alpha3bCode: "gre", Alpha2Code: "el", English: "Greek, Modern (1453-)"},
|
||||
{Alpha3bCode: "grn", Alpha2Code: "gn", English: "Guarani"},
|
||||
{Alpha3bCode: "guj", Alpha2Code: "gu", English: "Gujarati"},
|
||||
{Alpha3bCode: "hat", Alpha2Code: "ht", English: "Haitian; Haitian Creole"},
|
||||
{Alpha3bCode: "hau", Alpha2Code: "ha", English: "Hausa"},
|
||||
{Alpha3bCode: "heb", Alpha2Code: "he", English: "Hebrew"},
|
||||
{Alpha3bCode: "her", Alpha2Code: "hz", English: "Herero"},
|
||||
{Alpha3bCode: "hin", Alpha2Code: "hi", English: "Hindi"},
|
||||
{Alpha3bCode: "hmo", Alpha2Code: "ho", English: "Hiri Motu"},
|
||||
{Alpha3bCode: "hrv", Alpha2Code: "hr", English: "Croatian"},
|
||||
{Alpha3bCode: "hun", Alpha2Code: "hu", English: "Hungarian"},
|
||||
{Alpha3bCode: "ibo", Alpha2Code: "ig", English: "Igbo"},
|
||||
{Alpha3bCode: "ice", Alpha2Code: "is", English: "Icelandic"},
|
||||
{Alpha3bCode: "ido", Alpha2Code: "io", English: "Ido"},
|
||||
{Alpha3bCode: "iii", Alpha2Code: "ii", English: "Sichuan Yi; Nuosu"},
|
||||
{Alpha3bCode: "iku", Alpha2Code: "iu", English: "Inuktitut"},
|
||||
{Alpha3bCode: "ile", Alpha2Code: "ie", English: "Interlingue; Occidental"},
|
||||
{Alpha3bCode: "ina", Alpha2Code: "ia", English: "Interlingua (International Auxiliary Language Association)"},
|
||||
{Alpha3bCode: "ind", Alpha2Code: "id", English: "Indonesian"},
|
||||
{Alpha3bCode: "ipk", Alpha2Code: "ik", English: "Inupiaq"},
|
||||
{Alpha3bCode: "ita", Alpha2Code: "it", English: "Italian"},
|
||||
{Alpha3bCode: "jav", Alpha2Code: "jv", English: "Javanese"},
|
||||
{Alpha3bCode: "jpn", Alpha2Code: "ja", English: "Japanese"},
|
||||
{Alpha3bCode: "kal", Alpha2Code: "kl", English: "Kalaallisut; Greenlandic"},
|
||||
{Alpha3bCode: "kan", Alpha2Code: "kn", English: "Kannada"},
|
||||
{Alpha3bCode: "kas", Alpha2Code: "ks", English: "Kashmiri"},
|
||||
{Alpha3bCode: "kau", Alpha2Code: "kr", English: "Kanuri"},
|
||||
{Alpha3bCode: "kaz", Alpha2Code: "kk", English: "Kazakh"},
|
||||
{Alpha3bCode: "khm", Alpha2Code: "km", English: "Central Khmer"},
|
||||
{Alpha3bCode: "kik", Alpha2Code: "ki", English: "Kikuyu; Gikuyu"},
|
||||
{Alpha3bCode: "kin", Alpha2Code: "rw", English: "Kinyarwanda"},
|
||||
{Alpha3bCode: "kir", Alpha2Code: "ky", English: "Kirghiz; Kyrgyz"},
|
||||
{Alpha3bCode: "kom", Alpha2Code: "kv", English: "Komi"},
|
||||
{Alpha3bCode: "kon", Alpha2Code: "kg", English: "Kongo"},
|
||||
{Alpha3bCode: "kor", Alpha2Code: "ko", English: "Korean"},
|
||||
{Alpha3bCode: "kua", Alpha2Code: "kj", English: "Kuanyama; Kwanyama"},
|
||||
{Alpha3bCode: "kur", Alpha2Code: "ku", English: "Kurdish"},
|
||||
{Alpha3bCode: "lao", Alpha2Code: "lo", English: "Lao"},
|
||||
{Alpha3bCode: "lat", Alpha2Code: "la", English: "Latin"},
|
||||
{Alpha3bCode: "lav", Alpha2Code: "lv", English: "Latvian"},
|
||||
{Alpha3bCode: "lim", Alpha2Code: "li", English: "Limburgan; Limburger; Limburgish"},
|
||||
{Alpha3bCode: "lin", Alpha2Code: "ln", English: "Lingala"},
|
||||
{Alpha3bCode: "lit", Alpha2Code: "lt", English: "Lithuanian"},
|
||||
{Alpha3bCode: "ltz", Alpha2Code: "lb", English: "Luxembourgish; Letzeburgesch"},
|
||||
{Alpha3bCode: "lub", Alpha2Code: "lu", English: "Luba-Katanga"},
|
||||
{Alpha3bCode: "lug", Alpha2Code: "lg", English: "Ganda"},
|
||||
{Alpha3bCode: "mac", Alpha2Code: "mk", English: "Macedonian"},
|
||||
{Alpha3bCode: "mah", Alpha2Code: "mh", English: "Marshallese"},
|
||||
{Alpha3bCode: "mal", Alpha2Code: "ml", English: "Malayalam"},
|
||||
{Alpha3bCode: "mao", Alpha2Code: "mi", English: "Maori"},
|
||||
{Alpha3bCode: "mar", Alpha2Code: "mr", English: "Marathi"},
|
||||
{Alpha3bCode: "may", Alpha2Code: "ms", English: "Malay"},
|
||||
{Alpha3bCode: "mlg", Alpha2Code: "mg", English: "Malagasy"},
|
||||
{Alpha3bCode: "mlt", Alpha2Code: "mt", English: "Maltese"},
|
||||
{Alpha3bCode: "mon", Alpha2Code: "mn", English: "Mongolian"},
|
||||
{Alpha3bCode: "nau", Alpha2Code: "na", English: "Nauru"},
|
||||
{Alpha3bCode: "nav", Alpha2Code: "nv", English: "Navajo; Navaho"},
|
||||
{Alpha3bCode: "nbl", Alpha2Code: "nr", English: "Ndebele, South; South Ndebele"},
|
||||
{Alpha3bCode: "nde", Alpha2Code: "nd", English: "Ndebele, North; North Ndebele"},
|
||||
{Alpha3bCode: "ndo", Alpha2Code: "ng", English: "Ndonga"},
|
||||
{Alpha3bCode: "nep", Alpha2Code: "ne", English: "Nepali"},
|
||||
{Alpha3bCode: "nno", Alpha2Code: "nn", English: "Norwegian Nynorsk; Nynorsk, Norwegian"},
|
||||
{Alpha3bCode: "nob", Alpha2Code: "nb", English: "Bokmål, Norwegian; Norwegian Bokmål"},
|
||||
{Alpha3bCode: "nor", Alpha2Code: "no", English: "Norwegian"},
|
||||
{Alpha3bCode: "nya", Alpha2Code: "ny", English: "Chichewa; Chewa; Nyanja"},
|
||||
{Alpha3bCode: "oci", Alpha2Code: "oc", English: "Occitan (post 1500); Provençal"},
|
||||
{Alpha3bCode: "oji", Alpha2Code: "oj", English: "Ojibwa"},
|
||||
{Alpha3bCode: "ori", Alpha2Code: "or", English: "Oriya"},
|
||||
{Alpha3bCode: "orm", Alpha2Code: "om", English: "Oromo"},
|
||||
{Alpha3bCode: "oss", Alpha2Code: "os", English: "Ossetian; Ossetic"},
|
||||
{Alpha3bCode: "pan", Alpha2Code: "pa", English: "Panjabi; Punjabi"},
|
||||
{Alpha3bCode: "per", Alpha2Code: "fa", English: "Persian"},
|
||||
{Alpha3bCode: "pli", Alpha2Code: "pi", English: "Pali"},
|
||||
{Alpha3bCode: "pol", Alpha2Code: "pl", English: "Polish"},
|
||||
{Alpha3bCode: "por", Alpha2Code: "pt", English: "Portuguese"},
|
||||
{Alpha3bCode: "pus", Alpha2Code: "ps", English: "Pushto; Pashto"},
|
||||
{Alpha3bCode: "que", Alpha2Code: "qu", English: "Quechua"},
|
||||
{Alpha3bCode: "roh", Alpha2Code: "rm", English: "Romansh"},
|
||||
{Alpha3bCode: "rum", Alpha2Code: "ro", English: "Romanian; Moldavian; Moldovan"},
|
||||
{Alpha3bCode: "run", Alpha2Code: "rn", English: "Rundi"},
|
||||
{Alpha3bCode: "rus", Alpha2Code: "ru", English: "Russian"},
|
||||
{Alpha3bCode: "sag", Alpha2Code: "sg", English: "Sango"},
|
||||
{Alpha3bCode: "san", Alpha2Code: "sa", English: "Sanskrit"},
|
||||
{Alpha3bCode: "sin", Alpha2Code: "si", English: "Sinhala; Sinhalese"},
|
||||
{Alpha3bCode: "slo", Alpha2Code: "sk", English: "Slovak"},
|
||||
{Alpha3bCode: "slv", Alpha2Code: "sl", English: "Slovenian"},
|
||||
{Alpha3bCode: "sme", Alpha2Code: "se", English: "Northern Sami"},
|
||||
{Alpha3bCode: "smo", Alpha2Code: "sm", English: "Samoan"},
|
||||
{Alpha3bCode: "sna", Alpha2Code: "sn", English: "Shona"},
|
||||
{Alpha3bCode: "snd", Alpha2Code: "sd", English: "Sindhi"},
|
||||
{Alpha3bCode: "som", Alpha2Code: "so", English: "Somali"},
|
||||
{Alpha3bCode: "sot", Alpha2Code: "st", English: "Sotho, Southern"},
|
||||
{Alpha3bCode: "spa", Alpha2Code: "es", English: "Spanish; Castilian"},
|
||||
{Alpha3bCode: "srd", Alpha2Code: "sc", English: "Sardinian"},
|
||||
{Alpha3bCode: "srp", Alpha2Code: "sr", English: "Serbian"},
|
||||
{Alpha3bCode: "ssw", Alpha2Code: "ss", English: "Swati"},
|
||||
{Alpha3bCode: "sun", Alpha2Code: "su", English: "Sundanese"},
|
||||
{Alpha3bCode: "swa", Alpha2Code: "sw", English: "Swahili"},
|
||||
{Alpha3bCode: "swe", Alpha2Code: "sv", English: "Swedish"},
|
||||
{Alpha3bCode: "tah", Alpha2Code: "ty", English: "Tahitian"},
|
||||
{Alpha3bCode: "tam", Alpha2Code: "ta", English: "Tamil"},
|
||||
{Alpha3bCode: "tat", Alpha2Code: "tt", English: "Tatar"},
|
||||
{Alpha3bCode: "tel", Alpha2Code: "te", English: "Telugu"},
|
||||
{Alpha3bCode: "tgk", Alpha2Code: "tg", English: "Tajik"},
|
||||
{Alpha3bCode: "tgl", Alpha2Code: "tl", English: "Tagalog"},
|
||||
{Alpha3bCode: "tha", Alpha2Code: "th", English: "Thai"},
|
||||
{Alpha3bCode: "tib", Alpha2Code: "bo", English: "Tibetan"},
|
||||
{Alpha3bCode: "tir", Alpha2Code: "ti", English: "Tigrinya"},
|
||||
{Alpha3bCode: "ton", Alpha2Code: "to", English: "Tonga (Tonga Islands)"},
|
||||
{Alpha3bCode: "tsn", Alpha2Code: "tn", English: "Tswana"},
|
||||
{Alpha3bCode: "tso", Alpha2Code: "ts", English: "Tsonga"},
|
||||
{Alpha3bCode: "tuk", Alpha2Code: "tk", English: "Turkmen"},
|
||||
{Alpha3bCode: "tur", Alpha2Code: "tr", English: "Turkish"},
|
||||
{Alpha3bCode: "twi", Alpha2Code: "tw", English: "Twi"},
|
||||
{Alpha3bCode: "uig", Alpha2Code: "ug", English: "Uighur; Uyghur"},
|
||||
{Alpha3bCode: "ukr", Alpha2Code: "uk", English: "Ukrainian"},
|
||||
{Alpha3bCode: "urd", Alpha2Code: "ur", English: "Urdu"},
|
||||
{Alpha3bCode: "uzb", Alpha2Code: "uz", English: "Uzbek"},
|
||||
{Alpha3bCode: "ven", Alpha2Code: "ve", English: "Venda"},
|
||||
{Alpha3bCode: "vie", Alpha2Code: "vi", English: "Vietnamese"},
|
||||
{Alpha3bCode: "vol", Alpha2Code: "vo", English: "Volapük"},
|
||||
{Alpha3bCode: "wel", Alpha2Code: "cy", English: "Welsh"},
|
||||
{Alpha3bCode: "wln", Alpha2Code: "wa", English: "Walloon"},
|
||||
{Alpha3bCode: "wol", Alpha2Code: "wo", English: "Wolof"},
|
||||
{Alpha3bCode: "xho", Alpha2Code: "xh", English: "Xhosa"},
|
||||
{Alpha3bCode: "yid", Alpha2Code: "yi", English: "Yiddish"},
|
||||
{Alpha3bCode: "yor", Alpha2Code: "yo", English: "Yoruba"},
|
||||
{Alpha3bCode: "zha", Alpha2Code: "za", English: "Zhuang; Chuang"},
|
||||
{Alpha3bCode: "zul", Alpha2Code: "zu", English: "Zulu"},
|
||||
}
|
||||
264
vendor/github.com/asaskevich/govalidator/utils.go
generated
vendored
Normal file
264
vendor/github.com/asaskevich/govalidator/utils.go
generated
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
package govalidator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"html"
|
||||
"math"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Contains check if the string contains the substring.
|
||||
func Contains(str, substring string) bool {
|
||||
return strings.Contains(str, substring)
|
||||
}
|
||||
|
||||
// Matches check if string matches the pattern (pattern is regular expression)
|
||||
// In case of error return false
|
||||
func Matches(str, pattern string) bool {
|
||||
match, _ := regexp.MatchString(pattern, str)
|
||||
return match
|
||||
}
|
||||
|
||||
// LeftTrim trim characters from the left-side of the input.
|
||||
// If second argument is empty, it's will be remove leading spaces.
|
||||
func LeftTrim(str, chars string) string {
|
||||
if chars == "" {
|
||||
return strings.TrimLeftFunc(str, unicode.IsSpace)
|
||||
}
|
||||
r, _ := regexp.Compile("^[" + chars + "]+")
|
||||
return r.ReplaceAllString(str, "")
|
||||
}
|
||||
|
||||
// RightTrim trim characters from the right-side of the input.
|
||||
// If second argument is empty, it's will be remove spaces.
|
||||
func RightTrim(str, chars string) string {
|
||||
if chars == "" {
|
||||
return strings.TrimRightFunc(str, unicode.IsSpace)
|
||||
}
|
||||
r, _ := regexp.Compile("[" + chars + "]+$")
|
||||
return r.ReplaceAllString(str, "")
|
||||
}
|
||||
|
||||
// Trim trim characters from both sides of the input.
|
||||
// If second argument is empty, it's will be remove spaces.
|
||||
func Trim(str, chars string) string {
|
||||
return LeftTrim(RightTrim(str, chars), chars)
|
||||
}
|
||||
|
||||
// WhiteList remove characters that do not appear in the whitelist.
|
||||
func WhiteList(str, chars string) string {
|
||||
pattern := "[^" + chars + "]+"
|
||||
r, _ := regexp.Compile(pattern)
|
||||
return r.ReplaceAllString(str, "")
|
||||
}
|
||||
|
||||
// BlackList remove characters that appear in the blacklist.
|
||||
func BlackList(str, chars string) string {
|
||||
pattern := "[" + chars + "]+"
|
||||
r, _ := regexp.Compile(pattern)
|
||||
return r.ReplaceAllString(str, "")
|
||||
}
|
||||
|
||||
// StripLow remove characters with a numerical value < 32 and 127, mostly control characters.
|
||||
// If keep_new_lines is true, newline characters are preserved (\n and \r, hex 0xA and 0xD).
|
||||
func StripLow(str string, keepNewLines bool) string {
|
||||
chars := ""
|
||||
if keepNewLines {
|
||||
chars = "\x00-\x09\x0B\x0C\x0E-\x1F\x7F"
|
||||
} else {
|
||||
chars = "\x00-\x1F\x7F"
|
||||
}
|
||||
return BlackList(str, chars)
|
||||
}
|
||||
|
||||
// ReplacePattern replace regular expression pattern in string
|
||||
func ReplacePattern(str, pattern, replace string) string {
|
||||
r, _ := regexp.Compile(pattern)
|
||||
return r.ReplaceAllString(str, replace)
|
||||
}
|
||||
|
||||
// Escape replace <, >, & and " with HTML entities.
|
||||
var Escape = html.EscapeString
|
||||
|
||||
func addSegment(inrune, segment []rune) []rune {
|
||||
if len(segment) == 0 {
|
||||
return inrune
|
||||
}
|
||||
if len(inrune) != 0 {
|
||||
inrune = append(inrune, '_')
|
||||
}
|
||||
inrune = append(inrune, segment...)
|
||||
return inrune
|
||||
}
|
||||
|
||||
// UnderscoreToCamelCase converts from underscore separated form to camel case form.
|
||||
// Ex.: my_func => MyFunc
|
||||
func UnderscoreToCamelCase(s string) string {
|
||||
return strings.Replace(strings.Title(strings.Replace(strings.ToLower(s), "_", " ", -1)), " ", "", -1)
|
||||
}
|
||||
|
||||
// CamelCaseToUnderscore converts from camel case form to underscore separated form.
|
||||
// Ex.: MyFunc => my_func
|
||||
func CamelCaseToUnderscore(str string) string {
|
||||
var output []rune
|
||||
var segment []rune
|
||||
for _, r := range str {
|
||||
|
||||
// not treat number as separate segment
|
||||
if !unicode.IsLower(r) && string(r) != "_" && !unicode.IsNumber(r) {
|
||||
output = addSegment(output, segment)
|
||||
segment = nil
|
||||
}
|
||||
segment = append(segment, unicode.ToLower(r))
|
||||
}
|
||||
output = addSegment(output, segment)
|
||||
return string(output)
|
||||
}
|
||||
|
||||
// Reverse return reversed string
|
||||
func Reverse(s string) string {
|
||||
r := []rune(s)
|
||||
for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
|
||||
r[i], r[j] = r[j], r[i]
|
||||
}
|
||||
return string(r)
|
||||
}
|
||||
|
||||
// GetLines split string by "\n" and return array of lines
|
||||
func GetLines(s string) []string {
|
||||
return strings.Split(s, "\n")
|
||||
}
|
||||
|
||||
// GetLine return specified line of multiline string
|
||||
func GetLine(s string, index int) (string, error) {
|
||||
lines := GetLines(s)
|
||||
if index < 0 || index >= len(lines) {
|
||||
return "", errors.New("line index out of bounds")
|
||||
}
|
||||
return lines[index], nil
|
||||
}
|
||||
|
||||
// RemoveTags remove all tags from HTML string
|
||||
func RemoveTags(s string) string {
|
||||
return ReplacePattern(s, "<[^>]*>", "")
|
||||
}
|
||||
|
||||
// SafeFileName return safe string that can be used in file names
|
||||
func SafeFileName(str string) string {
|
||||
name := strings.ToLower(str)
|
||||
name = path.Clean(path.Base(name))
|
||||
name = strings.Trim(name, " ")
|
||||
separators, err := regexp.Compile(`[ &_=+:]`)
|
||||
if err == nil {
|
||||
name = separators.ReplaceAllString(name, "-")
|
||||
}
|
||||
legal, err := regexp.Compile(`[^[:alnum:]-.]`)
|
||||
if err == nil {
|
||||
name = legal.ReplaceAllString(name, "")
|
||||
}
|
||||
for strings.Contains(name, "--") {
|
||||
name = strings.Replace(name, "--", "-", -1)
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// NormalizeEmail canonicalize an email address.
|
||||
// The local part of the email address is lowercased for all domains; the hostname is always lowercased and
|
||||
// the local part of the email address is always lowercased for hosts that are known to be case-insensitive (currently only GMail).
|
||||
// Normalization follows special rules for known providers: currently, GMail addresses have dots removed in the local part and
|
||||
// are stripped of tags (e.g. some.one+tag@gmail.com becomes someone@gmail.com) and all @googlemail.com addresses are
|
||||
// normalized to @gmail.com.
|
||||
func NormalizeEmail(str string) (string, error) {
|
||||
if !IsEmail(str) {
|
||||
return "", fmt.Errorf("%s is not an email", str)
|
||||
}
|
||||
parts := strings.Split(str, "@")
|
||||
parts[0] = strings.ToLower(parts[0])
|
||||
parts[1] = strings.ToLower(parts[1])
|
||||
if parts[1] == "gmail.com" || parts[1] == "googlemail.com" {
|
||||
parts[1] = "gmail.com"
|
||||
parts[0] = strings.Split(ReplacePattern(parts[0], `\.`, ""), "+")[0]
|
||||
}
|
||||
return strings.Join(parts, "@"), nil
|
||||
}
|
||||
|
||||
// Truncate a string to the closest length without breaking words.
|
||||
func Truncate(str string, length int, ending string) string {
|
||||
var aftstr, befstr string
|
||||
if len(str) > length {
|
||||
words := strings.Fields(str)
|
||||
before, present := 0, 0
|
||||
for i := range words {
|
||||
befstr = aftstr
|
||||
before = present
|
||||
aftstr = aftstr + words[i] + " "
|
||||
present = len(aftstr)
|
||||
if present > length && i != 0 {
|
||||
if (length - before) < (present - length) {
|
||||
return Trim(befstr, " /\\.,\"'#!?&@+-") + ending
|
||||
}
|
||||
return Trim(aftstr, " /\\.,\"'#!?&@+-") + ending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// PadLeft pad left side of string if size of string is less then indicated pad length
|
||||
func PadLeft(str string, padStr string, padLen int) string {
|
||||
return buildPadStr(str, padStr, padLen, true, false)
|
||||
}
|
||||
|
||||
// PadRight pad right side of string if size of string is less then indicated pad length
|
||||
func PadRight(str string, padStr string, padLen int) string {
|
||||
return buildPadStr(str, padStr, padLen, false, true)
|
||||
}
|
||||
|
||||
// PadBoth pad sides of string if size of string is less then indicated pad length
|
||||
func PadBoth(str string, padStr string, padLen int) string {
|
||||
return buildPadStr(str, padStr, padLen, true, true)
|
||||
}
|
||||
|
||||
// PadString either left, right or both sides, not the padding string can be unicode and more then one
|
||||
// character
|
||||
func buildPadStr(str string, padStr string, padLen int, padLeft bool, padRight bool) string {
|
||||
|
||||
// When padded length is less then the current string size
|
||||
if padLen < utf8.RuneCountInString(str) {
|
||||
return str
|
||||
}
|
||||
|
||||
padLen -= utf8.RuneCountInString(str)
|
||||
|
||||
targetLen := padLen
|
||||
|
||||
targetLenLeft := targetLen
|
||||
targetLenRight := targetLen
|
||||
if padLeft && padRight {
|
||||
targetLenLeft = padLen / 2
|
||||
targetLenRight = padLen - targetLenLeft
|
||||
}
|
||||
|
||||
strToRepeatLen := utf8.RuneCountInString(padStr)
|
||||
|
||||
repeatTimes := int(math.Ceil(float64(targetLen) / float64(strToRepeatLen)))
|
||||
repeatedString := strings.Repeat(padStr, repeatTimes)
|
||||
|
||||
leftSide := ""
|
||||
if padLeft {
|
||||
leftSide = repeatedString[0:targetLenLeft]
|
||||
}
|
||||
|
||||
rightSide := ""
|
||||
if padRight {
|
||||
rightSide = repeatedString[0:targetLenRight]
|
||||
}
|
||||
|
||||
return leftSide + str + rightSide
|
||||
}
|
||||
17
vendor/github.com/asaskevich/govalidator/utils_benchmark_test.go
generated
vendored
Normal file
17
vendor/github.com/asaskevich/govalidator/utils_benchmark_test.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package govalidator
|
||||
|
||||
import "testing"
|
||||
|
||||
func BenchmarkContains(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
Contains("a0b01c012deffghijklmnopqrstu0123456vwxyz", "0123456789")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMatches(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
Matches("alfkjl12309fdjldfsa209jlksdfjLAKJjs9uJH234", "[\\w\\d]+")
|
||||
}
|
||||
}
|
||||
502
vendor/github.com/asaskevich/govalidator/utils_test.go
generated
vendored
Normal file
502
vendor/github.com/asaskevich/govalidator/utils_test.go
generated
vendored
Normal file
@@ -0,0 +1,502 @@
|
||||
package govalidator
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestContains(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param1 string
|
||||
param2 string
|
||||
expected bool
|
||||
}{
|
||||
{"abacada", "", true},
|
||||
{"abacada", "ritir", false},
|
||||
{"abacada", "a", true},
|
||||
{"abacada", "aca", true},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := Contains(test.param1, test.param2)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected Contains(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatches(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param1 string
|
||||
param2 string
|
||||
expected bool
|
||||
}{
|
||||
{"123456789", "[0-9]+", true},
|
||||
{"abacada", "cab$", false},
|
||||
{"111222333", "((111|222|333)+)+", true},
|
||||
{"abacaba", "((123+]", false},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := Matches(test.param1, test.param2)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected Matches(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLeftTrim(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param1 string
|
||||
param2 string
|
||||
expected string
|
||||
}{
|
||||
{" \r\n\tfoo \r\n\t ", "", "foo \r\n\t "},
|
||||
{"010100201000", "01", "201000"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := LeftTrim(test.param1, test.param2)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected LeftTrim(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRightTrim(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param1 string
|
||||
param2 string
|
||||
expected string
|
||||
}{
|
||||
{" \r\n\tfoo \r\n\t ", "", " \r\n\tfoo"},
|
||||
{"010100201000", "01", "0101002"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := RightTrim(test.param1, test.param2)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected RightTrim(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrim(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param1 string
|
||||
param2 string
|
||||
expected string
|
||||
}{
|
||||
{" \r\n\tfoo \r\n\t ", "", "foo"},
|
||||
{"010100201000", "01", "2"},
|
||||
{"1234567890987654321", "1-8", "909"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := Trim(test.param1, test.param2)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected Trim(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This small example illustrate how to work with Trim function.
|
||||
func ExampleTrim() {
|
||||
// Remove from left and right spaces and "\r", "\n", "\t" characters
|
||||
println(Trim(" \r\r\ntext\r \t\n", "") == "text")
|
||||
// Remove from left and right characters that are between "1" and "8".
|
||||
// "1-8" is like full list "12345678".
|
||||
println(Trim("1234567890987654321", "1-8") == "909")
|
||||
}
|
||||
|
||||
func TestWhiteList(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param1 string
|
||||
param2 string
|
||||
expected string
|
||||
}{
|
||||
{"abcdef", "abc", "abc"},
|
||||
{"aaaaaaaaaabbbbbbbbbb", "abc", "aaaaaaaaaabbbbbbbbbb"},
|
||||
{"a1b2c3", "abc", "abc"},
|
||||
{" ", "abc", ""},
|
||||
{"a3a43a5a4a3a2a23a4a5a4a3a4", "a-z", "aaaaaaaaaaaa"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := WhiteList(test.param1, test.param2)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected WhiteList(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This small example illustrate how to work with WhiteList function.
|
||||
func ExampleWhiteList() {
|
||||
// Remove all characters from string ignoring characters between "a" and "z"
|
||||
println(WhiteList("a3a43a5a4a3a2a23a4a5a4a3a4", "a-z") == "aaaaaaaaaaaa")
|
||||
}
|
||||
|
||||
func TestBlackList(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param1 string
|
||||
param2 string
|
||||
expected string
|
||||
}{
|
||||
{"abcdef", "abc", "def"},
|
||||
{"aaaaaaaaaabbbbbbbbbb", "abc", ""},
|
||||
{"a1b2c3", "abc", "123"},
|
||||
{" ", "abc", " "},
|
||||
{"a3a43a5a4a3a2a23a4a5a4a3a4", "a-z", "34354322345434"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := BlackList(test.param1, test.param2)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected BlackList(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStripLow(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param1 string
|
||||
param2 bool
|
||||
expected string
|
||||
}{
|
||||
{"foo\x00", false, "foo"},
|
||||
{"\x7Ffoo\x02", false, "foo"},
|
||||
{"\x01\x09", false, ""},
|
||||
{"foo\x0A\x0D", false, "foo"},
|
||||
{"perch\u00e9", false, "perch\u00e9"},
|
||||
{"\u20ac", false, "\u20ac"},
|
||||
{"\u2206\x0A", false, "\u2206"},
|
||||
{"foo\x0A\x0D", true, "foo\x0A\x0D"},
|
||||
{"\x03foo\x0A\x0D", true, "foo\x0A\x0D"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := StripLow(test.param1, test.param2)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected StripLow(%q,%t) to be %v, got %v", test.param1, test.param2, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplacePattern(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param1 string
|
||||
param2 string
|
||||
param3 string
|
||||
expected string
|
||||
}{
|
||||
{"ab123ba", "[0-9]+", "aca", "abacaba"},
|
||||
{"abacaba", "[0-9]+", "aca", "abacaba"},
|
||||
{"httpftp://github.comio", "(ftp|io)", "", "http://github.com"},
|
||||
{"aaaaaaaaaa", "a", "", ""},
|
||||
{"http123123ftp://git534543hub.comio", "(ftp|io|[0-9]+)", "", "http://github.com"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := ReplacePattern(test.param1, test.param2, test.param3)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected ReplacePattern(%q,%q,%q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This small example illustrate how to work with ReplacePattern function.
|
||||
func ExampleReplacePattern() {
|
||||
// Replace in "http123123ftp://git534543hub.comio" following (pattern "(ftp|io|[0-9]+)"):
|
||||
// - Sequence "ftp".
|
||||
// - Sequence "io".
|
||||
// - Sequence of digits.
|
||||
// with empty string.
|
||||
println(ReplacePattern("http123123ftp://git534543hub.comio", "(ftp|io|[0-9]+)", "") == "http://github.com")
|
||||
}
|
||||
|
||||
func TestEscape(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param string
|
||||
expected string
|
||||
}{
|
||||
{`<img alt="foo&bar">`, "<img alt="foo&bar">"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := Escape(test.param)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected Escape(%q) to be %v, got %v", test.param, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnderscoreToCamelCase(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param string
|
||||
expected string
|
||||
}{
|
||||
{"a_b_c", "ABC"},
|
||||
{"my_func", "MyFunc"},
|
||||
{"1ab_cd", "1abCd"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := UnderscoreToCamelCase(test.param)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected UnderscoreToCamelCase(%q) to be %v, got %v", test.param, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCamelCaseToUnderscore(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param string
|
||||
expected string
|
||||
}{
|
||||
{"MyFunc", "my_func"},
|
||||
{"ABC", "a_b_c"},
|
||||
{"1B", "1_b"},
|
||||
{"foo_bar", "foo_bar"},
|
||||
{"FooV2Bar", "foo_v2_bar"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := CamelCaseToUnderscore(test.param)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected CamelCaseToUnderscore(%q) to be %v, got %v", test.param, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReverse(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param string
|
||||
expected string
|
||||
}{
|
||||
{"abc", "cba"},
|
||||
{"カタカナ", "ナカタカ"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := Reverse(test.param)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected Reverse(%q) to be %v, got %v", test.param, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetLines(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param string
|
||||
expected []string
|
||||
}{
|
||||
{"abc", []string{"abc"}},
|
||||
{"a\nb\nc", []string{"a", "b", "c"}},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := GetLines(test.param)
|
||||
if !reflect.DeepEqual(actual, test.expected) {
|
||||
t.Errorf("Expected GetLines(%q) to be %v, got %v", test.param, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetLine(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param1 string
|
||||
param2 int
|
||||
expected string
|
||||
}{
|
||||
{"abc", 0, "abc"},
|
||||
{"a\nb\nc", 0, "a"},
|
||||
{"abc", -1, ""},
|
||||
{"abacaba\n", 1, ""},
|
||||
{"abc", 3, ""},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual, _ := GetLine(test.param1, test.param2)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected GetLine(%q, %d) to be %v, got %v", test.param1, test.param2, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveTags(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param string
|
||||
expected string
|
||||
}{
|
||||
{"abc", "abc"},
|
||||
{"<!-- Test -->", ""},
|
||||
{"<div><div><p><a>Text</a></p></div></div>", "Text"},
|
||||
{`<a href="#">Link</a>`, "Link"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := RemoveTags(test.param)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected RemoveTags(%q) to be %v, got %v", test.param, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSafeFileName(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param string
|
||||
expected string
|
||||
}{
|
||||
{"abc", "abc"},
|
||||
{"123456789 '_-?ASDF@£$%£%^é.html", "123456789-asdf.html"},
|
||||
{"ReadMe.md", "readme.md"},
|
||||
{"file:///c:/test.go", "test.go"},
|
||||
{"../../../Hello World!.txt", "hello-world.txt"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := SafeFileName(test.param)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected SafeFileName(%q) to be %v, got %v", test.param, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeEmail(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param string
|
||||
expected string
|
||||
}{
|
||||
{`test@me.com`, `test@me.com`},
|
||||
{`some.name@gmail.com`, `somename@gmail.com`},
|
||||
{`some.name@googlemail.com`, `somename@gmail.com`},
|
||||
{`some.name+extension@gmail.com`, `somename@gmail.com`},
|
||||
{`some.name+extension@googlemail.com`, `somename@gmail.com`},
|
||||
{`some.name.middlename+extension@gmail.com`, `somenamemiddlename@gmail.com`},
|
||||
{`some.name.middlename+extension@googlemail.com`, `somenamemiddlename@gmail.com`},
|
||||
{`some.name.midd.lena.me.+extension@gmail.com`, `somenamemiddlename@gmail.com`},
|
||||
{`some.name.midd.lena.me.+extension@googlemail.com`, `somenamemiddlename@gmail.com`},
|
||||
{`some.name+extension@unknown.com`, `some.name+extension@unknown.com`},
|
||||
// TODO: {`hans@m端ller.com`, `hans@m端ller.com`},
|
||||
{`hans`, ``},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual, err := NormalizeEmail(test.param)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected NormalizeEmail(%q) to be %v, got %v, err %v", test.param, test.expected, actual, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTruncate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param1 string
|
||||
param2 int
|
||||
param3 string
|
||||
expected string
|
||||
}{
|
||||
{`Lorem ipsum dolor sit amet, consectetur adipiscing elit.`, 25, `...`, `Lorem ipsum dolor sit amet...`},
|
||||
{`Measuring programming progress by lines of code is like measuring aircraft building progress by weight.`, 35, ` new born babies!`, `Measuring programming progress by new born babies!`},
|
||||
{`Testestestestestestestestestest testestestestestestestestest`, 7, `...`, `Testestestestestestestestestest...`},
|
||||
{`Testing`, 7, `...`, `Testing`},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := Truncate(test.param1, test.param2, test.param3)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected Truncate(%q, %d, %q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPadLeft(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param1 string
|
||||
param2 string
|
||||
param3 int
|
||||
expected string
|
||||
}{
|
||||
{"こんにちは", "xyz", 12, "xyzxyzxこんにちは"},
|
||||
{"こんにちは", "xyz", 11, "xyzxyzこんにちは"},
|
||||
{"abc", "x", 5, "xxabc"},
|
||||
{"abc", "xyz", 5, "xyabc"},
|
||||
{"abcde", "xyz", 5, "abcde"},
|
||||
{"abcde", "xyz", 4, "abcde"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := PadLeft(test.param1, test.param2, test.param3)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected PadLeft(%q,%q,%q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPadRight(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param1 string
|
||||
param2 string
|
||||
param3 int
|
||||
expected string
|
||||
}{
|
||||
{"こんにちは", "xyz", 12, "こんにちはxyzxyzx"},
|
||||
{"こんにちは", "xyz", 11, "こんにちはxyzxyz"},
|
||||
{"abc", "x", 5, "abcxx"},
|
||||
{"abc", "xyz", 5, "abcxy"},
|
||||
{"abcde", "xyz", 5, "abcde"},
|
||||
{"abcde", "xyz", 4, "abcde"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := PadRight(test.param1, test.param2, test.param3)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected PadRight(%q,%q,%q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPadBoth(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var tests = []struct {
|
||||
param1 string
|
||||
param2 string
|
||||
param3 int
|
||||
expected string
|
||||
}{
|
||||
{"こんにちは", "xyz", 12, "xyzこんにちはxyzx"},
|
||||
{"こんにちは", "xyz", 11, "xyzこんにちはxyz"},
|
||||
{"abc", "x", 5, "xabcx"},
|
||||
{"abc", "xyz", 5, "xabcx"},
|
||||
{"abcde", "xyz", 5, "abcde"},
|
||||
{"abcde", "xyz", 4, "abcde"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := PadBoth(test.param1, test.param2, test.param3)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected PadBoth(%q,%q,%q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
1213
vendor/github.com/asaskevich/govalidator/validator.go
generated
vendored
Normal file
1213
vendor/github.com/asaskevich/govalidator/validator.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3216
vendor/github.com/asaskevich/govalidator/validator_test.go
generated
vendored
Normal file
3216
vendor/github.com/asaskevich/govalidator/validator_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
15
vendor/github.com/asaskevich/govalidator/wercker.yml
generated
vendored
Normal file
15
vendor/github.com/asaskevich/govalidator/wercker.yml
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
box: golang
|
||||
build:
|
||||
steps:
|
||||
- setup-go-workspace
|
||||
|
||||
- script:
|
||||
name: go get
|
||||
code: |
|
||||
go version
|
||||
go get -t ./...
|
||||
|
||||
- script:
|
||||
name: go test
|
||||
code: |
|
||||
go test -race ./...
|
||||
4
vendor/github.com/docker/docker/.dockerignore
generated
vendored
Normal file
4
vendor/github.com/docker/docker/.dockerignore
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
bundles
|
||||
.gopath
|
||||
vendor/pkg
|
||||
.go-pkg-cache
|
||||
64
vendor/github.com/docker/docker/.github/ISSUE_TEMPLATE.md
generated
vendored
Normal file
64
vendor/github.com/docker/docker/.github/ISSUE_TEMPLATE.md
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
<!--
|
||||
If you are reporting a new issue, make sure that we do not have any duplicates
|
||||
already open. You can ensure this by searching the issue list for this
|
||||
repository. If there is a duplicate, please close your issue and add a comment
|
||||
to the existing issue instead.
|
||||
|
||||
If you suspect your issue is a bug, please edit your issue description to
|
||||
include the BUG REPORT INFORMATION shown below. If you fail to provide this
|
||||
information within 7 days, we cannot debug your issue and will close it. We
|
||||
will, however, reopen it if you later provide the information.
|
||||
|
||||
For more information about reporting issues, see
|
||||
https://github.com/docker/docker/blob/master/CONTRIBUTING.md#reporting-other-issues
|
||||
|
||||
---------------------------------------------------
|
||||
GENERAL SUPPORT INFORMATION
|
||||
---------------------------------------------------
|
||||
|
||||
The GitHub issue tracker is for bug reports and feature requests.
|
||||
General support can be found at the following locations:
|
||||
|
||||
- Docker Support Forums - https://forums.docker.com
|
||||
- IRC - irc.freenode.net #docker channel
|
||||
- Post a question on StackOverflow, using the Docker tag
|
||||
|
||||
---------------------------------------------------
|
||||
BUG REPORT INFORMATION
|
||||
---------------------------------------------------
|
||||
Use the commands below to provide key information from your environment:
|
||||
You do NOT have to include this information if this is a FEATURE REQUEST
|
||||
-->
|
||||
|
||||
**Description**
|
||||
|
||||
<!--
|
||||
Briefly describe the problem you are having in a few paragraphs.
|
||||
-->
|
||||
|
||||
**Steps to reproduce the issue:**
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
**Describe the results you received:**
|
||||
|
||||
|
||||
**Describe the results you expected:**
|
||||
|
||||
|
||||
**Additional information you deem important (e.g. issue happens only occasionally):**
|
||||
|
||||
**Output of `docker version`:**
|
||||
|
||||
```
|
||||
(paste your output here)
|
||||
```
|
||||
|
||||
**Output of `docker info`:**
|
||||
|
||||
```
|
||||
(paste your output here)
|
||||
```
|
||||
|
||||
**Additional environment details (AWS, VirtualBox, physical, etc.):**
|
||||
30
vendor/github.com/docker/docker/.github/PULL_REQUEST_TEMPLATE.md
generated
vendored
Normal file
30
vendor/github.com/docker/docker/.github/PULL_REQUEST_TEMPLATE.md
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<!--
|
||||
Please make sure you've read and understood our contributing guidelines;
|
||||
https://github.com/docker/docker/blob/master/CONTRIBUTING.md
|
||||
|
||||
** Make sure all your commits include a signature generated with `git commit -s` **
|
||||
|
||||
For additional information on our contributing process, read our contributing
|
||||
guide https://docs.docker.com/opensource/code/
|
||||
|
||||
If this is a bug fix, make sure your description includes "fixes #xxxx", or
|
||||
"closes #xxxx"
|
||||
|
||||
Please provide the following information:
|
||||
-->
|
||||
|
||||
**- What I did**
|
||||
|
||||
**- How I did it**
|
||||
|
||||
**- How to verify it**
|
||||
|
||||
**- Description for the changelog**
|
||||
<!--
|
||||
Write a short (one line) summary that describes the changes in this
|
||||
pull request for inclusion in the changelog:
|
||||
-->
|
||||
|
||||
|
||||
**- A picture of a cute animal (not mandatory but encouraged)**
|
||||
|
||||
33
vendor/github.com/docker/docker/.gitignore
generated
vendored
Normal file
33
vendor/github.com/docker/docker/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
# Docker project generated files to ignore
|
||||
# if you want to ignore files created by your editor/tools,
|
||||
# please consider a global .gitignore https://help.github.com/articles/ignoring-files
|
||||
*.exe
|
||||
*.exe~
|
||||
*.orig
|
||||
*.test
|
||||
.*.swp
|
||||
.DS_Store
|
||||
# a .bashrc may be added to customize the build environment
|
||||
.bashrc
|
||||
.editorconfig
|
||||
.gopath/
|
||||
.go-pkg-cache/
|
||||
autogen/
|
||||
bundles/
|
||||
cmd/dockerd/dockerd
|
||||
cmd/docker/docker
|
||||
dockerversion/version_autogen.go
|
||||
dockerversion/version_autogen_unix.go
|
||||
docs/AWS_S3_BUCKET
|
||||
docs/GITCOMMIT
|
||||
docs/GIT_BRANCH
|
||||
docs/VERSION
|
||||
docs/_build
|
||||
docs/_static
|
||||
docs/_templates
|
||||
docs/changed-files
|
||||
# generated by man/md2man-all.sh
|
||||
man/man1
|
||||
man/man5
|
||||
man/man8
|
||||
vendor/pkg/
|
||||
275
vendor/github.com/docker/docker/.mailmap
generated
vendored
Normal file
275
vendor/github.com/docker/docker/.mailmap
generated
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
# Generate AUTHORS: hack/generate-authors.sh
|
||||
|
||||
# Tip for finding duplicates (besides scanning the output of AUTHORS for name
|
||||
# duplicates that aren't also email duplicates): scan the output of:
|
||||
# git log --format='%aE - %aN' | sort -uf
|
||||
#
|
||||
# For explanation on this file format: man git-shortlog
|
||||
|
||||
Patrick Stapleton <github@gdi2290.com>
|
||||
Shishir Mahajan <shishir.mahajan@redhat.com> <smahajan@redhat.com>
|
||||
Erwin van der Koogh <info@erronis.nl>
|
||||
Ahmed Kamal <email.ahmedkamal@googlemail.com>
|
||||
Tejesh Mehta <tejesh.mehta@gmail.com> <tj@init.me>
|
||||
Cristian Staretu <cristian.staretu@gmail.com>
|
||||
Cristian Staretu <cristian.staretu@gmail.com> <unclejacksons@gmail.com>
|
||||
Cristian Staretu <cristian.staretu@gmail.com> <unclejack@users.noreply.github.com>
|
||||
Marcus Linke <marcus.linke@gmx.de>
|
||||
Aleksandrs Fadins <aleks@s-ko.net>
|
||||
Christopher Latham <sudosurootdev@gmail.com>
|
||||
Hu Keping <hukeping@huawei.com>
|
||||
Wayne Chang <wayne@neverfear.org>
|
||||
Chen Chao <cc272309126@gmail.com>
|
||||
Daehyeok Mun <daehyeok@gmail.com>
|
||||
<daehyeok@gmail.com> <daehyeok@daehyeokui-MacBook-Air.local>
|
||||
<jt@yadutaf.fr> <admin@jtlebi.fr>
|
||||
<jeff@docker.com> <jefferya@programmerq.net>
|
||||
<charles.hooper@dotcloud.com> <chooper@plumata.com>
|
||||
<daniel.mizyrycki@dotcloud.com> <daniel@dotcloud.com>
|
||||
<daniel.mizyrycki@dotcloud.com> <mzdaniel@glidelink.net>
|
||||
Guillaume J. Charmes <guillaume.charmes@docker.com> <charmes.guillaume@gmail.com>
|
||||
<guillaume.charmes@docker.com> <guillaume@dotcloud.com>
|
||||
<guillaume.charmes@docker.com> <guillaume@docker.com>
|
||||
<guillaume.charmes@docker.com> <guillaume.charmes@dotcloud.com>
|
||||
<guillaume.charmes@docker.com> <guillaume@charmes.net>
|
||||
<kencochrane@gmail.com> <KenCochrane@gmail.com>
|
||||
Thatcher Peskens <thatcher@docker.com>
|
||||
Thatcher Peskens <thatcher@docker.com> <thatcher@dotcloud.com>
|
||||
Thatcher Peskens <thatcher@docker.com> dhrp <thatcher@gmx.net>
|
||||
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com> jpetazzo <jerome.petazzoni@dotcloud.com>
|
||||
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com> <jp@enix.org>
|
||||
Joffrey F <joffrey@docker.com>
|
||||
Joffrey F <joffrey@docker.com> <joffrey@dotcloud.com>
|
||||
Joffrey F <joffrey@docker.com> <f.joffrey@gmail.com>
|
||||
Tim Terhorst <mynamewastaken+git@gmail.com>
|
||||
Andy Smith <github@anarkystic.com>
|
||||
<kalessin@kalessin.fr> <louis@dotcloud.com>
|
||||
<victor.vieux@docker.com> <victor.vieux@dotcloud.com>
|
||||
<victor.vieux@docker.com> <victor@dotcloud.com>
|
||||
<victor.vieux@docker.com> <dev@vvieux.com>
|
||||
<victor.vieux@docker.com> <victor@docker.com>
|
||||
<victor.vieux@docker.com> <vieux@docker.com>
|
||||
<victor.vieux@docker.com> <victorvieux@gmail.com>
|
||||
<dominik@honnef.co> <dominikh@fork-bomb.org>
|
||||
<ehanchrow@ine.com> <eric.hanchrow@gmail.com>
|
||||
Walter Stanish <walter@pratyeka.org>
|
||||
<daniel@gasienica.ch> <dgasienica@zynga.com>
|
||||
Roberto Hashioka <roberto_hashioka@hotmail.com>
|
||||
Konstantin Pelykh <kpelykh@zettaset.com>
|
||||
David Sissitka <me@dsissitka.com>
|
||||
Nolan Darilek <nolan@thewordnerd.info>
|
||||
<mastahyeti@gmail.com> <mastahyeti@users.noreply.github.com>
|
||||
Benoit Chesneau <bchesneau@gmail.com>
|
||||
Jordan Arentsen <blissdev@gmail.com>
|
||||
Daniel Garcia <daniel@danielgarcia.info>
|
||||
Miguel Angel Fernández <elmendalerenda@gmail.com>
|
||||
Bhiraj Butala <abhiraj.butala@gmail.com>
|
||||
Faiz Khan <faizkhan00@gmail.com>
|
||||
Victor Lyuboslavsky <victor@victoreda.com>
|
||||
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
|
||||
Matthew Mueller <mattmuelle@gmail.com>
|
||||
<mosoni@ebay.com> <mohitsoni1989@gmail.com>
|
||||
Shih-Yuan Lee <fourdollars@gmail.com>
|
||||
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com> root <root@vagrant-ubuntu-12.10.vagrantup.com>
|
||||
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
||||
<proppy@google.com> <proppy@aminche.com>
|
||||
<michael@docker.com> <michael@crosbymichael.com>
|
||||
<michael@docker.com> <crosby.michael@gmail.com>
|
||||
<michael@docker.com> <crosbymichael@gmail.com>
|
||||
<github@developersupport.net> <github@metaliveblog.com>
|
||||
<brandon@ifup.org> <brandon@ifup.co>
|
||||
<dano@spotify.com> <daniel.norberg@gmail.com>
|
||||
<danny@codeaholics.org> <Danny.Yates@mailonline.co.uk>
|
||||
<gurjeet@singh.im> <singh.gurjeet@gmail.com>
|
||||
<shawn@churchofgit.com> <shawnlandden@gmail.com>
|
||||
<sjoerd-github@linuxonly.nl> <sjoerd@byte.nl>
|
||||
<solomon@docker.com> <solomon.hykes@dotcloud.com>
|
||||
<solomon@docker.com> <solomon@dotcloud.com>
|
||||
<solomon@docker.com> <s@docker.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <SvenDowideit@fosiki.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <SvenDowideit@docker.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <¨SvenDowideit@home.org.au¨>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <SvenDowideit@home.org.au>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <SvenDowideit@users.noreply.github.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <sven@t440s.home.gateway>
|
||||
<alexl@redhat.com> <alexander.larsson@gmail.com>
|
||||
Alexander Morozov <lk4d4@docker.com> <lk4d4math@gmail.com>
|
||||
Alexander Morozov <lk4d4@docker.com>
|
||||
<git.nivoc@neverbox.com> <kuehnle@online.de>
|
||||
O.S. Tezer <ostezer@gmail.com>
|
||||
<ostezer@gmail.com> <ostezer@users.noreply.github.com>
|
||||
Roberto G. Hashioka <roberto.hashioka@docker.com> <roberto_hashioka@hotmail.com>
|
||||
<justin.p.simonelis@gmail.com> <justin.simonelis@PTS-JSIMON2.toronto.exclamation.com>
|
||||
<taim@bosboot.org> <maztaim@users.noreply.github.com>
|
||||
<viktor.vojnovski@amadeus.com> <vojnovski@gmail.com>
|
||||
<vbatts@redhat.com> <vbatts@hashbangbash.com>
|
||||
<altsysrq@gmail.com> <iamironbob@gmail.com>
|
||||
Sridhar Ratnakumar <sridharr@activestate.com>
|
||||
Sridhar Ratnakumar <sridharr@activestate.com> <github@srid.name>
|
||||
Liang-Chi Hsieh <viirya@gmail.com>
|
||||
Aleksa Sarai <asarai@suse.de>
|
||||
Aleksa Sarai <asarai@suse.de> <asarai@suse.com>
|
||||
Aleksa Sarai <asarai@suse.de> <cyphar@cyphar.com>
|
||||
Will Weaver <monkey@buildingbananas.com>
|
||||
Timothy Hobbs <timothyhobbs@seznam.cz>
|
||||
Nathan LeClaire <nathan.leclaire@docker.com> <nathan.leclaire@gmail.com>
|
||||
Nathan LeClaire <nathan.leclaire@docker.com> <nathanleclaire@gmail.com>
|
||||
<github@hollensbe.org> <erik+github@hollensbe.org>
|
||||
<github@albersweb.de> <albers@users.noreply.github.com>
|
||||
<lsm5@fedoraproject.org> <lsm5@redhat.com>
|
||||
<marc@marc-abramowitz.com> <msabramo@gmail.com>
|
||||
Matthew Heon <mheon@redhat.com> <mheon@mheonlaptop.redhat.com>
|
||||
<bernat@luffy.cx> <vincent@bernat.im>
|
||||
<bernat@luffy.cx> <Vincent.Bernat@exoscale.ch>
|
||||
<p@pwaller.net> <peter@scraperwiki.com>
|
||||
<andrew.weiss@outlook.com> <andrew.weiss@microsoft.com>
|
||||
Francisco Carriedo <fcarriedo@gmail.com>
|
||||
<julienbordellier@gmail.com> <git@julienbordellier.com>
|
||||
<ahmetb@microsoft.com> <ahmetalpbalkan@gmail.com>
|
||||
<arnaud.porterie@docker.com> <icecrime@gmail.com>
|
||||
<baloo@gandi.net> <superbaloo+registrations.github@superbaloo.net>
|
||||
Brian Goff <cpuguy83@gmail.com>
|
||||
<cpuguy83@gmail.com> <bgoff@cpuguy83-mbp.home>
|
||||
<eric@windisch.us> <ewindisch@docker.com>
|
||||
<frank.rosquin+github@gmail.com> <frank.rosquin@gmail.com>
|
||||
Hollie Teal <hollie@docker.com>
|
||||
<hollie@docker.com> <hollie.teal@docker.com>
|
||||
<hollie@docker.com> <hollietealok@users.noreply.github.com>
|
||||
<huu@prismskylabs.com> <whoshuu@gmail.com>
|
||||
Jessica Frazelle <jessfraz@google.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <me@jessfraz.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <jess@mesosphere.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <jfrazelle@users.noreply.github.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <acidburn@docker.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <jess@docker.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <princess@docker.com>
|
||||
<konrad.wilhelm.kleine@gmail.com> <kwk@users.noreply.github.com>
|
||||
<tintypemolly@gmail.com> <tintypemolly@Ohui-MacBook-Pro.local>
|
||||
<estesp@linux.vnet.ibm.com> <estesp@gmail.com>
|
||||
<github@gone.nl> <thaJeztah@users.noreply.github.com>
|
||||
Thomas LEVEIL <thomasleveil@gmail.com> Thomas LÉVEIL <thomasleveil@users.noreply.github.com>
|
||||
<oi@truffles.me.uk> <timruffles@googlemail.com>
|
||||
<Vincent.Bernat@exoscale.ch> <bernat@luffy.cx>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <amurdaca@redhat.com>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <runcom@redhat.com>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <me@runcom.ninja>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <runcom@linux.com>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <runcom@users.noreply.github.com>
|
||||
Darren Shepherd <darren.s.shepherd@gmail.com> <darren@rancher.com>
|
||||
Deshi Xiao <dxiao@redhat.com> <dsxiao@dataman-inc.com>
|
||||
Deshi Xiao <dxiao@redhat.com> <xiaods@gmail.com>
|
||||
Doug Davis <dug@us.ibm.com> <duglin@users.noreply.github.com>
|
||||
Jacob Atzen <jacob@jacobatzen.dk> <jatzen@gmail.com>
|
||||
Jeff Nickoloff <jeff.nickoloff@gmail.com> <jeff@allingeek.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com> <jhowardmsft@users.noreply.github.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com> <john.howard@microsoft.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com> <jhoward@microsoft.com>
|
||||
Madhu Venugopal <madhu@socketplane.io> <madhu@docker.com>
|
||||
Mary Anthony <mary.anthony@docker.com> <mary@docker.com>
|
||||
Mary Anthony <mary.anthony@docker.com> moxiegirl <mary@docker.com>
|
||||
Mary Anthony <mary.anthony@docker.com> <moxieandmore@gmail.com>
|
||||
mattyw <mattyw@me.com> <gh@mattyw.net>
|
||||
resouer <resouer@163.com> <resouer@gmail.com>
|
||||
AJ Bowen <aj@gandi.net> soulshake <amy@gandi.net>
|
||||
AJ Bowen <aj@gandi.net> soulshake <aj@gandi.net>
|
||||
Tibor Vass <teabee89@gmail.com> <tibor@docker.com>
|
||||
Tibor Vass <teabee89@gmail.com> <tiborvass@users.noreply.github.com>
|
||||
Vincent Bernat <bernat@luffy.cx> <Vincent.Bernat@exoscale.ch>
|
||||
Yestin Sun <sunyi0804@gmail.com> <yestin.sun@polyera.com>
|
||||
bin liu <liubin0329@users.noreply.github.com> <liubin0329@gmail.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com> jhowardmsft <jhoward@microsoft.com>
|
||||
Ankush Agarwal <ankushagarwal11@gmail.com> <ankushagarwal@users.noreply.github.com>
|
||||
Tangi COLIN <tangicolin@gmail.com> tangicolin <tangicolin@gmail.com>
|
||||
Allen Sun <allen.sun@daocloud.io>
|
||||
Adrien Gallouët <adrien@gallouet.fr> <angt@users.noreply.github.com>
|
||||
<aanm90@gmail.com> <martins@noironetworks.com>
|
||||
Anuj Bahuguna <anujbahuguna.dev@gmail.com>
|
||||
Anusha Ragunathan <anusha.ragunathan@docker.com> <anusha@docker.com>
|
||||
Avi Miller <avi.miller@oracle.com> <avi.miller@gmail.com>
|
||||
Brent Salisbury <brent.salisbury@docker.com> <brent@docker.com>
|
||||
Chander G <chandergovind@gmail.com>
|
||||
Chun Chen <ramichen@tencent.com> <chenchun.feed@gmail.com>
|
||||
Ying Li <cyli@twistedmatrix.com>
|
||||
Daehyeok Mun <daehyeok@gmail.com> <daehyeok@daehyeok-ui-MacBook-Air.local>
|
||||
<dqminh@cloudflare.com> <dqminh89@gmail.com>
|
||||
Daniel, Dao Quang Minh <dqminh@cloudflare.com>
|
||||
Daniel Nephin <dnephin@docker.com> <dnephin@gmail.com>
|
||||
Dave Tucker <dt@docker.com> <dave@dtucker.co.uk>
|
||||
Doug Tangren <d.tangren@gmail.com>
|
||||
Frederick F. Kautz IV <fkautz@redhat.com> <fkautz@alumni.cmu.edu>
|
||||
Ben Golub <ben.golub@dotcloud.com>
|
||||
Harold Cooper <hrldcpr@gmail.com>
|
||||
hsinko <21551195@zju.edu.cn> <hsinko@users.noreply.github.com>
|
||||
Josh Hawn <josh.hawn@docker.com> <jlhawn@berkeley.edu>
|
||||
Justin Cormack <justin.cormack@docker.com>
|
||||
<justin.cormack@docker.com> <justin.cormack@unikernel.com>
|
||||
<justin.cormack@docker.com> <justin@specialbusservice.com>
|
||||
Kamil Domański <kamil@domanski.co>
|
||||
Lei Jitang <leijitang@huawei.com>
|
||||
<leijitang@huawei.com> <leijitang@gmail.com>
|
||||
Linus Heckemann <lheckemann@twig-world.com>
|
||||
<lheckemann@twig-world.com> <anonymouse2048@gmail.com>
|
||||
Lynda O'Leary <lyndaoleary29@gmail.com>
|
||||
<lyndaoleary29@gmail.com> <lyndaoleary@hotmail.com>
|
||||
Marianna Tessel <mtesselh@gmail.com>
|
||||
Michael Huettermann <michael@huettermann.net>
|
||||
Moysés Borges <moysesb@gmail.com>
|
||||
<moysesb@gmail.com> <moyses.furtado@wplex.com.br>
|
||||
Nigel Poulton <nigelpoulton@hotmail.com>
|
||||
Qiang Huang <h.huangqiang@huawei.com>
|
||||
<h.huangqiang@huawei.com> <qhuang@10.0.2.15>
|
||||
Boaz Shuster <ripcurld.github@gmail.com>
|
||||
Shuwei Hao <haosw@cn.ibm.com>
|
||||
<haosw@cn.ibm.com> <haoshuwei24@gmail.com>
|
||||
Soshi Katsuta <soshi.katsuta@gmail.com>
|
||||
<soshi.katsuta@gmail.com> <katsuta_soshi@cyberagent.co.jp>
|
||||
Stefan Berger <stefanb@linux.vnet.ibm.com>
|
||||
<stefanb@linux.vnet.ibm.com> <stefanb@us.ibm.com>
|
||||
Stephen Day <stephen.day@docker.com>
|
||||
<stephen.day@docker.com> <stevvooe@users.noreply.github.com>
|
||||
Toli Kuznets <toli@docker.com>
|
||||
Tristan Carel <tristan@cogniteev.com>
|
||||
<tristan@cogniteev.com> <tristan.carel@gmail.com>
|
||||
Vincent Demeester <vincent@sbr.pm>
|
||||
<vincent@sbr.pm> <vincent+github@demeester.fr>
|
||||
Vishnu Kannan <vishnuk@google.com>
|
||||
xlgao-zju <xlgao@zju.edu.cn> xlgao <xlgao@zju.edu.cn>
|
||||
yuchangchun <yuchangchun1@huawei.com> y00277921 <yuchangchun1@huawei.com>
|
||||
<zij@case.edu> <zjaffee@us.ibm.com>
|
||||
<anujbahuguna.dev@gmail.com> <abahuguna@fiberlink.com>
|
||||
<eungjun.yi@navercorp.com> <semtlenori@gmail.com>
|
||||
<haosw@cn.ibm.com> <haoshuwei1989@163.com>
|
||||
Hao Shu Wei <haosw@cn.ibm.com>
|
||||
<matt.bentley@docker.com> <mbentley@mbentley.net>
|
||||
<MihaiBorob@gmail.com> <MihaiBorobocea@gmail.com>
|
||||
<redmond.martin@gmail.com> <xgithub@redmond5.com>
|
||||
<redmond.martin@gmail.com> <martin@tinychat.com>
|
||||
<srbrahma@us.ibm.com> <sbrahma@us.ibm.com>
|
||||
<suda.akihiro@lab.ntt.co.jp> <suda.kyoto@gmail.com>
|
||||
<thomas@gazagnaire.org> <thomas@gazagnaire.com>
|
||||
Shengbo Song <thomassong@tencent.com> mYmNeo <mymneo@163.com>
|
||||
Shengbo Song <thomassong@tencent.com>
|
||||
<sylvain@ascribe.io> <sylvain.bellemare@ezeep.com>
|
||||
Sylvain Bellemare <sylvain@ascribe.io>
|
||||
<alexandre.beslic@gmail.com> <abronan@docker.com>
|
||||
<bilal.amarni@gmail.com> <bamarni@users.noreply.github.com>
|
||||
<misty@docker.com> <misty@apache.org>
|
||||
Arnaud Porterie <arnaud.porterie@docker.com>
|
||||
<cpuguy83@gmail.com> <bgoff@cpuguy83-mbp.local>
|
||||
David M. Karr <davidmichaelkarr@gmail.com>
|
||||
<diogo@docker.com> <diogo.monica@gmail.com>
|
||||
<horwitz@addthis.com> <horwitzja@gmail.com>
|
||||
<kherner@progress.com> <chosenken@gmail.com>
|
||||
Kenfe-Mickaël Laventure <mickael.laventure@gmail.com>
|
||||
<mauricio@medallia.com> <mauriciogaravaglia@gmail.com>
|
||||
<dhenderson@gmail.com> <Dave.Henderson@ca.ibm.com>
|
||||
<wkq5325@gmail.com> <wkqwu@cn.ibm.com>
|
||||
<mike.goelzer@docker.com> <mgoelzer@docker.com>
|
||||
<nicholasjamesrusso@gmail.com> <nicholasrusso@icloud.com>
|
||||
Runshen Zhu <runshen.zhu@gmail.com>
|
||||
Tom Barlow <tomwbarlow@gmail.com>
|
||||
Xianlu Bird <xianlubird@gmail.com>
|
||||
Dan Feldman <danf@jfrog.com>
|
||||
Harry Zhang <harryz@hyper.sh> <harryzhang@zju.edu.cn>
|
||||
1652
vendor/github.com/docker/docker/AUTHORS
generated
vendored
Normal file
1652
vendor/github.com/docker/docker/AUTHORS
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3279
vendor/github.com/docker/docker/CHANGELOG.md
generated
vendored
Normal file
3279
vendor/github.com/docker/docker/CHANGELOG.md
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
401
vendor/github.com/docker/docker/CONTRIBUTING.md
generated
vendored
Normal file
401
vendor/github.com/docker/docker/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,401 @@
|
||||
# Contributing to Docker
|
||||
|
||||
Want to hack on Docker? Awesome! We have a contributor's guide that explains
|
||||
[setting up a Docker development environment and the contribution
|
||||
process](https://docs.docker.com/opensource/project/who-written-for/).
|
||||
|
||||
[](https://docs.docker.com/opensource/project/who-written-for/)
|
||||
|
||||
This page contains information about reporting issues as well as some tips and
|
||||
guidelines useful to experienced open source contributors. Finally, make sure
|
||||
you read our [community guidelines](#docker-community-guidelines) before you
|
||||
start participating.
|
||||
|
||||
## Topics
|
||||
|
||||
* [Reporting Security Issues](#reporting-security-issues)
|
||||
* [Design and Cleanup Proposals](#design-and-cleanup-proposals)
|
||||
* [Reporting Issues](#reporting-other-issues)
|
||||
* [Quick Contribution Tips and Guidelines](#quick-contribution-tips-and-guidelines)
|
||||
* [Community Guidelines](#docker-community-guidelines)
|
||||
|
||||
## Reporting security issues
|
||||
|
||||
The Docker maintainers take security seriously. If you discover a security
|
||||
issue, please bring it to their attention right away!
|
||||
|
||||
Please **DO NOT** file a public issue, instead send your report privately to
|
||||
[security@docker.com](mailto:security@docker.com).
|
||||
|
||||
Security reports are greatly appreciated and we will publicly thank you for it.
|
||||
We also like to send gifts—if you're into Docker schwag, make sure to let
|
||||
us know. We currently do not offer a paid security bounty program, but are not
|
||||
ruling it out in the future.
|
||||
|
||||
|
||||
## Reporting other issues
|
||||
|
||||
A great way to contribute to the project is to send a detailed report when you
|
||||
encounter an issue. We always appreciate a well-written, thorough bug report,
|
||||
and will thank you for it!
|
||||
|
||||
Check that [our issue database](https://github.com/docker/docker/issues)
|
||||
doesn't already include that problem or suggestion before submitting an issue.
|
||||
If you find a match, you can use the "subscribe" button to get notified on
|
||||
updates. Do *not* leave random "+1" or "I have this too" comments, as they
|
||||
only clutter the discussion, and don't help resolving it. However, if you
|
||||
have ways to reproduce the issue or have additional information that may help
|
||||
resolving the issue, please leave a comment.
|
||||
|
||||
When reporting issues, always include:
|
||||
|
||||
* The output of `docker version`.
|
||||
* The output of `docker info`.
|
||||
|
||||
Also include the steps required to reproduce the problem if possible and
|
||||
applicable. This information will help us review and fix your issue faster.
|
||||
When sending lengthy log-files, consider posting them as a gist (https://gist.github.com).
|
||||
Don't forget to remove sensitive data from your logfiles before posting (you can
|
||||
replace those parts with "REDACTED").
|
||||
|
||||
## Quick contribution tips and guidelines
|
||||
|
||||
This section gives the experienced contributor some tips and guidelines.
|
||||
|
||||
### Pull requests are always welcome
|
||||
|
||||
Not sure if that typo is worth a pull request? Found a bug and know how to fix
|
||||
it? Do it! We will appreciate it. Any significant improvement should be
|
||||
documented as [a GitHub issue](https://github.com/docker/docker/issues) before
|
||||
anybody starts working on it.
|
||||
|
||||
We are always thrilled to receive pull requests. We do our best to process them
|
||||
quickly. If your pull request is not accepted on the first try,
|
||||
don't get discouraged! Our contributor's guide explains [the review process we
|
||||
use for simple changes](https://docs.docker.com/opensource/workflow/make-a-contribution/).
|
||||
|
||||
### Design and cleanup proposals
|
||||
|
||||
You can propose new designs for existing Docker features. You can also design
|
||||
entirely new features. We really appreciate contributors who want to refactor or
|
||||
otherwise cleanup our project. For information on making these types of
|
||||
contributions, see [the advanced contribution
|
||||
section](https://docs.docker.com/opensource/workflow/advanced-contributing/) in
|
||||
the contributors guide.
|
||||
|
||||
We try hard to keep Docker lean and focused. Docker can't do everything for
|
||||
everybody. This means that we might decide against incorporating a new feature.
|
||||
However, there might be a way to implement that feature *on top of* Docker.
|
||||
|
||||
### Talking to other Docker users and contributors
|
||||
|
||||
<table class="tg">
|
||||
<col width="45%">
|
||||
<col width="65%">
|
||||
<tr>
|
||||
<td>Forums</td>
|
||||
<td>
|
||||
A public forum for users to discuss questions and explore current design patterns and
|
||||
best practices about Docker and related projects in the Docker Ecosystem. To participate,
|
||||
just log in with your Docker Hub account on <a href="https://forums.docker.com" target="_blank">https://forums.docker.com</a>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Internet Relay Chat (IRC)</td>
|
||||
<td>
|
||||
<p>
|
||||
IRC a direct line to our most knowledgeable Docker users; we have
|
||||
both the <code>#docker</code> and <code>#docker-dev</code> group on
|
||||
<strong>irc.freenode.net</strong>.
|
||||
IRC is a rich chat protocol but it can overwhelm new users. You can search
|
||||
<a href="https://botbot.me/freenode/docker/#" target="_blank">our chat archives</a>.
|
||||
</p>
|
||||
<p>
|
||||
Read our <a href="https://docs.docker.com/opensource/get-help/#irc-quickstart" target="_blank">IRC quickstart guide</a>
|
||||
for an easy way to get started.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Google Group</td>
|
||||
<td>
|
||||
The <a href="https://groups.google.com/forum/#!forum/docker-dev" target="_blank">docker-dev</a>
|
||||
group is for contributors and other people contributing to the Docker project.
|
||||
You can join them without a google account by sending an email to
|
||||
<a href="mailto:docker-dev+subscribe@googlegroups.com">docker-dev+subscribe@googlegroups.com</a>.
|
||||
After receiving the join-request message, you can simply reply to that to confirm the subscription.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Twitter</td>
|
||||
<td>
|
||||
You can follow <a href="https://twitter.com/docker/" target="_blank">Docker's Twitter feed</a>
|
||||
to get updates on our products. You can also tweet us questions or just
|
||||
share blogs or stories.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stack Overflow</td>
|
||||
<td>
|
||||
Stack Overflow has over 17000 Docker questions listed. We regularly
|
||||
monitor <a href="https://stackoverflow.com/search?tab=newest&q=docker" target="_blank">Docker questions</a>
|
||||
and so do many other knowledgeable Docker users.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
### Conventions
|
||||
|
||||
Fork the repository and make changes on your fork in a feature branch:
|
||||
|
||||
- If it's a bug fix branch, name it XXXX-something where XXXX is the number of
|
||||
the issue.
|
||||
- If it's a feature branch, create an enhancement issue to announce
|
||||
your intentions, and name it XXXX-something where XXXX is the number of the
|
||||
issue.
|
||||
|
||||
Submit unit tests for your changes. Go has a great test framework built in; use
|
||||
it! Take a look at existing tests for inspiration. [Run the full test
|
||||
suite](https://docs.docker.com/opensource/project/test-and-docs/) on your branch before
|
||||
submitting a pull request.
|
||||
|
||||
Update the documentation when creating or modifying features. Test your
|
||||
documentation changes for clarity, concision, and correctness, as well as a
|
||||
clean documentation build. See our contributors guide for [our style
|
||||
guide](https://docs.docker.com/opensource/doc-style) and instructions on [building
|
||||
the documentation](https://docs.docker.com/opensource/project/test-and-docs/#build-and-test-the-documentation).
|
||||
|
||||
Write clean code. Universally formatted code promotes ease of writing, reading,
|
||||
and maintenance. Always run `gofmt -s -w file.go` on each changed file before
|
||||
committing your changes. Most editors have plug-ins that do this automatically.
|
||||
|
||||
Pull request descriptions should be as clear as possible and include a reference
|
||||
to all the issues that they address.
|
||||
|
||||
Commit messages must start with a capitalized and short summary (max. 50 chars)
|
||||
written in the imperative, followed by an optional, more detailed explanatory
|
||||
text which is separated from the summary by an empty line.
|
||||
|
||||
Code review comments may be added to your pull request. Discuss, then make the
|
||||
suggested modifications and push additional commits to your feature branch. Post
|
||||
a comment after pushing. New commits show up in the pull request automatically,
|
||||
but the reviewers are notified only when you comment.
|
||||
|
||||
Pull requests must be cleanly rebased on top of master without multiple branches
|
||||
mixed into the PR.
|
||||
|
||||
**Git tip**: If your PR no longer merges cleanly, use `rebase master` in your
|
||||
feature branch to update your pull request rather than `merge master`.
|
||||
|
||||
Before you make a pull request, squash your commits into logical units of work
|
||||
using `git rebase -i` and `git push -f`. A logical unit of work is a consistent
|
||||
set of patches that should be reviewed together: for example, upgrading the
|
||||
version of a vendored dependency and taking advantage of its now available new
|
||||
feature constitute two separate units of work. Implementing a new function and
|
||||
calling it in another file constitute a single logical unit of work. The very
|
||||
high majority of submissions should have a single commit, so if in doubt: squash
|
||||
down to one.
|
||||
|
||||
After every commit, [make sure the test suite passes]
|
||||
(https://docs.docker.com/opensource/project/test-and-docs/). Include documentation
|
||||
changes in the same pull request so that a revert would remove all traces of
|
||||
the feature or fix.
|
||||
|
||||
Include an issue reference like `Closes #XXXX` or `Fixes #XXXX` in commits that
|
||||
close an issue. Including references automatically closes the issue on a merge.
|
||||
|
||||
Please do not add yourself to the `AUTHORS` file, as it is regenerated regularly
|
||||
from the Git history.
|
||||
|
||||
Please see the [Coding Style](#coding-style) for further guidelines.
|
||||
|
||||
### Merge approval
|
||||
|
||||
Docker maintainers use LGTM (Looks Good To Me) in comments on the code review to
|
||||
indicate acceptance.
|
||||
|
||||
A change requires LGTMs from an absolute majority of the maintainers of each
|
||||
component affected. For example, if a change affects `docs/` and `registry/`, it
|
||||
needs an absolute majority from the maintainers of `docs/` AND, separately, an
|
||||
absolute majority of the maintainers of `registry/`.
|
||||
|
||||
For more details, see the [MAINTAINERS](MAINTAINERS) page.
|
||||
|
||||
### Sign your work
|
||||
|
||||
The sign-off is a simple line at the end of the explanation for the patch. Your
|
||||
signature certifies that you wrote the patch or otherwise have the right to pass
|
||||
it on as an open-source patch. The rules are pretty simple: if you can certify
|
||||
the below (from [developercertificate.org](http://developercertificate.org/)):
|
||||
|
||||
```
|
||||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||
1 Letterman Drive
|
||||
Suite D4700
|
||||
San Francisco, CA, 94129
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
```
|
||||
|
||||
Then you just add a line to every git commit message:
|
||||
|
||||
Signed-off-by: Joe Smith <joe.smith@email.com>
|
||||
|
||||
Use your real name (sorry, no pseudonyms or anonymous contributions.)
|
||||
|
||||
If you set your `user.name` and `user.email` git configs, you can sign your
|
||||
commit automatically with `git commit -s`.
|
||||
|
||||
### How can I become a maintainer?
|
||||
|
||||
The procedures for adding new maintainers are explained in the
|
||||
global [MAINTAINERS](https://github.com/docker/opensource/blob/master/MAINTAINERS)
|
||||
file in the [https://github.com/docker/opensource/](https://github.com/docker/opensource/)
|
||||
repository.
|
||||
|
||||
Don't forget: being a maintainer is a time investment. Make sure you
|
||||
will have time to make yourself available. You don't have to be a
|
||||
maintainer to make a difference on the project!
|
||||
|
||||
## Docker community guidelines
|
||||
|
||||
We want to keep the Docker community awesome, growing and collaborative. We need
|
||||
your help to keep it that way. To help with this we've come up with some general
|
||||
guidelines for the community as a whole:
|
||||
|
||||
* Be nice: Be courteous, respectful and polite to fellow community members:
|
||||
no regional, racial, gender, or other abuse will be tolerated. We like
|
||||
nice people way better than mean ones!
|
||||
|
||||
* Encourage diversity and participation: Make everyone in our community feel
|
||||
welcome, regardless of their background and the extent of their
|
||||
contributions, and do everything possible to encourage participation in
|
||||
our community.
|
||||
|
||||
* Keep it legal: Basically, don't get us in trouble. Share only content that
|
||||
you own, do not share private or sensitive information, and don't break
|
||||
the law.
|
||||
|
||||
* Stay on topic: Make sure that you are posting to the correct channel and
|
||||
avoid off-topic discussions. Remember when you update an issue or respond
|
||||
to an email you are potentially sending to a large number of people. Please
|
||||
consider this before you update. Also remember that nobody likes spam.
|
||||
|
||||
* Don't send email to the maintainers: There's no need to send email to the
|
||||
maintainers to ask them to investigate an issue or to take a look at a
|
||||
pull request. Instead of sending an email, GitHub mentions should be
|
||||
used to ping maintainers to review a pull request, a proposal or an
|
||||
issue.
|
||||
|
||||
### Guideline violations — 3 strikes method
|
||||
|
||||
The point of this section is not to find opportunities to punish people, but we
|
||||
do need a fair way to deal with people who are making our community suck.
|
||||
|
||||
1. First occurrence: We'll give you a friendly, but public reminder that the
|
||||
behavior is inappropriate according to our guidelines.
|
||||
|
||||
2. Second occurrence: We will send you a private message with a warning that
|
||||
any additional violations will result in removal from the community.
|
||||
|
||||
3. Third occurrence: Depending on the violation, we may need to delete or ban
|
||||
your account.
|
||||
|
||||
**Notes:**
|
||||
|
||||
* Obvious spammers are banned on first occurrence. If we don't do this, we'll
|
||||
have spam all over the place.
|
||||
|
||||
* Violations are forgiven after 6 months of good behavior, and we won't hold a
|
||||
grudge.
|
||||
|
||||
* People who commit minor infractions will get some education, rather than
|
||||
hammering them in the 3 strikes process.
|
||||
|
||||
* The rules apply equally to everyone in the community, no matter how much
|
||||
you've contributed.
|
||||
|
||||
* Extreme violations of a threatening, abusive, destructive or illegal nature
|
||||
will be addressed immediately and are not subject to 3 strikes or forgiveness.
|
||||
|
||||
* Contact abuse@docker.com to report abuse or appeal violations. In the case of
|
||||
appeals, we know that mistakes happen, and we'll work with you to come up with a
|
||||
fair solution if there has been a misunderstanding.
|
||||
|
||||
## Coding Style
|
||||
|
||||
Unless explicitly stated, we follow all coding guidelines from the Go
|
||||
community. While some of these standards may seem arbitrary, they somehow seem
|
||||
to result in a solid, consistent codebase.
|
||||
|
||||
It is possible that the code base does not currently comply with these
|
||||
guidelines. We are not looking for a massive PR that fixes this, since that
|
||||
goes against the spirit of the guidelines. All new contributions should make a
|
||||
best effort to clean up and make the code base better than they left it.
|
||||
Obviously, apply your best judgement. Remember, the goal here is to make the
|
||||
code base easier for humans to navigate and understand. Always keep that in
|
||||
mind when nudging others to comply.
|
||||
|
||||
The rules:
|
||||
|
||||
1. All code should be formatted with `gofmt -s`.
|
||||
2. All code should pass the default levels of
|
||||
[`golint`](https://github.com/golang/lint).
|
||||
3. All code should follow the guidelines covered in [Effective
|
||||
Go](http://golang.org/doc/effective_go.html) and [Go Code Review
|
||||
Comments](https://github.com/golang/go/wiki/CodeReviewComments).
|
||||
4. Comment the code. Tell us the why, the history and the context.
|
||||
5. Document _all_ declarations and methods, even private ones. Declare
|
||||
expectations, caveats and anything else that may be important. If a type
|
||||
gets exported, having the comments already there will ensure it's ready.
|
||||
6. Variable name length should be proportional to its context and no longer.
|
||||
`noCommaALongVariableNameLikeThisIsNotMoreClearWhenASimpleCommentWouldDo`.
|
||||
In practice, short methods will have short variable names and globals will
|
||||
have longer names.
|
||||
7. No underscores in package names. If you need a compound name, step back,
|
||||
and re-examine why you need a compound name. If you still think you need a
|
||||
compound name, lose the underscore.
|
||||
8. No utils or helpers packages. If a function is not general enough to
|
||||
warrant its own package, it has not been written generally enough to be a
|
||||
part of a util package. Just leave it unexported and well-documented.
|
||||
9. All tests should run with `go test` and outside tooling should not be
|
||||
required. No, we don't need another unit testing framework. Assertion
|
||||
packages are acceptable if they provide _real_ incremental value.
|
||||
10. Even though we call these "rules" above, they are actually just
|
||||
guidelines. Since you've read all the rules, you now know that.
|
||||
|
||||
If you are having trouble getting into the mood of idiomatic Go, we recommend
|
||||
reading through [Effective Go](https://golang.org/doc/effective_go.html). The
|
||||
[Go Blog](https://blog.golang.org) is also a great resource. Drinking the
|
||||
kool-aid is a lot easier than going thirsty.
|
||||
246
vendor/github.com/docker/docker/Dockerfile
generated
vendored
Normal file
246
vendor/github.com/docker/docker/Dockerfile
generated
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
# This file describes the standard way to build Docker, using docker
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker .
|
||||
#
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||
#
|
||||
# # Run the test suite:
|
||||
# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py
|
||||
#
|
||||
# # Publish a release:
|
||||
# docker run --privileged \
|
||||
# -e AWS_S3_BUCKET=baz \
|
||||
# -e AWS_ACCESS_KEY=foo \
|
||||
# -e AWS_SECRET_KEY=bar \
|
||||
# -e GPG_PASSPHRASE=gloubiboulga \
|
||||
# docker hack/release.sh
|
||||
#
|
||||
# Note: AppArmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
FROM debian:jessie
|
||||
|
||||
# allow replacing httpredir or deb mirror
|
||||
ARG APT_MIRROR=deb.debian.org
|
||||
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
|
||||
|
||||
# Add zfs ppa
|
||||
RUN apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys E871F18B51E0147C77796AC81196BA81F6B0FC61 \
|
||||
|| apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys E871F18B51E0147C77796AC81196BA81F6B0FC61
|
||||
RUN echo deb http://ppa.launchpad.net/zfs-native/stable/ubuntu trusty main > /etc/apt/sources.list.d/zfs.list
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
apt-utils \
|
||||
aufs-tools \
|
||||
automake \
|
||||
bash-completion \
|
||||
binutils-mingw-w64 \
|
||||
bsdmainutils \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
clang \
|
||||
cmake \
|
||||
createrepo \
|
||||
curl \
|
||||
dpkg-sig \
|
||||
gcc-mingw-w64 \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
libapparmor-dev \
|
||||
libcap-dev \
|
||||
libltdl-dev \
|
||||
libnl-3-dev \
|
||||
libprotobuf-c0-dev \
|
||||
libprotobuf-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-journal-dev \
|
||||
libtool \
|
||||
mercurial \
|
||||
net-tools \
|
||||
pkg-config \
|
||||
protobuf-compiler \
|
||||
protobuf-c-compiler \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
ubuntu-zfs \
|
||||
xfsprogs \
|
||||
vim-common \
|
||||
libzfs-dev \
|
||||
tar \
|
||||
zip \
|
||||
--no-install-recommends \
|
||||
&& pip install awscli==1.10.15
|
||||
# Get lvm2 source for compiling statically
|
||||
ENV LVM2_VERSION 2.02.103
|
||||
RUN mkdir -p /usr/local/lvm2 \
|
||||
&& curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
|
||||
| tar -xzC /usr/local/lvm2 --strip-components=1
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure \
|
||||
--build="$(gcc -print-multiarch)" \
|
||||
--enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# Configure the container for OSX cross compilation
|
||||
ENV OSX_SDK MacOSX10.11.sdk
|
||||
ENV OSX_CROSS_COMMIT a9317c18a3a457ca0a657f08cc4d0d43c6cf8953
|
||||
RUN set -x \
|
||||
&& export OSXCROSS_PATH="/osxcross" \
|
||||
&& git clone https://github.com/tpoechtrager/osxcross.git $OSXCROSS_PATH \
|
||||
&& ( cd $OSXCROSS_PATH && git checkout -q $OSX_CROSS_COMMIT) \
|
||||
&& curl -sSL https://s3.dockerproject.org/darwin/v2/${OSX_SDK}.tar.xz -o "${OSXCROSS_PATH}/tarballs/${OSX_SDK}.tar.xz" \
|
||||
&& UNATTENDED=yes OSX_VERSION_MIN=10.6 ${OSXCROSS_PATH}/build.sh
|
||||
ENV PATH /osxcross/target/bin:$PATH
|
||||
|
||||
# Install seccomp: the version shipped in trusty is too old
|
||||
ENV SECCOMP_VERSION 2.3.1
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH="$(mktemp -d)" \
|
||||
&& curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
|
||||
| tar -xzC "$SECCOMP_PATH" --strip-components=1 \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& ./configure --prefix=/usr/local \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
# Install Go
|
||||
# IMPORTANT: If the version of Go is updated, the Windows to Linux CI machines
|
||||
# will need updating, to avoid errors. Ping #docker-maintainers on IRC
|
||||
# with a heads-up.
|
||||
ENV GO_VERSION 1.7.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
ENV GOPATH /go
|
||||
|
||||
# Compile Go for cross compilation
|
||||
ENV DOCKER_CROSSPLATFORMS \
|
||||
linux/386 linux/arm \
|
||||
darwin/amd64 \
|
||||
freebsd/amd64 freebsd/386 freebsd/arm \
|
||||
windows/amd64 windows/386 \
|
||||
solaris/amd64
|
||||
|
||||
# Dependency for golint
|
||||
ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3
|
||||
RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \
|
||||
&& (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT)
|
||||
|
||||
# Grab Go's lint tool
|
||||
ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456
|
||||
RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \
|
||||
&& (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \
|
||||
&& go install -v github.com/golang/lint/golint
|
||||
|
||||
# Install CRIU for checkpoint/restore support
|
||||
ENV CRIU_VERSION 2.2
|
||||
RUN mkdir -p /usr/src/criu \
|
||||
&& curl -sSL https://github.com/xemul/criu/archive/v${CRIU_VERSION}.tar.gz | tar -v -C /usr/src/criu/ -xz --strip-components=1 \
|
||||
&& cd /usr/src/criu \
|
||||
&& make \
|
||||
&& make install-criu
|
||||
|
||||
# Install two versions of the registry. The first is an older version that
|
||||
# only supports schema1 manifests. The second is a newer version that supports
|
||||
# both. This allows integration-cli tests to cover push/pull with both schema1
|
||||
# and schema2 manifests.
|
||||
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
|
||||
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Install notary and notary-server
|
||||
ENV NOTARY_VERSION v0.4.2
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT \
|
||||
&& pip install -r test-requirements.txt
|
||||
|
||||
# Install yamllint for validating swagger.yaml
|
||||
RUN pip install yamllint==1.5.0
|
||||
|
||||
# Install go-swagger for validating swagger.yaml
|
||||
ENV GO_SWAGGER_COMMIT c28258affb0b6251755d92489ef685af8d4ff3eb
|
||||
RUN git clone https://github.com/go-swagger/go-swagger.git /go/src/github.com/go-swagger/go-swagger \
|
||||
&& (cd /go/src/github.com/go-swagger/go-swagger && git checkout -q $GO_SWAGGER_COMMIT) \
|
||||
&& go install -v github.com/go-swagger/go-swagger/cmd/swagger
|
||||
|
||||
# Set user.email so crosbymichael's in-container merge commits go smoothly
|
||||
RUN git config --global user.email 'docker-dummy@example.com'
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor pkcs11 seccomp selinux
|
||||
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv $PWD/.bashrc ~/.bashrc
|
||||
# Add integration helps to bashrc
|
||||
RUN echo "source $PWD/hack/make/.integration-test-helpers" >> /etc/bash.bashrc
|
||||
|
||||
# Register Docker's bash completion.
|
||||
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||
buildpack-deps:jessie@sha256:25785f89240fbcdd8a74bdaf30dd5599a9523882c6dfc567f2e9ef7cf6f79db6 \
|
||||
busybox:latest@sha256:e4f93f6ed15a0cdd342f5aae387886fba0ab98af0a102da6276eaf24d6e6ade0 \
|
||||
debian:jessie@sha256:f968f10b4b523737e253a97eac59b0d1420b5c19b69928d35801a6373ffe330e \
|
||||
hello-world:latest@sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7
|
||||
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||
|
||||
# Install tomlv, vndr, runc, containerd, tini, docker-proxy
|
||||
# Please edit hack/dockerfile/install-binaries.sh to update them.
|
||||
COPY hack/dockerfile/binaries-commits /tmp/binaries-commits
|
||||
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
|
||||
RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy
|
||||
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
175
vendor/github.com/docker/docker/Dockerfile.aarch64
generated
vendored
Normal file
175
vendor/github.com/docker/docker/Dockerfile.aarch64
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
# This file describes the standard way to build Docker on aarch64, using docker
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker -f Dockerfile.aarch64 .
|
||||
#
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||
#
|
||||
# # Run the test suite:
|
||||
# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py
|
||||
#
|
||||
# Note: AppArmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
FROM aarch64/ubuntu:wily
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
aufs-tools \
|
||||
automake \
|
||||
bash-completion \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
cmake \
|
||||
createrepo \
|
||||
curl \
|
||||
dpkg-sig \
|
||||
g++ \
|
||||
gcc \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
libapparmor-dev \
|
||||
libc6-dev \
|
||||
libcap-dev \
|
||||
libltdl-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-dev \
|
||||
mercurial \
|
||||
net-tools \
|
||||
parallel \
|
||||
pkg-config \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
gccgo \
|
||||
iproute2 \
|
||||
iputils-ping \
|
||||
vim-common \
|
||||
--no-install-recommends
|
||||
|
||||
# Get lvm2 source for compiling statically
|
||||
ENV LVM2_VERSION 2.02.103
|
||||
RUN mkdir -p /usr/local/lvm2 \
|
||||
&& curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
|
||||
| tar -xzC /usr/local/lvm2 --strip-components=1
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# Fix platform enablement in lvm2 to support aarch64 properly
|
||||
RUN set -e \
|
||||
&& for f in config.guess config.sub; do \
|
||||
curl -fsSL -o "/usr/local/lvm2/autoconf/$f" "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=$f;hb=HEAD"; \
|
||||
done
|
||||
# "arch.c:78:2: error: #error the arch code needs to know about your machine type"
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure \
|
||||
--build="$(gcc -print-multiarch)" \
|
||||
--enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# Install seccomp: the version shipped in trusty is too old
|
||||
ENV SECCOMP_VERSION 2.3.1
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH="$(mktemp -d)" \
|
||||
&& curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
|
||||
| tar -xzC "$SECCOMP_PATH" --strip-components=1 \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& ./configure --prefix=/usr/local \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
# Install Go
|
||||
# We don't have official binary tarballs for ARM64, eigher for Go or bootstrap,
|
||||
# so we use gccgo as bootstrap to build Go from source code.
|
||||
# We don't use the official ARMv6 released binaries as a GOROOT_BOOTSTRAP, because
|
||||
# not all ARM64 platforms support 32-bit mode. 32-bit mode is optional for ARMv8.
|
||||
ENV GO_VERSION 1.7.3
|
||||
RUN mkdir /usr/src/go && curl -fsSL https://golang.org/dl/go${GO_VERSION}.src.tar.gz | tar -v -C /usr/src/go -xz --strip-components=1 \
|
||||
&& cd /usr/src/go/src \
|
||||
&& GOOS=linux GOARCH=arm64 GOROOT_BOOTSTRAP="$(go env GOROOT)" ./make.bash
|
||||
|
||||
ENV PATH /usr/src/go/bin:$PATH
|
||||
ENV GOPATH /go
|
||||
|
||||
# Only install one version of the registry, because old version which support
|
||||
# schema1 manifests is not working on ARM64, we should skip integration-cli
|
||||
# tests for schema1 manifests on ARM64.
|
||||
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Install notary and notary-server
|
||||
ENV NOTARY_VERSION v0.4.2
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT \
|
||||
&& pip install -r test-requirements.txt
|
||||
|
||||
# Set user.email so crosbymichael's in-container merge commits go smoothly
|
||||
RUN git config --global user.email 'docker-dummy@example.com'
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor pkcs11 seccomp selinux
|
||||
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv $PWD/.bashrc ~/.bashrc
|
||||
|
||||
# Register Docker's bash completion.
|
||||
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||
aarch64/buildpack-deps:jessie@sha256:6aa1d6910791b7ac78265fd0798e5abd6cb3f27ae992f6f960f6c303ec9535f2 \
|
||||
aarch64/busybox:latest@sha256:b23a6a37cf269dff6e46d2473b6e227afa42b037e6d23435f1d2bc40fc8c2828 \
|
||||
aarch64/debian:jessie@sha256:4be74a41a7c70ebe887b634b11ffe516cf4fcd56864a54941e56bb49883c3170 \
|
||||
aarch64/hello-world:latest@sha256:65a4a158587b307bb02db4de41b836addb0c35175bdc801367b1ac1ddeb9afda
|
||||
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||
|
||||
# Install tomlv, vndr, runc, containerd, tini, docker-proxy
|
||||
# Please edit hack/dockerfile/install-binaries.sh to update them.
|
||||
COPY hack/dockerfile/binaries-commits /tmp/binaries-commits
|
||||
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
|
||||
RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy
|
||||
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
182
vendor/github.com/docker/docker/Dockerfile.armhf
generated
vendored
Normal file
182
vendor/github.com/docker/docker/Dockerfile.armhf
generated
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
# This file describes the standard way to build Docker on ARMv7, using docker
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker -f Dockerfile.armhf .
|
||||
#
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||
#
|
||||
# # Run the test suite:
|
||||
# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py
|
||||
#
|
||||
# Note: AppArmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
FROM armhf/debian:jessie
|
||||
|
||||
# allow replacing httpredir or deb mirror
|
||||
ARG APT_MIRROR=deb.debian.org
|
||||
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
aufs-tools \
|
||||
automake \
|
||||
bash-completion \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
createrepo \
|
||||
curl \
|
||||
cmake \
|
||||
dpkg-sig \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
net-tools \
|
||||
libapparmor-dev \
|
||||
libcap-dev \
|
||||
libltdl-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-journal-dev \
|
||||
libtool \
|
||||
mercurial \
|
||||
pkg-config \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
xfsprogs \
|
||||
tar \
|
||||
vim-common \
|
||||
--no-install-recommends \
|
||||
&& pip install awscli==1.10.15
|
||||
|
||||
# Get lvm2 source for compiling statically
|
||||
ENV LVM2_VERSION 2.02.103
|
||||
RUN mkdir -p /usr/local/lvm2 \
|
||||
&& curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
|
||||
| tar -xzC /usr/local/lvm2 --strip-components=1
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure \
|
||||
--build="$(gcc -print-multiarch)" \
|
||||
--enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# Install Go
|
||||
ENV GO_VERSION 1.7.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-armv6l.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
ENV GOPATH /go
|
||||
|
||||
# We're building for armhf, which is ARMv7, so let's be explicit about that
|
||||
ENV GOARCH arm
|
||||
ENV GOARM 7
|
||||
|
||||
# Dependency for golint
|
||||
ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3
|
||||
RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \
|
||||
&& (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT)
|
||||
|
||||
# Grab Go's lint tool
|
||||
ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456
|
||||
RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \
|
||||
&& (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \
|
||||
&& go install -v github.com/golang/lint/golint
|
||||
|
||||
# Install seccomp: the version shipped in trusty is too old
|
||||
ENV SECCOMP_VERSION 2.3.1
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH="$(mktemp -d)" \
|
||||
&& curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
|
||||
| tar -xzC "$SECCOMP_PATH" --strip-components=1 \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& ./configure --prefix=/usr/local \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
# Install two versions of the registry. The first is an older version that
|
||||
# only supports schema1 manifests. The second is a newer version that supports
|
||||
# both. This allows integration-cli tests to cover push/pull with both schema1
|
||||
# and schema2 manifests.
|
||||
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
|
||||
ENV REGISTRY_COMMIT cb08de17d74bef86ce6c5abe8b240e282f5750be
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Install notary and notary-server
|
||||
ENV NOTARY_VERSION v0.4.2
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT \
|
||||
&& pip install -r test-requirements.txt
|
||||
|
||||
# Set user.email so crosbymichael's in-container merge commits go smoothly
|
||||
RUN git config --global user.email 'docker-dummy@example.com'
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor pkcs11 seccomp selinux
|
||||
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv $PWD/.bashrc ~/.bashrc
|
||||
|
||||
# Register Docker's bash completion.
|
||||
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||
armhf/buildpack-deps:jessie@sha256:ca6cce8e5bf5c952129889b5cc15cd6aa8d995d77e55e3749bbaadae50e476cb \
|
||||
armhf/busybox:latest@sha256:d98a7343ac750ffe387e3d514f8521ba69846c216778919b01414b8617cfb3d4 \
|
||||
armhf/debian:jessie@sha256:4a2187483f04a84f9830910fe3581d69b3c985cc045d9f01d8e2f3795b28107b \
|
||||
armhf/hello-world:latest@sha256:161dcecea0225975b2ad5f768058212c1e0d39e8211098666ffa1ac74cfb7791
|
||||
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||
|
||||
# Install tomlv, vndr, runc, containerd, tini, docker-proxy
|
||||
# Please edit hack/dockerfile/install-binaries.sh to update them.
|
||||
COPY hack/dockerfile/binaries-commits /tmp/binaries-commits
|
||||
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
|
||||
RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy
|
||||
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
202
vendor/github.com/docker/docker/Dockerfile.ppc64le
generated
vendored
Normal file
202
vendor/github.com/docker/docker/Dockerfile.ppc64le
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
# This file describes the standard way to build Docker on ppc64le, using docker
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker -f Dockerfile.ppc64le .
|
||||
#
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||
#
|
||||
# # Run the test suite:
|
||||
# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py
|
||||
#
|
||||
# Note: AppArmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
# ppc64le/golang is a debian:jessie based image with golang installed
|
||||
FROM ppc64le/golang:1.6.3
|
||||
|
||||
# allow replacing httpredir or deb mirror
|
||||
ARG APT_MIRROR=deb.debian.org
|
||||
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
aufs-tools \
|
||||
automake \
|
||||
bash-completion \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
cmake \
|
||||
createrepo \
|
||||
curl \
|
||||
dpkg-sig \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
net-tools \
|
||||
libapparmor-dev \
|
||||
libcap-dev \
|
||||
libltdl-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-journal-dev \
|
||||
libtool \
|
||||
mercurial \
|
||||
pkg-config \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
xfsprogs \
|
||||
tar \
|
||||
vim-common \
|
||||
--no-install-recommends
|
||||
|
||||
# Get lvm2 source for compiling statically
|
||||
ENV LVM2_VERSION 2.02.103
|
||||
RUN mkdir -p /usr/local/lvm2 \
|
||||
&& curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
|
||||
| tar -xzC /usr/local/lvm2 --strip-components=1
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# Fix platform enablement in lvm2 to support ppc64le properly
|
||||
RUN set -e \
|
||||
&& for f in config.guess config.sub; do \
|
||||
curl -fsSL -o "/usr/local/lvm2/autoconf/$f" "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=$f;hb=HEAD"; \
|
||||
done
|
||||
# "arch.c:78:2: error: #error the arch code needs to know about your machine type"
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure \
|
||||
--build="$(gcc -print-multiarch)" \
|
||||
--enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# Install seccomp: the version shipped in jessie is too old
|
||||
ENV SECCOMP_VERSION 2.3.1
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH="$(mktemp -d)" \
|
||||
&& curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
|
||||
| tar -xzC "$SECCOMP_PATH" --strip-components=1 \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& ./configure --prefix=/usr/local \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
|
||||
# Install Go
|
||||
# ppc64le doesn't have official go binaries, so use the version of go installed from the image
|
||||
# to build go from source.
|
||||
# NOTE: ppc64le has compatibility issues with older versions of go, so make sure the version >= 1.6
|
||||
ENV GO_VERSION 1.7.3
|
||||
ENV GO_DOWNLOAD_URL https://golang.org/dl/go${GO_VERSION}.src.tar.gz
|
||||
|
||||
RUN set -x \
|
||||
&& TEMPDIR="$(mktemp -d)" \
|
||||
&& mv /usr/local/go $TEMPDIR \
|
||||
&& GOROOT_BOOTSTRAP=$TEMPDIR/go \
|
||||
&& cd /usr/local \
|
||||
&& curl -fsSL "$GO_DOWNLOAD_URL" -o golang.tar.gz \
|
||||
&& tar -C /usr/local -xzf golang.tar.gz \
|
||||
&& rm golang.tar.gz \
|
||||
&& cd go/src && ./make.bash 2>&1 \
|
||||
&& rm -rf $TEMPDIR
|
||||
|
||||
ENV GOROOT_BOOTSTRAP /usr/local/go
|
||||
ENV PATH /usr/local/go/bin/:$PATH
|
||||
ENV GOPATH /go
|
||||
|
||||
# Dependency for golint
|
||||
ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3
|
||||
RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \
|
||||
&& (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT)
|
||||
|
||||
# Grab Go's lint tool
|
||||
ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456
|
||||
RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \
|
||||
&& (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \
|
||||
&& go install -v github.com/golang/lint/golint
|
||||
|
||||
# Install two versions of the registry. The first is an older version that
|
||||
# only supports schema1 manifests. The second is a newer version that supports
|
||||
# both. This allows integration-cli tests to cover push/pull with both schema1
|
||||
# and schema2 manifests.
|
||||
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
|
||||
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Install notary and notary-server
|
||||
ENV NOTARY_VERSION v0.4.2
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT \
|
||||
&& pip install -r test-requirements.txt
|
||||
|
||||
# Set user.email so crosbymichael's in-container merge commits go smoothly
|
||||
RUN git config --global user.email 'docker-dummy@example.com'
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor pkcs11 seccomp selinux
|
||||
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv $PWD/.bashrc ~/.bashrc
|
||||
|
||||
# Register Docker's bash completion.
|
||||
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||
ppc64le/buildpack-deps:jessie@sha256:902bfe4ef1389f94d143d64516dd50a2de75bca2e66d4a44b1d73f63ddf05dda \
|
||||
ppc64le/busybox:latest@sha256:38bb82085248d5a3c24bd7a5dc146f2f2c191e189da0441f1c2ca560e3fc6f1b \
|
||||
ppc64le/debian:jessie@sha256:412845f51b6ab662afba71bc7a716e20fdb9b84f185d180d4c7504f8a75c4f91 \
|
||||
ppc64le/hello-world:latest@sha256:186a40a9a02ca26df0b6c8acdfb8ac2f3ae6678996a838f977e57fac9d963974
|
||||
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||
|
||||
# Install tomlv, vndr, runc, containerd, tini, docker-proxy
|
||||
# Please edit hack/dockerfile/install-binaries.sh to update them.
|
||||
COPY hack/dockerfile/binaries-commits /tmp/binaries-commits
|
||||
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
|
||||
RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy
|
||||
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
190
vendor/github.com/docker/docker/Dockerfile.s390x
generated
vendored
Normal file
190
vendor/github.com/docker/docker/Dockerfile.s390x
generated
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
# This file describes the standard way to build Docker on s390x, using docker
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker -f Dockerfile.s390x .
|
||||
#
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||
#
|
||||
# # Run the test suite:
|
||||
# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py
|
||||
#
|
||||
# Note: AppArmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
FROM s390x/gcc:6.1
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
aufs-tools \
|
||||
automake \
|
||||
bash-completion \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
cmake \
|
||||
createrepo \
|
||||
curl \
|
||||
dpkg-sig \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
net-tools \
|
||||
libapparmor-dev \
|
||||
libcap-dev \
|
||||
libltdl-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-journal-dev \
|
||||
libtool \
|
||||
mercurial \
|
||||
pkg-config \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
xfsprogs \
|
||||
tar \
|
||||
vim-common \
|
||||
--no-install-recommends
|
||||
|
||||
# glibc in Debian has a bug specific to s390x that won't be fixed until Debian 8.6 is released
|
||||
# - https://github.com/docker/docker/issues/24748
|
||||
# - https://sourceware.org/git/?p=glibc.git;a=commit;h=890b7a4b33d482b5c768ab47d70758b80227e9bc
|
||||
# - https://sourceware.org/git/?p=glibc.git;a=commit;h=2e807f29595eb5b1e5d0decc6e356a3562ecc58e
|
||||
RUN echo 'deb http://httpredir.debian.org/debian jessie-proposed-updates main' >> /etc/apt/sources.list.d/pu.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y libc6 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install seccomp: the version shipped in jessie is too old
|
||||
ENV SECCOMP_VERSION 2.3.1
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH="$(mktemp -d)" \
|
||||
&& curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
|
||||
| tar -xzC "$SECCOMP_PATH" --strip-components=1 \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& ./configure --prefix=/usr/local \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
# Get lvm2 source for compiling statically
|
||||
ENV LVM2_VERSION 2.02.103
|
||||
RUN mkdir -p /usr/local/lvm2 \
|
||||
&& curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
|
||||
| tar -xzC /usr/local/lvm2 --strip-components=1
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# Fix platform enablement in lvm2 to support s390x properly
|
||||
RUN set -e \
|
||||
&& for f in config.guess config.sub; do \
|
||||
curl -fsSL -o "/usr/local/lvm2/autoconf/$f" "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=$f;hb=HEAD"; \
|
||||
done
|
||||
# "arch.c:78:2: error: #error the arch code needs to know about your machine type"
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure \
|
||||
--build="$(gcc -print-multiarch)" \
|
||||
--enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
ENV GO_VERSION 1.7.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-s390x.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
ENV GOPATH /go
|
||||
|
||||
# Dependency for golint
|
||||
ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3
|
||||
RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \
|
||||
&& (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT)
|
||||
|
||||
# Grab Go's lint tool
|
||||
ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456
|
||||
RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \
|
||||
&& (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \
|
||||
&& go install -v github.com/golang/lint/golint
|
||||
|
||||
# Install two versions of the registry. The first is an older version that
|
||||
# only supports schema1 manifests. The second is a newer version that supports
|
||||
# both. This allows integration-cli tests to cover push/pull with both schema1
|
||||
# and schema2 manifests.
|
||||
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
|
||||
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Install notary and notary-server
|
||||
ENV NOTARY_VERSION v0.4.2
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT \
|
||||
&& pip install -r test-requirements.txt
|
||||
|
||||
# Set user.email so crosbymichael's in-container merge commits go smoothly
|
||||
RUN git config --global user.email 'docker-dummy@example.com'
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor selinux seccomp
|
||||
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv $PWD/.bashrc ~/.bashrc
|
||||
|
||||
# Register Docker's bash completion.
|
||||
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||
s390x/buildpack-deps:jessie@sha256:4d1381224acaca6c4bfe3604de3af6972083a8558a99672cb6989c7541780099 \
|
||||
s390x/busybox:latest@sha256:dd61522c983884a66ed72d60301925889028c6d2d5e0220a8fe1d9b4c6a4f01b \
|
||||
s390x/debian:jessie@sha256:b74c863400909eff3c5e196cac9bfd1f6333ce47aae6a38398d87d5875da170a \
|
||||
s390x/hello-world:latest@sha256:780d80b3a7677c3788c0d5cd9168281320c8d4a6d9183892d8ee5cdd610f5699
|
||||
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||
|
||||
# Install tomlv, vndr, runc, containerd, tini, docker-proxy
|
||||
# Please edit hack/dockerfile/install-binaries.sh to update them.
|
||||
COPY hack/dockerfile/binaries-commits /tmp/binaries-commits
|
||||
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
|
||||
RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy
|
||||
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
73
vendor/github.com/docker/docker/Dockerfile.simple
generated
vendored
Normal file
73
vendor/github.com/docker/docker/Dockerfile.simple
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
# docker build -t docker:simple -f Dockerfile.simple .
|
||||
# docker run --rm docker:simple hack/make.sh dynbinary
|
||||
# docker run --rm --privileged docker:simple hack/dind hack/make.sh test-unit
|
||||
# docker run --rm --privileged -v /var/lib/docker docker:simple hack/dind hack/make.sh dynbinary test-integration-cli
|
||||
|
||||
# This represents the bare minimum required to build and test Docker.
|
||||
|
||||
FROM debian:jessie
|
||||
|
||||
# allow replacing httpredir or deb mirror
|
||||
ARG APT_MIRROR=deb.debian.org
|
||||
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
|
||||
|
||||
# Compile and runtime deps
|
||||
# https://github.com/docker/docker/blob/master/project/PACKAGERS.md#build-dependencies
|
||||
# https://github.com/docker/docker/blob/master/project/PACKAGERS.md#runtime-dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
curl \
|
||||
cmake \
|
||||
gcc \
|
||||
git \
|
||||
libapparmor-dev \
|
||||
libdevmapper-dev \
|
||||
libsqlite3-dev \
|
||||
\
|
||||
ca-certificates \
|
||||
e2fsprogs \
|
||||
iptables \
|
||||
procps \
|
||||
xfsprogs \
|
||||
xz-utils \
|
||||
\
|
||||
aufs-tools \
|
||||
vim-common \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install seccomp: the version shipped in trusty is too old
|
||||
ENV SECCOMP_VERSION 2.3.1
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH="$(mktemp -d)" \
|
||||
&& curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
|
||||
| tar -xzC "$SECCOMP_PATH" --strip-components=1 \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& ./configure --prefix=/usr/local \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
# Install Go
|
||||
# IMPORTANT: If the version of Go is updated, the Windows to Linux CI machines
|
||||
# will need updating, to avoid errors. Ping #docker-maintainers on IRC
|
||||
# with a heads-up.
|
||||
ENV GO_VERSION 1.7.3
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
ENV GOPATH /go
|
||||
ENV CGO_LDFLAGS -L/lib
|
||||
|
||||
# Install runc, containerd, tini and docker-proxy
|
||||
# Please edit hack/dockerfile/install-binaries.sh to update them.
|
||||
COPY hack/dockerfile/binaries-commits /tmp/binaries-commits
|
||||
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
|
||||
RUN /tmp/install-binaries.sh runc containerd tini proxy
|
||||
|
||||
ENV AUTO_GOPATH 1
|
||||
WORKDIR /usr/src/docker
|
||||
COPY . /usr/src/docker
|
||||
20
vendor/github.com/docker/docker/Dockerfile.solaris
generated
vendored
Normal file
20
vendor/github.com/docker/docker/Dockerfile.solaris
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
# Defines an image that hosts a native Docker build environment for Solaris
|
||||
# TODO: Improve stub
|
||||
|
||||
FROM solaris:latest
|
||||
|
||||
# compile and runtime deps
|
||||
RUN pkg install --accept \
|
||||
git \
|
||||
gnu-coreutils \
|
||||
gnu-make \
|
||||
gnu-tar \
|
||||
diagnostic/top \
|
||||
golang \
|
||||
library/golang/* \
|
||||
developer/gcc-*
|
||||
|
||||
ENV GOPATH /go/:/usr/lib/gocode/1.5/
|
||||
ENV DOCKER_CROSSPLATFORMS solaris/amd64
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
267
vendor/github.com/docker/docker/Dockerfile.windows
generated
vendored
Normal file
267
vendor/github.com/docker/docker/Dockerfile.windows
generated
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
# escape=`
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
# This file describes the standard way to build Docker in a container on Windows
|
||||
# Server 2016 or Windows 10.
|
||||
#
|
||||
# Maintainer: @jhowardmsft
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Prerequisites:
|
||||
# --------------
|
||||
#
|
||||
# 1. Windows Server 2016 or Windows 10 with all Windows updates applied. The major
|
||||
# build number must be at least 14393. This can be confirmed, for example, by
|
||||
# running the following from an elevated PowerShell prompt - this sample output
|
||||
# is from a fully up to date machine as at mid-November 2016:
|
||||
#
|
||||
# >> PS C:\> $(gin).WindowsBuildLabEx
|
||||
# >> 14393.447.amd64fre.rs1_release_inmarket.161102-0100
|
||||
#
|
||||
# 2. Git for Windows (or another git client) must be installed. https://git-scm.com/download/win.
|
||||
#
|
||||
# 3. The machine must be configured to run containers. For example, by following
|
||||
# the quick start guidance at https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/quick_start or
|
||||
# https://github.com/docker/labs/blob/master/windows/windows-containers/Setup.md
|
||||
#
|
||||
# 4. If building in a Hyper-V VM: For Windows Server 2016 using Windows Server
|
||||
# containers as the default option, it is recommended you have at least 1GB
|
||||
# of memory assigned; For Windows 10 where Hyper-V Containers are employed, you
|
||||
# should have at least 4GB of memory assigned. Note also, to run Hyper-V
|
||||
# containers in a VM, it is necessary to configure the VM for nested virtualization.
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Usage:
|
||||
# -----
|
||||
#
|
||||
# The following steps should be run from an (elevated*) Windows PowerShell prompt.
|
||||
#
|
||||
# (*In a default installation of containers on Windows following the quick-start guidance at
|
||||
# https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/quick_start,
|
||||
# the docker.exe client must run elevated to be able to connect to the daemon).
|
||||
#
|
||||
# 1. Clone the sources from github.com:
|
||||
#
|
||||
# >> git clone https://github.com/docker/docker.git C:\go\src\github.com\docker\docker
|
||||
# >> Cloning into 'C:\go\src\github.com\docker\docker'...
|
||||
# >> remote: Counting objects: 186216, done.
|
||||
# >> remote: Compressing objects: 100% (21/21), done.
|
||||
# >> remote: Total 186216 (delta 5), reused 0 (delta 0), pack-reused 186195
|
||||
# >> Receiving objects: 100% (186216/186216), 104.32 MiB | 8.18 MiB/s, done.
|
||||
# >> Resolving deltas: 100% (123139/123139), done.
|
||||
# >> Checking connectivity... done.
|
||||
# >> Checking out files: 100% (3912/3912), done.
|
||||
# >> PS C:\>
|
||||
#
|
||||
#
|
||||
# 2. Change directory to the cloned docker sources:
|
||||
#
|
||||
# >> cd C:\go\src\github.com\docker\docker
|
||||
#
|
||||
#
|
||||
# 3. Build a docker image with the components required to build the docker binaries from source
|
||||
# by running one of the following:
|
||||
#
|
||||
# >> docker build -t nativebuildimage -f Dockerfile.windows .
|
||||
# >> docker build -t nativebuildimage -f Dockerfile.windows -m 2GB . (if using Hyper-V containers)
|
||||
#
|
||||
#
|
||||
# 4. Build the docker executable binaries by running one of the following:
|
||||
#
|
||||
# >> docker run --name binaries nativebuildimage hack\make.ps1 -Binary
|
||||
# >> docker run --name binaries -m 2GB nativebuildimage hack\make.ps1 -Binary (if using Hyper-V containers)
|
||||
#
|
||||
#
|
||||
# 5. Copy the binaries out of the container, replacing HostPath with an appropriate destination
|
||||
# folder on the host system where you want the binaries to be located.
|
||||
#
|
||||
# >> docker cp binaries:C:\go\src\github.com\docker\docker\bundles\docker.exe C:\HostPath\docker.exe
|
||||
# >> docker cp binaries:C:\go\src\github.com\docker\docker\bundles\dockerd.exe C:\HostPath\dockerd.exe
|
||||
#
|
||||
#
|
||||
# 6. (Optional) Remove the interim container holding the built executable binaries:
|
||||
#
|
||||
# >> docker rm binaries
|
||||
#
|
||||
#
|
||||
# 7. (Optional) Remove the image used for the container in which the executable
|
||||
# binaries are build. Tip - it may be useful to keep this image around if you need to
|
||||
# build multiple times. Then you can take advantage of the builder cache to have an
|
||||
# image which has all the components required to build the binaries already installed.
|
||||
#
|
||||
# >> docker rmi nativebuildimage
|
||||
#
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# The validation tests can either run in a container, or directly on the host. To run in a
|
||||
# container, ensure you have created the nativebuildimage above. Then run one of the
|
||||
# following from an (elevated) Windows PowerShell prompt:
|
||||
#
|
||||
# >> docker run --rm nativebuildimage hack\make.ps1 -DCO -PkgImports -GoFormat
|
||||
# >> docker run --rm -m 2GB nativebuildimage hack\make.ps1 -DCO -PkgImports -GoFormat (if using Hyper-V containers)
|
||||
|
||||
# To run the validation tests on the host, from the root of the repository, run the
|
||||
# following from a Windows PowerShell prompt (elevation is not required): (Note Go
|
||||
# must be installed to run these tests)
|
||||
#
|
||||
# >> hack\make.ps1 -DCO -PkgImports -GoFormat
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# To run unit tests, ensure you have created the nativebuildimage above. Then run one of
|
||||
# the following from an (elevated) Windows PowerShell prompt:
|
||||
#
|
||||
# >> docker run --rm nativebuildimage hack\make.ps1 -TestUnit
|
||||
# >> docker run --rm -m 2GB nativebuildimage hack\make.ps1 -TestUnit (if using Hyper-V containers)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# To run all tests and binary build, ensure you have created the nativebuildimage above. Then
|
||||
# run one of the following from an (elevated) Windows PowerShell prompt:
|
||||
#
|
||||
# >> docker run nativebuildimage hack\make.ps1 -All
|
||||
# >> docker run -m 2GB nativebuildimage hack\make.ps1 -All (if using Hyper-V containers)
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Important notes:
|
||||
# ---------------
|
||||
#
|
||||
# Don't attempt to use a bind-mount to pass a local directory as the bundles target
|
||||
# directory. It does not work (golang attempts for follow a mapped folder incorrectly).
|
||||
# Instead, use docker cp as per the example.
|
||||
#
|
||||
# go.zip is not removed from the image as it is used by the Windows CI servers
|
||||
# to ensure the host and image are running consistent versions of go.
|
||||
#
|
||||
# Nanoserver support is a work in progress. Although the image will build if the
|
||||
# FROM statement is updated, it will not work when running autogen through hack\make.ps1.
|
||||
# It is suspected that the required GCC utilities (eg gcc, windres, windmc) silently
|
||||
# quit due to the use of console hooks which are not available.
|
||||
#
|
||||
# The docker integration tests do not currently run in a container on Windows, predominantly
|
||||
# due to Windows not supporting privileged mode, so anything using a volume would fail.
|
||||
# They (along with the rest of the docker CI suite) can be run using
|
||||
# https://github.com/jhowardmsft/docker-w2wCIScripts/blob/master/runCI/Invoke-DockerCI.ps1.
|
||||
#
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# The number of build steps below are explicitly minimised to improve performance.
|
||||
FROM microsoft/windowsservercore
|
||||
|
||||
# Use PowerShell as the default shell
|
||||
SHELL ["powershell", "-command"]
|
||||
|
||||
# Environment variable notes:
|
||||
# - GO_VERSION must be consistent with 'Dockerfile' used by Linux.
|
||||
# - FROM_DOCKERFILE is used for detection of building within a container.
|
||||
ENV GO_VERSION=1.7.3 `
|
||||
GIT_VERSION=2.10.2 `
|
||||
GOPATH=C:\go `
|
||||
FROM_DOCKERFILE=1
|
||||
|
||||
RUN `
|
||||
$ErrorActionPreference = 'Stop'; `
|
||||
$ProgressPreference = 'SilentlyContinue'; `
|
||||
`
|
||||
Function Test-Nano() { `
|
||||
$EditionId = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name 'EditionID').EditionId; `
|
||||
return (($EditionId -eq 'ServerStandardNano') -or ($EditionId -eq 'ServerDataCenterNano') -or ($EditionId -eq 'NanoServer')); `
|
||||
}`
|
||||
`
|
||||
Function Download-File([string] $source, [string] $target) { `
|
||||
if (Test-Nano) { `
|
||||
$handler = New-Object System.Net.Http.HttpClientHandler; `
|
||||
$client = New-Object System.Net.Http.HttpClient($handler); `
|
||||
$client.Timeout = New-Object System.TimeSpan(0, 30, 0); `
|
||||
$cancelTokenSource = [System.Threading.CancellationTokenSource]::new(); `
|
||||
$responseMsg = $client.GetAsync([System.Uri]::new($source), $cancelTokenSource.Token); `
|
||||
$responseMsg.Wait(); `
|
||||
if (!$responseMsg.IsCanceled) { `
|
||||
$response = $responseMsg.Result; `
|
||||
if ($response.IsSuccessStatusCode) { `
|
||||
$downloadedFileStream = [System.IO.FileStream]::new($target, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write); `
|
||||
$copyStreamOp = $response.Content.CopyToAsync($downloadedFileStream); `
|
||||
$copyStreamOp.Wait(); `
|
||||
$downloadedFileStream.Close(); `
|
||||
if ($copyStreamOp.Exception -ne $null) { throw $copyStreamOp.Exception } `
|
||||
} `
|
||||
} else { `
|
||||
Throw ("Failed to download " + $source) `
|
||||
}`
|
||||
} else { `
|
||||
$webClient = New-Object System.Net.WebClient; `
|
||||
$webClient.DownloadFile($source, $target); `
|
||||
} `
|
||||
} `
|
||||
`
|
||||
setx /M PATH $('C:\git\bin;C:\git\usr\bin;'+$Env:PATH+';C:\gcc\bin;C:\go\bin'); `
|
||||
`
|
||||
Write-Host INFO: Downloading git...; `
|
||||
$location='https://github.com/git-for-windows/git/releases/download/v'+$env:GIT_VERSION+'.windows.1/PortableGit-'+$env:GIT_VERSION+'-64-bit.7z.exe'; `
|
||||
Download-File $location C:\gitsetup.7z.exe; `
|
||||
`
|
||||
Write-Host INFO: Downloading go...; `
|
||||
Download-File $('https://golang.org/dl/go'+$Env:GO_VERSION+'.windows-amd64.zip') C:\go.zip; `
|
||||
`
|
||||
Write-Host INFO: Downloading compiler 1 of 3...; `
|
||||
Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/gcc.zip C:\gcc.zip; `
|
||||
`
|
||||
Write-Host INFO: Downloading compiler 2 of 3...; `
|
||||
Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/runtime.zip C:\runtime.zip; `
|
||||
`
|
||||
Write-Host INFO: Downloading compiler 3 of 3...; `
|
||||
Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/binutils.zip C:\binutils.zip; `
|
||||
`
|
||||
Write-Host INFO: Installing PS7Zip package...; `
|
||||
Install-Package PS7Zip -Force | Out-Null; `
|
||||
Write-Host INFO: Importing PS7Zip...; `
|
||||
Import-Module PS7Zip -Force; `
|
||||
New-Item C:\git -ItemType Directory | Out-Null ; `
|
||||
cd C:\git; `
|
||||
Write-Host INFO: Extracting git...; `
|
||||
Expand-7Zip C:\gitsetup.7z.exe | Out-Null; `
|
||||
cd C:\; `
|
||||
`
|
||||
Write-Host INFO: Expanding go...; `
|
||||
Expand-Archive C:\go.zip -DestinationPath C:\; `
|
||||
`
|
||||
Write-Host INFO: Expanding compiler 1 of 3...; `
|
||||
Expand-Archive C:\gcc.zip -DestinationPath C:\gcc -Force; `
|
||||
Write-Host INFO: Expanding compiler 2 of 3...; `
|
||||
Expand-Archive C:\runtime.zip -DestinationPath C:\gcc -Force; `
|
||||
Write-Host INFO: Expanding compiler 3 of 3...; `
|
||||
Expand-Archive C:\binutils.zip -DestinationPath C:\gcc -Force; `
|
||||
`
|
||||
Write-Host INFO: Removing downloaded files...; `
|
||||
Remove-Item C:\gcc.zip; `
|
||||
Remove-Item C:\runtime.zip; `
|
||||
Remove-Item C:\binutils.zip; `
|
||||
Remove-Item C:\gitsetup.7z.exe; `
|
||||
`
|
||||
Write-Host INFO: Creating source directory...; `
|
||||
New-Item -ItemType Directory -Path C:\go\src\github.com\docker\docker | Out-Null; `
|
||||
`
|
||||
Write-Host INFO: Configuring git core.autocrlf...; `
|
||||
C:\git\bin\git config --global core.autocrlf true; `
|
||||
`
|
||||
Write-Host INFO: Completed
|
||||
|
||||
# Make PowerShell the default entrypoint
|
||||
ENTRYPOINT ["powershell.exe"]
|
||||
|
||||
# Set the working directory to the location of the sources
|
||||
WORKDIR C:\go\src\github.com\docker\docker
|
||||
|
||||
# Copy the sources into the container
|
||||
COPY . .
|
||||
191
vendor/github.com/docker/docker/LICENSE
generated
vendored
Normal file
191
vendor/github.com/docker/docker/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://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
|
||||
|
||||
Copyright 2013-2016 Docker, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://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.
|
||||
376
vendor/github.com/docker/docker/MAINTAINERS
generated
vendored
Normal file
376
vendor/github.com/docker/docker/MAINTAINERS
generated
vendored
Normal file
@@ -0,0 +1,376 @@
|
||||
# Docker maintainers file
|
||||
#
|
||||
# This file describes who runs the docker/docker project and how.
|
||||
# This is a living document - if you see something out of date or missing, speak up!
|
||||
#
|
||||
# It is structured to be consumable by both humans and programs.
|
||||
# To extract its contents programmatically, use any TOML-compliant
|
||||
# parser.
|
||||
#
|
||||
# This file is compiled into the MAINTAINERS file in docker/opensource.
|
||||
#
|
||||
[Org]
|
||||
|
||||
[Org."Core maintainers"]
|
||||
|
||||
# The Core maintainers are the ghostbusters of the project: when there's a problem others
|
||||
# can't solve, they show up and fix it with bizarre devices and weaponry.
|
||||
# They have final say on technical implementation and coding style.
|
||||
# They are ultimately responsible for quality in all its forms: usability polish,
|
||||
# bugfixes, performance, stability, etc. When ownership can cleanly be passed to
|
||||
# a subsystem, they are responsible for doing so and holding the
|
||||
# subsystem maintainers accountable. If ownership is unclear, they are the de facto owners.
|
||||
|
||||
# For each release (including minor releases), a "release captain" is assigned from the
|
||||
# pool of core maintainers. Rotation is encouraged across all maintainers, to ensure
|
||||
# the release process is clear and up-to-date.
|
||||
|
||||
people = [
|
||||
"aaronlehmann",
|
||||
"akihirosuda",
|
||||
"aluzzardi",
|
||||
"anusha",
|
||||
"coolljt0725",
|
||||
"cpuguy83",
|
||||
"crosbymichael",
|
||||
"dnephin",
|
||||
"duglin",
|
||||
"estesp",
|
||||
"icecrime",
|
||||
"jhowardmsft",
|
||||
"justincormack",
|
||||
"lk4d4",
|
||||
"mavenugo",
|
||||
"mhbauer",
|
||||
"mlaventure",
|
||||
"mrjana",
|
||||
"runcom",
|
||||
"stevvooe",
|
||||
"tianon",
|
||||
"tibor",
|
||||
"tonistiigi",
|
||||
"unclejack",
|
||||
"vdemeester",
|
||||
"vieux"
|
||||
]
|
||||
|
||||
[Org."Docs maintainers"]
|
||||
|
||||
# TODO Describe the docs maintainers role.
|
||||
|
||||
people = [
|
||||
"jamtur01",
|
||||
"misty",
|
||||
"sven",
|
||||
"thajeztah"
|
||||
]
|
||||
|
||||
[Org.Curators]
|
||||
|
||||
# The curators help ensure that incoming issues and pull requests are properly triaged and
|
||||
# that our various contribution and reviewing processes are respected. With their knowledge of
|
||||
# the repository activity, they can also guide contributors to relevant material or
|
||||
# discussions.
|
||||
#
|
||||
# They are neither code nor docs reviewers, so they are never expected to merge. They can
|
||||
# however:
|
||||
# - close an issue or pull request when it's an exact duplicate
|
||||
# - close an issue or pull request when it's inappropriate or off-topic
|
||||
|
||||
people = [
|
||||
"aboch",
|
||||
"andrewhsu",
|
||||
"ehazlett",
|
||||
"mgoelzer",
|
||||
"programmerq",
|
||||
"thajeztah"
|
||||
]
|
||||
|
||||
[Org.Alumni]
|
||||
|
||||
# This list contains maintainers that are no longer active on the project.
|
||||
# It is thanks to these people that the project has become what it is today.
|
||||
# Thank you!
|
||||
|
||||
people = [
|
||||
# David Calavera contributed many features to Docker, such as an improved
|
||||
# event system, dynamic configuration reloading, volume plugins, fancy
|
||||
# new templating options, and an external client credential store. As a
|
||||
# maintainer, David was release captain for Docker 1.8, and competing
|
||||
# with Jess Frazelle to be "top dream killer".
|
||||
# David is now doing amazing stuff as CTO for https://www.netlify.com,
|
||||
# and tweets as @calavera.
|
||||
"calavera",
|
||||
|
||||
# As a maintainer, Erik was responsible for the "builder", and
|
||||
# started the first designs for the new networking model in
|
||||
# Docker. Erik is now working on all kinds of plugins for Docker
|
||||
# (https://github.com/contiv) and various open source projects
|
||||
# in his own repository https://github.com/erikh. You may
|
||||
# still stumble into him in our issue tracker, or on IRC.
|
||||
"erikh",
|
||||
|
||||
# Jessica Frazelle, also known as the "Keyser Söze of containers",
|
||||
# runs *everything* in containers. She started contributing to
|
||||
# Docker with a (fun fun) change involving both iptables and regular
|
||||
# expressions (coz, YOLO!) on July 10, 2014
|
||||
# https://github.com/docker/docker/pull/6950/commits/f3a68ffa390fb851115c77783fa4031f1d3b2995.
|
||||
# Jess was Release Captain for Docker 1.4, 1.6 and 1.7, and contributed
|
||||
# many features and improvement, among which "seccomp profiles" (making
|
||||
# containers a lot more secure). Besides being a maintainer, she
|
||||
# set up the CI infrastructure for the project, giving everyone
|
||||
# something to shout at if a PR failed ("noooo Janky!").
|
||||
# Jess is currently working on the DCOS security team at Mesosphere,
|
||||
# and contributing to various open source projects.
|
||||
# Be sure you don't miss her talks at a conference near you (a must-see),
|
||||
# read her blog at https://blog.jessfraz.com (a must-read), and
|
||||
# check out her open source projects on GitHub https://github.com/jessfraz (a must-try).
|
||||
"jessfraz",
|
||||
|
||||
# As a docs maintainer, Mary Anthony contributed greatly to the Docker
|
||||
# docs. She wrote the Docker Contributor Guide and Getting Started
|
||||
# Guides. She helped create a doc build system independent of
|
||||
# docker/docker project, and implemented a new docs.docker.com theme and
|
||||
# nav for 2015 Dockercon. Fun fact: the most inherited layer in DockerHub
|
||||
# public repositories was originally referenced in
|
||||
# maryatdocker/docker-whale back in May 2015.
|
||||
"moxiegirl",
|
||||
|
||||
# Vincent "vbatts!" Batts made his first contribution to the project
|
||||
# in November 2013, to become a maintainer a few months later, on
|
||||
# May 10, 2014 (https://github.com/docker/docker/commit/d6e666a87a01a5634c250358a94c814bf26cb778).
|
||||
# As a maintainer, Vincent made important contributions to core elements
|
||||
# of Docker, such as "distribution" (tarsum) and graphdrivers (btrfs, devicemapper).
|
||||
# He also contributed the "tar-split" library, an important element
|
||||
# for the content-addressable store.
|
||||
# Vincent is currently a member of the Open Containers Initiative
|
||||
# Technical Oversight Board (TOB), besides his work at Red Hat and
|
||||
# Project Atomic. You can still find him regularly hanging out in
|
||||
# our repository and the #docker-dev and #docker-maintainers IRC channels
|
||||
# for a chat, as he's always a lot of fun.
|
||||
"vbatts",
|
||||
|
||||
# Vishnu became a maintainer to help out on the daemon codebase and
|
||||
# libcontainer integration. He's currently involved in the
|
||||
# Open Containers Initiative, working on the specifications,
|
||||
# besides his work on cAdvisor and Kubernetes for Google.
|
||||
"vishh"
|
||||
]
|
||||
|
||||
[people]
|
||||
|
||||
# A reference list of all people associated with the project.
|
||||
# All other sections should refer to people by their canonical key
|
||||
# in the people section.
|
||||
|
||||
# ADD YOURSELF HERE IN ALPHABETICAL ORDER
|
||||
|
||||
[people.aaronlehmann]
|
||||
Name = "Aaron Lehmann"
|
||||
Email = "aaron.lehmann@docker.com"
|
||||
GitHub = "aaronlehmann"
|
||||
|
||||
[people.aboch]
|
||||
Name = "Alessandro Boch"
|
||||
Email = "aboch@docker.com"
|
||||
GitHub = "aboch"
|
||||
|
||||
[people.akihirosuda]
|
||||
Name = "Akihiro Suda"
|
||||
Email = "suda.akihiro@lab.ntt.co.jp"
|
||||
GitHub = "AkihiroSuda"
|
||||
|
||||
[people.aluzzardi]
|
||||
Name = "Andrea Luzzardi"
|
||||
Email = "al@docker.com"
|
||||
GitHub = "aluzzardi"
|
||||
|
||||
[people.andrewhsu]
|
||||
Name = "Andrew Hsu"
|
||||
Email = "andrewhsu@docker.com"
|
||||
GitHub = "andrewhsu"
|
||||
|
||||
[people.anusha]
|
||||
Name = "Anusha Ragunathan"
|
||||
Email = "anusha@docker.com"
|
||||
GitHub = "anusha-ragunathan"
|
||||
|
||||
[people.calavera]
|
||||
Name = "David Calavera"
|
||||
Email = "david.calavera@gmail.com"
|
||||
GitHub = "calavera"
|
||||
|
||||
[people.coolljt0725]
|
||||
Name = "Lei Jitang"
|
||||
Email = "leijitang@huawei.com"
|
||||
GitHub = "coolljt0725"
|
||||
|
||||
[people.cpuguy83]
|
||||
Name = "Brian Goff"
|
||||
Email = "cpuguy83@gmail.com"
|
||||
Github = "cpuguy83"
|
||||
|
||||
[people.crosbymichael]
|
||||
Name = "Michael Crosby"
|
||||
Email = "crosbymichael@gmail.com"
|
||||
GitHub = "crosbymichael"
|
||||
|
||||
[people.dnephin]
|
||||
Name = "Daniel Nephin"
|
||||
Email = "dnephin@gmail.com"
|
||||
GitHub = "dnephin"
|
||||
|
||||
[people.duglin]
|
||||
Name = "Doug Davis"
|
||||
Email = "dug@us.ibm.com"
|
||||
GitHub = "duglin"
|
||||
|
||||
[people.ehazlett]
|
||||
Name = "Evan Hazlett"
|
||||
Email = "ejhazlett@gmail.com"
|
||||
GitHub = "ehazlett"
|
||||
|
||||
[people.erikh]
|
||||
Name = "Erik Hollensbe"
|
||||
Email = "erik@docker.com"
|
||||
GitHub = "erikh"
|
||||
|
||||
[people.estesp]
|
||||
Name = "Phil Estes"
|
||||
Email = "estesp@linux.vnet.ibm.com"
|
||||
GitHub = "estesp"
|
||||
|
||||
[people.icecrime]
|
||||
Name = "Arnaud Porterie"
|
||||
Email = "arnaud@docker.com"
|
||||
GitHub = "icecrime"
|
||||
|
||||
[people.jamtur01]
|
||||
Name = "James Turnbull"
|
||||
Email = "james@lovedthanlost.net"
|
||||
GitHub = "jamtur01"
|
||||
|
||||
[people.jhowardmsft]
|
||||
Name = "John Howard"
|
||||
Email = "jhoward@microsoft.com"
|
||||
GitHub = "jhowardmsft"
|
||||
|
||||
[people.jessfraz]
|
||||
Name = "Jessie Frazelle"
|
||||
Email = "jess@linux.com"
|
||||
GitHub = "jessfraz"
|
||||
|
||||
[people.justincormack]
|
||||
Name = "Justin Cormack"
|
||||
Email = "justin.cormack@docker.com"
|
||||
GitHub = "justincormack"
|
||||
|
||||
[people.lk4d4]
|
||||
Name = "Alexander Morozov"
|
||||
Email = "lk4d4@docker.com"
|
||||
GitHub = "lk4d4"
|
||||
|
||||
[people.mavenugo]
|
||||
Name = "Madhu Venugopal"
|
||||
Email = "madhu@docker.com"
|
||||
GitHub = "mavenugo"
|
||||
|
||||
[people.mgoelzer]
|
||||
Name = "Mike Goelzer"
|
||||
Email = "mike.goelzer@docker.com"
|
||||
GitHub = "mgoelzer"
|
||||
|
||||
[people.mhbauer]
|
||||
Name = "Morgan Bauer"
|
||||
Email = "mbauer@us.ibm.com"
|
||||
GitHub = "mhbauer"
|
||||
|
||||
[people.misty]
|
||||
Name = "Misty Stanley-Jones"
|
||||
Email = "misty@docker.com"
|
||||
GitHub = "mstanleyjones"
|
||||
|
||||
[people.mlaventure]
|
||||
Name = "Kenfe-Mickaël Laventure"
|
||||
Email = "mickael.laventure@docker.com"
|
||||
GitHub = "mlaventure"
|
||||
|
||||
[people.moxiegirl]
|
||||
Name = "Mary Anthony"
|
||||
Email = "mary.anthony@docker.com"
|
||||
GitHub = "moxiegirl"
|
||||
|
||||
[people.mrjana]
|
||||
Name = "Jana Radhakrishnan"
|
||||
Email = "mrjana@docker.com"
|
||||
GitHub = "mrjana"
|
||||
|
||||
[people.programmerq]
|
||||
Name = "Jeff Anderson"
|
||||
Email = "jeff@docker.com"
|
||||
GitHub = "programmerq"
|
||||
|
||||
[people.runcom]
|
||||
Name = "Antonio Murdaca"
|
||||
Email = "runcom@redhat.com"
|
||||
GitHub = "runcom"
|
||||
|
||||
[people.shykes]
|
||||
Name = "Solomon Hykes"
|
||||
Email = "solomon@docker.com"
|
||||
GitHub = "shykes"
|
||||
|
||||
[people.stevvooe]
|
||||
Name = "Stephen Day"
|
||||
Email = "stephen.day@docker.com"
|
||||
GitHub = "stevvooe"
|
||||
|
||||
[people.sven]
|
||||
Name = "Sven Dowideit"
|
||||
Email = "SvenDowideit@home.org.au"
|
||||
GitHub = "SvenDowideit"
|
||||
|
||||
[people.thajeztah]
|
||||
Name = "Sebastiaan van Stijn"
|
||||
Email = "github@gone.nl"
|
||||
GitHub = "thaJeztah"
|
||||
|
||||
[people.tianon]
|
||||
Name = "Tianon Gravi"
|
||||
Email = "admwiggin@gmail.com"
|
||||
GitHub = "tianon"
|
||||
|
||||
[people.tibor]
|
||||
Name = "Tibor Vass"
|
||||
Email = "tibor@docker.com"
|
||||
GitHub = "tiborvass"
|
||||
|
||||
[people.tonistiigi]
|
||||
Name = "Tõnis Tiigi"
|
||||
Email = "tonis@docker.com"
|
||||
GitHub = "tonistiigi"
|
||||
|
||||
[people.unclejack]
|
||||
Name = "Cristian Staretu"
|
||||
Email = "cristian.staretu@gmail.com"
|
||||
GitHub = "unclejack"
|
||||
|
||||
[people.vbatts]
|
||||
Name = "Vincent Batts"
|
||||
Email = "vbatts@redhat.com"
|
||||
GitHub = "vbatts"
|
||||
|
||||
[people.vdemeester]
|
||||
Name = "Vincent Demeester"
|
||||
Email = "vincent@sbr.pm"
|
||||
GitHub = "vdemeester"
|
||||
|
||||
[people.vieux]
|
||||
Name = "Victor Vieux"
|
||||
Email = "vieux@docker.com"
|
||||
GitHub = "vieux"
|
||||
|
||||
[people.vishh]
|
||||
Name = "Vishnu Kannan"
|
||||
Email = "vishnuk@google.com"
|
||||
GitHub = "vishh"
|
||||
147
vendor/github.com/docker/docker/Makefile
generated
vendored
Normal file
147
vendor/github.com/docker/docker/Makefile
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
.PHONY: all binary build cross deb help init-go-pkg-cache install manpages rpm run shell test test-docker-py test-integration-cli test-unit tgz validate win
|
||||
|
||||
# set the graph driver as the current graphdriver if not set
|
||||
DOCKER_GRAPHDRIVER := $(if $(DOCKER_GRAPHDRIVER),$(DOCKER_GRAPHDRIVER),$(shell docker info 2>&1 | grep "Storage Driver" | sed 's/.*: //'))
|
||||
|
||||
# get OS/Arch of docker engine
|
||||
DOCKER_OSARCH := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKER_ENGINE_OSARCH:-$$DOCKER_CLIENT_OSARCH}')
|
||||
DOCKERFILE := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKERFILE}')
|
||||
|
||||
# env vars passed through directly to Docker's build scripts
|
||||
# to allow things like `make KEEPBUNDLE=1 binary` easily
|
||||
# `project/PACKAGERS.md` have some limited documentation of some of these
|
||||
DOCKER_ENVS := \
|
||||
-e BUILD_APT_MIRROR \
|
||||
-e BUILDFLAGS \
|
||||
-e KEEPBUNDLE \
|
||||
-e DOCKER_BUILD_ARGS \
|
||||
-e DOCKER_BUILD_GOGC \
|
||||
-e DOCKER_BUILD_PKGS \
|
||||
-e DOCKER_DEBUG \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT \
|
||||
-e DOCKER_GRAPHDRIVER=$(DOCKER_GRAPHDRIVER) \
|
||||
-e DOCKER_INCREMENTAL_BINARY \
|
||||
-e DOCKER_PORT \
|
||||
-e DOCKER_REMAP_ROOT \
|
||||
-e DOCKER_STORAGE_OPTS \
|
||||
-e DOCKER_USERLANDPROXY \
|
||||
-e TESTDIRS \
|
||||
-e TESTFLAGS \
|
||||
-e TIMEOUT \
|
||||
-e HTTP_PROXY \
|
||||
-e HTTPS_PROXY \
|
||||
-e NO_PROXY \
|
||||
-e http_proxy \
|
||||
-e https_proxy \
|
||||
-e no_proxy
|
||||
# note: we _cannot_ add "-e DOCKER_BUILDTAGS" here because even if it's unset in the shell, that would shadow the "ENV DOCKER_BUILDTAGS" set in our Dockerfile, which is very important for our official builds
|
||||
|
||||
# to allow `make BIND_DIR=. shell` or `make BIND_DIR= test`
|
||||
# (default to no bind mount if DOCKER_HOST is set)
|
||||
# note: BINDDIR is supported for backwards-compatibility here
|
||||
BIND_DIR := $(if $(BINDDIR),$(BINDDIR),$(if $(DOCKER_HOST),,bundles))
|
||||
DOCKER_MOUNT := $(if $(BIND_DIR),-v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/docker/docker/$(BIND_DIR)")
|
||||
|
||||
# This allows the test suite to be able to run without worrying about the underlying fs used by the container running the daemon (e.g. aufs-on-aufs), so long as the host running the container is running a supported fs.
|
||||
# The volume will be cleaned up when the container is removed due to `--rm`.
|
||||
# Note that `BIND_DIR` will already be set to `bundles` if `DOCKER_HOST` is not set (see above BIND_DIR line), in such case this will do nothing since `DOCKER_MOUNT` will already be set.
|
||||
DOCKER_MOUNT := $(if $(DOCKER_MOUNT),$(DOCKER_MOUNT),-v /go/src/github.com/docker/docker/bundles)
|
||||
|
||||
# enable .go-pkg-cache if DOCKER_INCREMENTAL_BINARY and DOCKER_MOUNT (i.e.DOCKER_HOST) are set
|
||||
PKGCACHE_DIR := $(if $(PKGCACHE_DIR),$(PKGCACHE_DIR),.go-pkg-cache)
|
||||
PKGCACHE_MAP := gopath:/go/pkg goroot-linux_amd64_netgo:/usr/local/go/pkg/linux_amd64_netgo
|
||||
DOCKER_MOUNT := $(if $(DOCKER_INCREMENTAL_BINARY),$(DOCKER_MOUNT) $(shell echo $(PKGCACHE_MAP) | sed -E 's@([^ ]*)@-v "$(CURDIR)/$(PKGCACHE_DIR)/\1"@g'),$(DOCKER_MOUNT))
|
||||
|
||||
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
||||
GIT_BRANCH_CLEAN := $(shell echo $(GIT_BRANCH) | sed -e "s/[^[:alnum:]]/-/g")
|
||||
DOCKER_IMAGE := docker-dev$(if $(GIT_BRANCH_CLEAN),:$(GIT_BRANCH_CLEAN))
|
||||
DOCKER_PORT_FORWARD := $(if $(DOCKER_PORT),-p "$(DOCKER_PORT)",)
|
||||
|
||||
DOCKER_FLAGS := docker run --rm -i --privileged $(DOCKER_ENVS) $(DOCKER_MOUNT) $(DOCKER_PORT_FORWARD)
|
||||
BUILD_APT_MIRROR := $(if $(DOCKER_BUILD_APT_MIRROR),--build-arg APT_MIRROR=$(DOCKER_BUILD_APT_MIRROR))
|
||||
export BUILD_APT_MIRROR
|
||||
|
||||
# if this session isn't interactive, then we don't want to allocate a
|
||||
# TTY, which would fail, but if it is interactive, we do want to attach
|
||||
# so that the user can send e.g. ^C through.
|
||||
INTERACTIVE := $(shell [ -t 0 ] && echo 1 || echo 0)
|
||||
ifeq ($(INTERACTIVE), 1)
|
||||
DOCKER_FLAGS += -t
|
||||
endif
|
||||
|
||||
DOCKER_RUN_DOCKER := $(DOCKER_FLAGS) "$(DOCKER_IMAGE)"
|
||||
|
||||
default: binary
|
||||
|
||||
all: build ## validate all checks, build linux binaries, run all tests\ncross build non-linux binaries and generate archives
|
||||
$(DOCKER_RUN_DOCKER) bash -c 'hack/validate/default && hack/make.sh'
|
||||
|
||||
binary: build ## build the linux binaries
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh binary
|
||||
|
||||
build: bundles init-go-pkg-cache
|
||||
docker build ${BUILD_APT_MIRROR} ${DOCKER_BUILD_ARGS} -t "$(DOCKER_IMAGE)" -f "$(DOCKERFILE)" .
|
||||
|
||||
bundles:
|
||||
mkdir bundles
|
||||
|
||||
cross: build ## cross build the binaries for darwin, freebsd and\nwindows
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary binary cross
|
||||
|
||||
deb: build ## build the deb packages
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary build-deb
|
||||
|
||||
|
||||
help: ## this help
|
||||
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {sub("\\\\n",sprintf("\n%22c"," "), $$2);printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||
|
||||
init-go-pkg-cache:
|
||||
mkdir -p $(shell echo $(PKGCACHE_MAP) | sed -E 's@([^: ]*):[^ ]*@$(PKGCACHE_DIR)/\1@g')
|
||||
|
||||
install: ## install the linux binaries
|
||||
KEEPBUNDLE=1 hack/make.sh install-binary
|
||||
|
||||
manpages: ## Generate man pages from go source and markdown
|
||||
docker build -t docker-manpage-dev -f "man/$(DOCKERFILE)" ./man
|
||||
docker run --rm \
|
||||
-v $(PWD):/go/src/github.com/docker/docker/ \
|
||||
docker-manpage-dev
|
||||
|
||||
rpm: build ## build the rpm packages
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary build-rpm
|
||||
|
||||
run: build ## run the docker daemon in a container
|
||||
$(DOCKER_RUN_DOCKER) sh -c "KEEPBUNDLE=1 hack/make.sh install-binary run"
|
||||
|
||||
shell: build ## start a shell inside the build env
|
||||
$(DOCKER_RUN_DOCKER) bash
|
||||
|
||||
test: build ## run the unit, integration and docker-py tests
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary cross test-unit test-integration-cli test-docker-py
|
||||
|
||||
test-docker-py: build ## run the docker-py tests
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary test-docker-py
|
||||
|
||||
test-integration-cli: build ## run the integration tests
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh build-integration-test-binary dynbinary test-integration-cli
|
||||
|
||||
test-unit: build ## run the unit tests
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh test-unit
|
||||
|
||||
tgz: build ## build the archives (.zip on windows and .tgz\notherwise) containing the binaries
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary binary cross tgz
|
||||
|
||||
validate: build ## validate DCO, Seccomp profile generation, gofmt,\n./pkg/ isolation, golint, tests, tomls, go vet and vendor
|
||||
$(DOCKER_RUN_DOCKER) hack/validate/all
|
||||
|
||||
win: build ## cross build the binary for windows
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh win
|
||||
|
||||
.PHONY: swagger-gen
|
||||
swagger-gen:
|
||||
docker run --rm -v $(PWD):/go/src/github.com/docker/docker \
|
||||
-w /go/src/github.com/docker/docker \
|
||||
--entrypoint hack/generate-swagger-api.sh \
|
||||
-e GOPATH=/go \
|
||||
quay.io/goswagger/swagger:0.7.4
|
||||
19
vendor/github.com/docker/docker/NOTICE
generated
vendored
Normal file
19
vendor/github.com/docker/docker/NOTICE
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Docker
|
||||
Copyright 2012-2016 Docker, Inc.
|
||||
|
||||
This product includes software developed at Docker, Inc. (https://www.docker.com).
|
||||
|
||||
This product contains software (https://github.com/kr/pty) developed
|
||||
by Keith Rarick, licensed under the MIT License.
|
||||
|
||||
The following is courtesy of our legal counsel:
|
||||
|
||||
|
||||
Use and transfer of Docker may be subject to certain restrictions by the
|
||||
United States and other governments.
|
||||
It is your responsibility to ensure that your use and/or transfer does not
|
||||
violate applicable laws.
|
||||
|
||||
For more information, please see https://www.bis.doc.gov
|
||||
|
||||
See also https://www.apache.org/dev/crypto.html and/or seek legal counsel.
|
||||
304
vendor/github.com/docker/docker/README.md
generated
vendored
Normal file
304
vendor/github.com/docker/docker/README.md
generated
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
Docker: the container engine [](https://github.com/docker/docker/releases/latest)
|
||||
============================
|
||||
|
||||
Docker is an open source project to pack, ship and run any application
|
||||
as a lightweight container.
|
||||
|
||||
Docker containers are both *hardware-agnostic* and *platform-agnostic*.
|
||||
This means they can run anywhere, from your laptop to the largest
|
||||
cloud compute instance and everything in between - and they don't require
|
||||
you to use a particular language, framework or packaging system. That
|
||||
makes them great building blocks for deploying and scaling web apps,
|
||||
databases, and backend services without depending on a particular stack
|
||||
or provider.
|
||||
|
||||
Docker began as an open-source implementation of the deployment engine which
|
||||
powered [dotCloud](http://web.archive.org/web/20130530031104/https://www.dotcloud.com/),
|
||||
a popular Platform-as-a-Service. It benefits directly from the experience
|
||||
accumulated over several years of large-scale operation and support of hundreds
|
||||
of thousands of applications and databases.
|
||||
|
||||

|
||||
|
||||
## Security Disclosure
|
||||
|
||||
Security is very important to us. If you have any issue regarding security,
|
||||
please disclose the information responsibly by sending an email to
|
||||
security@docker.com and not by creating a GitHub issue.
|
||||
|
||||
## Better than VMs
|
||||
|
||||
A common method for distributing applications and sandboxing their
|
||||
execution is to use virtual machines, or VMs. Typical VM formats are
|
||||
VMware's vmdk, Oracle VirtualBox's vdi, and Amazon EC2's ami. In theory
|
||||
these formats should allow every developer to automatically package
|
||||
their application into a "machine" for easy distribution and deployment.
|
||||
In practice, that almost never happens, for a few reasons:
|
||||
|
||||
* *Size*: VMs are very large which makes them impractical to store
|
||||
and transfer.
|
||||
* *Performance*: running VMs consumes significant CPU and memory,
|
||||
which makes them impractical in many scenarios, for example local
|
||||
development of multi-tier applications, and large-scale deployment
|
||||
of cpu and memory-intensive applications on large numbers of
|
||||
machines.
|
||||
* *Portability*: competing VM environments don't play well with each
|
||||
other. Although conversion tools do exist, they are limited and
|
||||
add even more overhead.
|
||||
* *Hardware-centric*: VMs were designed with machine operators in
|
||||
mind, not software developers. As a result, they offer very
|
||||
limited tooling for what developers need most: building, testing
|
||||
and running their software. For example, VMs offer no facilities
|
||||
for application versioning, monitoring, configuration, logging or
|
||||
service discovery.
|
||||
|
||||
By contrast, Docker relies on a different sandboxing method known as
|
||||
*containerization*. Unlike traditional virtualization, containerization
|
||||
takes place at the kernel level. Most modern operating system kernels
|
||||
now support the primitives necessary for containerization, including
|
||||
Linux with [openvz](https://openvz.org),
|
||||
[vserver](http://linux-vserver.org) and more recently
|
||||
[lxc](https://linuxcontainers.org/), Solaris with
|
||||
[zones](https://docs.oracle.com/cd/E26502_01/html/E29024/preface-1.html#scrolltoc),
|
||||
and FreeBSD with
|
||||
[Jails](https://www.freebsd.org/doc/handbook/jails.html).
|
||||
|
||||
Docker builds on top of these low-level primitives to offer developers a
|
||||
portable format and runtime environment that solves all four problems.
|
||||
Docker containers are small (and their transfer can be optimized with
|
||||
layers), they have basically zero memory and cpu overhead, they are
|
||||
completely portable, and are designed from the ground up with an
|
||||
application-centric design.
|
||||
|
||||
Perhaps best of all, because Docker operates at the OS level, it can still be
|
||||
run inside a VM!
|
||||
|
||||
## Plays well with others
|
||||
|
||||
Docker does not require you to buy into a particular programming
|
||||
language, framework, packaging system, or configuration language.
|
||||
|
||||
Is your application a Unix process? Does it use files, tcp connections,
|
||||
environment variables, standard Unix streams and command-line arguments
|
||||
as inputs and outputs? Then Docker can run it.
|
||||
|
||||
Can your application's build be expressed as a sequence of such
|
||||
commands? Then Docker can build it.
|
||||
|
||||
## Escape dependency hell
|
||||
|
||||
A common problem for developers is the difficulty of managing all
|
||||
their application's dependencies in a simple and automated way.
|
||||
|
||||
This is usually difficult for several reasons:
|
||||
|
||||
* *Cross-platform dependencies*. Modern applications often depend on
|
||||
a combination of system libraries and binaries, language-specific
|
||||
packages, framework-specific modules, internal components
|
||||
developed for another project, etc. These dependencies live in
|
||||
different "worlds" and require different tools - these tools
|
||||
typically don't work well with each other, requiring awkward
|
||||
custom integrations.
|
||||
|
||||
* *Conflicting dependencies*. Different applications may depend on
|
||||
different versions of the same dependency. Packaging tools handle
|
||||
these situations with various degrees of ease - but they all
|
||||
handle them in different and incompatible ways, which again forces
|
||||
the developer to do extra work.
|
||||
|
||||
* *Custom dependencies*. A developer may need to prepare a custom
|
||||
version of their application's dependency. Some packaging systems
|
||||
can handle custom versions of a dependency, others can't - and all
|
||||
of them handle it differently.
|
||||
|
||||
|
||||
Docker solves the problem of dependency hell by giving the developer a simple
|
||||
way to express *all* their application's dependencies in one place, while
|
||||
streamlining the process of assembling them. If this makes you think of
|
||||
[XKCD 927](https://xkcd.com/927/), don't worry. Docker doesn't
|
||||
*replace* your favorite packaging systems. It simply orchestrates
|
||||
their use in a simple and repeatable way. How does it do that? With
|
||||
layers.
|
||||
|
||||
Docker defines a build as running a sequence of Unix commands, one
|
||||
after the other, in the same container. Build commands modify the
|
||||
contents of the container (usually by installing new files on the
|
||||
filesystem), the next command modifies it some more, etc. Since each
|
||||
build command inherits the result of the previous commands, the
|
||||
*order* in which the commands are executed expresses *dependencies*.
|
||||
|
||||
Here's a typical Docker build process:
|
||||
|
||||
```bash
|
||||
FROM ubuntu:12.04
|
||||
RUN apt-get update && apt-get install -y python python-pip curl
|
||||
RUN curl -sSL https://github.com/shykes/helloflask/archive/master.tar.gz | tar -xzv
|
||||
RUN cd helloflask-master && pip install -r requirements.txt
|
||||
```
|
||||
|
||||
Note that Docker doesn't care *how* dependencies are built - as long
|
||||
as they can be built by running a Unix command in a container.
|
||||
|
||||
|
||||
Getting started
|
||||
===============
|
||||
|
||||
Docker can be installed either on your computer for building applications or
|
||||
on servers for running them. To get started, [check out the installation
|
||||
instructions in the
|
||||
documentation](https://docs.docker.com/engine/installation/).
|
||||
|
||||
Usage examples
|
||||
==============
|
||||
|
||||
Docker can be used to run short-lived commands, long-running daemons
|
||||
(app servers, databases, etc.), interactive shell sessions, etc.
|
||||
|
||||
You can find a [list of real-world
|
||||
examples](https://docs.docker.com/engine/examples/) in the
|
||||
documentation.
|
||||
|
||||
Under the hood
|
||||
--------------
|
||||
|
||||
Under the hood, Docker is built on the following components:
|
||||
|
||||
* The
|
||||
[cgroups](https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt)
|
||||
and
|
||||
[namespaces](http://man7.org/linux/man-pages/man7/namespaces.7.html)
|
||||
capabilities of the Linux kernel
|
||||
* The [Go](https://golang.org) programming language
|
||||
* The [Docker Image Specification](https://github.com/docker/docker/blob/master/image/spec/v1.md)
|
||||
* The [Libcontainer Specification](https://github.com/opencontainers/runc/blob/master/libcontainer/SPEC.md)
|
||||
|
||||
Contributing to Docker [](https://godoc.org/github.com/docker/docker)
|
||||
======================
|
||||
|
||||
| **Master** (Linux) | **Experimental** (Linux) | **Windows** | **FreeBSD** |
|
||||
|------------------|----------------------|---------|---------|
|
||||
| [](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master/) | [](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master%20%28experimental%29/) | [/badge/icon)](http://jenkins.dockerproject.org/job/Docker%20Master%20(windows)/) | [/badge/icon)](http://jenkins.dockerproject.org/job/Docker%20Master%20(freebsd)/) |
|
||||
|
||||
Want to hack on Docker? Awesome! We have [instructions to help you get
|
||||
started contributing code or documentation](https://docs.docker.com/opensource/project/who-written-for/).
|
||||
|
||||
These instructions are probably not perfect, please let us know if anything
|
||||
feels wrong or incomplete. Better yet, submit a PR and improve them yourself.
|
||||
|
||||
Getting the development builds
|
||||
==============================
|
||||
|
||||
Want to run Docker from a master build? You can download
|
||||
master builds at [master.dockerproject.org](https://master.dockerproject.org).
|
||||
They are updated with each commit merged into the master branch.
|
||||
|
||||
Don't know how to use that super cool new feature in the master build? Check
|
||||
out the master docs at
|
||||
[docs.master.dockerproject.org](http://docs.master.dockerproject.org).
|
||||
|
||||
How the project is run
|
||||
======================
|
||||
|
||||
Docker is a very, very active project. If you want to learn more about how it is run,
|
||||
or want to get more involved, the best place to start is [the project directory](https://github.com/docker/docker/tree/master/project).
|
||||
|
||||
We are always open to suggestions on process improvements, and are always looking for more maintainers.
|
||||
|
||||
### Talking to other Docker users and contributors
|
||||
|
||||
<table class="tg">
|
||||
<col width="45%">
|
||||
<col width="65%">
|
||||
<tr>
|
||||
<td>Internet Relay Chat (IRC)</td>
|
||||
<td>
|
||||
<p>
|
||||
IRC is a direct line to our most knowledgeable Docker users; we have
|
||||
both the <code>#docker</code> and <code>#docker-dev</code> group on
|
||||
<strong>irc.freenode.net</strong>.
|
||||
IRC is a rich chat protocol but it can overwhelm new users. You can search
|
||||
<a href="https://botbot.me/freenode/docker/#" target="_blank">our chat archives</a>.
|
||||
</p>
|
||||
Read our <a href="https://docs.docker.com/opensource/get-help/#/irc-quickstart" target="_blank">IRC quickstart guide</a> for an easy way to get started.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Docker Community Forums</td>
|
||||
<td>
|
||||
The <a href="https://forums.docker.com/c/open-source-projects/de" target="_blank">Docker Engine</a>
|
||||
group is for users of the Docker Engine project.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Google Groups</td>
|
||||
<td>
|
||||
The <a href="https://groups.google.com/forum/#!forum/docker-dev"
|
||||
target="_blank">docker-dev</a> group is for contributors and other people
|
||||
contributing to the Docker project. You can join this group without a
|
||||
Google account by sending an email to <a
|
||||
href="mailto:docker-dev+subscribe@googlegroups.com">docker-dev+subscribe@googlegroups.com</a>.
|
||||
You'll receive a join-request message; simply reply to the message to
|
||||
confirm your subscription.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Twitter</td>
|
||||
<td>
|
||||
You can follow <a href="https://twitter.com/docker/" target="_blank">Docker's Twitter feed</a>
|
||||
to get updates on our products. You can also tweet us questions or just
|
||||
share blogs or stories.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stack Overflow</td>
|
||||
<td>
|
||||
Stack Overflow has over 7000 Docker questions listed. We regularly
|
||||
monitor <a href="https://stackoverflow.com/search?tab=newest&q=docker" target="_blank">Docker questions</a>
|
||||
and so do many other knowledgeable Docker users.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Legal
|
||||
|
||||
*Brought to you courtesy of our legal counsel. For more context,
|
||||
please see the [NOTICE](https://github.com/docker/docker/blob/master/NOTICE) document in this repo.*
|
||||
|
||||
Use and transfer of Docker may be subject to certain restrictions by the
|
||||
United States and other governments.
|
||||
|
||||
It is your responsibility to ensure that your use and/or transfer does not
|
||||
violate applicable laws.
|
||||
|
||||
For more information, please see https://www.bis.doc.gov
|
||||
|
||||
|
||||
Licensing
|
||||
=========
|
||||
Docker is licensed under the Apache License, Version 2.0. See
|
||||
[LICENSE](https://github.com/docker/docker/blob/master/LICENSE) for the full
|
||||
license text.
|
||||
|
||||
Other Docker Related Projects
|
||||
=============================
|
||||
There are a number of projects under development that are based on Docker's
|
||||
core technology. These projects expand the tooling built around the
|
||||
Docker platform to broaden its application and utility.
|
||||
|
||||
* [Docker Registry](https://github.com/docker/distribution): Registry
|
||||
server for Docker (hosting/delivery of repositories and images)
|
||||
* [Docker Machine](https://github.com/docker/machine): Machine management
|
||||
for a container-centric world
|
||||
* [Docker Swarm](https://github.com/docker/swarm): A Docker-native clustering
|
||||
system
|
||||
* [Docker Compose](https://github.com/docker/compose) (formerly Fig):
|
||||
Define and run multi-container apps
|
||||
* [Kitematic](https://github.com/docker/kitematic): The easiest way to use
|
||||
Docker on Mac and Windows
|
||||
|
||||
If you know of another project underway that should be listed here, please help
|
||||
us keep this list up-to-date by submitting a PR.
|
||||
|
||||
Awesome-Docker
|
||||
==============
|
||||
You can find more projects, tools and articles related to Docker on the [awesome-docker list](https://github.com/veggiemonk/awesome-docker). Add your project there.
|
||||
118
vendor/github.com/docker/docker/ROADMAP.md
generated
vendored
Normal file
118
vendor/github.com/docker/docker/ROADMAP.md
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
Docker Engine Roadmap
|
||||
=====================
|
||||
|
||||
### How should I use this document?
|
||||
|
||||
This document provides description of items that the project decided to prioritize. This should
|
||||
serve as a reference point for Docker contributors to understand where the project is going, and
|
||||
help determine if a contribution could be conflicting with some longer terms plans.
|
||||
|
||||
The fact that a feature isn't listed here doesn't mean that a patch for it will automatically be
|
||||
refused (except for those mentioned as "frozen features" below)! We are always happy to receive
|
||||
patches for new cool features we haven't thought about, or didn't judge priority. Please however
|
||||
understand that such patches might take longer for us to review.
|
||||
|
||||
### How can I help?
|
||||
|
||||
Short term objectives are listed in the [wiki](https://github.com/docker/docker/wiki) and described
|
||||
in [Issues](https://github.com/docker/docker/issues?q=is%3Aopen+is%3Aissue+label%3Aroadmap). Our
|
||||
goal is to split down the workload in such way that anybody can jump in and help. Please comment on
|
||||
issues if you want to take it to avoid duplicating effort! Similarly, if a maintainer is already
|
||||
assigned on an issue you'd like to participate in, pinging him on IRC or GitHub to offer your help is
|
||||
the best way to go.
|
||||
|
||||
### How can I add something to the roadmap?
|
||||
|
||||
The roadmap process is new to the Docker Engine: we are only beginning to structure and document the
|
||||
project objectives. Our immediate goal is to be more transparent, and work with our community to
|
||||
focus our efforts on fewer prioritized topics.
|
||||
|
||||
We hope to offer in the near future a process allowing anyone to propose a topic to the roadmap, but
|
||||
we are not quite there yet. For the time being, the BDFL remains the keeper of the roadmap, and we
|
||||
won't be accepting pull requests adding or removing items from this file.
|
||||
|
||||
# 1. Features and refactoring
|
||||
|
||||
## 1.1 Runtime improvements
|
||||
|
||||
We recently introduced [`runC`](https://runc.io) as a standalone low-level tool for container
|
||||
execution. The initial goal was to integrate runC as a replacement in the Engine for the traditional
|
||||
default libcontainer `execdriver`, but the Engine internals were not ready for this.
|
||||
|
||||
As runC continued evolving, and the OCI specification along with it, we created
|
||||
[`containerd`](https://containerd.tools/), a daemon to control and monitor multiple `runC`. This is
|
||||
the new target for Engine integration, as it can entirely replace the whole `execdriver`
|
||||
architecture, and container monitoring along with it.
|
||||
|
||||
Docker Engine will rely on a long-running `containerd` companion daemon for all container execution
|
||||
related operations. This could open the door in the future for Engine restarts without interrupting
|
||||
running containers.
|
||||
|
||||
## 1.2 Plugins improvements
|
||||
|
||||
Docker Engine 1.7.0 introduced plugin support, initially for the use cases of volumes and networks
|
||||
extensions. The plugin infrastructure was kept minimal as we were collecting use cases and real
|
||||
world feedback before optimizing for any particular workflow.
|
||||
|
||||
In the future, we'd like plugins to become first class citizens, and encourage an ecosystem of
|
||||
plugins. This implies in particular making it trivially easy to distribute plugins as containers
|
||||
through any Registry instance, as well as solving the commonly heard pain points of plugins needing
|
||||
to be treated as somewhat special (being active at all time, started before any other user
|
||||
containers, and not as easily dismissed).
|
||||
|
||||
## 1.3 Internal decoupling
|
||||
|
||||
A lot of work has been done in trying to decouple the Docker Engine's internals. In particular, the
|
||||
API implementation has been refactored, and the Builder side of the daemon is now
|
||||
[fully independent](https://github.com/docker/docker/tree/master/builder) while still residing in
|
||||
the same repository.
|
||||
|
||||
We are exploring ways to go further with that decoupling, capitalizing on the work introduced by the
|
||||
runtime renovation and plugins improvement efforts. Indeed, the combination of `containerd` support
|
||||
with the concept of "special" containers opens the door for bootstrapping more Engine internals
|
||||
using the same facilities.
|
||||
|
||||
## 1.4 Cluster capable Engine
|
||||
|
||||
The community has been pushing for a more cluster capable Docker Engine, and a huge effort was spent
|
||||
adding features such as multihost networking, and node discovery down at the Engine level. Yet, the
|
||||
Engine is currently incapable of taking scheduling decisions alone, and continues relying on Swarm
|
||||
for that.
|
||||
|
||||
We plan to complete this effort and make Engine fully cluster capable. Multiple instances of the
|
||||
Docker Engine being already capable of discovering each other and establish overlay networking for
|
||||
their container to communicate, the next step is for a given Engine to gain ability to dispatch work
|
||||
to another node in the cluster. This will be introduced in a backward compatible way, such that a
|
||||
`docker run` invocation on a particular node remains fully deterministic.
|
||||
|
||||
# 2 Frozen features
|
||||
|
||||
## 2.1 Docker exec
|
||||
|
||||
We won't accept patches expanding the surface of `docker exec`, which we intend to keep as a
|
||||
*debugging* feature, as well as being strongly dependent on the Runtime ingredient effort.
|
||||
|
||||
## 2.2 Remote Registry Operations
|
||||
|
||||
A large amount of work is ongoing in the area of image distribution and provenance. This includes
|
||||
moving to the V2 Registry API and heavily refactoring the code that powers these features. The
|
||||
desired result is more secure, reliable and easier to use image distribution.
|
||||
|
||||
Part of the problem with this part of the code base is the lack of a stable and flexible interface.
|
||||
If new features are added that access the registry without solidifying these interfaces, achieving
|
||||
feature parity will continue to be elusive. While we get a handle on this situation, we are imposing
|
||||
a moratorium on new code that accesses the Registry API in commands that don't already make remote
|
||||
calls.
|
||||
|
||||
Currently, only the following commands cause interaction with a remote registry:
|
||||
|
||||
- push
|
||||
- pull
|
||||
- run
|
||||
- build
|
||||
- search
|
||||
- login
|
||||
|
||||
In the interest of stabilizing the registry access model during this ongoing work, we are not
|
||||
accepting additions to other commands that will cause remote interaction with the Registry API. This
|
||||
moratorium will lift when the goals of the distribution project have been met.
|
||||
45
vendor/github.com/docker/docker/VENDORING.md
generated
vendored
Normal file
45
vendor/github.com/docker/docker/VENDORING.md
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
# Vendoring policies
|
||||
|
||||
This document outlines recommended Vendoring policies for Docker repositories.
|
||||
(Example, libnetwork is a Docker repo and logrus is not.)
|
||||
|
||||
## Vendoring using tags
|
||||
|
||||
Commit ID based vendoring provides little/no information about the updates
|
||||
vendored. To fix this, vendors will now require that repositories use annotated
|
||||
tags along with commit ids to snapshot commits. Annotated tags by themselves
|
||||
are not sufficient, since the same tag can be force updated to reference
|
||||
different commits.
|
||||
|
||||
Each tag should:
|
||||
- Follow Semantic Versioning rules (refer to section on "Semantic Versioning")
|
||||
- Have a corresponding entry in the change tracking document.
|
||||
|
||||
Each repo should:
|
||||
- Have a change tracking document between tags/releases. Ex: CHANGELOG.md,
|
||||
github releases file.
|
||||
|
||||
The goal here is for consuming repos to be able to use the tag version and
|
||||
changelog updates to determine whether the vendoring will cause any breaking or
|
||||
backward incompatible changes. This also means that repos can specify having
|
||||
dependency on a package of a specific version or greater up to the next major
|
||||
release, without encountering breaking changes.
|
||||
|
||||
## Semantic Versioning
|
||||
Annotated version tags should follow Schema Versioning policies.
|
||||
According to http://semver.org:
|
||||
|
||||
"Given a version number MAJOR.MINOR.PATCH, increment the:
|
||||
MAJOR version when you make incompatible API changes,
|
||||
MINOR version when you add functionality in a backwards-compatible manner, and
|
||||
PATCH version when you make backwards-compatible bug fixes.
|
||||
Additional labels for pre-release and build metadata are available as extensions
|
||||
to the MAJOR.MINOR.PATCH format."
|
||||
|
||||
## Vendoring cadence
|
||||
In order to avoid huge vendoring changes, it is recommended to have a regular
|
||||
cadence for vendoring updates. e.g. monthly.
|
||||
|
||||
## Pre-merge vendoring tests
|
||||
All related repos will be vendored into docker/docker.
|
||||
CI on docker/docker should catch any breaking changes involving multiple repos.
|
||||
1
vendor/github.com/docker/docker/VERSION
generated
vendored
Normal file
1
vendor/github.com/docker/docker/VERSION
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
1.13.0
|
||||
42
vendor/github.com/docker/docker/api/README.md
generated
vendored
Normal file
42
vendor/github.com/docker/docker/api/README.md
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
# Working on the Engine API
|
||||
|
||||
The Engine API is an HTTP API used by the command-line client to communicate with the daemon. It can also be used by third-party software to control the daemon.
|
||||
|
||||
It consists of various components in this repository:
|
||||
|
||||
- `api/swagger.yaml` A Swagger definition of the API.
|
||||
- `api/types/` Types shared by both the client and server, representing various objects, options, responses, etc. Most are written manually, but some are automatically generated from the Swagger definition. See [#27919](https://github.com/docker/docker/issues/27919) for progress on this.
|
||||
- `cli/` The command-line client.
|
||||
- `client/` The Go client used by the command-line client. It can also be used by third-party Go programs.
|
||||
- `daemon/` The daemon, which serves the API.
|
||||
|
||||
## Swagger definition
|
||||
|
||||
The API is defined by the [Swagger](http://swagger.io/specification/) definition in `api/swagger.yaml`. This definition can be used to:
|
||||
|
||||
1. To automatically generate documentation.
|
||||
2. To automatically generate the Go server and client. (A work-in-progress.)
|
||||
3. Provide a machine readable version of the API for introspecting what it can do, automatically generating clients for other languages, etc.
|
||||
|
||||
## Updating the API documentation
|
||||
|
||||
The API documentation is generated entirely from `api/swagger.yaml`. If you make updates to the API, you'll need to edit this file to represent the change in the documentation.
|
||||
|
||||
The file is split into two main sections:
|
||||
|
||||
- `definitions`, which defines re-usable objects used in requests and responses
|
||||
- `paths`, which defines the API endpoints (and some inline objects which don't need to be reusable)
|
||||
|
||||
To make an edit, first look for the endpoint you want to edit under `paths`, then make the required edits. Endpoints may reference reusable objects with `$ref`, which can be found in the `definitions` section.
|
||||
|
||||
There is hopefully enough example material in the file for you to copy a similar pattern from elsewhere in the file (e.g. adding new fields or endpoints), but for the full reference, see the [Swagger specification](https://github.com/docker/docker/issues/27919)
|
||||
|
||||
`swagger.yaml` is validated by `hack/validate/swagger` to ensure it is a valid Swagger definition. This is useful for when you are making edits to ensure you are doing the right thing.
|
||||
|
||||
## Viewing the API documentation
|
||||
|
||||
When you make edits to `swagger.yaml`, you may want to check the generated API documentation to ensure it renders correctly.
|
||||
|
||||
All the documentation generation is done in the documentation repository, [docker/docker.github.io](https://github.com/docker/docker.github.io). The Swagger definition is vendored periodically into this repository, but you can manually copy over the Swagger definition to test changes.
|
||||
|
||||
Copy `api/swagger.yaml` in this repository to `engine/api/[VERSION_NUMBER]/swagger.yaml` in the documentation repository, overwriting what is already there. Then, run `docker-compose up` in the documentation repository and browse to [http://localhost:4000/engine/api/](http://localhost:4000/engine/api/) when it finishes rendering.
|
||||
166
vendor/github.com/docker/docker/api/common.go
generated
vendored
Normal file
166
vendor/github.com/docker/docker/api/common.go
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"mime"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/libtrust"
|
||||
)
|
||||
|
||||
// Common constants for daemon and client.
|
||||
const (
|
||||
// DefaultVersion of Current REST API
|
||||
DefaultVersion string = "1.25"
|
||||
|
||||
// NoBaseImageSpecifier is the symbol used by the FROM
|
||||
// command to specify that no base image is to be used.
|
||||
NoBaseImageSpecifier string = "scratch"
|
||||
)
|
||||
|
||||
// byPortInfo is a temporary type used to sort types.Port by its fields
|
||||
type byPortInfo []types.Port
|
||||
|
||||
func (r byPortInfo) Len() int { return len(r) }
|
||||
func (r byPortInfo) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||
func (r byPortInfo) Less(i, j int) bool {
|
||||
if r[i].PrivatePort != r[j].PrivatePort {
|
||||
return r[i].PrivatePort < r[j].PrivatePort
|
||||
}
|
||||
|
||||
if r[i].IP != r[j].IP {
|
||||
return r[i].IP < r[j].IP
|
||||
}
|
||||
|
||||
if r[i].PublicPort != r[j].PublicPort {
|
||||
return r[i].PublicPort < r[j].PublicPort
|
||||
}
|
||||
|
||||
return r[i].Type < r[j].Type
|
||||
}
|
||||
|
||||
// DisplayablePorts returns formatted string representing open ports of container
|
||||
// e.g. "0.0.0.0:80->9090/tcp, 9988/tcp"
|
||||
// it's used by command 'docker ps'
|
||||
func DisplayablePorts(ports []types.Port) string {
|
||||
type portGroup struct {
|
||||
first uint16
|
||||
last uint16
|
||||
}
|
||||
groupMap := make(map[string]*portGroup)
|
||||
var result []string
|
||||
var hostMappings []string
|
||||
var groupMapKeys []string
|
||||
sort.Sort(byPortInfo(ports))
|
||||
for _, port := range ports {
|
||||
current := port.PrivatePort
|
||||
portKey := port.Type
|
||||
if port.IP != "" {
|
||||
if port.PublicPort != current {
|
||||
hostMappings = append(hostMappings, fmt.Sprintf("%s:%d->%d/%s", port.IP, port.PublicPort, port.PrivatePort, port.Type))
|
||||
continue
|
||||
}
|
||||
portKey = fmt.Sprintf("%s/%s", port.IP, port.Type)
|
||||
}
|
||||
group := groupMap[portKey]
|
||||
|
||||
if group == nil {
|
||||
groupMap[portKey] = &portGroup{first: current, last: current}
|
||||
// record order that groupMap keys are created
|
||||
groupMapKeys = append(groupMapKeys, portKey)
|
||||
continue
|
||||
}
|
||||
if current == (group.last + 1) {
|
||||
group.last = current
|
||||
continue
|
||||
}
|
||||
|
||||
result = append(result, formGroup(portKey, group.first, group.last))
|
||||
groupMap[portKey] = &portGroup{first: current, last: current}
|
||||
}
|
||||
for _, portKey := range groupMapKeys {
|
||||
g := groupMap[portKey]
|
||||
result = append(result, formGroup(portKey, g.first, g.last))
|
||||
}
|
||||
result = append(result, hostMappings...)
|
||||
return strings.Join(result, ", ")
|
||||
}
|
||||
|
||||
func formGroup(key string, start, last uint16) string {
|
||||
parts := strings.Split(key, "/")
|
||||
groupType := parts[0]
|
||||
var ip string
|
||||
if len(parts) > 1 {
|
||||
ip = parts[0]
|
||||
groupType = parts[1]
|
||||
}
|
||||
group := strconv.Itoa(int(start))
|
||||
if start != last {
|
||||
group = fmt.Sprintf("%s-%d", group, last)
|
||||
}
|
||||
if ip != "" {
|
||||
group = fmt.Sprintf("%s:%s->%s", ip, group, group)
|
||||
}
|
||||
return fmt.Sprintf("%s/%s", group, groupType)
|
||||
}
|
||||
|
||||
// MatchesContentType validates the content type against the expected one
|
||||
func MatchesContentType(contentType, expectedType string) bool {
|
||||
mimetype, _, err := mime.ParseMediaType(contentType)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error parsing media type: %s error: %v", contentType, err)
|
||||
}
|
||||
return err == nil && mimetype == expectedType
|
||||
}
|
||||
|
||||
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path,
|
||||
// otherwise generates a new one
|
||||
func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
|
||||
err := system.MkdirAll(filepath.Dir(trustKeyPath), 0700)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
trustKey, err := libtrust.LoadKeyFile(trustKeyPath)
|
||||
if err == libtrust.ErrKeyFileDoesNotExist {
|
||||
trustKey, err = libtrust.GenerateECP256PrivateKey()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error generating key: %s", err)
|
||||
}
|
||||
encodedKey, err := serializePrivateKey(trustKey, filepath.Ext(trustKeyPath))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error serializing key: %s", err)
|
||||
}
|
||||
if err := ioutils.AtomicWriteFile(trustKeyPath, encodedKey, os.FileMode(0600)); err != nil {
|
||||
return nil, fmt.Errorf("Error saving key file: %s", err)
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err)
|
||||
}
|
||||
return trustKey, nil
|
||||
}
|
||||
|
||||
func serializePrivateKey(key libtrust.PrivateKey, ext string) (encoded []byte, err error) {
|
||||
if ext == ".json" || ext == ".jwk" {
|
||||
encoded, err = json.Marshal(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to encode private key JWK: %s", err)
|
||||
}
|
||||
} else {
|
||||
pemBlock, err := key.PEMBlock()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to encode private key PEM: %s", err)
|
||||
}
|
||||
encoded = pem.EncodeToMemory(pemBlock)
|
||||
}
|
||||
return
|
||||
}
|
||||
341
vendor/github.com/docker/docker/api/common_test.go
generated
vendored
Normal file
341
vendor/github.com/docker/docker/api/common_test.go
generated
vendored
Normal file
@@ -0,0 +1,341 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"os"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
type ports struct {
|
||||
ports []types.Port
|
||||
expected string
|
||||
}
|
||||
|
||||
// DisplayablePorts
|
||||
func TestDisplayablePorts(t *testing.T) {
|
||||
cases := []ports{
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9988,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"9988/tcp"},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9988,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"9988/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "0.0.0.0",
|
||||
PrivatePort: 9988,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"0.0.0.0:0->9988/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"9988/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "4.3.2.1",
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"4.3.2.1:8899->9988/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "4.3.2.1",
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 9988,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"4.3.2.1:9988->9988/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9988,
|
||||
Type: "udp",
|
||||
}, {
|
||||
PrivatePort: 9988,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"9988/udp, 9988/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "1.2.3.4",
|
||||
PublicPort: 9998,
|
||||
PrivatePort: 9998,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.2.3.4",
|
||||
PublicPort: 9999,
|
||||
PrivatePort: 9999,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"1.2.3.4:9998-9999->9998-9999/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "1.2.3.4",
|
||||
PublicPort: 8887,
|
||||
PrivatePort: 9998,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.2.3.4",
|
||||
PublicPort: 8888,
|
||||
PrivatePort: 9999,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"1.2.3.4:8887->9998/udp, 1.2.3.4:8888->9999/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9998,
|
||||
Type: "udp",
|
||||
}, {
|
||||
PrivatePort: 9999,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"9998-9999/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "1.2.3.4",
|
||||
PrivatePort: 6677,
|
||||
PublicPort: 7766,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"9988/udp, 1.2.3.4:7766->6677/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "1.2.3.4",
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.2.3.4",
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "4.3.2.1",
|
||||
PrivatePort: 2233,
|
||||
PublicPort: 3322,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"4.3.2.1:3322->2233/tcp, 1.2.3.4:8899->9988/tcp, 1.2.3.4:8899->9988/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.2.3.4",
|
||||
PrivatePort: 6677,
|
||||
PublicPort: 7766,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "4.3.2.1",
|
||||
PrivatePort: 2233,
|
||||
PublicPort: 3322,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"9988/udp, 4.3.2.1:3322->2233/tcp, 1.2.3.4:7766->6677/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 80,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
PrivatePort: 1024,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
PrivatePort: 80,
|
||||
Type: "udp",
|
||||
}, {
|
||||
PrivatePort: 1024,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.1.1.1",
|
||||
PublicPort: 80,
|
||||
PrivatePort: 1024,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "1.1.1.1",
|
||||
PublicPort: 80,
|
||||
PrivatePort: 1024,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.1.1.1",
|
||||
PublicPort: 1024,
|
||||
PrivatePort: 80,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "1.1.1.1",
|
||||
PublicPort: 1024,
|
||||
PrivatePort: 80,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "2.1.1.1",
|
||||
PublicPort: 80,
|
||||
PrivatePort: 1024,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "2.1.1.1",
|
||||
PublicPort: 80,
|
||||
PrivatePort: 1024,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "2.1.1.1",
|
||||
PublicPort: 1024,
|
||||
PrivatePort: 80,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "2.1.1.1",
|
||||
PublicPort: 1024,
|
||||
PrivatePort: 80,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"80/tcp, 80/udp, 1024/tcp, 1024/udp, 1.1.1.1:1024->80/tcp, 1.1.1.1:1024->80/udp, 2.1.1.1:1024->80/tcp, 2.1.1.1:1024->80/udp, 1.1.1.1:80->1024/tcp, 1.1.1.1:80->1024/udp, 2.1.1.1:80->1024/tcp, 2.1.1.1:80->1024/udp",
|
||||
},
|
||||
}
|
||||
|
||||
for _, port := range cases {
|
||||
actual := DisplayablePorts(port.ports)
|
||||
if port.expected != actual {
|
||||
t.Fatalf("Expected %s, got %s.", port.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MatchesContentType
|
||||
func TestJsonContentType(t *testing.T) {
|
||||
if !MatchesContentType("application/json", "application/json") {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if !MatchesContentType("application/json; charset=utf-8", "application/json") {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if MatchesContentType("dockerapplication/json", "application/json") {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
// LoadOrCreateTrustKey
|
||||
func TestLoadOrCreateTrustKeyInvalidKeyFile(t *testing.T) {
|
||||
tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpKeyFolderPath)
|
||||
|
||||
tmpKeyFile, err := ioutil.TempFile(tmpKeyFolderPath, "keyfile")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := LoadOrCreateTrustKey(tmpKeyFile.Name()); err == nil {
|
||||
t.Fatalf("expected an error, got nothing.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestLoadOrCreateTrustKeyCreateKey(t *testing.T) {
|
||||
tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpKeyFolderPath)
|
||||
|
||||
// Without the need to create the folder hierarchy
|
||||
tmpKeyFile := filepath.Join(tmpKeyFolderPath, "keyfile")
|
||||
|
||||
if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil {
|
||||
t.Fatalf("expected a new key file, got : %v and %v", err, key)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(tmpKeyFile); err != nil {
|
||||
t.Fatalf("Expected to find a file %s, got %v", tmpKeyFile, err)
|
||||
}
|
||||
|
||||
// With the need to create the folder hierarchy as tmpKeyFie is in a path
|
||||
// where some folders do not exist.
|
||||
tmpKeyFile = filepath.Join(tmpKeyFolderPath, "folder/hierarchy/keyfile")
|
||||
|
||||
if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil {
|
||||
t.Fatalf("expected a new key file, got : %v and %v", err, key)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(tmpKeyFile); err != nil {
|
||||
t.Fatalf("Expected to find a file %s, got %v", tmpKeyFile, err)
|
||||
}
|
||||
|
||||
// With no path at all
|
||||
defer os.Remove("keyfile")
|
||||
if key, err := LoadOrCreateTrustKey("keyfile"); err != nil || key == nil {
|
||||
t.Fatalf("expected a new key file, got : %v and %v", err, key)
|
||||
}
|
||||
|
||||
if _, err := os.Stat("keyfile"); err != nil {
|
||||
t.Fatalf("Expected to find a file keyfile, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadOrCreateTrustKeyLoadValidKey(t *testing.T) {
|
||||
tmpKeyFile := filepath.Join("fixtures", "keyfile")
|
||||
|
||||
if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil {
|
||||
t.Fatalf("expected a key file, got : %v and %v", err, key)
|
||||
}
|
||||
}
|
||||
6
vendor/github.com/docker/docker/api/common_unix.go
generated
vendored
Normal file
6
vendor/github.com/docker/docker/api/common_unix.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
// +build !windows
|
||||
|
||||
package api
|
||||
|
||||
// MinVersion represents Minimum REST API version supported
|
||||
const MinVersion string = "1.12"
|
||||
8
vendor/github.com/docker/docker/api/common_windows.go
generated
vendored
Normal file
8
vendor/github.com/docker/docker/api/common_windows.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
package api
|
||||
|
||||
// MinVersion represents Minimum REST API version supported
|
||||
// Technically the first daemon API version released on Windows is v1.25 in
|
||||
// engine version 1.13. However, some clients are explicitly using downlevel
|
||||
// APIs (eg docker-compose v2.1 file format) and that is just too restrictive.
|
||||
// Hence also allowing 1.24 on Windows.
|
||||
const MinVersion string = "1.24"
|
||||
47
vendor/github.com/docker/docker/api/errors/errors.go
generated
vendored
Normal file
47
vendor/github.com/docker/docker/api/errors/errors.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
package errors
|
||||
|
||||
import "net/http"
|
||||
|
||||
// apiError is an error wrapper that also
|
||||
// holds information about response status codes.
|
||||
type apiError struct {
|
||||
error
|
||||
statusCode int
|
||||
}
|
||||
|
||||
// HTTPErrorStatusCode returns a status code.
|
||||
func (e apiError) HTTPErrorStatusCode() int {
|
||||
return e.statusCode
|
||||
}
|
||||
|
||||
// NewErrorWithStatusCode allows you to associate
|
||||
// a specific HTTP Status Code to an error.
|
||||
// The Server will take that code and set
|
||||
// it as the response status.
|
||||
func NewErrorWithStatusCode(err error, code int) error {
|
||||
return apiError{err, code}
|
||||
}
|
||||
|
||||
// NewBadRequestError creates a new API error
|
||||
// that has the 400 HTTP status code associated to it.
|
||||
func NewBadRequestError(err error) error {
|
||||
return NewErrorWithStatusCode(err, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
// NewRequestForbiddenError creates a new API error
|
||||
// that has the 403 HTTP status code associated to it.
|
||||
func NewRequestForbiddenError(err error) error {
|
||||
return NewErrorWithStatusCode(err, http.StatusForbidden)
|
||||
}
|
||||
|
||||
// NewRequestNotFoundError creates a new API error
|
||||
// that has the 404 HTTP status code associated to it.
|
||||
func NewRequestNotFoundError(err error) error {
|
||||
return NewErrorWithStatusCode(err, http.StatusNotFound)
|
||||
}
|
||||
|
||||
// NewRequestConflictError creates a new API error
|
||||
// that has the 409 HTTP status code associated to it.
|
||||
func NewRequestConflictError(err error) error {
|
||||
return NewErrorWithStatusCode(err, http.StatusConflict)
|
||||
}
|
||||
7
vendor/github.com/docker/docker/api/fixtures/keyfile
generated
vendored
Normal file
7
vendor/github.com/docker/docker/api/fixtures/keyfile
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
keyID: AWX2:I27X:WQFX:IOMK:CNAK:O7PW:VYNB:ZLKC:CVAE:YJP2:SI4A:XXAY
|
||||
|
||||
MHcCAQEEILHTRWdcpKWsnORxSFyBnndJ4ROU41hMtr/GCiLVvwBQoAoGCCqGSM49
|
||||
AwEHoUQDQgAElpVFbQ2V2UQKajqdE3fVxJ+/pE/YuEFOxWbOxF2be19BY209/iky
|
||||
NzeFFK7SLpQ4CBJ7zDVXOHsMzrkY/GquGA==
|
||||
-----END EC PRIVATE KEY-----
|
||||
16
vendor/github.com/docker/docker/api/server/httputils/decoder.go
generated
vendored
Normal file
16
vendor/github.com/docker/docker/api/server/httputils/decoder.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
)
|
||||
|
||||
// ContainerDecoder specifies how
|
||||
// to translate an io.Reader into
|
||||
// container configuration.
|
||||
type ContainerDecoder interface {
|
||||
DecodeConfig(src io.Reader) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error)
|
||||
DecodeHostConfig(src io.Reader) (*container.HostConfig, error)
|
||||
}
|
||||
101
vendor/github.com/docker/docker/api/server/httputils/errors.go
generated
vendored
Normal file
101
vendor/github.com/docker/docker/api/server/httputils/errors.go
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/gorilla/mux"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// httpStatusError is an interface
|
||||
// that errors with custom status codes
|
||||
// implement to tell the api layer
|
||||
// which response status to set.
|
||||
type httpStatusError interface {
|
||||
HTTPErrorStatusCode() int
|
||||
}
|
||||
|
||||
// inputValidationError is an interface
|
||||
// that errors generated by invalid
|
||||
// inputs can implement to tell the
|
||||
// api layer to set a 400 status code
|
||||
// in the response.
|
||||
type inputValidationError interface {
|
||||
IsValidationError() bool
|
||||
}
|
||||
|
||||
// GetHTTPErrorStatusCode retrieves status code from error message
|
||||
func GetHTTPErrorStatusCode(err error) int {
|
||||
if err == nil {
|
||||
logrus.WithFields(logrus.Fields{"error": err}).Error("unexpected HTTP error handling")
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
|
||||
var statusCode int
|
||||
errMsg := err.Error()
|
||||
|
||||
switch e := err.(type) {
|
||||
case httpStatusError:
|
||||
statusCode = e.HTTPErrorStatusCode()
|
||||
case inputValidationError:
|
||||
statusCode = http.StatusBadRequest
|
||||
default:
|
||||
// FIXME: this is brittle and should not be necessary, but we still need to identify if
|
||||
// there are errors falling back into this logic.
|
||||
// If we need to differentiate between different possible error types,
|
||||
// we should create appropriate error types that implement the httpStatusError interface.
|
||||
errStr := strings.ToLower(errMsg)
|
||||
for _, status := range []struct {
|
||||
keyword string
|
||||
code int
|
||||
}{
|
||||
{"not found", http.StatusNotFound},
|
||||
{"no such", http.StatusNotFound},
|
||||
{"bad parameter", http.StatusBadRequest},
|
||||
{"no command", http.StatusBadRequest},
|
||||
{"conflict", http.StatusConflict},
|
||||
{"impossible", http.StatusNotAcceptable},
|
||||
{"wrong login/password", http.StatusUnauthorized},
|
||||
{"unauthorized", http.StatusUnauthorized},
|
||||
{"hasn't been activated", http.StatusForbidden},
|
||||
{"this node", http.StatusServiceUnavailable},
|
||||
} {
|
||||
if strings.Contains(errStr, status.keyword) {
|
||||
statusCode = status.code
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if statusCode == 0 {
|
||||
statusCode = http.StatusInternalServerError
|
||||
}
|
||||
|
||||
return statusCode
|
||||
}
|
||||
|
||||
func apiVersionSupportsJSONErrors(version string) bool {
|
||||
const firstAPIVersionWithJSONErrors = "1.23"
|
||||
return version == "" || versions.GreaterThan(version, firstAPIVersionWithJSONErrors)
|
||||
}
|
||||
|
||||
// MakeErrorHandler makes an HTTP handler that decodes a Docker error and
|
||||
// returns it in the response.
|
||||
func MakeErrorHandler(err error) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
statusCode := GetHTTPErrorStatusCode(err)
|
||||
vars := mux.Vars(r)
|
||||
if apiVersionSupportsJSONErrors(vars["version"]) {
|
||||
response := &types.ErrorResponse{
|
||||
Message: err.Error(),
|
||||
}
|
||||
WriteJSON(w, statusCode, response)
|
||||
} else {
|
||||
http.Error(w, grpc.ErrorDesc(err), statusCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
73
vendor/github.com/docker/docker/api/server/httputils/form.go
generated
vendored
Normal file
73
vendor/github.com/docker/docker/api/server/httputils/form.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BoolValue transforms a form value in different formats into a boolean type.
|
||||
func BoolValue(r *http.Request, k string) bool {
|
||||
s := strings.ToLower(strings.TrimSpace(r.FormValue(k)))
|
||||
return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none")
|
||||
}
|
||||
|
||||
// BoolValueOrDefault returns the default bool passed if the query param is
|
||||
// missing, otherwise it's just a proxy to boolValue above
|
||||
func BoolValueOrDefault(r *http.Request, k string, d bool) bool {
|
||||
if _, ok := r.Form[k]; !ok {
|
||||
return d
|
||||
}
|
||||
return BoolValue(r, k)
|
||||
}
|
||||
|
||||
// Int64ValueOrZero parses a form value into an int64 type.
|
||||
// It returns 0 if the parsing fails.
|
||||
func Int64ValueOrZero(r *http.Request, k string) int64 {
|
||||
val, err := Int64ValueOrDefault(r, k, 0)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Int64ValueOrDefault parses a form value into an int64 type. If there is an
|
||||
// error, returns the error. If there is no value returns the default value.
|
||||
func Int64ValueOrDefault(r *http.Request, field string, def int64) (int64, error) {
|
||||
if r.Form.Get(field) != "" {
|
||||
value, err := strconv.ParseInt(r.Form.Get(field), 10, 64)
|
||||
if err != nil {
|
||||
return value, err
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
return def, nil
|
||||
}
|
||||
|
||||
// ArchiveOptions stores archive information for different operations.
|
||||
type ArchiveOptions struct {
|
||||
Name string
|
||||
Path string
|
||||
}
|
||||
|
||||
// ArchiveFormValues parses form values and turns them into ArchiveOptions.
|
||||
// It fails if the archive name and path are not in the request.
|
||||
func ArchiveFormValues(r *http.Request, vars map[string]string) (ArchiveOptions, error) {
|
||||
if err := ParseForm(r); err != nil {
|
||||
return ArchiveOptions{}, err
|
||||
}
|
||||
|
||||
name := vars["name"]
|
||||
path := filepath.FromSlash(r.Form.Get("path"))
|
||||
|
||||
switch {
|
||||
case name == "":
|
||||
return ArchiveOptions{}, fmt.Errorf("bad parameter: 'name' cannot be empty")
|
||||
case path == "":
|
||||
return ArchiveOptions{}, fmt.Errorf("bad parameter: 'path' cannot be empty")
|
||||
}
|
||||
|
||||
return ArchiveOptions{name, path}, nil
|
||||
}
|
||||
105
vendor/github.com/docker/docker/api/server/httputils/form_test.go
generated
vendored
Normal file
105
vendor/github.com/docker/docker/api/server/httputils/form_test.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBoolValue(t *testing.T) {
|
||||
cases := map[string]bool{
|
||||
"": false,
|
||||
"0": false,
|
||||
"no": false,
|
||||
"false": false,
|
||||
"none": false,
|
||||
"1": true,
|
||||
"yes": true,
|
||||
"true": true,
|
||||
"one": true,
|
||||
"100": true,
|
||||
}
|
||||
|
||||
for c, e := range cases {
|
||||
v := url.Values{}
|
||||
v.Set("test", c)
|
||||
r, _ := http.NewRequest("POST", "", nil)
|
||||
r.Form = v
|
||||
|
||||
a := BoolValue(r, "test")
|
||||
if a != e {
|
||||
t.Fatalf("Value: %s, expected: %v, actual: %v", c, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoolValueOrDefault(t *testing.T) {
|
||||
r, _ := http.NewRequest("GET", "", nil)
|
||||
if !BoolValueOrDefault(r, "queryparam", true) {
|
||||
t.Fatal("Expected to get true default value, got false")
|
||||
}
|
||||
|
||||
v := url.Values{}
|
||||
v.Set("param", "")
|
||||
r, _ = http.NewRequest("GET", "", nil)
|
||||
r.Form = v
|
||||
if BoolValueOrDefault(r, "param", true) {
|
||||
t.Fatal("Expected not to get true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64ValueOrZero(t *testing.T) {
|
||||
cases := map[string]int64{
|
||||
"": 0,
|
||||
"asdf": 0,
|
||||
"0": 0,
|
||||
"1": 1,
|
||||
}
|
||||
|
||||
for c, e := range cases {
|
||||
v := url.Values{}
|
||||
v.Set("test", c)
|
||||
r, _ := http.NewRequest("POST", "", nil)
|
||||
r.Form = v
|
||||
|
||||
a := Int64ValueOrZero(r, "test")
|
||||
if a != e {
|
||||
t.Fatalf("Value: %s, expected: %v, actual: %v", c, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64ValueOrDefault(t *testing.T) {
|
||||
cases := map[string]int64{
|
||||
"": -1,
|
||||
"-1": -1,
|
||||
"42": 42,
|
||||
}
|
||||
|
||||
for c, e := range cases {
|
||||
v := url.Values{}
|
||||
v.Set("test", c)
|
||||
r, _ := http.NewRequest("POST", "", nil)
|
||||
r.Form = v
|
||||
|
||||
a, err := Int64ValueOrDefault(r, "test", -1)
|
||||
if a != e {
|
||||
t.Fatalf("Value: %s, expected: %v, actual: %v", c, e, a)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("Error should be nil, but received: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64ValueOrDefaultWithError(t *testing.T) {
|
||||
v := url.Values{}
|
||||
v.Set("test", "invalid")
|
||||
r, _ := http.NewRequest("POST", "", nil)
|
||||
r.Form = v
|
||||
|
||||
_, err := Int64ValueOrDefault(r, "test", -1)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected an error.")
|
||||
}
|
||||
}
|
||||
90
vendor/github.com/docker/docker/api/server/httputils/httputils.go
generated
vendored
Normal file
90
vendor/github.com/docker/docker/api/server/httputils/httputils.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/api"
|
||||
)
|
||||
|
||||
// APIVersionKey is the client's requested API version.
|
||||
const APIVersionKey = "api-version"
|
||||
|
||||
// UAStringKey is used as key type for user-agent string in net/context struct
|
||||
const UAStringKey = "upstream-user-agent"
|
||||
|
||||
// APIFunc is an adapter to allow the use of ordinary functions as Docker API endpoints.
|
||||
// Any function that has the appropriate signature can be registered as an API endpoint (e.g. getVersion).
|
||||
type APIFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error
|
||||
|
||||
// HijackConnection interrupts the http response writer to get the
|
||||
// underlying connection and operate with it.
|
||||
func HijackConnection(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
|
||||
conn, _, err := w.(http.Hijacker).Hijack()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Flush the options to make sure the client sets the raw mode
|
||||
conn.Write([]byte{})
|
||||
return conn, conn, nil
|
||||
}
|
||||
|
||||
// CloseStreams ensures that a list for http streams are properly closed.
|
||||
func CloseStreams(streams ...interface{}) {
|
||||
for _, stream := range streams {
|
||||
if tcpc, ok := stream.(interface {
|
||||
CloseWrite() error
|
||||
}); ok {
|
||||
tcpc.CloseWrite()
|
||||
} else if closer, ok := stream.(io.Closer); ok {
|
||||
closer.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CheckForJSON makes sure that the request's Content-Type is application/json.
|
||||
func CheckForJSON(r *http.Request) error {
|
||||
ct := r.Header.Get("Content-Type")
|
||||
|
||||
// No Content-Type header is ok as long as there's no Body
|
||||
if ct == "" {
|
||||
if r.Body == nil || r.ContentLength == 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise it better be json
|
||||
if api.MatchesContentType(ct, "application/json") {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Content-Type specified (%s) must be 'application/json'", ct)
|
||||
}
|
||||
|
||||
// ParseForm ensures the request form is parsed even with invalid content types.
|
||||
// If we don't do this, POST method without Content-type (even with empty body) will fail.
|
||||
func ParseForm(r *http.Request) error {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
if err := r.ParseForm(); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// VersionFromContext returns an API version from the context using APIVersionKey.
|
||||
// It panics if the context value does not have version.Version type.
|
||||
func VersionFromContext(ctx context.Context) (ver string) {
|
||||
if ctx == nil {
|
||||
return
|
||||
}
|
||||
val := ctx.Value(APIVersionKey)
|
||||
if val == nil {
|
||||
return
|
||||
}
|
||||
return val.(string)
|
||||
}
|
||||
17
vendor/github.com/docker/docker/api/server/httputils/httputils_write_json.go
generated
vendored
Normal file
17
vendor/github.com/docker/docker/api/server/httputils/httputils_write_json.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// +build go1.7
|
||||
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// WriteJSON writes the value v to the http response stream as json with standard json encoding.
|
||||
func WriteJSON(w http.ResponseWriter, code int, v interface{}) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(code)
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetEscapeHTML(false)
|
||||
return enc.Encode(v)
|
||||
}
|
||||
16
vendor/github.com/docker/docker/api/server/httputils/httputils_write_json_go16.go
generated
vendored
Normal file
16
vendor/github.com/docker/docker/api/server/httputils/httputils_write_json_go16.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// +build go1.6,!go1.7
|
||||
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// WriteJSON writes the value v to the http response stream as json with standard json encoding.
|
||||
func WriteJSON(w http.ResponseWriter, code int, v interface{}) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(code)
|
||||
enc := json.NewEncoder(w)
|
||||
return enc.Encode(v)
|
||||
}
|
||||
24
vendor/github.com/docker/docker/api/server/middleware.go
generated
vendored
Normal file
24
vendor/github.com/docker/docker/api/server/middleware.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/server/middleware"
|
||||
)
|
||||
|
||||
// handlerWithGlobalMiddlewares wraps the handler function for a request with
|
||||
// the server's global middlewares. The order of the middlewares is backwards,
|
||||
// meaning that the first in the list will be evaluated last.
|
||||
func (s *Server) handlerWithGlobalMiddlewares(handler httputils.APIFunc) httputils.APIFunc {
|
||||
next := handler
|
||||
|
||||
for _, m := range s.middlewares {
|
||||
next = m.WrapHandler(next)
|
||||
}
|
||||
|
||||
if s.cfg.Logging && logrus.GetLevel() == logrus.DebugLevel {
|
||||
next = middleware.DebugRequestMiddleware(next)
|
||||
}
|
||||
|
||||
return next
|
||||
}
|
||||
37
vendor/github.com/docker/docker/api/server/middleware/cors.go
generated
vendored
Normal file
37
vendor/github.com/docker/docker/api/server/middleware/cors.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// CORSMiddleware injects CORS headers to each request
|
||||
// when it's configured.
|
||||
type CORSMiddleware struct {
|
||||
defaultHeaders string
|
||||
}
|
||||
|
||||
// NewCORSMiddleware creates a new CORSMiddleware with default headers.
|
||||
func NewCORSMiddleware(d string) CORSMiddleware {
|
||||
return CORSMiddleware{defaultHeaders: d}
|
||||
}
|
||||
|
||||
// WrapHandler returns a new handler function wrapping the previous one in the request chain.
|
||||
func (c CORSMiddleware) WrapHandler(handler func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error) func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
// If "api-cors-header" is not given, but "api-enable-cors" is true, we set cors to "*"
|
||||
// otherwise, all head values will be passed to HTTP handler
|
||||
corsHeaders := c.defaultHeaders
|
||||
if corsHeaders == "" {
|
||||
corsHeaders = "*"
|
||||
}
|
||||
|
||||
logrus.Debugf("CORS header is enabled and set to: %s", corsHeaders)
|
||||
w.Header().Add("Access-Control-Allow-Origin", corsHeaders)
|
||||
w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth")
|
||||
w.Header().Add("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS")
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
}
|
||||
76
vendor/github.com/docker/docker/api/server/middleware/debug.go
generated
vendored
Normal file
76
vendor/github.com/docker/docker/api/server/middleware/debug.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// DebugRequestMiddleware dumps the request to logger
|
||||
func DebugRequestMiddleware(handler func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error) func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
logrus.Debugf("Calling %s %s", r.Method, r.RequestURI)
|
||||
|
||||
if r.Method != "POST" {
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
maxBodySize := 4096 // 4KB
|
||||
if r.ContentLength > int64(maxBodySize) {
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
|
||||
body := r.Body
|
||||
bufReader := bufio.NewReaderSize(body, maxBodySize)
|
||||
r.Body = ioutils.NewReadCloserWrapper(bufReader, func() error { return body.Close() })
|
||||
|
||||
b, err := bufReader.Peek(maxBodySize)
|
||||
if err != io.EOF {
|
||||
// either there was an error reading, or the buffer is full (in which case the request is too large)
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
|
||||
var postForm map[string]interface{}
|
||||
if err := json.Unmarshal(b, &postForm); err == nil {
|
||||
maskSecretKeys(postForm)
|
||||
formStr, errMarshal := json.Marshal(postForm)
|
||||
if errMarshal == nil {
|
||||
logrus.Debugf("form data: %s", string(formStr))
|
||||
} else {
|
||||
logrus.Debugf("form data: %q", postForm)
|
||||
}
|
||||
}
|
||||
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
}
|
||||
|
||||
func maskSecretKeys(inp interface{}) {
|
||||
if arr, ok := inp.([]interface{}); ok {
|
||||
for _, f := range arr {
|
||||
maskSecretKeys(f)
|
||||
}
|
||||
return
|
||||
}
|
||||
if form, ok := inp.(map[string]interface{}); ok {
|
||||
loop0:
|
||||
for k, v := range form {
|
||||
for _, m := range []string{"password", "secret", "jointoken", "unlockkey"} {
|
||||
if strings.EqualFold(m, k) {
|
||||
form[k] = "*****"
|
||||
continue loop0
|
||||
}
|
||||
}
|
||||
maskSecretKeys(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
29
vendor/github.com/docker/docker/api/server/middleware/experimental.go
generated
vendored
Normal file
29
vendor/github.com/docker/docker/api/server/middleware/experimental.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// ExperimentalMiddleware is a the middleware in charge of adding the
|
||||
// 'Docker-Experimental' header to every outgoing request
|
||||
type ExperimentalMiddleware struct {
|
||||
experimental string
|
||||
}
|
||||
|
||||
// NewExperimentalMiddleware creates a new ExperimentalMiddleware
|
||||
func NewExperimentalMiddleware(experimentalEnabled bool) ExperimentalMiddleware {
|
||||
if experimentalEnabled {
|
||||
return ExperimentalMiddleware{"true"}
|
||||
}
|
||||
return ExperimentalMiddleware{"false"}
|
||||
}
|
||||
|
||||
// WrapHandler returns a new handler function wrapping the previous one in the request chain.
|
||||
func (e ExperimentalMiddleware) WrapHandler(handler func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error) func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
w.Header().Set("Docker-Experimental", e.experimental)
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
}
|
||||
13
vendor/github.com/docker/docker/api/server/middleware/middleware.go
generated
vendored
Normal file
13
vendor/github.com/docker/docker/api/server/middleware/middleware.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Middleware is an interface to allow the use of ordinary functions as Docker API filters.
|
||||
// Any struct that has the appropriate signature can be registered as a middleware.
|
||||
type Middleware interface {
|
||||
WrapHandler(func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error) func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error
|
||||
}
|
||||
50
vendor/github.com/docker/docker/api/server/middleware/version.go
generated
vendored
Normal file
50
vendor/github.com/docker/docker/api/server/middleware/version.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/docker/api/errors"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// VersionMiddleware is a middleware that
|
||||
// validates the client and server versions.
|
||||
type VersionMiddleware struct {
|
||||
serverVersion string
|
||||
defaultVersion string
|
||||
minVersion string
|
||||
}
|
||||
|
||||
// NewVersionMiddleware creates a new VersionMiddleware
|
||||
// with the default versions.
|
||||
func NewVersionMiddleware(s, d, m string) VersionMiddleware {
|
||||
return VersionMiddleware{
|
||||
serverVersion: s,
|
||||
defaultVersion: d,
|
||||
minVersion: m,
|
||||
}
|
||||
}
|
||||
|
||||
// WrapHandler returns a new handler function wrapping the previous one in the request chain.
|
||||
func (v VersionMiddleware) WrapHandler(handler func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error) func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
apiVersion := vars["version"]
|
||||
if apiVersion == "" {
|
||||
apiVersion = v.defaultVersion
|
||||
}
|
||||
|
||||
if versions.LessThan(apiVersion, v.minVersion) {
|
||||
return errors.NewBadRequestError(fmt.Errorf("client version %s is too old. Minimum supported API version is %s, please upgrade your client to a newer version", apiVersion, v.minVersion))
|
||||
}
|
||||
|
||||
header := fmt.Sprintf("Docker/%s (%s)", v.serverVersion, runtime.GOOS)
|
||||
w.Header().Set("Server", header)
|
||||
w.Header().Set("API-Version", v.defaultVersion)
|
||||
ctx = context.WithValue(ctx, "api-version", apiVersion)
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
|
||||
}
|
||||
57
vendor/github.com/docker/docker/api/server/middleware/version_test.go
generated
vendored
Normal file
57
vendor/github.com/docker/docker/api/server/middleware/version_test.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestVersionMiddleware(t *testing.T) {
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if httputils.VersionFromContext(ctx) == "" {
|
||||
t.Fatalf("Expected version, got empty string")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
defaultVersion := "1.10.0"
|
||||
minVersion := "1.2.0"
|
||||
m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
|
||||
h := m.WrapHandler(handler)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/containers/json", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
ctx := context.Background()
|
||||
if err := h(ctx, resp, req, map[string]string{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionMiddlewareWithErrors(t *testing.T) {
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if httputils.VersionFromContext(ctx) == "" {
|
||||
t.Fatalf("Expected version, got empty string")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
defaultVersion := "1.10.0"
|
||||
minVersion := "1.2.0"
|
||||
m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
|
||||
h := m.WrapHandler(handler)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/containers/json", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
ctx := context.Background()
|
||||
|
||||
vars := map[string]string{"version": "0.1"}
|
||||
err := h(ctx, resp, req, vars)
|
||||
|
||||
if !strings.Contains(err.Error(), "client version 0.1 is too old. Minimum supported API version is 1.2.0") {
|
||||
t.Fatalf("Expected too old client error, got %v", err)
|
||||
}
|
||||
}
|
||||
41
vendor/github.com/docker/docker/api/server/profiler.go
generated
vendored
Normal file
41
vendor/github.com/docker/docker/api/server/profiler.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"expvar"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
const debugPathPrefix = "/debug/"
|
||||
|
||||
func profilerSetup(mainRouter *mux.Router) {
|
||||
var r = mainRouter.PathPrefix(debugPathPrefix).Subrouter()
|
||||
r.HandleFunc("/vars", expVars)
|
||||
r.HandleFunc("/pprof/", pprof.Index)
|
||||
r.HandleFunc("/pprof/cmdline", pprof.Cmdline)
|
||||
r.HandleFunc("/pprof/profile", pprof.Profile)
|
||||
r.HandleFunc("/pprof/symbol", pprof.Symbol)
|
||||
r.HandleFunc("/pprof/trace", pprof.Trace)
|
||||
r.HandleFunc("/pprof/block", pprof.Handler("block").ServeHTTP)
|
||||
r.HandleFunc("/pprof/heap", pprof.Handler("heap").ServeHTTP)
|
||||
r.HandleFunc("/pprof/goroutine", pprof.Handler("goroutine").ServeHTTP)
|
||||
r.HandleFunc("/pprof/threadcreate", pprof.Handler("threadcreate").ServeHTTP)
|
||||
}
|
||||
|
||||
// Replicated from expvar.go as not public.
|
||||
func expVars(w http.ResponseWriter, r *http.Request) {
|
||||
first := true
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
fmt.Fprintf(w, "{\n")
|
||||
expvar.Do(func(kv expvar.KeyValue) {
|
||||
if !first {
|
||||
fmt.Fprintf(w, ",\n")
|
||||
}
|
||||
first = false
|
||||
fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
|
||||
})
|
||||
fmt.Fprintf(w, "\n}\n")
|
||||
}
|
||||
20
vendor/github.com/docker/docker/api/server/router/build/backend.go
generated
vendored
Normal file
20
vendor/github.com/docker/docker/api/server/router/build/backend.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Backend abstracts an image builder whose only purpose is to build an image referenced by an imageID.
|
||||
type Backend interface {
|
||||
// Build builds a Docker image referenced by an imageID string.
|
||||
//
|
||||
// Note: Tagging an image should not be done by a Builder, it should instead be done
|
||||
// by the caller.
|
||||
//
|
||||
// TODO: make this return a reference instead of string
|
||||
BuildFromContext(ctx context.Context, src io.ReadCloser, remote string, buildOptions *types.ImageBuildOptions, pg backend.ProgressWriter) (string, error)
|
||||
}
|
||||
29
vendor/github.com/docker/docker/api/server/router/build/build.go
generated
vendored
Normal file
29
vendor/github.com/docker/docker/api/server/router/build/build.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
package build
|
||||
|
||||
import "github.com/docker/docker/api/server/router"
|
||||
|
||||
// buildRouter is a router to talk with the build controller
|
||||
type buildRouter struct {
|
||||
backend Backend
|
||||
routes []router.Route
|
||||
}
|
||||
|
||||
// NewRouter initializes a new build router
|
||||
func NewRouter(b Backend) router.Router {
|
||||
r := &buildRouter{
|
||||
backend: b,
|
||||
}
|
||||
r.initRoutes()
|
||||
return r
|
||||
}
|
||||
|
||||
// Routes returns the available routers to the build controller
|
||||
func (r *buildRouter) Routes() []router.Route {
|
||||
return r.routes
|
||||
}
|
||||
|
||||
func (r *buildRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
router.Cancellable(router.NewPostRoute("/build", r.postBuild)),
|
||||
}
|
||||
}
|
||||
225
vendor/github.com/docker/docker/api/server/router/build/build_routes.go
generated
vendored
Normal file
225
vendor/github.com/docker/docker/api/server/router/build/build_routes.go
generated
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/docker/go-units"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBuildOptions, error) {
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
options := &types.ImageBuildOptions{}
|
||||
if httputils.BoolValue(r, "forcerm") && versions.GreaterThanOrEqualTo(version, "1.12") {
|
||||
options.Remove = true
|
||||
} else if r.FormValue("rm") == "" && versions.GreaterThanOrEqualTo(version, "1.12") {
|
||||
options.Remove = true
|
||||
} else {
|
||||
options.Remove = httputils.BoolValue(r, "rm")
|
||||
}
|
||||
if httputils.BoolValue(r, "pull") && versions.GreaterThanOrEqualTo(version, "1.16") {
|
||||
options.PullParent = true
|
||||
}
|
||||
|
||||
options.Dockerfile = r.FormValue("dockerfile")
|
||||
options.SuppressOutput = httputils.BoolValue(r, "q")
|
||||
options.NoCache = httputils.BoolValue(r, "nocache")
|
||||
options.ForceRemove = httputils.BoolValue(r, "forcerm")
|
||||
options.MemorySwap = httputils.Int64ValueOrZero(r, "memswap")
|
||||
options.Memory = httputils.Int64ValueOrZero(r, "memory")
|
||||
options.CPUShares = httputils.Int64ValueOrZero(r, "cpushares")
|
||||
options.CPUPeriod = httputils.Int64ValueOrZero(r, "cpuperiod")
|
||||
options.CPUQuota = httputils.Int64ValueOrZero(r, "cpuquota")
|
||||
options.CPUSetCPUs = r.FormValue("cpusetcpus")
|
||||
options.CPUSetMems = r.FormValue("cpusetmems")
|
||||
options.CgroupParent = r.FormValue("cgroupparent")
|
||||
options.NetworkMode = r.FormValue("networkmode")
|
||||
options.Tags = r.Form["t"]
|
||||
options.SecurityOpt = r.Form["securityopt"]
|
||||
options.Squash = httputils.BoolValue(r, "squash")
|
||||
|
||||
if r.Form.Get("shmsize") != "" {
|
||||
shmSize, err := strconv.ParseInt(r.Form.Get("shmsize"), 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options.ShmSize = shmSize
|
||||
}
|
||||
|
||||
if i := container.Isolation(r.FormValue("isolation")); i != "" {
|
||||
if !container.Isolation.IsValid(i) {
|
||||
return nil, fmt.Errorf("Unsupported isolation: %q", i)
|
||||
}
|
||||
options.Isolation = i
|
||||
}
|
||||
|
||||
if runtime.GOOS != "windows" && options.SecurityOpt != nil {
|
||||
return nil, fmt.Errorf("the daemon on this platform does not support --security-opt to build")
|
||||
}
|
||||
|
||||
var buildUlimits = []*units.Ulimit{}
|
||||
ulimitsJSON := r.FormValue("ulimits")
|
||||
if ulimitsJSON != "" {
|
||||
if err := json.Unmarshal([]byte(ulimitsJSON), &buildUlimits); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options.Ulimits = buildUlimits
|
||||
}
|
||||
|
||||
var buildArgs = map[string]*string{}
|
||||
buildArgsJSON := r.FormValue("buildargs")
|
||||
|
||||
// Note that there are two ways a --build-arg might appear in the
|
||||
// json of the query param:
|
||||
// "foo":"bar"
|
||||
// and "foo":nil
|
||||
// The first is the normal case, ie. --build-arg foo=bar
|
||||
// or --build-arg foo
|
||||
// where foo's value was picked up from an env var.
|
||||
// The second ("foo":nil) is where they put --build-arg foo
|
||||
// but "foo" isn't set as an env var. In that case we can't just drop
|
||||
// the fact they mentioned it, we need to pass that along to the builder
|
||||
// so that it can print a warning about "foo" being unused if there is
|
||||
// no "ARG foo" in the Dockerfile.
|
||||
if buildArgsJSON != "" {
|
||||
if err := json.Unmarshal([]byte(buildArgsJSON), &buildArgs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options.BuildArgs = buildArgs
|
||||
}
|
||||
|
||||
var labels = map[string]string{}
|
||||
labelsJSON := r.FormValue("labels")
|
||||
if labelsJSON != "" {
|
||||
if err := json.Unmarshal([]byte(labelsJSON), &labels); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options.Labels = labels
|
||||
}
|
||||
|
||||
var cacheFrom = []string{}
|
||||
cacheFromJSON := r.FormValue("cachefrom")
|
||||
if cacheFromJSON != "" {
|
||||
if err := json.Unmarshal([]byte(cacheFromJSON), &cacheFrom); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options.CacheFrom = cacheFrom
|
||||
}
|
||||
|
||||
return options, nil
|
||||
}
|
||||
|
||||
type syncWriter struct {
|
||||
w io.Writer
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (s *syncWriter) Write(b []byte) (count int, err error) {
|
||||
s.mu.Lock()
|
||||
count, err = s.w.Write(b)
|
||||
s.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var (
|
||||
authConfigs = map[string]types.AuthConfig{}
|
||||
authConfigsEncoded = r.Header.Get("X-Registry-Config")
|
||||
notVerboseBuffer = bytes.NewBuffer(nil)
|
||||
)
|
||||
|
||||
if authConfigsEncoded != "" {
|
||||
authConfigsJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authConfigsEncoded))
|
||||
if err := json.NewDecoder(authConfigsJSON).Decode(&authConfigs); err != nil {
|
||||
// for a pull it is not an error if no auth was given
|
||||
// to increase compatibility with the existing api it is defaulting
|
||||
// to be empty.
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
output := ioutils.NewWriteFlusher(w)
|
||||
defer output.Close()
|
||||
sf := streamformatter.NewJSONStreamFormatter()
|
||||
errf := func(err error) error {
|
||||
if httputils.BoolValue(r, "q") && notVerboseBuffer.Len() > 0 {
|
||||
output.Write(notVerboseBuffer.Bytes())
|
||||
}
|
||||
// Do not write the error in the http output if it's still empty.
|
||||
// This prevents from writing a 200(OK) when there is an internal error.
|
||||
if !output.Flushed() {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(sf.FormatError(err))
|
||||
if err != nil {
|
||||
logrus.Warnf("could not write error response: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
buildOptions, err := newImageBuildOptions(ctx, r)
|
||||
if err != nil {
|
||||
return errf(err)
|
||||
}
|
||||
buildOptions.AuthConfigs = authConfigs
|
||||
|
||||
remoteURL := r.FormValue("remote")
|
||||
|
||||
// Currently, only used if context is from a remote url.
|
||||
// Look at code in DetectContextFromRemoteURL for more information.
|
||||
createProgressReader := func(in io.ReadCloser) io.ReadCloser {
|
||||
progressOutput := sf.NewProgressOutput(output, true)
|
||||
if buildOptions.SuppressOutput {
|
||||
progressOutput = sf.NewProgressOutput(notVerboseBuffer, true)
|
||||
}
|
||||
return progress.NewProgressReader(in, progressOutput, r.ContentLength, "Downloading context", remoteURL)
|
||||
}
|
||||
|
||||
out := io.Writer(output)
|
||||
if buildOptions.SuppressOutput {
|
||||
out = notVerboseBuffer
|
||||
}
|
||||
out = &syncWriter{w: out}
|
||||
stdout := &streamformatter.StdoutFormatter{Writer: out, StreamFormatter: sf}
|
||||
stderr := &streamformatter.StderrFormatter{Writer: out, StreamFormatter: sf}
|
||||
|
||||
pg := backend.ProgressWriter{
|
||||
Output: out,
|
||||
StdoutFormatter: stdout,
|
||||
StderrFormatter: stderr,
|
||||
ProgressReaderFunc: createProgressReader,
|
||||
}
|
||||
|
||||
imgID, err := br.backend.BuildFromContext(ctx, r.Body, remoteURL, buildOptions, pg)
|
||||
if err != nil {
|
||||
return errf(err)
|
||||
}
|
||||
|
||||
// Everything worked so if -q was provided the output from the daemon
|
||||
// should be just the image ID and we'll print that to stdout.
|
||||
if buildOptions.SuppressOutput {
|
||||
stdout := &streamformatter.StdoutFormatter{Writer: output, StreamFormatter: sf}
|
||||
fmt.Fprintf(stdout, "%s\n", string(imgID))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
10
vendor/github.com/docker/docker/api/server/router/checkpoint/backend.go
generated
vendored
Normal file
10
vendor/github.com/docker/docker/api/server/router/checkpoint/backend.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
package checkpoint
|
||||
|
||||
import "github.com/docker/docker/api/types"
|
||||
|
||||
// Backend for Checkpoint
|
||||
type Backend interface {
|
||||
CheckpointCreate(container string, config types.CheckpointCreateOptions) error
|
||||
CheckpointDelete(container string, config types.CheckpointDeleteOptions) error
|
||||
CheckpointList(container string, config types.CheckpointListOptions) ([]types.Checkpoint, error)
|
||||
}
|
||||
36
vendor/github.com/docker/docker/api/server/router/checkpoint/checkpoint.go
generated
vendored
Normal file
36
vendor/github.com/docker/docker/api/server/router/checkpoint/checkpoint.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package checkpoint
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/server/router"
|
||||
)
|
||||
|
||||
// checkpointRouter is a router to talk with the checkpoint controller
|
||||
type checkpointRouter struct {
|
||||
backend Backend
|
||||
decoder httputils.ContainerDecoder
|
||||
routes []router.Route
|
||||
}
|
||||
|
||||
// NewRouter initializes a new checkpoint router
|
||||
func NewRouter(b Backend, decoder httputils.ContainerDecoder) router.Router {
|
||||
r := &checkpointRouter{
|
||||
backend: b,
|
||||
decoder: decoder,
|
||||
}
|
||||
r.initRoutes()
|
||||
return r
|
||||
}
|
||||
|
||||
// Routes returns the available routers to the checkpoint controller
|
||||
func (r *checkpointRouter) Routes() []router.Route {
|
||||
return r.routes
|
||||
}
|
||||
|
||||
func (r *checkpointRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
router.Experimental(router.NewGetRoute("/containers/{name:.*}/checkpoints", r.getContainerCheckpoints)),
|
||||
router.Experimental(router.NewPostRoute("/containers/{name:.*}/checkpoints", r.postContainerCheckpoint)),
|
||||
router.Experimental(router.NewDeleteRoute("/containers/{name}/checkpoints/{checkpoint}", r.deleteContainerCheckpoint)),
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user