diff options
177 files changed, 3887 insertions, 9137 deletions
diff --git a/vendor/github.com/containerd/continuity/LICENSE b/vendor/github.com/containerd/continuity/LICENSE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/vendor/github.com/containerd/continuity/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/vendor/github.com/containerd/continuity/README.md b/vendor/github.com/containerd/continuity/README.md new file mode 100644 index 000000000..0e91ce07b --- /dev/null +++ b/vendor/github.com/containerd/continuity/README.md @@ -0,0 +1,74 @@ +# continuity + +[![GoDoc](https://godoc.org/github.com/containerd/continuity?status.svg)](https://godoc.org/github.com/containerd/continuity) +[![Build Status](https://travis-ci.org/containerd/continuity.svg?branch=master)](https://travis-ci.org/containerd/continuity) + +A transport-agnostic, filesystem metadata manifest system + +This project is a staging area for experiments in providing transport agnostic +metadata storage. + +Please see https://github.com/opencontainers/specs/issues/11 for more details. + +## Manifest Format + +A continuity manifest encodes filesystem metadata in Protocol Buffers. +Please refer to [proto/manifest.proto](proto/manifest.proto). + +## Usage + +Build: + +```console +$ make +``` + +Create a manifest (of this repo itself): + +```console +$ ./bin/continuity build . > /tmp/a.pb +``` + +Dump a manifest: + +```console +$ ./bin/continuity ls /tmp/a.pb +... +-rw-rw-r-- 270 B /.gitignore +-rw-rw-r-- 88 B /.mailmap +-rw-rw-r-- 187 B /.travis.yml +-rw-rw-r-- 359 B /AUTHORS +-rw-rw-r-- 11 kB /LICENSE +-rw-rw-r-- 1.5 kB /Makefile +... +-rw-rw-r-- 986 B /testutil_test.go +drwxrwxr-x 0 B /version +-rw-rw-r-- 478 B /version/version.go +``` + +Verify a manifest: + +```console +$ ./bin/continuity verify . /tmp/a.pb +``` + +Break the directory and restore using the manifest: +```console +$ chmod 777 Makefile +$ ./bin/continuity verify . /tmp/a.pb +2017/06/23 08:00:34 error verifying manifest: resource "/Makefile" has incorrect mode: -rwxrwxrwx != -rw-rw-r-- +$ ./bin/continuity apply . /tmp/a.pb +$ stat -c %a Makefile +664 +$ ./bin/continuity verify . /tmp/a.pb +``` + + +## Contribution Guide +### Building Proto Package + +If you change the proto file you will need to rebuild the generated Go with `go generate`. + +```console +$ go generate ./proto +``` diff --git a/vendor/github.com/containerd/continuity/pathdriver/path_driver.go b/vendor/github.com/containerd/continuity/pathdriver/path_driver.go new file mode 100644 index 000000000..b43d55fe9 --- /dev/null +++ b/vendor/github.com/containerd/continuity/pathdriver/path_driver.go @@ -0,0 +1,85 @@ +package pathdriver + +import ( + "path/filepath" +) + +// PathDriver provides all of the path manipulation functions in a common +// interface. The context should call these and never use the `filepath` +// package or any other package to manipulate paths. +type PathDriver interface { + Join(paths ...string) string + IsAbs(path string) bool + Rel(base, target string) (string, error) + Base(path string) string + Dir(path string) string + Clean(path string) string + Split(path string) (dir, file string) + Separator() byte + Abs(path string) (string, error) + Walk(string, filepath.WalkFunc) error + FromSlash(path string) string + ToSlash(path string) string + Match(pattern, name string) (matched bool, err error) +} + +// pathDriver is a simple default implementation calls the filepath package. +type pathDriver struct{} + +// LocalPathDriver is the exported pathDriver struct for convenience. +var LocalPathDriver PathDriver = &pathDriver{} + +func (*pathDriver) Join(paths ...string) string { + return filepath.Join(paths...) +} + +func (*pathDriver) IsAbs(path string) bool { + return filepath.IsAbs(path) +} + +func (*pathDriver) Rel(base, target string) (string, error) { + return filepath.Rel(base, target) +} + +func (*pathDriver) Base(path string) string { + return filepath.Base(path) +} + +func (*pathDriver) Dir(path string) string { + return filepath.Dir(path) +} + +func (*pathDriver) Clean(path string) string { + return filepath.Clean(path) +} + +func (*pathDriver) Split(path string) (dir, file string) { + return filepath.Split(path) +} + +func (*pathDriver) Separator() byte { + return filepath.Separator +} + +func (*pathDriver) Abs(path string) (string, error) { + return filepath.Abs(path) +} + +// Note that filepath.Walk calls os.Stat, so if the context wants to +// to call Driver.Stat() for Walk, they need to create a new struct that +// overrides this method. +func (*pathDriver) Walk(root string, walkFn filepath.WalkFunc) error { + return filepath.Walk(root, walkFn) +} + +func (*pathDriver) FromSlash(path string) string { + return filepath.FromSlash(path) +} + +func (*pathDriver) ToSlash(path string) string { + return filepath.ToSlash(path) +} + +func (*pathDriver) Match(pattern, name string) (bool, error) { + return filepath.Match(pattern, name) +} diff --git a/vendor/github.com/containerd/continuity/vendor.conf b/vendor/github.com/containerd/continuity/vendor.conf new file mode 100644 index 000000000..feecf3568 --- /dev/null +++ b/vendor/github.com/containerd/continuity/vendor.conf @@ -0,0 +1,12 @@ +bazil.org/fuse 371fbbdaa8987b715bdd21d6adc4c9b20155f748 +github.com/dustin/go-humanize bb3d318650d48840a39aa21a027c6630e198e626 +github.com/golang/protobuf 1e59b77b52bf8e4b449a57e6f79f21226d571845 +github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 +github.com/opencontainers/go-digest 279bed98673dd5bef374d3b6e4b09e2af76183bf +github.com/pkg/errors f15c970de5b76fac0b59abb32d62c17cc7bed265 +github.com/sirupsen/logrus 89742aefa4b206dcf400792f3bd35b542998eb3b +github.com/spf13/cobra 2da4a54c5ceefcee7ca5dd0eea1e18a3b6366489 +github.com/spf13/pflag 4c012f6dcd9546820e378d0bdda4d8fc772cdfea +golang.org/x/crypto 9f005a07e0d31d45e6656d241bb5c0f2efd4bc94 +golang.org/x/net a337091b0525af65de94df2eb7e98bd9962dcbe2 +golang.org/x/sys 665f6529cca930e27b831a0d1dafffbe1c172924 diff --git a/vendor/github.com/docker/docker/README.md b/vendor/github.com/docker/docker/README.md index 533d7717d..534fd97db 100644 --- a/vendor/github.com/docker/docker/README.md +++ b/vendor/github.com/docker/docker/README.md @@ -1,70 +1,38 @@ -### Docker users, see [Moby and Docker](https://mobyproject.org/#moby-and-docker) to clarify the relationship between the projects - -### Docker maintainers and contributors, see [Transitioning to Moby](#transitioning-to-moby) for more details - The Moby Project ================ ![Moby Project logo](docs/static_files/moby-project-logo.png "The Moby Project") -Moby is an open-source project created by Docker to advance the software containerization movement. -It provides a “Lego set” of dozens of components, the framework for assembling them into custom container-based systems, and a place for all container enthusiasts to experiment and exchange ideas. - -# Moby - -## Overview +Moby is an open-source project created by Docker to enable and accelerate software containerization. -At the core of Moby is a framework to assemble specialized container systems. -It provides: - -- A library of containerized components for all vital aspects of a container system: OS, container runtime, orchestration, infrastructure management, networking, storage, security, build, image distribution, etc. -- Tools to assemble the components into runnable artifacts for a variety of platforms and architectures: bare metal (both x86 and Arm); executables for Linux, Mac and Windows; VM images for popular cloud and virtualization providers. -- A set of reference assemblies which can be used as-is, modified, or used as inspiration to create your own. - -All Moby components are containers, so creating new components is as easy as building a new OCI-compatible container. +It provides a "Lego set" of toolkit components, the framework for assembling them into custom container-based systems, and a place for all container enthusiasts and professionals to experiment and exchange ideas. +Components include container build tools, a container registry, orchestration tools, a runtime and more, and these can be used as building blocks in conjunction with other tools and projects. ## Principles -Moby is an open project guided by strong principles, but modular, flexible and without too strong an opinion on user experience, so it is open to the community to help set its direction. -The guiding principles are: +Moby is an open project guided by strong principles, aiming to be modular, flexible and without too strong an opinion on user experience. +It is open to the community to help set its direction. +- Modular: the project includes lots of components that have well-defined functions and APIs that work together. - Batteries included but swappable: Moby includes enough components to build fully featured container system, but its modular architecture ensures that most of the components can be swapped by different implementations. -- Usable security: Moby will provide secure defaults without compromising usability. -- Container centric: Moby is built with containers, for running containers. - -With Moby, you should be able to describe all the components of your distributed application, from the high-level configuration files down to the kernel you would like to use and build and deploy it easily. - -Moby uses [containerd](https://github.com/containerd/containerd) as the default container runtime. +- Usable security: Moby provides secure defaults without compromising usability. +- Developer focused: The APIs are intended to be functional and useful to build powerful tools. +They are not necessarily intended as end user tools but as components aimed at developers. +Documentation and UX is aimed at developers not end users. ## Audience -Moby is recommended for anyone who wants to assemble a container-based system. This includes: - -- Hackers who want to customize or patch their Docker build -- System engineers or integrators building a container system -- Infrastructure providers looking to adapt existing container systems to their environment -- Container enthusiasts who want to experiment with the latest container tech -- Open-source developers looking to test their project in a variety of different systems -- Anyone curious about Docker internals and how it’s built - -Moby is NOT recommended for: +The Moby Project is intended for engineers, integrators and enthusiasts looking to modify, hack, fix, experiment, invent and build systems based on containers. +It is not for people looking for a commercially supported system, but for people who want to work and learn with open source code. -- Application developers looking for an easy way to run their applications in containers. We recommend Docker CE instead. -- Enterprise IT and development teams looking for a ready-to-use, commercially supported container platform. We recommend Docker EE instead. -- Anyone curious about containers and looking for an easy way to learn. We recommend the [docker.com](https://www.docker.com/) website instead. +## Relationship with Docker -# Transitioning to Moby +The components and tools in the Moby Project are initially the open source components that Docker and the community have built for the Docker Project. +New projects can be added if they fit with the community goals. Docker is committed to using Moby as the upstream for the Docker Product. +However, other projects are also encouraged to use Moby as an upstream, and to reuse the components in diverse ways, and all these uses will be treated in the same way. External maintainers and contributors are welcomed. -Docker is transitioning all of its open source collaborations to the Moby project going forward. -During the transition, all open source activity should continue as usual. - -We are proposing the following list of changes: - -- splitting up the engine into more open components -- removing the docker UI, SDK etc to keep them in the Docker org -- clarifying that the project is not limited to the engine, but to the assembly of all the individual components of the Docker platform -- open-source new tools & components which we currently use to assemble the Docker product, but could benefit the community -- defining an open, community-centric governance inspired by the Fedora project (a very successful example of balancing the needs of the community with the constraints of the primary corporate sponsor) +The Moby project is not intended as a location for support or feature requests for Docker products, but as a place for contributors to work on open source code, fix bugs, and make the code more useful. +The releases are supported by the maintainers, community and users, on a best efforts basis only, and are not intended for customers who want enterprise or commercial support; Docker EE is the appropriate product for these use cases. ----- @@ -82,7 +50,6 @@ violate applicable laws. For more information, please see https://www.bis.doc.gov - Licensing ========= Moby is licensed under the Apache License, Version 2.0. See diff --git a/vendor/github.com/docker/docker/api/README.md b/vendor/github.com/docker/docker/api/README.md index bb8813252..f136c3433 100644 --- a/vendor/github.com/docker/docker/api/README.md +++ b/vendor/github.com/docker/docker/api/README.md @@ -10,7 +10,7 @@ It consists of various components in this repository: - `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 +## Swagger definition The API is defined by the [Swagger](http://swagger.io/specification/) definition in `api/swagger.yaml`. This definition can be used to: @@ -20,7 +20,7 @@ The API is defined by the [Swagger](http://swagger.io/specification/) definition ## 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 API documentation is generated entirely from `api/swagger.yaml`. If you make updates to the API, edit this file to represent the change in the documentation. The file is split into two main sections: @@ -29,9 +29,9 @@ The file is split into two main sections: 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) +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. +`swagger.yaml` is validated by `hack/validate/swagger` to ensure it is a valid Swagger definition. This is useful when making edits to ensure you are doing the right thing. ## Viewing the API documentation diff --git a/vendor/github.com/docker/docker/api/common.go b/vendor/github.com/docker/docker/api/common.go index 6e462aeda..af34d0b35 100644 --- a/vendor/github.com/docker/docker/api/common.go +++ b/vendor/github.com/docker/docker/api/common.go @@ -1,65 +1,11 @@ package api -import ( - "encoding/json" - "encoding/pem" - "fmt" - "os" - "path/filepath" - - "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.32" + DefaultVersion string = "1.35" // NoBaseImageSpecifier is the symbol used by the FROM // command to specify that no base image is to be used. NoBaseImageSpecifier string = "scratch" ) - -// 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 -} diff --git a/vendor/github.com/docker/docker/api/names.go b/vendor/github.com/docker/docker/api/names.go deleted file mode 100644 index f147d1f4c..000000000 --- a/vendor/github.com/docker/docker/api/names.go +++ /dev/null @@ -1,9 +0,0 @@ -package api - -import "regexp" - -// RestrictedNameChars collects the characters allowed to represent a name, normally used to validate container and volume names. -const RestrictedNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.-]` - -// RestrictedNamePattern is a regular expression to validate names against the collection of restricted characters. -var RestrictedNamePattern = regexp.MustCompile(`^` + RestrictedNameChars + `+$`) diff --git a/vendor/github.com/docker/docker/api/types/client.go b/vendor/github.com/docker/docker/api/types/client.go index 18a1263f1..93ca42854 100644 --- a/vendor/github.com/docker/docker/api/types/client.go +++ b/vendor/github.com/docker/docker/api/types/client.go @@ -74,6 +74,7 @@ type ContainerLogsOptions struct { ShowStdout bool ShowStderr bool Since string + Until string Timestamps bool Follow bool Tail string @@ -179,10 +180,7 @@ type ImageBuildOptions struct { ExtraHosts []string // List of extra hosts Target string SessionID string - - // TODO @jhowardmsft LCOW Support: This will require extending to include - // `Platform string`, but is ommited for now as it's hard-coded temporarily - // to avoid API changes. + Platform string } // ImageBuildResponse holds information @@ -195,7 +193,8 @@ type ImageBuildResponse struct { // ImageCreateOptions holds information to create images. type ImageCreateOptions struct { - RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry + RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry. + Platform string // Platform is the target platform of the image if it needs to be pulled from the registry. } // ImageImportSource holds source information for ImageImport @@ -206,9 +205,10 @@ type ImageImportSource struct { // ImageImportOptions holds information to import images from the client host. type ImageImportOptions struct { - Tag string // Tag is the name to tag this image with. This attribute is deprecated. - Message string // Message is the message to tag the image with - Changes []string // Changes are the raw changes to apply to this image + Tag string // Tag is the name to tag this image with. This attribute is deprecated. + Message string // Message is the message to tag the image with + Changes []string // Changes are the raw changes to apply to this image + Platform string // Platform is the target platform of the image } // ImageListOptions holds parameters to filter the list of images with. @@ -229,6 +229,7 @@ type ImagePullOptions struct { All bool RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry PrivilegeFunc RequestPrivilegeFunc + Platform string } // RequestPrivilegeFunc is a function interface that diff --git a/vendor/github.com/docker/docker/api/types/configs.go b/vendor/github.com/docker/docker/api/types/configs.go index e4d2ce6e3..20c19f213 100644 --- a/vendor/github.com/docker/docker/api/types/configs.go +++ b/vendor/github.com/docker/docker/api/types/configs.go @@ -16,7 +16,6 @@ type ContainerCreateConfig struct { HostConfig *container.HostConfig NetworkingConfig *network.NetworkingConfig AdjustCPUShares bool - Platform string } // ContainerRmConfig holds arguments for the container remove diff --git a/vendor/github.com/docker/docker/api/types/container/container_wait.go b/vendor/github.com/docker/docker/api/types/container/container_wait.go index 77ecdbaf7..47fb17578 100644 --- a/vendor/github.com/docker/docker/api/types/container/container_wait.go +++ b/vendor/github.com/docker/docker/api/types/container/container_wait.go @@ -7,10 +7,22 @@ package container // See hack/generate-swagger-api.sh // ---------------------------------------------------------------------------- +// ContainerWaitOKBodyError container waiting error, if any +// swagger:model ContainerWaitOKBodyError +type ContainerWaitOKBodyError struct { + + // Details of an error + Message string `json:"Message,omitempty"` +} + // ContainerWaitOKBody container wait o k body // swagger:model ContainerWaitOKBody type ContainerWaitOKBody struct { + // error + // Required: true + Error *ContainerWaitOKBodyError `json:"Error"` + // Exit code of the container // Required: true StatusCode int64 `json:"StatusCode"` diff --git a/vendor/github.com/docker/docker/api/types/container/host_config.go b/vendor/github.com/docker/docker/api/types/container/host_config.go index 9fea9eb04..568cdcca9 100644 --- a/vendor/github.com/docker/docker/api/types/container/host_config.go +++ b/vendor/github.com/docker/docker/api/types/container/host_config.go @@ -20,44 +20,70 @@ func (i Isolation) IsDefault() bool { return strings.ToLower(string(i)) == "default" || string(i) == "" } +// IsHyperV indicates the use of a Hyper-V partition for isolation +func (i Isolation) IsHyperV() bool { + return strings.ToLower(string(i)) == "hyperv" +} + +// IsProcess indicates the use of process isolation +func (i Isolation) IsProcess() bool { + return strings.ToLower(string(i)) == "process" +} + +const ( + // IsolationEmpty is unspecified (same behavior as default) + IsolationEmpty = Isolation("") + // IsolationDefault is the default isolation mode on current daemon + IsolationDefault = Isolation("default") + // IsolationProcess is process isolation mode + IsolationProcess = Isolation("process") + // IsolationHyperV is HyperV isolation mode + IsolationHyperV = Isolation("hyperv") +) + // IpcMode represents the container ipc stack. type IpcMode string -// IsPrivate indicates whether the container uses its private ipc stack. +// IsPrivate indicates whether the container uses its own private ipc namespace which can not be shared. func (n IpcMode) IsPrivate() bool { - return !(n.IsHost() || n.IsContainer()) + return n == "private" } -// IsHost indicates whether the container uses the host's ipc stack. +// IsHost indicates whether the container shares the host's ipc namespace. func (n IpcMode) IsHost() bool { return n == "host" } -// IsContainer indicates whether the container uses a container's ipc stack. +// IsShareable indicates whether the container's ipc namespace can be shared with another container. +func (n IpcMode) IsShareable() bool { + return n == "shareable" +} + +// IsContainer indicates whether the container uses another container's ipc namespace. func (n IpcMode) IsContainer() bool { parts := strings.SplitN(string(n), ":", 2) return len(parts) > 1 && parts[0] == "container" } -// Valid indicates whether the ipc stack is valid. +// IsNone indicates whether container IpcMode is set to "none". +func (n IpcMode) IsNone() bool { + return n == "none" +} + +// IsEmpty indicates whether container IpcMode is empty +func (n IpcMode) IsEmpty() bool { + return n == "" +} + +// Valid indicates whether the ipc mode is valid. func (n IpcMode) Valid() bool { - parts := strings.Split(string(n), ":") - switch mode := parts[0]; mode { - case "", "host": - case "container": - if len(parts) != 2 || parts[1] == "" { - return false - } - default: - return false - } - return true + return n.IsEmpty() || n.IsNone() || n.IsPrivate() || n.IsHost() || n.IsShareable() || n.IsContainer() } // Container returns the name of the container ipc stack is going to be used. func (n IpcMode) Container() string { parts := strings.SplitN(string(n), ":", 2) - if len(parts) > 1 { + if len(parts) > 1 && parts[0] == "container" { return parts[1] } return "" diff --git a/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go b/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go index 469923f7e..3374d737f 100644 --- a/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go +++ b/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go @@ -1,9 +1,5 @@ package container -import ( - "strings" -) - // IsBridge indicates whether container uses the bridge network stack // in windows it is given the name NAT func (n NetworkMode) IsBridge() bool { @@ -21,16 +17,6 @@ func (n NetworkMode) IsUserDefined() bool { return !n.IsDefault() && !n.IsNone() && !n.IsBridge() && !n.IsContainer() } -// IsHyperV indicates the use of a Hyper-V partition for isolation -func (i Isolation) IsHyperV() bool { - return strings.ToLower(string(i)) == "hyperv" -} - -// IsProcess indicates the use of process isolation -func (i Isolation) IsProcess() bool { - return strings.ToLower(string(i)) == "process" -} - // IsValid indicates if an isolation technology is valid func (i Isolation) IsValid() bool { return i.IsDefault() || i.IsHyperV() || i.IsProcess() diff --git a/vendor/github.com/docker/docker/api/types/filters/parse.go b/vendor/github.com/docker/docker/api/types/filters/parse.go index beec3d494..d45d0528f 100644 --- a/vendor/github.com/docker/docker/api/types/filters/parse.go +++ b/vendor/github.com/docker/docker/api/types/filters/parse.go @@ -1,38 +1,45 @@ -// Package filters provides helper function to parse and handle command line -// filter, used for example in docker ps or docker images commands. +/*Package filters provides tools for encoding a mapping of keys to a set of +multiple values. +*/ package filters import ( "encoding/json" "errors" - "fmt" "regexp" "strings" "github.com/docker/docker/api/types/versions" ) -// Args stores filter arguments as map key:{map key: bool}. -// It contains an aggregation of the map of arguments (which are in the form -// of -f 'key=value') based on the key, and stores values for the same key -// in a map with string keys and boolean values. -// e.g given -f 'label=label1=1' -f 'label=label2=2' -f 'image.name=ubuntu' -// the args will be {"image.name":{"ubuntu":true},"label":{"label1=1":true,"label2=2":true}} +// Args stores a mapping of keys to a set of multiple values. type Args struct { fields map[string]map[string]bool } -// NewArgs initializes a new Args struct. -func NewArgs() Args { - return Args{fields: map[string]map[string]bool{}} +// KeyValuePair are used to initialize a new Args +type KeyValuePair struct { + Key string + Value string } -// ParseFlag parses the argument to the filter flag. Like -// -// `docker ps -f 'created=today' -f 'image.name=ubuntu*'` +// Arg creates a new KeyValuePair for initializing Args +func Arg(key, value string) KeyValuePair { + return KeyValuePair{Key: key, Value: value} +} + +// NewArgs returns a new Args populated with the initial args +func NewArgs(initialArgs ...KeyValuePair) Args { + args := Args{fields: map[string]map[string]bool{}} + for _, arg := range initialArgs { + args.Add(arg.Key, arg.Value) + } + return args +} + +// ParseFlag parses a key=value string and adds it to an Args. // -// If prev map is provided, then it is appended to, and returned. By default a new -// map is created. +// Deprecated: Use Args.Add() func ParseFlag(arg string, prev Args) (Args, error) { filters := prev if len(arg) == 0 { @@ -53,74 +60,95 @@ func ParseFlag(arg string, prev Args) (Args, error) { return filters, nil } -// ErrBadFormat is an error returned in case of bad format for a filter. +// ErrBadFormat is an error returned when a filter is not in the form key=value +// +// Deprecated: this error will be removed in a future version var ErrBadFormat = errors.New("bad format of filter (expected name=value)") -// ToParam packs the Args into a string for easy transport from client to server. +// ToParam encodes the Args as args JSON encoded string +// +// Deprecated: use ToJSON func ToParam(a Args) (string, error) { - // this way we don't URL encode {}, just empty space - if a.Len() == 0 { - return "", nil + return ToJSON(a) +} + +// MarshalJSON returns a JSON byte representation of the Args +func (args Args) MarshalJSON() ([]byte, error) { + if len(args.fields) == 0 { + return []byte{}, nil } + return json.Marshal(args.fields) +} - buf, err := json.Marshal(a.fields) - if err != nil { - return "", err +// ToJSON returns the Args as a JSON encoded string +func ToJSON(a Args) (string, error) { + if a.Len() == 0 { + return "", nil } - return string(buf), nil + buf, err := json.Marshal(a) + return string(buf), err } -// ToParamWithVersion packs the Args into a string for easy transport from client to server. -// The generated string will depend on the specified version (corresponding to the API version). +// ToParamWithVersion encodes Args as a JSON string. If version is less than 1.22 +// then the encoded format will use an older legacy format where the values are a +// list of strings, instead of a set. +// +// Deprecated: Use ToJSON func ToParamWithVersion(version string, a Args) (string, error) { - // this way we don't URL encode {}, just empty space if a.Len() == 0 { return "", nil } - // for daemons older than v1.10, filter must be of the form map[string][]string - var buf []byte - var err error if version != "" && versions.LessThan(version, "1.22") { - buf, err = json.Marshal(convertArgsToSlice(a.fields)) - } else { - buf, err = json.Marshal(a.fields) - } - if err != nil { - return "", err + buf, err := json.Marshal(convertArgsToSlice(a.fields)) + return string(buf), err } - return string(buf), nil + + return ToJSON(a) } -// FromParam unpacks the filter Args. +// FromParam decodes a JSON encoded string into Args +// +// Deprecated: use FromJSON func FromParam(p string) (Args, error) { - if len(p) == 0 { - return NewArgs(), nil + return FromJSON(p) +} + +// FromJSON decodes a JSON encoded string into Args +func FromJSON(p string) (Args, error) { + args := NewArgs() + + if p == "" { + return args, nil } - r := strings.NewReader(p) - d := json.NewDecoder(r) + raw := []byte(p) + err := json.Unmarshal(raw, &args) + if err == nil { + return args, nil + } - m := map[string]map[string]bool{} - if err := d.Decode(&m); err != nil { - r.Seek(0, 0) - - // Allow parsing old arguments in slice format. - // Because other libraries might be sending them in this format. - deprecated := map[string][]string{} - if deprecatedErr := d.Decode(&deprecated); deprecatedErr == nil { - m = deprecatedArgs(deprecated) - } else { - return NewArgs(), err - } + // Fallback to parsing arguments in the legacy slice format + deprecated := map[string][]string{} + if legacyErr := json.Unmarshal(raw, &deprecated); legacyErr != nil { + return args, err + } + + args.fields = deprecatedArgs(deprecated) + return args, nil +} + +// UnmarshalJSON populates the Args from JSON encode bytes +func (args Args) UnmarshalJSON(raw []byte) error { + if len(raw) == 0 { + return nil } - return Args{m}, nil + return json.Unmarshal(raw, &args.fields) } -// Get returns the list of values associates with a field. -// It returns a slice of strings to keep backwards compatibility with old code. -func (filters Args) Get(field string) []string { - values := filters.fields[field] +// Get returns the list of values associated with the key +func (args Args) Get(key string) []string { + values := args.fields[key] if values == nil { return make([]string, 0) } @@ -131,37 +159,34 @@ func (filters Args) Get(field string) []string { return slice } -// Add adds a new value to a filter field. -func (filters Args) Add(name, value string) { - if _, ok := filters.fields[name]; ok { - filters.fields[name][value] = true +// Add a new value to the set of values +func (args Args) Add(key, value string) { + if _, ok := args.fields[key]; ok { + args.fields[key][value] = true } else { - filters.fields[name] = map[string]bool{value: true} + args.fields[key] = map[string]bool{value: true} } } -// Del removes a value from a filter field. -func (filters Args) Del(name, value string) { - if _, ok := filters.fields[name]; ok { - delete(filters.fields[name], value) - if len(filters.fields[name]) == 0 { - delete(filters.fields, name) +// Del removes a value from the set +func (args Args) Del(key, value string) { + if _, ok := args.fields[key]; ok { + delete(args.fields[key], value) + if len(args.fields[key]) == 0 { + delete(args.fields, key) } } } -// Len returns the number of fields in the arguments. -func (filters Args) Len() int { - return len(filters.fields) +// Len returns the number of keys in the mapping +func (args Args) Len() int { + return len(args.fields) } -// MatchKVList returns true if the values for the specified field matches the ones -// from the sources. -// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}}, -// field is 'label' and sources are {'label1': '1', 'label2': '2'} -// it returns true. -func (filters Args) MatchKVList(field string, sources map[string]string) bool { - fieldValues := filters.fields[field] +// MatchKVList returns true if all the pairs in sources exist as key=value +// pairs in the mapping at key, or if there are no values at key. +func (args Args) MatchKVList(key string, sources map[string]string) bool { + fieldValues := args.fields[key] //do not filter if there is no filter set or cannot determine filter if len(fieldValues) == 0 { @@ -172,8 +197,8 @@ func (filters Args) MatchKVList(field string, sources map[string]string) bool { return false } - for name2match := range fieldValues { - testKV := strings.SplitN(name2match, "=", 2) + for value := range fieldValues { + testKV := strings.SplitN(value, "=", 2) v, ok := sources[testKV[0]] if !ok { @@ -187,16 +212,13 @@ func (filters Args) MatchKVList(field string, sources map[string]string) bool { return true } -// Match returns true if the values for the specified field matches the source string -// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}}, -// field is 'image.name' and source is 'ubuntu' -// it returns true. -func (filters Args) Match(field, source string) bool { - if filters.ExactMatch(field, source) { +// Match returns true if any of the values at key match the source string +func (args Args) Match(field, source string) bool { + if args.ExactMatch(field, source) { return true } - fieldValues := filters.fields[field] + fieldValues := args.fields[field] for name2match := range fieldValues { match, err := regexp.MatchString(name2match, source) if err != nil { @@ -209,9 +231,9 @@ func (filters Args) Match(field, source string) bool { return false } -// ExactMatch returns true if the source matches exactly one of the filters. -func (filters Args) ExactMatch(field, source string) bool { - fieldValues, ok := filters.fields[field] +// ExactMatch returns true if the source matches exactly one of the values. +func (args Args) ExactMatch(key, source string) bool { + fieldValues, ok := args.fields[key] //do not filter if there is no filter set or cannot determine filter if !ok || len(fieldValues) == 0 { return true @@ -221,14 +243,15 @@ func (filters Args) ExactMatch(field, source string) bool { return fieldValues[source] } -// UniqueExactMatch returns true if there is only one filter and the source matches exactly this one. -func (filters Args) UniqueExactMatch(field, source string) bool { - fieldValues := filters.fields[field] +// UniqueExactMatch returns true if there is only one value and the source +// matches exactly the value. +func (args Args) UniqueExactMatch(key, source string) bool { + fieldValues := args.fields[key] //do not filter if there is no filter set or cannot determine filter if len(fieldValues) == 0 { return true } - if len(filters.fields[field]) != 1 { + if len(args.fields[key]) != 1 { return false } @@ -236,14 +259,14 @@ func (filters Args) UniqueExactMatch(field, source string) bool { return fieldValues[source] } -// FuzzyMatch returns true if the source matches exactly one of the filters, -// or the source has one of the filters as a prefix. -func (filters Args) FuzzyMatch(field, source string) bool { - if filters.ExactMatch(field, source) { +// FuzzyMatch returns true if the source matches exactly one value, or the +// source has one of the values as a prefix. +func (args Args) FuzzyMatch(key, source string) bool { + if args.ExactMatch(key, source) { return true } - fieldValues := filters.fields[field] + fieldValues := args.fields[key] for prefix := range fieldValues { if strings.HasPrefix(source, prefix) { return true @@ -252,30 +275,47 @@ func (filters Args) FuzzyMatch(field, source string) bool { return false } -// Include returns true if the name of the field to filter is in the filters. -func (filters Args) Include(field string) bool { - _, ok := filters.fields[field] +// Include returns true if the key exists in the mapping +// +// Deprecated: use Contains +func (args Args) Include(field string) bool { + _, ok := args.fields[field] + return ok +} + +// Contains returns true if the key exists in the mapping +func (args Args) Contains(field string) bool { + _, ok := args.fields[field] return ok } -// Validate ensures that all the fields in the filter are valid. -// It returns an error as soon as it finds an invalid field. -func (filters Args) Validate(accepted map[string]bool) error { - for name := range filters.fields { +type invalidFilter string + +func (e invalidFilter) Error() string { + return "Invalid filter '" + string(e) + "'" +} + +func (invalidFilter) InvalidParameter() {} + +// Validate compared the set of accepted keys against the keys in the mapping. +// An error is returned if any mapping keys are not in the accepted set. +func (args Args) Validate(accepted map[string]bool) error { + for name := range args.fields { if !accepted[name] { - return fmt.Errorf("Invalid filter '%s'", name) + return invalidFilter(name) } } return nil } -// WalkValues iterates over the list of filtered values for a field. -// It stops the iteration if it finds an error and it returns that error. -func (filters Args) WalkValues(field string, op func(value string) error) error { - if _, ok := filters.fields[field]; !ok { +// WalkValues iterates over the list of values for a key in the mapping and calls +// op() for each value. If op returns an error the iteration stops and the +// error is returned. +func (args Args) WalkValues(field string, op func(value string) error) error { + if _, ok := args.fields[field]; !ok { return nil } - for v := range filters.fields[field] { + for v := range args.fields[field] { if err := op(v); err != nil { return err } diff --git a/vendor/github.com/docker/docker/api/types/mount/mount.go b/vendor/github.com/docker/docker/api/types/mount/mount.go index 2744f85d6..b7d133cd8 100644 --- a/vendor/github.com/docker/docker/api/types/mount/mount.go +++ b/vendor/github.com/docker/docker/api/types/mount/mount.go @@ -15,6 +15,8 @@ const ( TypeVolume Type = "volume" // TypeTmpfs is the type for mounting tmpfs TypeTmpfs Type = "tmpfs" + // TypeNamedPipe is the type for mounting Windows named pipes + TypeNamedPipe Type = "npipe" ) // Mount represents a mount (volume). @@ -65,7 +67,7 @@ var Propagations = []Propagation{ type Consistency string const ( - // ConsistencyFull guarantees bind-mount-like consistency + // ConsistencyFull guarantees bind mount-like consistency ConsistencyFull Consistency = "consistent" // ConsistencyCached mounts can cache read data and FS structure ConsistencyCached Consistency = "cached" diff --git a/vendor/github.com/docker/docker/api/types/swarm/container.go b/vendor/github.com/docker/docker/api/types/swarm/container.go index 6f8b45f6b..734236c4b 100644 --- a/vendor/github.com/docker/docker/api/types/swarm/container.go +++ b/vendor/github.com/docker/docker/api/types/swarm/container.go @@ -65,8 +65,9 @@ type ContainerSpec struct { // The format of extra hosts on swarmkit is specified in: // http://man7.org/linux/man-pages/man5/hosts.5.html // IP_address canonical_hostname [aliases...] - Hosts []string `json:",omitempty"` - DNSConfig *DNSConfig `json:",omitempty"` - Secrets []*SecretReference `json:",omitempty"` - Configs []*ConfigReference `json:",omitempty"` + Hosts []string `json:",omitempty"` + DNSConfig *DNSConfig `json:",omitempty"` + Secrets []*SecretReference `json:",omitempty"` + Configs []*ConfigReference `json:",omitempty"` + Isolation container.Isolation `json:",omitempty"` } diff --git a/vendor/github.com/docker/docker/api/types/time/timestamp.go b/vendor/github.com/docker/docker/api/types/time/timestamp.go index 9aa9702da..ed9c1168b 100644 --- a/vendor/github.com/docker/docker/api/types/time/timestamp.go +++ b/vendor/github.com/docker/docker/api/types/time/timestamp.go @@ -29,10 +29,8 @@ func GetTimestamp(value string, reference time.Time) (string, error) { } var format string - var parseInLocation bool - // if the string has a Z or a + or three dashes use parse otherwise use parseinlocation - parseInLocation = !(strings.ContainsAny(value, "zZ+") || strings.Count(value, "-") == 3) + parseInLocation := !(strings.ContainsAny(value, "zZ+") || strings.Count(value, "-") == 3) if strings.Contains(value, ".") { if parseInLocation { diff --git a/vendor/github.com/docker/docker/client/checkpoint_list.go b/vendor/github.com/docker/docker/client/checkpoint_list.go index ffe44bc97..9835bad5c 100644 --- a/vendor/github.com/docker/docker/client/checkpoint_list.go +++ b/vendor/github.com/docker/docker/client/checkpoint_list.go @@ -2,7 +2,6 @@ package client import ( "encoding/json" - "net/http" "net/url" "github.com/docker/docker/api/types" @@ -20,10 +19,7 @@ func (cli *Client) CheckpointList(ctx context.Context, container string, options resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil) if err != nil { - if resp.statusCode == http.StatusNotFound { - return checkpoints, containerNotFoundError{container} - } - return checkpoints, err + return checkpoints, wrapResponseError(err, resp, "container", container) } err = json.NewDecoder(resp.body).Decode(&checkpoints) diff --git a/vendor/github.com/docker/docker/client/client.go b/vendor/github.com/docker/docker/client/client.go index c4e3914b1..893124853 100644 --- a/vendor/github.com/docker/docker/client/client.go +++ b/vendor/github.com/docker/docker/client/client.go @@ -1,10 +1,6 @@ /* Package client is a Go client for the Docker Engine API. -The "docker" command uses this package to communicate with the daemon. It can also -be used by your own Go applications to do anything the command-line interface does -- running containers, pulling images, managing swarms, etc. - For more information about the Engine API, see the documentation: https://docs.docker.com/engine/reference/api/ @@ -51,6 +47,7 @@ import ( "net/http" "net/url" "os" + "path" "path/filepath" "strings" @@ -159,7 +156,7 @@ func NewEnvClient() (*Client, error) { // highly recommended that you set a version or your client may break if the // server is upgraded. func NewClient(host string, version string, client *http.Client, httpHeaders map[string]string) (*Client, error) { - proto, addr, basePath, err := ParseHost(host) + hostURL, err := ParseHostURL(host) if err != nil { return nil, err } @@ -170,7 +167,7 @@ func NewClient(host string, version string, client *http.Client, httpHeaders map } } else { transport := new(http.Transport) - sockets.ConfigureTransport(transport, proto, addr) + sockets.ConfigureTransport(transport, hostURL.Scheme, hostURL.Host) client = &http.Client{ Transport: transport, CheckRedirect: CheckRedirect, @@ -188,28 +185,24 @@ func NewClient(host string, version string, client *http.Client, httpHeaders map scheme = "https" } + // TODO: store URL instead of proto/addr/basePath return &Client{ scheme: scheme, host: host, - proto: proto, - addr: addr, - basePath: basePath, + proto: hostURL.Scheme, + addr: hostURL.Host, + basePath: hostURL.Path, client: client, version: version, customHTTPHeaders: httpHeaders, }, nil } -// Close ensures that transport.Client is closed -// especially needed while using NewClient with *http.Client = nil -// for example -// client.NewClient("unix:///var/run/docker.sock", nil, "v1.18", map[string]string{"User-Agent": "engine-api-cli-1.0"}) +// Close the transport used by the client func (cli *Client) Close() error { - if t, ok := cli.client.Transport.(*http.Transport); ok { t.CloseIdleConnections() } - return nil } @@ -219,37 +212,27 @@ func (cli *Client) getAPIPath(p string, query url.Values) string { var apiPath string if cli.version != "" { v := strings.TrimPrefix(cli.version, "v") - apiPath = cli.basePath + "/v" + v + p + apiPath = path.Join(cli.basePath, "/v"+v, p) } else { - apiPath = cli.basePath + p - } - - u := &url.URL{ - Path: apiPath, - } - if len(query) > 0 { - u.RawQuery = query.Encode() + apiPath = path.Join(cli.basePath, p) } - return u.String() + return (&url.URL{Path: apiPath, RawQuery: query.Encode()}).String() } -// ClientVersion returns the version string associated with this -// instance of the Client. Note that this value can be changed -// via the DOCKER_API_VERSION env var. -// This operation doesn't acquire a mutex. +// ClientVersion returns the API version used by this client. func (cli *Client) ClientVersion() string { return cli.version } -// NegotiateAPIVersion updates the version string associated with this -// instance of the Client to match the latest version the server supports +// NegotiateAPIVersion queries the API and updates the version to match the +// API version. Any errors are silently ignored. func (cli *Client) NegotiateAPIVersion(ctx context.Context) { ping, _ := cli.Ping(ctx) cli.NegotiateAPIVersionPing(ping) } -// NegotiateAPIVersionPing updates the version string associated with this -// instance of the Client to match the latest version the server supports +// NegotiateAPIVersionPing updates the client version to match the Ping.APIVersion +// if the ping version is less than the default version. func (cli *Client) NegotiateAPIVersionPing(p types.Ping) { if cli.manualOverride { return @@ -265,23 +248,34 @@ func (cli *Client) NegotiateAPIVersionPing(p types.Ping) { cli.version = api.DefaultVersion } - // if server version is lower than the maximum version supported by the Client, downgrade - if versions.LessThan(p.APIVersion, api.DefaultVersion) { + // if server version is lower than the client version, downgrade + if versions.LessThan(p.APIVersion, cli.version) { cli.version = p.APIVersion } } -// DaemonHost returns the host associated with this instance of the Client. -// This operation doesn't acquire a mutex. +// DaemonHost returns the host address used by the client func (cli *Client) DaemonHost() string { return cli.host } -// ParseHost verifies that the given host strings is valid. +// ParseHost parses a url string, validates the strings is a host url, and returns +// the parsed host as: protocol, address, and base path +// Deprecated: use ParseHostURL func ParseHost(host string) (string, string, string, error) { + hostURL, err := ParseHostURL(host) + if err != nil { + return "", "", "", err + } + return hostURL.Scheme, hostURL.Host, hostURL.Path, nil +} + +// ParseHostURL parses a url string, validates the string is a host url, and +// returns the parsed URL +func ParseHostURL(host string) (*url.URL, error) { protoAddrParts := strings.SplitN(host, "://", 2) if len(protoAddrParts) == 1 { - return "", "", "", fmt.Errorf("unable to parse docker host `%s`", host) + return nil, fmt.Errorf("unable to parse docker host `%s`", host) } var basePath string @@ -289,16 +283,19 @@ func ParseHost(host string) (string, string, string, error) { if proto == "tcp" { parsed, err := url.Parse("tcp://" + addr) if err != nil { - return "", "", "", err + return nil, err } addr = parsed.Host basePath = parsed.Path } - return proto, addr, basePath, nil + return &url.URL{ + Scheme: proto, + Host: addr, + Path: basePath, + }, nil } -// CustomHTTPHeaders returns the custom http headers associated with this -// instance of the Client. This operation doesn't acquire a mutex. +// CustomHTTPHeaders returns the custom http headers stored by the client. func (cli *Client) CustomHTTPHeaders() map[string]string { m := make(map[string]string) for k, v := range cli.customHTTPHeaders { @@ -307,8 +304,7 @@ func (cli *Client) CustomHTTPHeaders() map[string]string { return m } -// SetCustomHTTPHeaders updates the custom http headers associated with this -// instance of the Client. This operation doesn't acquire a mutex. +// SetCustomHTTPHeaders that will be set on every HTTP request made by the client. func (cli *Client) SetCustomHTTPHeaders(headers map[string]string) { cli.customHTTPHeaders = headers } diff --git a/vendor/github.com/docker/docker/client/client_unix.go b/vendor/github.com/docker/docker/client/client_unix.go index 89de892c8..eba8d909a 100644 --- a/vendor/github.com/docker/docker/client/client_unix.go +++ b/vendor/github.com/docker/docker/client/client_unix.go @@ -1,4 +1,4 @@ -// +build linux freebsd solaris openbsd darwin +// +build linux freebsd openbsd darwin package client diff --git a/vendor/github.com/docker/docker/client/config_inspect.go b/vendor/github.com/docker/docker/client/config_inspect.go index ebb6d636c..b44d6fdd7 100644 --- a/vendor/github.com/docker/docker/client/config_inspect.go +++ b/vendor/github.com/docker/docker/client/config_inspect.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "github.com/docker/docker/api/types/swarm" "golang.org/x/net/context" @@ -17,10 +16,7 @@ func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.C } resp, err := cli.get(ctx, "/configs/"+id, nil, nil) if err != nil { - if resp.statusCode == http.StatusNotFound { - return swarm.Config{}, nil, configNotFoundError{id} - } - return swarm.Config{}, nil, err + return swarm.Config{}, nil, wrapResponseError(err, resp, "config", id) } defer ensureReaderClosed(resp) diff --git a/vendor/github.com/docker/docker/client/config_list.go b/vendor/github.com/docker/docker/client/config_list.go index 8483ca14d..57febc9ff 100644 --- a/vendor/github.com/docker/docker/client/config_list.go +++ b/vendor/github.com/docker/docker/client/config_list.go @@ -18,7 +18,7 @@ func (cli *Client) ConfigList(ctx context.Context, options types.ConfigListOptio query := url.Values{} if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return nil, err } diff --git a/vendor/github.com/docker/docker/client/config_remove.go b/vendor/github.com/docker/docker/client/config_remove.go index 726b5c853..e025d44f7 100644 --- a/vendor/github.com/docker/docker/client/config_remove.go +++ b/vendor/github.com/docker/docker/client/config_remove.go @@ -9,5 +9,5 @@ func (cli *Client) ConfigRemove(ctx context.Context, id string) error { } resp, err := cli.delete(ctx, "/configs/"+id, nil, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "config", id) } diff --git a/vendor/github.com/docker/docker/client/container_commit.go b/vendor/github.com/docker/docker/client/container_commit.go index 531d796ee..b3b16abfd 100644 --- a/vendor/github.com/docker/docker/client/container_commit.go +++ b/vendor/github.com/docker/docker/client/container_commit.go @@ -39,7 +39,7 @@ func (cli *Client) ContainerCommit(ctx context.Context, container string, option for _, change := range options.Changes { query.Add("changes", change) } - if options.Pause != true { + if !options.Pause { query.Set("pause", "0") } diff --git a/vendor/github.com/docker/docker/client/container_create.go b/vendor/github.com/docker/docker/client/container_create.go index 6841b0b28..bd817e7fd 100644 --- a/vendor/github.com/docker/docker/client/container_create.go +++ b/vendor/github.com/docker/docker/client/container_create.go @@ -45,7 +45,7 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config serverResp, err := cli.post(ctx, "/containers/create", query, body, nil) if err != nil { if serverResp.statusCode == 404 && strings.Contains(err.Error(), "No such image") { - return response, imageNotFoundError{config.Image} + return response, objectNotFoundError{object: "image", id: config.Image} } return response, err } diff --git a/vendor/github.com/docker/docker/client/container_exec.go b/vendor/github.com/docker/docker/client/container_exec.go index 0665c54fb..29670d02e 100644 --- a/vendor/github.com/docker/docker/client/container_exec.go +++ b/vendor/github.com/docker/docker/client/container_exec.go @@ -35,7 +35,7 @@ func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config // It returns a types.HijackedConnection with the hijacked connection // and the a reader to get output. It's up to the called to close // the hijacked connection by calling types.HijackedResponse.Close. -func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config types.ExecConfig) (types.HijackedResponse, error) { +func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error) { headers := map[string][]string{"Content-Type": {"application/json"}} return cli.postHijacked(ctx, "/exec/"+execID+"/start", nil, config, headers) } diff --git a/vendor/github.com/docker/docker/client/container_inspect.go b/vendor/github.com/docker/docker/client/container_inspect.go index 17f180974..a15db14be 100644 --- a/vendor/github.com/docker/docker/client/container_inspect.go +++ b/vendor/github.com/docker/docker/client/container_inspect.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "net/url" "github.com/docker/docker/api/types" @@ -15,10 +14,7 @@ import ( func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (types.ContainerJSON, error) { serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", nil, nil) if err != nil { - if serverResp.statusCode == http.StatusNotFound { - return types.ContainerJSON{}, containerNotFoundError{containerID} - } - return types.ContainerJSON{}, err + return types.ContainerJSON{}, wrapResponseError(err, serverResp, "container", containerID) } var response types.ContainerJSON @@ -35,10 +31,7 @@ func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID stri } serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil) if err != nil { - if serverResp.statusCode == http.StatusNotFound { - return types.ContainerJSON{}, nil, containerNotFoundError{containerID} - } - return types.ContainerJSON{}, nil, err + return types.ContainerJSON{}, nil, wrapResponseError(err, serverResp, "container", containerID) } defer ensureReaderClosed(serverResp) diff --git a/vendor/github.com/docker/docker/client/container_logs.go b/vendor/github.com/docker/docker/client/container_logs.go index 0f32e9f12..35c297c5f 100644 --- a/vendor/github.com/docker/docker/client/container_logs.go +++ b/vendor/github.com/docker/docker/client/container_logs.go @@ -51,6 +51,14 @@ func (cli *Client) ContainerLogs(ctx context.Context, container string, options query.Set("since", ts) } + if options.Until != "" { + ts, err := timetypes.GetTimestamp(options.Until, time.Now()) + if err != nil { + return nil, err + } + query.Set("until", ts) + } + if options.Timestamps { query.Set("timestamps", "1") } diff --git a/vendor/github.com/docker/docker/client/container_remove.go b/vendor/github.com/docker/docker/client/container_remove.go index 3a79590ce..070108bf3 100644 --- a/vendor/github.com/docker/docker/client/container_remove.go +++ b/vendor/github.com/docker/docker/client/container_remove.go @@ -23,5 +23,5 @@ func (cli *Client) ContainerRemove(ctx context.Context, containerID string, opti resp, err := cli.delete(ctx, "/containers/"+containerID, query, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "container", containerID) } diff --git a/vendor/github.com/docker/docker/client/errors.go b/vendor/github.com/docker/docker/client/errors.go index fc7df9f1e..e41b728d3 100644 --- a/vendor/github.com/docker/docker/client/errors.go +++ b/vendor/github.com/docker/docker/client/errors.go @@ -3,6 +3,8 @@ package client import ( "fmt" + "net/http" + "github.com/docker/docker/api/types/versions" "github.com/pkg/errors" ) @@ -36,95 +38,37 @@ type notFound interface { NotFound() bool // Is the error a NotFound error } -// IsErrNotFound returns true if the error is caused with an -// object (image, container, network, volume, …) is not found in the docker host. +// IsErrNotFound returns true if the error is a NotFound error, which is returned +// by the API when some object is not found. func IsErrNotFound(err error) bool { te, ok := err.(notFound) return ok && te.NotFound() } -// imageNotFoundError implements an error returned when an image is not in the docker host. -type imageNotFoundError struct { - imageID string -} - -// NotFound indicates that this error type is of NotFound -func (e imageNotFoundError) NotFound() bool { - return true -} - -// Error returns a string representation of an imageNotFoundError -func (e imageNotFoundError) Error() string { - return fmt.Sprintf("Error: No such image: %s", e.imageID) -} - -// IsErrImageNotFound returns true if the error is caused -// when an image is not found in the docker host. -func IsErrImageNotFound(err error) bool { - return IsErrNotFound(err) -} - -// containerNotFoundError implements an error returned when a container is not in the docker host. -type containerNotFoundError struct { - containerID string -} - -// NotFound indicates that this error type is of NotFound -func (e containerNotFoundError) NotFound() bool { - return true -} - -// Error returns a string representation of a containerNotFoundError -func (e containerNotFoundError) Error() string { - return fmt.Sprintf("Error: No such container: %s", e.containerID) -} - -// IsErrContainerNotFound returns true if the error is caused -// when a container is not found in the docker host. -func IsErrContainerNotFound(err error) bool { - return IsErrNotFound(err) -} - -// networkNotFoundError implements an error returned when a network is not in the docker host. -type networkNotFoundError struct { - networkID string -} - -// NotFound indicates that this error type is of NotFound -func (e networkNotFoundError) NotFound() bool { - return true -} - -// Error returns a string representation of a networkNotFoundError -func (e networkNotFoundError) Error() string { - return fmt.Sprintf("Error: No such network: %s", e.networkID) +type objectNotFoundError struct { + object string + id string } -// IsErrNetworkNotFound returns true if the error is caused -// when a network is not found in the docker host. -func IsErrNetworkNotFound(err error) bool { - return IsErrNotFound(err) -} - -// volumeNotFoundError implements an error returned when a volume is not in the docker host. -type volumeNotFoundError struct { - volumeID string -} - -// NotFound indicates that this error type is of NotFound -func (e volumeNotFoundError) NotFound() bool { +func (e objectNotFoundError) NotFound() bool { return true } -// Error returns a string representation of a volumeNotFoundError -func (e volumeNotFoundError) Error() string { - return fmt.Sprintf("Error: No such volume: %s", e.volumeID) +func (e objectNotFoundError) Error() string { + return fmt.Sprintf("Error: No such %s: %s", e.object, e.id) } -// IsErrVolumeNotFound returns true if the error is caused -// when a volume is not found in the docker host. -func IsErrVolumeNotFound(err error) bool { - return IsErrNotFound(err) +func wrapResponseError(err error, resp serverResponse, object, id string) error { + switch { + case err == nil: + return nil + case resp.statusCode == http.StatusNotFound: + return objectNotFoundError{object: object, id: id} + case resp.statusCode == http.StatusNotImplemented: + return notImplementedError{message: err.Error()} + default: + return err + } } // unauthorizedError represents an authorization error in a remote registry. @@ -144,72 +88,6 @@ func IsErrUnauthorized(err error) bool { return ok } -// nodeNotFoundError implements an error returned when a node is not found. -type nodeNotFoundError struct { - nodeID string -} - -// Error returns a string representation of a nodeNotFoundError -func (e nodeNotFoundError) Error() string { - return fmt.Sprintf("Error: No such node: %s", e.nodeID) -} - -// NotFound indicates that this error type is of NotFound -func (e nodeNotFoundError) NotFound() bool { - return true -} - -// IsErrNodeNotFound returns true if the error is caused -// when a node is not found. -func IsErrNodeNotFound(err error) bool { - _, ok := err.(nodeNotFoundError) - return ok -} - -// serviceNotFoundError implements an error returned when a service is not found. -type serviceNotFoundError struct { - serviceID string -} - -// Error returns a string representation of a serviceNotFoundError -func (e serviceNotFoundError) Error() string { - return fmt.Sprintf("Error: No such service: %s", e.serviceID) -} - -// NotFound indicates that this error type is of NotFound -func (e serviceNotFoundError) NotFound() bool { - return true -} - -// IsErrServiceNotFound returns true if the error is caused -// when a service is not found. -func IsErrServiceNotFound(err error) bool { - _, ok := err.(serviceNotFoundError) - return ok -} - -// taskNotFoundError implements an error returned when a task is not found. -type taskNotFoundError struct { - taskID string -} - -// Error returns a string representation of a taskNotFoundError -func (e taskNotFoundError) Error() string { - return fmt.Sprintf("Error: No such task: %s", e.taskID) -} - -// NotFound indicates that this error type is of NotFound -func (e taskNotFoundError) NotFound() bool { - return true -} - -// IsErrTaskNotFound returns true if the error is caused -// when a task is not found. -func IsErrTaskNotFound(err error) bool { - _, ok := err.(taskNotFoundError) - return ok -} - type pluginPermissionDenied struct { name string } @@ -225,76 +103,31 @@ func IsErrPluginPermissionDenied(err error) bool { return ok } -// NewVersionError returns an error if the APIVersion required -// if less than the current supported version -func (cli *Client) NewVersionError(APIrequired, feature string) error { - if cli.version != "" && versions.LessThan(cli.version, APIrequired) { - return fmt.Errorf("%q requires API version %s, but the Docker daemon API version is %s", feature, APIrequired, cli.version) - } - return nil -} - -// secretNotFoundError implements an error returned when a secret is not found. -type secretNotFoundError struct { - name string -} - -// Error returns a string representation of a secretNotFoundError -func (e secretNotFoundError) Error() string { - return fmt.Sprintf("Error: no such secret: %s", e.name) -} - -// NotFound indicates that this error type is of NotFound -func (e secretNotFoundError) NotFound() bool { - return true -} - -// IsErrSecretNotFound returns true if the error is caused -// when a secret is not found. -func IsErrSecretNotFound(err error) bool { - _, ok := err.(secretNotFoundError) - return ok -} - -// configNotFoundError implements an error returned when a config is not found. -type configNotFoundError struct { - name string -} - -// Error returns a string representation of a configNotFoundError -func (e configNotFoundError) Error() string { - return fmt.Sprintf("Error: no such config: %s", e.name) -} - -// NotFound indicates that this error type is of NotFound -func (e configNotFoundError) NotFound() bool { - return true -} - -// IsErrConfigNotFound returns true if the error is caused -// when a config is not found. -func IsErrConfigNotFound(err error) bool { - _, ok := err.(configNotFoundError) - return ok +type notImplementedError struct { + message string } -// pluginNotFoundError implements an error returned when a plugin is not in the docker host. -type pluginNotFoundError struct { - name string +func (e notImplementedError) Error() string { + return e.message } -// NotFound indicates that this error type is of NotFound -func (e pluginNotFoundError) NotFound() bool { +func (e notImplementedError) NotImplemented() bool { return true } -// Error returns a string representation of a pluginNotFoundError -func (e pluginNotFoundError) Error() string { - return fmt.Sprintf("Error: No such plugin: %s", e.name) +// IsErrNotImplemented returns true if the error is a NotImplemented error. +// This is returned by the API when a requested feature has not been +// implemented. +func IsErrNotImplemented(err error) bool { + te, ok := err.(notImplementedError) + return ok && te.NotImplemented() } -// IsErrPluginNotFound returns true if the error is caused -// when a plugin is not found in the docker host. -func IsErrPluginNotFound(err error) bool { - return IsErrNotFound(err) +// NewVersionError returns an error if the APIVersion required +// if less than the current supported version +func (cli *Client) NewVersionError(APIrequired, feature string) error { + if cli.version != "" && versions.LessThan(cli.version, APIrequired) { + return fmt.Errorf("%q requires API version %s, but the Docker daemon API version is %s", feature, APIrequired, cli.version) + } + return nil } diff --git a/vendor/github.com/docker/docker/client/hijack.go b/vendor/github.com/docker/docker/client/hijack.go index 8cf0119f3..d04cebdcf 100644 --- a/vendor/github.com/docker/docker/client/hijack.go +++ b/vendor/github.com/docker/docker/client/hijack.go @@ -12,7 +12,6 @@ import ( "time" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/tlsconfig" "github.com/docker/go-connections/sockets" "github.com/pkg/errors" "golang.org/x/net/context" @@ -71,7 +70,7 @@ func tlsDialWithDialer(dialer *net.Dialer, network, addr string, config *tls.Con timeout := dialer.Timeout if !dialer.Deadline.IsZero() { - deadlineTimeout := dialer.Deadline.Sub(time.Now()) + deadlineTimeout := time.Until(dialer.Deadline) if timeout == 0 || deadlineTimeout < timeout { timeout = deadlineTimeout } @@ -115,7 +114,7 @@ func tlsDialWithDialer(dialer *net.Dialer, network, addr string, config *tls.Con // from the hostname we're connecting to. if config.ServerName == "" { // Make a copy to avoid polluting argument or default. - config = tlsconfig.Clone(config) + config = tlsConfigClone(config) config.ServerName = hostname } diff --git a/vendor/github.com/docker/docker/client/image_build.go b/vendor/github.com/docker/docker/client/image_build.go index 44a215f90..cd0f54d13 100644 --- a/vendor/github.com/docker/docker/client/image_build.go +++ b/vendor/github.com/docker/docker/client/image_build.go @@ -7,6 +7,7 @@ import ( "net/http" "net/url" "strconv" + "strings" "golang.org/x/net/context" @@ -29,6 +30,13 @@ func (cli *Client) ImageBuild(ctx context.Context, buildContext io.Reader, optio return types.ImageBuildResponse{}, err } headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf)) + + if options.Platform != "" { + if err := cli.NewVersionError("1.32", "platform"); err != nil { + return types.ImageBuildResponse{}, err + } + query.Set("platform", options.Platform) + } headers.Set("Content-Type", "application/x-tar") serverResp, err := cli.postRaw(ctx, "/build", query, buildContext, headers) @@ -123,6 +131,8 @@ func (cli *Client) imageBuildOptionsToQuery(options types.ImageBuildOptions) (ur if options.SessionID != "" { query.Set("session", options.SessionID) } - + if options.Platform != "" { + query.Set("platform", strings.ToLower(options.Platform)) + } return query, nil } diff --git a/vendor/github.com/docker/docker/client/image_create.go b/vendor/github.com/docker/docker/client/image_create.go index 4436abb0d..fb5447b9b 100644 --- a/vendor/github.com/docker/docker/client/image_create.go +++ b/vendor/github.com/docker/docker/client/image_create.go @@ -3,6 +3,7 @@ package client import ( "io" "net/url" + "strings" "golang.org/x/net/context" @@ -21,6 +22,9 @@ func (cli *Client) ImageCreate(ctx context.Context, parentReference string, opti query := url.Values{} query.Set("fromImage", reference.FamiliarName(ref)) query.Set("tag", getAPITagFromNamedRef(ref)) + if options.Platform != "" { + query.Set("platform", strings.ToLower(options.Platform)) + } resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth) if err != nil { return nil, err diff --git a/vendor/github.com/docker/docker/client/image_import.go b/vendor/github.com/docker/docker/client/image_import.go index d7dedd823..ab55ddbac 100644 --- a/vendor/github.com/docker/docker/client/image_import.go +++ b/vendor/github.com/docker/docker/client/image_import.go @@ -3,6 +3,7 @@ package client import ( "io" "net/url" + "strings" "golang.org/x/net/context" @@ -25,6 +26,9 @@ func (cli *Client) ImageImport(ctx context.Context, source types.ImageImportSour query.Set("repo", ref) query.Set("tag", options.Tag) query.Set("message", options.Message) + if options.Platform != "" { + query.Set("platform", strings.ToLower(options.Platform)) + } for _, change := range options.Changes { query.Add("changes", change) } diff --git a/vendor/github.com/docker/docker/client/image_inspect.go b/vendor/github.com/docker/docker/client/image_inspect.go index b3a64ce2f..1bc591990 100644 --- a/vendor/github.com/docker/docker/client/image_inspect.go +++ b/vendor/github.com/docker/docker/client/image_inspect.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "github.com/docker/docker/api/types" "golang.org/x/net/context" @@ -14,10 +13,7 @@ import ( func (cli *Client) ImageInspectWithRaw(ctx context.Context, imageID string) (types.ImageInspect, []byte, error) { serverResp, err := cli.get(ctx, "/images/"+imageID+"/json", nil, nil) if err != nil { - if serverResp.statusCode == http.StatusNotFound { - return types.ImageInspect{}, nil, imageNotFoundError{imageID} - } - return types.ImageInspect{}, nil, err + return types.ImageInspect{}, nil, wrapResponseError(err, serverResp, "image", imageID) } defer ensureReaderClosed(serverResp) diff --git a/vendor/github.com/docker/docker/client/image_pull.go b/vendor/github.com/docker/docker/client/image_pull.go index a72b9bf7f..92942d2e5 100644 --- a/vendor/github.com/docker/docker/client/image_pull.go +++ b/vendor/github.com/docker/docker/client/image_pull.go @@ -4,6 +4,7 @@ import ( "io" "net/http" "net/url" + "strings" "golang.org/x/net/context" @@ -30,6 +31,9 @@ func (cli *Client) ImagePull(ctx context.Context, refStr string, options types.I if !options.All { query.Set("tag", getAPITagFromNamedRef(ref)) } + if options.Platform != "" { + query.Set("platform", strings.ToLower(options.Platform)) + } resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth) if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil { diff --git a/vendor/github.com/docker/docker/client/image_remove.go b/vendor/github.com/docker/docker/client/image_remove.go index 6921209ee..81d6c5438 100644 --- a/vendor/github.com/docker/docker/client/image_remove.go +++ b/vendor/github.com/docker/docker/client/image_remove.go @@ -19,12 +19,12 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options type query.Set("noprune", "1") } + var dels []types.ImageDeleteResponseItem resp, err := cli.delete(ctx, "/images/"+imageID, query, nil) if err != nil { - return nil, err + return dels, wrapResponseError(err, resp, "image", imageID) } - var dels []types.ImageDeleteResponseItem err = json.NewDecoder(resp.body).Decode(&dels) ensureReaderClosed(resp) return dels, err diff --git a/vendor/github.com/docker/docker/client/image_search.go b/vendor/github.com/docker/docker/client/image_search.go index b0fcd5c23..5566e9255 100644 --- a/vendor/github.com/docker/docker/client/image_search.go +++ b/vendor/github.com/docker/docker/client/image_search.go @@ -21,7 +21,7 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I query.Set("limit", fmt.Sprintf("%d", options.Limit)) if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return results, err } diff --git a/vendor/github.com/docker/docker/client/interface.go b/vendor/github.com/docker/docker/client/interface.go index acd4de1db..dd8b388cf 100644 --- a/vendor/github.com/docker/docker/client/interface.go +++ b/vendor/github.com/docker/docker/client/interface.go @@ -45,7 +45,7 @@ type ContainerAPIClient interface { ContainerCommit(ctx context.Context, container string, options types.ContainerCommitOptions) (types.IDResponse, error) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (container.ContainerCreateCreatedBody, error) ContainerDiff(ctx context.Context, container string) ([]container.ContainerChangeResponseItem, error) - ContainerExecAttach(ctx context.Context, execID string, config types.ExecConfig) (types.HijackedResponse, error) + ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error) ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error) ContainerExecInspect(ctx context.Context, execID string) (types.ContainerExecInspect, error) ContainerExecResize(ctx context.Context, execID string, options types.ResizeOptions) error diff --git a/vendor/github.com/docker/docker/client/network_inspect.go b/vendor/github.com/docker/docker/client/network_inspect.go index 848c9799f..afabe6597 100644 --- a/vendor/github.com/docker/docker/client/network_inspect.go +++ b/vendor/github.com/docker/docker/client/network_inspect.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "net/url" "github.com/docker/docker/api/types" @@ -33,10 +32,7 @@ func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, } resp, err = cli.get(ctx, "/networks/"+networkID, query, nil) if err != nil { - if resp.statusCode == http.StatusNotFound { - return networkResource, nil, networkNotFoundError{networkID} - } - return networkResource, nil, err + return networkResource, nil, wrapResponseError(err, resp, "network", networkID) } defer ensureReaderClosed(resp) diff --git a/vendor/github.com/docker/docker/client/network_remove.go b/vendor/github.com/docker/docker/client/network_remove.go index 6bd674892..0811b5b51 100644 --- a/vendor/github.com/docker/docker/client/network_remove.go +++ b/vendor/github.com/docker/docker/client/network_remove.go @@ -6,5 +6,5 @@ import "golang.org/x/net/context" func (cli *Client) NetworkRemove(ctx context.Context, networkID string) error { resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "network", networkID) } diff --git a/vendor/github.com/docker/docker/client/node_inspect.go b/vendor/github.com/docker/docker/client/node_inspect.go index abf505d29..791d2c006 100644 --- a/vendor/github.com/docker/docker/client/node_inspect.go +++ b/vendor/github.com/docker/docker/client/node_inspect.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "github.com/docker/docker/api/types/swarm" "golang.org/x/net/context" @@ -14,10 +13,7 @@ import ( func (cli *Client) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error) { serverResp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil) if err != nil { - if serverResp.statusCode == http.StatusNotFound { - return swarm.Node{}, nil, nodeNotFoundError{nodeID} - } - return swarm.Node{}, nil, err + return swarm.Node{}, nil, wrapResponseError(err, serverResp, "node", nodeID) } defer ensureReaderClosed(serverResp) diff --git a/vendor/github.com/docker/docker/client/node_list.go b/vendor/github.com/docker/docker/client/node_list.go index 3e8440f08..fed22992c 100644 --- a/vendor/github.com/docker/docker/client/node_list.go +++ b/vendor/github.com/docker/docker/client/node_list.go @@ -15,7 +15,7 @@ func (cli *Client) NodeList(ctx context.Context, options types.NodeListOptions) query := url.Values{} if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return nil, err diff --git a/vendor/github.com/docker/docker/client/node_remove.go b/vendor/github.com/docker/docker/client/node_remove.go index 0a77f3d57..adbf52feb 100644 --- a/vendor/github.com/docker/docker/client/node_remove.go +++ b/vendor/github.com/docker/docker/client/node_remove.go @@ -17,5 +17,5 @@ func (cli *Client) NodeRemove(ctx context.Context, nodeID string, options types. resp, err := cli.delete(ctx, "/nodes/"+nodeID, query, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "node", nodeID) } diff --git a/vendor/github.com/docker/docker/client/parse_logs.go b/vendor/github.com/docker/docker/client/parse_logs.go deleted file mode 100644 index e427f80a7..000000000 --- a/vendor/github.com/docker/docker/client/parse_logs.go +++ /dev/null @@ -1,41 +0,0 @@ -package client - -// parse_logs.go contains utility helpers for getting information out of docker -// log lines. really, it only contains ParseDetails right now. maybe in the -// future there will be some desire to parse log messages back into a struct? -// that would go here if we did - -import ( - "net/url" - "strings" - - "github.com/pkg/errors" -) - -// ParseLogDetails takes a details string of key value pairs in the form -// "k=v,l=w", where the keys and values are url query escaped, and each pair -// is separated by a comma, returns a map. returns an error if the details -// string is not in a valid format -// the exact form of details encoding is implemented in -// api/server/httputils/write_log_stream.go -func ParseLogDetails(details string) (map[string]string, error) { - pairs := strings.Split(details, ",") - detailsMap := make(map[string]string, len(pairs)) - for _, pair := range pairs { - p := strings.SplitN(pair, "=", 2) - // if there is no equals sign, we will only get 1 part back - if len(p) != 2 { - return nil, errors.New("invalid details format") - } - k, err := url.QueryUnescape(p[0]) - if err != nil { - return nil, err - } - v, err := url.QueryUnescape(p[1]) - if err != nil { - return nil, err - } - detailsMap[k] = v - } - return detailsMap, nil -} diff --git a/vendor/github.com/docker/docker/client/ping.go b/vendor/github.com/docker/docker/client/ping.go index a4c2e2c4d..0b6e450da 100644 --- a/vendor/github.com/docker/docker/client/ping.go +++ b/vendor/github.com/docker/docker/client/ping.go @@ -1,6 +1,8 @@ package client import ( + "path" + "github.com/docker/docker/api/types" "golang.org/x/net/context" ) @@ -8,7 +10,7 @@ import ( // Ping pings the server and returns the value of the "Docker-Experimental", "OS-Type" & "API-Version" headers func (cli *Client) Ping(ctx context.Context) (types.Ping, error) { var ping types.Ping - req, err := cli.buildRequest("GET", cli.basePath+"/_ping", nil, nil) + req, err := cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil) if err != nil { return ping, err } @@ -26,7 +28,5 @@ func (cli *Client) Ping(ctx context.Context) (types.Ping, error) { } ping.OSType = serverResp.header.Get("OSType") } - - err = cli.checkResponseErr(serverResp) - return ping, err + return ping, cli.checkResponseErr(serverResp) } diff --git a/vendor/github.com/docker/docker/client/plugin_inspect.go b/vendor/github.com/docker/docker/client/plugin_inspect.go index 89f39ee2c..6a6fc18df 100644 --- a/vendor/github.com/docker/docker/client/plugin_inspect.go +++ b/vendor/github.com/docker/docker/client/plugin_inspect.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "github.com/docker/docker/api/types" "golang.org/x/net/context" @@ -14,10 +13,7 @@ import ( func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) { resp, err := cli.get(ctx, "/plugins/"+name+"/json", nil, nil) if err != nil { - if resp.statusCode == http.StatusNotFound { - return nil, nil, pluginNotFoundError{name} - } - return nil, nil, err + return nil, nil, wrapResponseError(err, resp, "plugin", name) } defer ensureReaderClosed(resp) diff --git a/vendor/github.com/docker/docker/client/plugin_list.go b/vendor/github.com/docker/docker/client/plugin_list.go index 3acde3b96..78dbeb8be 100644 --- a/vendor/github.com/docker/docker/client/plugin_list.go +++ b/vendor/github.com/docker/docker/client/plugin_list.go @@ -23,7 +23,7 @@ func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (types.P } resp, err := cli.get(ctx, "/plugins", query, nil) if err != nil { - return plugins, err + return plugins, wrapResponseError(err, resp, "plugin", "") } err = json.NewDecoder(resp.body).Decode(&plugins) diff --git a/vendor/github.com/docker/docker/client/plugin_remove.go b/vendor/github.com/docker/docker/client/plugin_remove.go index b017e4d34..b498c4820 100644 --- a/vendor/github.com/docker/docker/client/plugin_remove.go +++ b/vendor/github.com/docker/docker/client/plugin_remove.go @@ -16,5 +16,5 @@ func (cli *Client) PluginRemove(ctx context.Context, name string, options types. resp, err := cli.delete(ctx, "/plugins/"+name, query, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "plugin", name) } diff --git a/vendor/github.com/docker/docker/client/request.go b/vendor/github.com/docker/docker/client/request.go index 3e7d43fea..615d0b989 100644 --- a/vendor/github.com/docker/docker/client/request.go +++ b/vendor/github.com/docker/docker/client/request.go @@ -203,7 +203,7 @@ func (cli *Client) checkResponseErr(serverResp serverResponse) error { return err } if len(body) == 0 { - return fmt.Errorf("Error: request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), serverResp.reqURL) + return fmt.Errorf("request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), serverResp.reqURL) } var ct string diff --git a/vendor/github.com/docker/docker/client/secret_inspect.go b/vendor/github.com/docker/docker/client/secret_inspect.go index 9b602972b..6927ea96f 100644 --- a/vendor/github.com/docker/docker/client/secret_inspect.go +++ b/vendor/github.com/docker/docker/client/secret_inspect.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "github.com/docker/docker/api/types/swarm" "golang.org/x/net/context" @@ -17,10 +16,7 @@ func (cli *Client) SecretInspectWithRaw(ctx context.Context, id string) (swarm.S } resp, err := cli.get(ctx, "/secrets/"+id, nil, nil) if err != nil { - if resp.statusCode == http.StatusNotFound { - return swarm.Secret{}, nil, secretNotFoundError{id} - } - return swarm.Secret{}, nil, err + return swarm.Secret{}, nil, wrapResponseError(err, resp, "secret", id) } defer ensureReaderClosed(resp) diff --git a/vendor/github.com/docker/docker/client/secret_list.go b/vendor/github.com/docker/docker/client/secret_list.go index 0d33ecfbc..fdee6e2e0 100644 --- a/vendor/github.com/docker/docker/client/secret_list.go +++ b/vendor/github.com/docker/docker/client/secret_list.go @@ -18,7 +18,7 @@ func (cli *Client) SecretList(ctx context.Context, options types.SecretListOptio query := url.Values{} if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return nil, err } diff --git a/vendor/github.com/docker/docker/client/secret_remove.go b/vendor/github.com/docker/docker/client/secret_remove.go index c5e37af17..9b4ee71e2 100644 --- a/vendor/github.com/docker/docker/client/secret_remove.go +++ b/vendor/github.com/docker/docker/client/secret_remove.go @@ -9,5 +9,5 @@ func (cli *Client) SecretRemove(ctx context.Context, id string) error { } resp, err := cli.delete(ctx, "/secrets/"+id, nil, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "secret", id) } diff --git a/vendor/github.com/docker/docker/client/service_create.go b/vendor/github.com/docker/docker/client/service_create.go index a36839443..834709d1f 100644 --- a/vendor/github.com/docker/docker/client/service_create.go +++ b/vendor/github.com/docker/docker/client/service_create.go @@ -3,11 +3,12 @@ package client import ( "encoding/json" "fmt" + "strings" "github.com/docker/distribution/reference" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" - "github.com/opencontainers/go-digest" + digest "github.com/opencontainers/go-digest" "github.com/pkg/errors" "golang.org/x/net/context" ) @@ -85,21 +86,30 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec, return response, err } -func imageDigestAndPlatforms(ctx context.Context, cli *Client, image, encodedAuth string) (string, []swarm.Platform, error) { +func imageDigestAndPlatforms(ctx context.Context, cli DistributionAPIClient, image, encodedAuth string) (string, []swarm.Platform, error) { distributionInspect, err := cli.DistributionInspect(ctx, image, encodedAuth) - imageWithDigest := image var platforms []swarm.Platform if err != nil { return "", nil, err } - imageWithDigest = imageWithDigestString(image, distributionInspect.Descriptor.Digest) + imageWithDigest := imageWithDigestString(image, distributionInspect.Descriptor.Digest) if len(distributionInspect.Platforms) > 0 { platforms = make([]swarm.Platform, 0, len(distributionInspect.Platforms)) for _, p := range distributionInspect.Platforms { + // clear architecture field for arm. This is a temporary patch to address + // https://github.com/docker/swarmkit/issues/2294. The issue is that while + // image manifests report "arm" as the architecture, the node reports + // something like "armv7l" (includes the variant), which causes arm images + // to stop working with swarm mode. This patch removes the architecture + // constraint for arm images to ensure tasks get scheduled. + arch := p.Architecture + if strings.ToLower(arch) == "arm" { + arch = "" + } platforms = append(platforms, swarm.Platform{ - Architecture: p.Architecture, + Architecture: arch, OS: p.OS, }) } diff --git a/vendor/github.com/docker/docker/client/service_inspect.go b/vendor/github.com/docker/docker/client/service_inspect.go index d7e051e3a..3e9699e5e 100644 --- a/vendor/github.com/docker/docker/client/service_inspect.go +++ b/vendor/github.com/docker/docker/client/service_inspect.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "io/ioutil" - "net/http" "net/url" "github.com/docker/docker/api/types" @@ -19,10 +18,7 @@ func (cli *Client) ServiceInspectWithRaw(ctx context.Context, serviceID string, query.Set("insertDefaults", fmt.Sprintf("%v", opts.InsertDefaults)) serverResp, err := cli.get(ctx, "/services/"+serviceID, query, nil) if err != nil { - if serverResp.statusCode == http.StatusNotFound { - return swarm.Service{}, nil, serviceNotFoundError{serviceID} - } - return swarm.Service{}, nil, err + return swarm.Service{}, nil, wrapResponseError(err, serverResp, "service", serviceID) } defer ensureReaderClosed(serverResp) diff --git a/vendor/github.com/docker/docker/client/service_list.go b/vendor/github.com/docker/docker/client/service_list.go index c29e6d407..eb3ff9739 100644 --- a/vendor/github.com/docker/docker/client/service_list.go +++ b/vendor/github.com/docker/docker/client/service_list.go @@ -15,7 +15,7 @@ func (cli *Client) ServiceList(ctx context.Context, options types.ServiceListOpt query := url.Values{} if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return nil, err } diff --git a/vendor/github.com/docker/docker/client/service_remove.go b/vendor/github.com/docker/docker/client/service_remove.go index a9331f92c..ad992c01d 100644 --- a/vendor/github.com/docker/docker/client/service_remove.go +++ b/vendor/github.com/docker/docker/client/service_remove.go @@ -6,5 +6,5 @@ import "golang.org/x/net/context" func (cli *Client) ServiceRemove(ctx context.Context, serviceID string) error { resp, err := cli.delete(ctx, "/services/"+serviceID, nil, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "service", serviceID) } diff --git a/vendor/github.com/docker/docker/client/task_inspect.go b/vendor/github.com/docker/docker/client/task_inspect.go index bc8058fc3..dc08cedb9 100644 --- a/vendor/github.com/docker/docker/client/task_inspect.go +++ b/vendor/github.com/docker/docker/client/task_inspect.go @@ -4,10 +4,8 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "github.com/docker/docker/api/types/swarm" - "golang.org/x/net/context" ) @@ -15,10 +13,7 @@ import ( func (cli *Client) TaskInspectWithRaw(ctx context.Context, taskID string) (swarm.Task, []byte, error) { serverResp, err := cli.get(ctx, "/tasks/"+taskID, nil, nil) if err != nil { - if serverResp.statusCode == http.StatusNotFound { - return swarm.Task{}, nil, taskNotFoundError{taskID} - } - return swarm.Task{}, nil, err + return swarm.Task{}, nil, wrapResponseError(err, serverResp, "task", taskID) } defer ensureReaderClosed(serverResp) diff --git a/vendor/github.com/docker/docker/client/task_list.go b/vendor/github.com/docker/docker/client/task_list.go index 66324da95..01bd69525 100644 --- a/vendor/github.com/docker/docker/client/task_list.go +++ b/vendor/github.com/docker/docker/client/task_list.go @@ -15,7 +15,7 @@ func (cli *Client) TaskList(ctx context.Context, options types.TaskListOptions) query := url.Values{} if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return nil, err } diff --git a/vendor/github.com/docker/docker/client/tlsconfig_clone.go b/vendor/github.com/docker/docker/client/tlsconfig_clone.go new file mode 100644 index 000000000..99b6be1ce --- /dev/null +++ b/vendor/github.com/docker/docker/client/tlsconfig_clone.go @@ -0,0 +1,11 @@ +// +build go1.8 + +package client + +import "crypto/tls" + +// tlsConfigClone returns a clone of tls.Config. This function is provided for +// compatibility for go1.7 that doesn't include this method in stdlib. +func tlsConfigClone(c *tls.Config) *tls.Config { + return c.Clone() +} diff --git a/vendor/github.com/docker/docker/pkg/tlsconfig/tlsconfig_clone_go17.go b/vendor/github.com/docker/docker/client/tlsconfig_clone_go17.go index 0d5b448fe..b837b2ade 100644 --- a/vendor/github.com/docker/docker/pkg/tlsconfig/tlsconfig_clone_go17.go +++ b/vendor/github.com/docker/docker/client/tlsconfig_clone_go17.go @@ -1,12 +1,12 @@ // +build go1.7,!go1.8 -package tlsconfig +package client import "crypto/tls" -// Clone returns a clone of tls.Config. This function is provided for +// tlsConfigClone returns a clone of tls.Config. This function is provided for // compatibility for go1.7 that doesn't include this method in stdlib. -func Clone(c *tls.Config) *tls.Config { +func tlsConfigClone(c *tls.Config) *tls.Config { return &tls.Config{ Rand: c.Rand, Time: c.Time, diff --git a/vendor/github.com/docker/docker/client/transport.go b/vendor/github.com/docker/docker/client/transport.go index 401ab15d3..73f6ef7b4 100644 --- a/vendor/github.com/docker/docker/client/transport.go +++ b/vendor/github.com/docker/docker/client/transport.go @@ -5,14 +5,6 @@ import ( "net/http" ) -// transportFunc allows us to inject a mock transport for testing. We define it -// here so we can detect the tlsconfig and return nil for only this type. -type transportFunc func(*http.Request) (*http.Response, error) - -func (tf transportFunc) RoundTrip(req *http.Request) (*http.Response, error) { - return tf(req) -} - // resolveTLSConfig attempts to resolve the TLS configuration from the // RoundTripper. func resolveTLSConfig(transport http.RoundTripper) *tls.Config { diff --git a/vendor/github.com/docker/docker/client/utils.go b/vendor/github.com/docker/docker/client/utils.go index f3d8877df..137705065 100644 --- a/vendor/github.com/docker/docker/client/utils.go +++ b/vendor/github.com/docker/docker/client/utils.go @@ -24,7 +24,7 @@ func getDockerOS(serverHeader string) string { func getFiltersQuery(f filters.Args) (url.Values, error) { query := url.Values{} if f.Len() > 0 { - filterJSON, err := filters.ToParam(f) + filterJSON, err := filters.ToJSON(f) if err != nil { return query, err } diff --git a/vendor/github.com/docker/docker/client/volume_inspect.go b/vendor/github.com/docker/docker/client/volume_inspect.go index 3860e9b22..988934384 100644 --- a/vendor/github.com/docker/docker/client/volume_inspect.go +++ b/vendor/github.com/docker/docker/client/volume_inspect.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" + "path" "github.com/docker/docker/api/types" "golang.org/x/net/context" @@ -18,13 +18,17 @@ func (cli *Client) VolumeInspect(ctx context.Context, volumeID string) (types.Vo // VolumeInspectWithRaw returns the information about a specific volume in the docker host and its raw representation func (cli *Client) VolumeInspectWithRaw(ctx context.Context, volumeID string) (types.Volume, []byte, error) { + // The empty ID needs to be handled here because with an empty ID the + // request url will not contain a trailing / which calls the volume list API + // instead of volume inspect + if volumeID == "" { + return types.Volume{}, nil, objectNotFoundError{object: "volume", id: volumeID} + } + var volume types.Volume - resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil) + resp, err := cli.get(ctx, path.Join("/volumes", volumeID), nil, nil) if err != nil { - if resp.statusCode == http.StatusNotFound { - return volume, nil, volumeNotFoundError{volumeID} - } - return volume, nil, err + return volume, nil, wrapResponseError(err, resp, "volume", volumeID) } defer ensureReaderClosed(resp) diff --git a/vendor/github.com/docker/docker/client/volume_remove.go b/vendor/github.com/docker/docker/client/volume_remove.go index 6c26575b4..3ffb8bcf2 100644 --- a/vendor/github.com/docker/docker/client/volume_remove.go +++ b/vendor/github.com/docker/docker/client/volume_remove.go @@ -17,5 +17,5 @@ func (cli *Client) VolumeRemove(ctx context.Context, volumeID string, force bool } resp, err := cli.delete(ctx, "/volumes/"+volumeID, query, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "volume", volumeID) } diff --git a/vendor/github.com/docker/docker/daemon/caps/utils_unix.go b/vendor/github.com/docker/docker/daemon/caps/utils_unix.go index c99485f51..28a8df653 100644 --- a/vendor/github.com/docker/docker/daemon/caps/utils_unix.go +++ b/vendor/github.com/docker/docker/daemon/caps/utils_unix.go @@ -6,7 +6,6 @@ import ( "fmt" "strings" - "github.com/docker/docker/pkg/stringutils" "github.com/syndtr/gocapability/capability" ) @@ -69,6 +68,17 @@ func GetAllCapabilities() []string { return output } +// inSlice tests whether a string is contained in a slice of strings or not. +// Comparison is case insensitive +func inSlice(slice []string, s string) bool { + for _, ss := range slice { + if strings.ToLower(s) == strings.ToLower(ss) { + return true + } + } + return false +} + // TweakCapabilities can tweak capabilities by adding or dropping capabilities // based on the basics capabilities. func TweakCapabilities(basics, adds, drops []string) ([]string, error) { @@ -86,17 +96,17 @@ func TweakCapabilities(basics, adds, drops []string) ([]string, error) { continue } - if !stringutils.InSlice(allCaps, "CAP_"+cap) { + if !inSlice(allCaps, "CAP_"+cap) { return nil, fmt.Errorf("Unknown capability drop: %q", cap) } } // handle --cap-add=all - if stringutils.InSlice(adds, "all") { + if inSlice(adds, "all") { basics = allCaps } - if !stringutils.InSlice(drops, "all") { + if !inSlice(drops, "all") { for _, cap := range basics { // skip `all` already handled above if strings.ToLower(cap) == "all" { @@ -104,7 +114,7 @@ func TweakCapabilities(basics, adds, drops []string) ([]string, error) { } // if we don't drop `all`, add back all the non-dropped caps - if !stringutils.InSlice(drops, cap[4:]) { + if !inSlice(drops, cap[4:]) { newCaps = append(newCaps, strings.ToUpper(cap)) } } @@ -118,12 +128,12 @@ func TweakCapabilities(basics, adds, drops []string) ([]string, error) { cap = "CAP_" + cap - if !stringutils.InSlice(allCaps, cap) { + if !inSlice(allCaps, cap) { return nil, fmt.Errorf("Unknown capability to add: %q", cap) } // add cap if not already in the list - if !stringutils.InSlice(newCaps, cap) { + if !inSlice(newCaps, cap) { newCaps = append(newCaps, strings.ToUpper(cap)) } } diff --git a/vendor/github.com/docker/docker/hack/README.md b/vendor/github.com/docker/docker/hack/README.md index 802395d53..9e588db25 100644 --- a/vendor/github.com/docker/docker/hack/README.md +++ b/vendor/github.com/docker/docker/hack/README.md @@ -37,14 +37,14 @@ More information is found within `make.ps1` by the author, @jhowardmsft - Referenced via `make test` when running tests on a local machine, or directly referenced when running tests inside a Docker development container. - When running on a local machine, `make test` to run all tests found in -`test`, `test-unit`, `test-integration-cli`, and `test-docker-py` on +`test`, `test-unit`, `test-integration`, and `test-docker-py` on your local machine. The default timeout is set in `make.sh` to 60 minutes (`${TIMEOUT:=60m}`), since it currently takes up to an hour to run all of the tests. - When running inside a Docker development container, `hack/make.sh` does not have a single target that runs all the tests. You need to provide a single command line with multiple targets that performs the same thing. -An example referenced from [Run targets inside a development container](https://docs.docker.com/opensource/project/test-and-docs/#run-targets-inside-a-development-container): `root@5f8630b873fe:/go/src/github.com/moby/moby# hack/make.sh dynbinary binary cross test-unit test-integration-cli test-docker-py` +An example referenced from [Run targets inside a development container](https://docs.docker.com/opensource/project/test-and-docs/#run-targets-inside-a-development-container): `root@5f8630b873fe:/go/src/github.com/moby/moby# hack/make.sh dynbinary binary cross test-unit test-integration test-docker-py` - For more information related to testing outside the scope of this README, refer to [Run tests and test documentation](https://docs.docker.com/opensource/project/test-and-docs/) diff --git a/vendor/github.com/docker/docker/pkg/README.md b/vendor/github.com/docker/docker/pkg/README.md index c4b78a8ad..755cd9683 100644 --- a/vendor/github.com/docker/docker/pkg/README.md +++ b/vendor/github.com/docker/docker/pkg/README.md @@ -1,8 +1,8 @@ -pkg/ is a collection of utility packages used by the Docker project without being specific to its internals. +pkg/ is a collection of utility packages used by the Moby project without being specific to its internals. -Utility packages are kept separate from the docker core codebase to keep it as small and concise as possible. +Utility packages are kept separate from the moby core codebase to keep it as small and concise as possible. If some utilities grow larger and their APIs stabilize, they may be moved to their own repository under the -Docker organization, to facilitate re-use by other projects. However that is not the priority. +Moby organization, to facilitate re-use by other projects. However that is not the priority. The directory `pkg` is named after the same directory in the camlistore project. Since Brad is a core Go maintainer, we thought it made sense to copy his methods for organizing Go code :) Thanks Brad! diff --git a/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go b/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go index 8701bb7fa..ff7968f85 100644 --- a/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go +++ b/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go @@ -26,14 +26,19 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown // so that we can chown all of them properly at the end. If chownExisting is false, we won't // chown the full directory path if it exists var paths []string - if _, err := os.Stat(path); err != nil && os.IsNotExist(err) { - paths = []string{path} - } else if err == nil && chownExisting { + + stat, err := system.Stat(path) + if err == nil { + if !chownExisting { + return nil + } + // short-circuit--we were called with an existing directory and chown was requested - return os.Chown(path, ownerUID, ownerGID) - } else if err == nil { - // nothing to do; directory path fully exists already and chown was NOT requested - return nil + return lazyChown(path, ownerUID, ownerGID, stat) + } + + if os.IsNotExist(err) { + paths = []string{path} } if mkAll { @@ -60,7 +65,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown // even if it existed, we will chown the requested path + any subpaths that // didn't exist when we called MkdirAll for _, pathComponent := range paths { - if err := os.Chown(pathComponent, ownerUID, ownerGID); err != nil { + if err := lazyChown(pathComponent, ownerUID, ownerGID, nil); err != nil { return err } } @@ -202,3 +207,20 @@ func callGetent(args string) (io.Reader, error) { } return bytes.NewReader(out), nil } + +// lazyChown performs a chown only if the uid/gid don't match what's requested +// Normally a Chown is a no-op if uid/gid match, but in some cases this can still cause an error, e.g. if the +// dir is on an NFS share, so don't call chown unless we absolutely must. +func lazyChown(p string, uid, gid int, stat *system.StatT) error { + if stat == nil { + var err error + stat, err = system.Stat(p) + if err != nil { + return err + } + } + if stat.UID() == uint32(uid) && stat.GID() == uint32(gid) { + return nil + } + return os.Chown(p, uid, gid) +} diff --git a/vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go b/vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go index 9ed741e3f..43d5e339f 100644 --- a/vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go +++ b/vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!freebsd freebsd,!cgo solaris,!cgo +// +build !linux,!freebsd freebsd,!cgo package mount diff --git a/vendor/github.com/docker/docker/pkg/mount/mount.go b/vendor/github.com/docker/docker/pkg/mount/mount.go index c9fdfd694..ee5833c49 100644 --- a/vendor/github.com/docker/docker/pkg/mount/mount.go +++ b/vendor/github.com/docker/docker/pkg/mount/mount.go @@ -3,6 +3,8 @@ package mount import ( "sort" "strings" + + "github.com/sirupsen/logrus" ) // GetMounts retrieves a list of mounts for the current running process. @@ -11,7 +13,7 @@ func GetMounts() ([]*Info, error) { } // Mounted determines if a specified mountpoint has been mounted. -// On Linux it looks at /proc/self/mountinfo and on Solaris at mnttab. +// On Linux it looks at /proc/self/mountinfo. func Mounted(mountpoint string) (bool, error) { entries, err := parseMountTable() if err != nil { @@ -74,12 +76,18 @@ func RecursiveUnmount(target string) error { if !strings.HasPrefix(m.Mountpoint, target) { continue } - if err := Unmount(m.Mountpoint); err != nil && i == len(mounts)-1 { + logrus.Debugf("Trying to unmount %s", m.Mountpoint) + err = Unmount(m.Mountpoint) + if err != nil && i == len(mounts)-1 { if mounted, err := Mounted(m.Mountpoint); err != nil || mounted { return err } // Ignore errors for submounts and continue trying to unmount others // The final unmount should fail if there ane any submounts remaining + } else if err != nil { + logrus.Errorf("Failed to unmount %s: %v", m.Mountpoint, err) + } else if err == nil { + logrus.Debugf("Unmounted %s", m.Mountpoint) } } return nil diff --git a/vendor/github.com/docker/docker/pkg/mount/mounter_solaris.go b/vendor/github.com/docker/docker/pkg/mount/mounter_solaris.go deleted file mode 100644 index c684aa81f..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/mounter_solaris.go +++ /dev/null @@ -1,33 +0,0 @@ -// +build solaris,cgo - -package mount - -import ( - "golang.org/x/sys/unix" - "unsafe" -) - -// #include <stdlib.h> -// #include <stdio.h> -// #include <sys/mount.h> -// int Mount(const char *spec, const char *dir, int mflag, -// char *fstype, char *dataptr, int datalen, char *optptr, int optlen) { -// return mount(spec, dir, mflag, fstype, dataptr, datalen, optptr, optlen); -// } -import "C" - -func mount(device, target, mType string, flag uintptr, data string) error { - spec := C.CString(device) - dir := C.CString(target) - fstype := C.CString(mType) - _, err := C.Mount(spec, dir, C.int(flag), fstype, nil, 0, nil, 0) - C.free(unsafe.Pointer(spec)) - C.free(unsafe.Pointer(dir)) - C.free(unsafe.Pointer(fstype)) - return err -} - -func unmount(target string, flag int) error { - err := unix.Unmount(target, flag) - return err -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go b/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go index a2a3bb457..eb93365eb 100644 --- a/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go +++ b/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo +// +build !linux,!freebsd freebsd,!cgo package mount diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo_solaris.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo_solaris.go deleted file mode 100644 index ad9ab57f8..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/mountinfo_solaris.go +++ /dev/null @@ -1,37 +0,0 @@ -// +build solaris,cgo - -package mount - -/* -#include <stdio.h> -#include <sys/mnttab.h> -*/ -import "C" - -import ( - "fmt" -) - -func parseMountTable() ([]*Info, error) { - mnttab := C.fopen(C.CString(C.MNTTAB), C.CString("r")) - if mnttab == nil { - return nil, fmt.Errorf("Failed to open %s", C.MNTTAB) - } - - var out []*Info - var mp C.struct_mnttab - - ret := C.getmntent(mnttab, &mp) - for ret == 0 { - var mountinfo Info - mountinfo.Mountpoint = C.GoString(mp.mnt_mountp) - mountinfo.Source = C.GoString(mp.mnt_special) - mountinfo.Fstype = C.GoString(mp.mnt_fstype) - mountinfo.Opts = C.GoString(mp.mnt_mntopts) - out = append(out, &mountinfo) - ret = C.getmntent(mnttab, &mp) - } - - C.fclose(mnttab) - return out, nil -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go index 7fbcf1921..b8d9aa5c7 100644 --- a/vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go +++ b/vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go @@ -1,4 +1,4 @@ -// +build !windows,!linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo +// +build !windows,!linux,!freebsd freebsd,!cgo package mount diff --git a/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_solaris.go b/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_solaris.go deleted file mode 100644 index 09f6b03cb..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_solaris.go +++ /dev/null @@ -1,58 +0,0 @@ -// +build solaris - -package mount - -// MakeShared ensures a mounted filesystem has the SHARED mount option enabled. -// See the supported options in flags.go for further reference. -func MakeShared(mountPoint string) error { - return ensureMountedAs(mountPoint, "shared") -} - -// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled. -// See the supported options in flags.go for further reference. -func MakeRShared(mountPoint string) error { - return ensureMountedAs(mountPoint, "rshared") -} - -// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled. -// See the supported options in flags.go for further reference. -func MakePrivate(mountPoint string) error { - return ensureMountedAs(mountPoint, "private") -} - -// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option -// enabled. See the supported options in flags.go for further reference. -func MakeRPrivate(mountPoint string) error { - return ensureMountedAs(mountPoint, "rprivate") -} - -// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled. -// See the supported options in flags.go for further reference. -func MakeSlave(mountPoint string) error { - return ensureMountedAs(mountPoint, "slave") -} - -// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled. -// See the supported options in flags.go for further reference. -func MakeRSlave(mountPoint string) error { - return ensureMountedAs(mountPoint, "rslave") -} - -// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option -// enabled. See the supported options in flags.go for further reference. -func MakeUnbindable(mountPoint string) error { - return ensureMountedAs(mountPoint, "unbindable") -} - -// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount -// option enabled. See the supported options in flags.go for further reference. -func MakeRUnbindable(mountPoint string) error { - return ensureMountedAs(mountPoint, "runbindable") -} - -func ensureMountedAs(mountPoint, options string) error { - // TODO: Solaris does not support bind mounts. - // Evaluate lofs and also look at the relevant - // mount flags to be supported. - return nil -} diff --git a/vendor/github.com/docker/docker/pkg/parsers/parsers.go b/vendor/github.com/docker/docker/pkg/parsers/parsers.go new file mode 100644 index 000000000..acc897168 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/parsers/parsers.go @@ -0,0 +1,69 @@ +// Package parsers provides helper functions to parse and validate different type +// of string. It can be hosts, unix addresses, tcp addresses, filters, kernel +// operating system versions. +package parsers + +import ( + "fmt" + "strconv" + "strings" +) + +// ParseKeyValueOpt parses and validates the specified string as a key/value pair (key=value) +func ParseKeyValueOpt(opt string) (string, string, error) { + parts := strings.SplitN(opt, "=", 2) + if len(parts) != 2 { + return "", "", fmt.Errorf("Unable to parse key/value option: %s", opt) + } + return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil +} + +// ParseUintList parses and validates the specified string as the value +// found in some cgroup file (e.g. `cpuset.cpus`, `cpuset.mems`), which could be +// one of the formats below. Note that duplicates are actually allowed in the +// input string. It returns a `map[int]bool` with available elements from `val` +// set to `true`. +// Supported formats: +// 7 +// 1-6 +// 0,3-4,7,8-10 +// 0-0,0,1-7 +// 03,1-3 <- this is gonna get parsed as [1,2,3] +// 3,2,1 +// 0-2,3,1 +func ParseUintList(val string) (map[int]bool, error) { + if val == "" { + return map[int]bool{}, nil + } + + availableInts := make(map[int]bool) + split := strings.Split(val, ",") + errInvalidFormat := fmt.Errorf("invalid format: %s", val) + + for _, r := range split { + if !strings.Contains(r, "-") { + v, err := strconv.Atoi(r) + if err != nil { + return nil, errInvalidFormat + } + availableInts[v] = true + } else { + split := strings.SplitN(r, "-", 2) + min, err := strconv.Atoi(split[0]) + if err != nil { + return nil, errInvalidFormat + } + max, err := strconv.Atoi(split[1]) + if err != nil { + return nil, errInvalidFormat + } + if max < min { + return nil, errInvalidFormat + } + for i := min; i <= max; i++ { + availableInts[i] = true + } + } + } + return availableInts, nil +} diff --git a/vendor/github.com/docker/docker/pkg/signal/signal_linux.go b/vendor/github.com/docker/docker/pkg/signal/signal_linux.go index 3594796ca..66c85c8e0 100644 --- a/vendor/github.com/docker/docker/pkg/signal/signal_linux.go +++ b/vendor/github.com/docker/docker/pkg/signal/signal_linux.go @@ -40,7 +40,6 @@ var SignalMap = map[string]syscall.Signal{ "TSTP": unix.SIGTSTP, "TTIN": unix.SIGTTIN, "TTOU": unix.SIGTTOU, - "UNUSED": unix.SIGUNUSED, "URG": unix.SIGURG, "USR1": unix.SIGUSR1, "USR2": unix.SIGUSR2, diff --git a/vendor/github.com/docker/docker/pkg/signal/signal_solaris.go b/vendor/github.com/docker/docker/pkg/signal/signal_solaris.go deleted file mode 100644 index 89576b9e3..000000000 --- a/vendor/github.com/docker/docker/pkg/signal/signal_solaris.go +++ /dev/null @@ -1,42 +0,0 @@ -package signal - -import ( - "syscall" -) - -// SignalMap is a map of Solaris signals. -// SIGINFO and SIGTHR not defined for Solaris -var SignalMap = map[string]syscall.Signal{ - "ABRT": syscall.SIGABRT, - "ALRM": syscall.SIGALRM, - "BUF": syscall.SIGBUS, - "CHLD": syscall.SIGCHLD, - "CONT": syscall.SIGCONT, - "EMT": syscall.SIGEMT, - "FPE": syscall.SIGFPE, - "HUP": syscall.SIGHUP, - "ILL": syscall.SIGILL, - "INT": syscall.SIGINT, - "IO": syscall.SIGIO, - "IOT": syscall.SIGIOT, - "KILL": syscall.SIGKILL, - "LWP": syscall.SIGLWP, - "PIPE": syscall.SIGPIPE, - "PROF": syscall.SIGPROF, - "QUIT": syscall.SIGQUIT, - "SEGV": syscall.SIGSEGV, - "STOP": syscall.SIGSTOP, - "SYS": syscall.SIGSYS, - "TERM": syscall.SIGTERM, - "TRAP": syscall.SIGTRAP, - "TSTP": syscall.SIGTSTP, - "TTIN": syscall.SIGTTIN, - "TTOU": syscall.SIGTTOU, - "URG": syscall.SIGURG, - "USR1": syscall.SIGUSR1, - "USR2": syscall.SIGUSR2, - "VTALRM": syscall.SIGVTALRM, - "WINCH": syscall.SIGWINCH, - "XCPU": syscall.SIGXCPU, - "XFSZ": syscall.SIGXFSZ, -} diff --git a/vendor/github.com/docker/docker/pkg/signal/signal_unsupported.go b/vendor/github.com/docker/docker/pkg/signal/signal_unsupported.go index c592d37df..161ba2739 100644 --- a/vendor/github.com/docker/docker/pkg/signal/signal_unsupported.go +++ b/vendor/github.com/docker/docker/pkg/signal/signal_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!darwin,!freebsd,!windows,!solaris +// +build !linux,!darwin,!freebsd,!windows package signal diff --git a/vendor/github.com/docker/docker/pkg/stringutils/README.md b/vendor/github.com/docker/docker/pkg/stringutils/README.md deleted file mode 100644 index b3e454573..000000000 --- a/vendor/github.com/docker/docker/pkg/stringutils/README.md +++ /dev/null @@ -1 +0,0 @@ -This package provides helper functions for dealing with strings diff --git a/vendor/github.com/docker/docker/pkg/stringutils/stringutils.go b/vendor/github.com/docker/docker/pkg/stringutils/stringutils.go deleted file mode 100644 index 8c4c39875..000000000 --- a/vendor/github.com/docker/docker/pkg/stringutils/stringutils.go +++ /dev/null @@ -1,99 +0,0 @@ -// Package stringutils provides helper functions for dealing with strings. -package stringutils - -import ( - "bytes" - "math/rand" - "strings" -) - -// GenerateRandomAlphaOnlyString generates an alphabetical random string with length n. -func GenerateRandomAlphaOnlyString(n int) string { - // make a really long string - letters := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") - b := make([]byte, n) - for i := range b { - b[i] = letters[rand.Intn(len(letters))] - } - return string(b) -} - -// GenerateRandomASCIIString generates an ASCII random string with length n. -func GenerateRandomASCIIString(n int) string { - chars := "abcdefghijklmnopqrstuvwxyz" + - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + - "~!@#$%^&*()-_+={}[]\\|<,>.?/\"';:` " - res := make([]byte, n) - for i := 0; i < n; i++ { - res[i] = chars[rand.Intn(len(chars))] - } - return string(res) -} - -// Ellipsis truncates a string to fit within maxlen, and appends ellipsis (...). -// For maxlen of 3 and lower, no ellipsis is appended. -func Ellipsis(s string, maxlen int) string { - r := []rune(s) - if len(r) <= maxlen { - return s - } - if maxlen <= 3 { - return string(r[:maxlen]) - } - return string(r[:maxlen-3]) + "..." -} - -// Truncate truncates a string to maxlen. -func Truncate(s string, maxlen int) string { - r := []rune(s) - if len(r) <= maxlen { - return s - } - return string(r[:maxlen]) -} - -// InSlice tests whether a string is contained in a slice of strings or not. -// Comparison is case insensitive -func InSlice(slice []string, s string) bool { - for _, ss := range slice { - if strings.ToLower(s) == strings.ToLower(ss) { - return true - } - } - return false -} - -func quote(word string, buf *bytes.Buffer) { - // Bail out early for "simple" strings - if word != "" && !strings.ContainsAny(word, "\\'\"`${[|&;<>()~*?! \t\n") { - buf.WriteString(word) - return - } - - buf.WriteString("'") - - for i := 0; i < len(word); i++ { - b := word[i] - if b == '\'' { - // Replace literal ' with a close ', a \', and an open ' - buf.WriteString("'\\''") - } else { - buf.WriteByte(b) - } - } - - buf.WriteString("'") -} - -// ShellQuoteArguments takes a list of strings and escapes them so they will be -// handled right when passed as arguments to a program via a shell -func ShellQuoteArguments(args []string) string { - var buf bytes.Buffer - for i, arg := range args { - if i != 0 { - buf.WriteByte(' ') - } - quote(arg, &buf) - } - return buf.String() -} diff --git a/vendor/github.com/docker/docker/pkg/sysinfo/README.md b/vendor/github.com/docker/docker/pkg/sysinfo/README.md new file mode 100644 index 000000000..c1530cef0 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/sysinfo/README.md @@ -0,0 +1 @@ +SysInfo stores information about which features a kernel supports. diff --git a/vendor/github.com/docker/docker/pkg/sysinfo/numcpu.go b/vendor/github.com/docker/docker/pkg/sysinfo/numcpu.go new file mode 100644 index 000000000..aeb1a3a80 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/sysinfo/numcpu.go @@ -0,0 +1,12 @@ +// +build !linux,!windows + +package sysinfo + +import ( + "runtime" +) + +// NumCPU returns the number of CPUs +func NumCPU() int { + return runtime.NumCPU() +} diff --git a/vendor/github.com/docker/docker/pkg/sysinfo/numcpu_linux.go b/vendor/github.com/docker/docker/pkg/sysinfo/numcpu_linux.go new file mode 100644 index 000000000..f1d2d9db3 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/sysinfo/numcpu_linux.go @@ -0,0 +1,44 @@ +// +build linux + +package sysinfo + +import ( + "runtime" + "unsafe" + + "golang.org/x/sys/unix" +) + +// numCPU queries the system for the count of threads available +// for use to this process. +// +// Issues two syscalls. +// Returns 0 on errors. Use |runtime.NumCPU| in that case. +func numCPU() int { + // Gets the affinity mask for a process: The very one invoking this function. + pid, _, _ := unix.RawSyscall(unix.SYS_GETPID, 0, 0, 0) + + var mask [1024 / 64]uintptr + _, _, err := unix.RawSyscall(unix.SYS_SCHED_GETAFFINITY, pid, uintptr(len(mask)*8), uintptr(unsafe.Pointer(&mask[0]))) + if err != 0 { + return 0 + } + + // For every available thread a bit is set in the mask. + ncpu := 0 + for _, e := range mask { + if e == 0 { + continue + } + ncpu += int(popcnt(uint64(e))) + } + return ncpu +} + +// NumCPU returns the number of CPUs which are currently online +func NumCPU() int { + if ncpu := numCPU(); ncpu > 0 { + return ncpu + } + return runtime.NumCPU() +} diff --git a/vendor/github.com/docker/docker/pkg/sysinfo/numcpu_windows.go b/vendor/github.com/docker/docker/pkg/sysinfo/numcpu_windows.go new file mode 100644 index 000000000..1d89dd550 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/sysinfo/numcpu_windows.go @@ -0,0 +1,37 @@ +// +build windows + +package sysinfo + +import ( + "runtime" + "unsafe" + + "golang.org/x/sys/windows" +) + +var ( + kernel32 = windows.NewLazySystemDLL("kernel32.dll") + getCurrentProcess = kernel32.NewProc("GetCurrentProcess") + getProcessAffinityMask = kernel32.NewProc("GetProcessAffinityMask") +) + +func numCPU() int { + // Gets the affinity mask for a process + var mask, sysmask uintptr + currentProcess, _, _ := getCurrentProcess.Call() + ret, _, _ := getProcessAffinityMask.Call(currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask))) + if ret == 0 { + return 0 + } + // For every available thread a bit is set in the mask. + ncpu := int(popcnt(uint64(mask))) + return ncpu +} + +// NumCPU returns the number of CPUs which are currently online +func NumCPU() int { + if ncpu := numCPU(); ncpu > 0 { + return ncpu + } + return runtime.NumCPU() +} diff --git a/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo.go b/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo.go new file mode 100644 index 000000000..f046de4b1 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo.go @@ -0,0 +1,144 @@ +package sysinfo + +import "github.com/docker/docker/pkg/parsers" + +// SysInfo stores information about which features a kernel supports. +// TODO Windows: Factor out platform specific capabilities. +type SysInfo struct { + // Whether the kernel supports AppArmor or not + AppArmor bool + // Whether the kernel supports Seccomp or not + Seccomp bool + + cgroupMemInfo + cgroupCPUInfo + cgroupBlkioInfo + cgroupCpusetInfo + cgroupPids + + // Whether IPv4 forwarding is supported or not, if this was disabled, networking will not work + IPv4ForwardingDisabled bool + + // Whether bridge-nf-call-iptables is supported or not + BridgeNFCallIPTablesDisabled bool + + // Whether bridge-nf-call-ip6tables is supported or not + BridgeNFCallIP6TablesDisabled bool + + // Whether the cgroup has the mountpoint of "devices" or not + CgroupDevicesEnabled bool +} + +type cgroupMemInfo struct { + // Whether memory limit is supported or not + MemoryLimit bool + + // Whether swap limit is supported or not + SwapLimit bool + + // Whether soft limit is supported or not + MemoryReservation bool + + // Whether OOM killer disable is supported or not + OomKillDisable bool + + // Whether memory swappiness is supported or not + MemorySwappiness bool + + // Whether kernel memory limit is supported or not + KernelMemory bool +} + +type cgroupCPUInfo struct { + // Whether CPU shares is supported or not + CPUShares bool + + // Whether CPU CFS(Completely Fair Scheduler) period is supported or not + CPUCfsPeriod bool + + // Whether CPU CFS(Completely Fair Scheduler) quota is supported or not + CPUCfsQuota bool + + // Whether CPU real-time period is supported or not + CPURealtimePeriod bool + + // Whether CPU real-time runtime is supported or not + CPURealtimeRuntime bool +} + +type cgroupBlkioInfo struct { + // Whether Block IO weight is supported or not + BlkioWeight bool + + // Whether Block IO weight_device is supported or not + BlkioWeightDevice bool + + // Whether Block IO read limit in bytes per second is supported or not + BlkioReadBpsDevice bool + + // Whether Block IO write limit in bytes per second is supported or not + BlkioWriteBpsDevice bool + + // Whether Block IO read limit in IO per second is supported or not + BlkioReadIOpsDevice bool + + // Whether Block IO write limit in IO per second is supported or not + BlkioWriteIOpsDevice bool +} + +type cgroupCpusetInfo struct { + // Whether Cpuset is supported or not + Cpuset bool + + // Available Cpuset's cpus + Cpus string + + // Available Cpuset's memory nodes + Mems string +} + +type cgroupPids struct { + // Whether Pids Limit is supported or not + PidsLimit bool +} + +// IsCpusetCpusAvailable returns `true` if the provided string set is contained +// in cgroup's cpuset.cpus set, `false` otherwise. +// If error is not nil a parsing error occurred. +func (c cgroupCpusetInfo) IsCpusetCpusAvailable(provided string) (bool, error) { + return isCpusetListAvailable(provided, c.Cpus) +} + +// IsCpusetMemsAvailable returns `true` if the provided string set is contained +// in cgroup's cpuset.mems set, `false` otherwise. +// If error is not nil a parsing error occurred. +func (c cgroupCpusetInfo) IsCpusetMemsAvailable(provided string) (bool, error) { + return isCpusetListAvailable(provided, c.Mems) +} + +func isCpusetListAvailable(provided, available string) (bool, error) { + parsedProvided, err := parsers.ParseUintList(provided) + if err != nil { + return false, err + } + parsedAvailable, err := parsers.ParseUintList(available) + if err != nil { + return false, err + } + for k := range parsedProvided { + if !parsedAvailable[k] { + return false, nil + } + } + return true, nil +} + +// Returns bit count of 1, used by NumCPU +func popcnt(x uint64) (n byte) { + x -= (x >> 1) & 0x5555555555555555 + x = (x>>2)&0x3333333333333333 + x&0x3333333333333333 + x += x >> 4 + x &= 0x0f0f0f0f0f0f0f0f + x *= 0x0101010101010101 + return byte(x >> 56) +} diff --git a/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_linux.go b/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_linux.go new file mode 100644 index 000000000..471f786a7 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_linux.go @@ -0,0 +1,254 @@ +package sysinfo + +import ( + "fmt" + "io/ioutil" + "os" + "path" + "strings" + + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" +) + +func findCgroupMountpoints() (map[string]string, error) { + cgMounts, err := cgroups.GetCgroupMounts(false) + if err != nil { + return nil, fmt.Errorf("Failed to parse cgroup information: %v", err) + } + mps := make(map[string]string) + for _, m := range cgMounts { + for _, ss := range m.Subsystems { + mps[ss] = m.Mountpoint + } + } + return mps, nil +} + +// New returns a new SysInfo, using the filesystem to detect which features +// the kernel supports. If `quiet` is `false` warnings are printed in logs +// whenever an error occurs or misconfigurations are present. +func New(quiet bool) *SysInfo { + sysInfo := &SysInfo{} + cgMounts, err := findCgroupMountpoints() + if err != nil { + logrus.Warnf("Failed to parse cgroup information: %v", err) + } else { + sysInfo.cgroupMemInfo = checkCgroupMem(cgMounts, quiet) + sysInfo.cgroupCPUInfo = checkCgroupCPU(cgMounts, quiet) + sysInfo.cgroupBlkioInfo = checkCgroupBlkioInfo(cgMounts, quiet) + sysInfo.cgroupCpusetInfo = checkCgroupCpusetInfo(cgMounts, quiet) + sysInfo.cgroupPids = checkCgroupPids(quiet) + } + + _, ok := cgMounts["devices"] + sysInfo.CgroupDevicesEnabled = ok + + sysInfo.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward") + sysInfo.BridgeNFCallIPTablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables") + sysInfo.BridgeNFCallIP6TablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables") + + // Check if AppArmor is supported. + if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) { + sysInfo.AppArmor = true + } + + // Check if Seccomp is supported, via CONFIG_SECCOMP. + if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL { + // Make sure the kernel has CONFIG_SECCOMP_FILTER. + if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL { + sysInfo.Seccomp = true + } + } + + return sysInfo +} + +// checkCgroupMem reads the memory information from the memory cgroup mount point. +func checkCgroupMem(cgMounts map[string]string, quiet bool) cgroupMemInfo { + mountPoint, ok := cgMounts["memory"] + if !ok { + if !quiet { + logrus.Warn("Your kernel does not support cgroup memory limit") + } + return cgroupMemInfo{} + } + + swapLimit := cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes") + if !quiet && !swapLimit { + logrus.Warn("Your kernel does not support swap memory limit") + } + memoryReservation := cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes") + if !quiet && !memoryReservation { + logrus.Warn("Your kernel does not support memory reservation") + } + oomKillDisable := cgroupEnabled(mountPoint, "memory.oom_control") + if !quiet && !oomKillDisable { + logrus.Warn("Your kernel does not support oom control") + } + memorySwappiness := cgroupEnabled(mountPoint, "memory.swappiness") + if !quiet && !memorySwappiness { + logrus.Warn("Your kernel does not support memory swappiness") + } + kernelMemory := cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes") + if !quiet && !kernelMemory { + logrus.Warn("Your kernel does not support kernel memory limit") + } + + return cgroupMemInfo{ + MemoryLimit: true, + SwapLimit: swapLimit, + MemoryReservation: memoryReservation, + OomKillDisable: oomKillDisable, + MemorySwappiness: memorySwappiness, + KernelMemory: kernelMemory, + } +} + +// checkCgroupCPU reads the cpu information from the cpu cgroup mount point. +func checkCgroupCPU(cgMounts map[string]string, quiet bool) cgroupCPUInfo { + mountPoint, ok := cgMounts["cpu"] + if !ok { + if !quiet { + logrus.Warn("Unable to find cpu cgroup in mounts") + } + return cgroupCPUInfo{} + } + + cpuShares := cgroupEnabled(mountPoint, "cpu.shares") + if !quiet && !cpuShares { + logrus.Warn("Your kernel does not support cgroup cpu shares") + } + + cpuCfsPeriod := cgroupEnabled(mountPoint, "cpu.cfs_period_us") + if !quiet && !cpuCfsPeriod { + logrus.Warn("Your kernel does not support cgroup cfs period") + } + + cpuCfsQuota := cgroupEnabled(mountPoint, "cpu.cfs_quota_us") + if !quiet && !cpuCfsQuota { + logrus.Warn("Your kernel does not support cgroup cfs quotas") + } + + cpuRealtimePeriod := cgroupEnabled(mountPoint, "cpu.rt_period_us") + if !quiet && !cpuRealtimePeriod { + logrus.Warn("Your kernel does not support cgroup rt period") + } + + cpuRealtimeRuntime := cgroupEnabled(mountPoint, "cpu.rt_runtime_us") + if !quiet && !cpuRealtimeRuntime { + logrus.Warn("Your kernel does not support cgroup rt runtime") + } + + return cgroupCPUInfo{ + CPUShares: cpuShares, + CPUCfsPeriod: cpuCfsPeriod, + CPUCfsQuota: cpuCfsQuota, + CPURealtimePeriod: cpuRealtimePeriod, + CPURealtimeRuntime: cpuRealtimeRuntime, + } +} + +// checkCgroupBlkioInfo reads the blkio information from the blkio cgroup mount point. +func checkCgroupBlkioInfo(cgMounts map[string]string, quiet bool) cgroupBlkioInfo { + mountPoint, ok := cgMounts["blkio"] + if !ok { + if !quiet { + logrus.Warn("Unable to find blkio cgroup in mounts") + } + return cgroupBlkioInfo{} + } + + weight := cgroupEnabled(mountPoint, "blkio.weight") + if !quiet && !weight { + logrus.Warn("Your kernel does not support cgroup blkio weight") + } + + weightDevice := cgroupEnabled(mountPoint, "blkio.weight_device") + if !quiet && !weightDevice { + logrus.Warn("Your kernel does not support cgroup blkio weight_device") + } + + readBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device") + if !quiet && !readBpsDevice { + logrus.Warn("Your kernel does not support cgroup blkio throttle.read_bps_device") + } + + writeBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device") + if !quiet && !writeBpsDevice { + logrus.Warn("Your kernel does not support cgroup blkio throttle.write_bps_device") + } + readIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device") + if !quiet && !readIOpsDevice { + logrus.Warn("Your kernel does not support cgroup blkio throttle.read_iops_device") + } + + writeIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device") + if !quiet && !writeIOpsDevice { + logrus.Warn("Your kernel does not support cgroup blkio throttle.write_iops_device") + } + return cgroupBlkioInfo{ + BlkioWeight: weight, + BlkioWeightDevice: weightDevice, + BlkioReadBpsDevice: readBpsDevice, + BlkioWriteBpsDevice: writeBpsDevice, + BlkioReadIOpsDevice: readIOpsDevice, + BlkioWriteIOpsDevice: writeIOpsDevice, + } +} + +// checkCgroupCpusetInfo reads the cpuset information from the cpuset cgroup mount point. +func checkCgroupCpusetInfo(cgMounts map[string]string, quiet bool) cgroupCpusetInfo { + mountPoint, ok := cgMounts["cpuset"] + if !ok { + if !quiet { + logrus.Warn("Unable to find cpuset cgroup in mounts") + } + return cgroupCpusetInfo{} + } + + cpus, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.cpus")) + if err != nil { + return cgroupCpusetInfo{} + } + + mems, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.mems")) + if err != nil { + return cgroupCpusetInfo{} + } + + return cgroupCpusetInfo{ + Cpuset: true, + Cpus: strings.TrimSpace(string(cpus)), + Mems: strings.TrimSpace(string(mems)), + } +} + +// checkCgroupPids reads the pids information from the pids cgroup mount point. +func checkCgroupPids(quiet bool) cgroupPids { + _, err := cgroups.FindCgroupMountpoint("pids") + if err != nil { + if !quiet { + logrus.Warn(err) + } + return cgroupPids{} + } + + return cgroupPids{ + PidsLimit: true, + } +} + +func cgroupEnabled(mountPoint, name string) bool { + _, err := os.Stat(path.Join(mountPoint, name)) + return err == nil +} + +func readProcBool(path string) bool { + val, err := ioutil.ReadFile(path) + if err != nil { + return false + } + return strings.TrimSpace(string(val)) == "1" +} diff --git a/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_unix.go b/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_unix.go new file mode 100644 index 000000000..beac32840 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_unix.go @@ -0,0 +1,9 @@ +// +build !linux,!windows + +package sysinfo + +// New returns an empty SysInfo for non linux for now. +func New(quiet bool) *SysInfo { + sysInfo := &SysInfo{} + return sysInfo +} diff --git a/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_windows.go b/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_windows.go new file mode 100644 index 000000000..4e6255bc5 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_windows.go @@ -0,0 +1,9 @@ +// +build windows + +package sysinfo + +// New returns an empty SysInfo for windows for now. +func New(quiet bool) *SysInfo { + sysInfo := &SysInfo{} + return sysInfo +} diff --git a/vendor/github.com/docker/docker/pkg/system/events_windows.go b/vendor/github.com/docker/docker/pkg/system/events_windows.go deleted file mode 100644 index 192e36788..000000000 --- a/vendor/github.com/docker/docker/pkg/system/events_windows.go +++ /dev/null @@ -1,85 +0,0 @@ -package system - -// This file implements syscalls for Win32 events which are not implemented -// in golang. - -import ( - "syscall" - "unsafe" - - "golang.org/x/sys/windows" -) - -var ( - procCreateEvent = modkernel32.NewProc("CreateEventW") - procOpenEvent = modkernel32.NewProc("OpenEventW") - procSetEvent = modkernel32.NewProc("SetEvent") - procResetEvent = modkernel32.NewProc("ResetEvent") - procPulseEvent = modkernel32.NewProc("PulseEvent") -) - -// CreateEvent implements win32 CreateEventW func in golang. It will create an event object. -func CreateEvent(eventAttributes *windows.SecurityAttributes, manualReset bool, initialState bool, name string) (handle windows.Handle, err error) { - namep, _ := windows.UTF16PtrFromString(name) - var _p1 uint32 - if manualReset { - _p1 = 1 - } - var _p2 uint32 - if initialState { - _p2 = 1 - } - r0, _, e1 := procCreateEvent.Call(uintptr(unsafe.Pointer(eventAttributes)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(namep))) - use(unsafe.Pointer(namep)) - handle = windows.Handle(r0) - if handle == windows.InvalidHandle { - err = e1 - } - return -} - -// OpenEvent implements win32 OpenEventW func in golang. It opens an event object. -func OpenEvent(desiredAccess uint32, inheritHandle bool, name string) (handle windows.Handle, err error) { - namep, _ := windows.UTF16PtrFromString(name) - var _p1 uint32 - if inheritHandle { - _p1 = 1 - } - r0, _, e1 := procOpenEvent.Call(uintptr(desiredAccess), uintptr(_p1), uintptr(unsafe.Pointer(namep))) - use(unsafe.Pointer(namep)) - handle = windows.Handle(r0) - if handle == windows.InvalidHandle { - err = e1 - } - return -} - -// SetEvent implements win32 SetEvent func in golang. -func SetEvent(handle windows.Handle) (err error) { - return setResetPulse(handle, procSetEvent) -} - -// ResetEvent implements win32 ResetEvent func in golang. -func ResetEvent(handle windows.Handle) (err error) { - return setResetPulse(handle, procResetEvent) -} - -// PulseEvent implements win32 PulseEvent func in golang. -func PulseEvent(handle windows.Handle) (err error) { - return setResetPulse(handle, procPulseEvent) -} - -func setResetPulse(handle windows.Handle, proc *windows.LazyProc) (err error) { - r0, _, _ := proc.Call(uintptr(handle)) - if r0 != 0 { - err = syscall.Errno(r0) - } - return -} - -var temp unsafe.Pointer - -// use ensures a variable is kept alive without the GC freeing while still needed -func use(p unsafe.Pointer) { - temp = p -} diff --git a/vendor/github.com/docker/docker/pkg/system/exitcode.go b/vendor/github.com/docker/docker/pkg/system/exitcode.go index 60f0514b1..a5e5616c4 100644 --- a/vendor/github.com/docker/docker/pkg/system/exitcode.go +++ b/vendor/github.com/docker/docker/pkg/system/exitcode.go @@ -17,17 +17,3 @@ func GetExitCode(err error) (int, error) { } return exitCode, fmt.Errorf("failed to get exit code") } - -// ProcessExitCode process the specified error and returns the exit status code -// if the error was of type exec.ExitError, returns nothing otherwise. -func ProcessExitCode(err error) (exitCode int) { - if err != nil { - var exiterr error - if exitCode, exiterr = GetExitCode(err); exiterr != nil { - // TODO: Fix this so we check the error's text. - // we've failed to retrieve exit code, so we set it to 127 - exitCode = 127 - } - } - return -} diff --git a/vendor/github.com/docker/docker/pkg/system/init_unix.go b/vendor/github.com/docker/docker/pkg/system/init_unix.go new file mode 100644 index 000000000..a219895e6 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/init_unix.go @@ -0,0 +1,7 @@ +// +build !windows + +package system + +// InitLCOW does nothing since LCOW is a windows only feature +func InitLCOW(experimental bool) { +} diff --git a/vendor/github.com/docker/docker/pkg/system/init_windows.go b/vendor/github.com/docker/docker/pkg/system/init_windows.go index 019c66441..75f8f2c06 100644 --- a/vendor/github.com/docker/docker/pkg/system/init_windows.go +++ b/vendor/github.com/docker/docker/pkg/system/init_windows.go @@ -2,16 +2,16 @@ package system import "os" -// LCOWSupported determines if Linux Containers on Windows are supported. -// Note: This feature is in development (06/17) and enabled through an -// environment variable. At a future time, it will be enabled based -// on build number. @jhowardmsft +// lcowSupported determines if Linux Containers on Windows are supported. var lcowSupported = false -func init() { - // LCOW initialization - if os.Getenv("LCOW_SUPPORTED") != "" { +// InitLCOW sets whether LCOW is supported or not +// TODO @jhowardmsft. +// 1. Replace with RS3 RTM build number. +// 2. Remove the getenv check when image-store is coalesced as shouldn't be needed anymore. +func InitLCOW(experimental bool) { + v := GetOSVersion() + if experimental && v.Build > 16270 && os.Getenv("LCOW_SUPPORTED") != "" { lcowSupported = true } - } diff --git a/vendor/github.com/docker/docker/pkg/system/lcow.go b/vendor/github.com/docker/docker/pkg/system/lcow.go new file mode 100644 index 000000000..b88c11e31 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/lcow.go @@ -0,0 +1,58 @@ +package system + +import ( + "fmt" + "runtime" + "strings" + + specs "github.com/opencontainers/image-spec/specs-go/v1" +) + +// ValidatePlatform determines if a platform structure is valid. +// TODO This is a temporary function - can be replaced by parsing from +// https://github.com/containerd/containerd/pull/1403/files at a later date. +// @jhowardmsft +func ValidatePlatform(platform *specs.Platform) error { + platform.Architecture = strings.ToLower(platform.Architecture) + platform.OS = strings.ToLower(platform.OS) + // Based on https://github.com/moby/moby/pull/34642#issuecomment-330375350, do + // not support anything except operating system. + if platform.Architecture != "" { + return fmt.Errorf("invalid platform architecture %q", platform.Architecture) + } + if platform.OS != "" { + if !(platform.OS == runtime.GOOS || (LCOWSupported() && platform.OS == "linux")) { + return fmt.Errorf("invalid platform os %q", platform.OS) + } + } + if len(platform.OSFeatures) != 0 { + return fmt.Errorf("invalid platform osfeatures %q", platform.OSFeatures) + } + if platform.OSVersion != "" { + return fmt.Errorf("invalid platform osversion %q", platform.OSVersion) + } + if platform.Variant != "" { + return fmt.Errorf("invalid platform variant %q", platform.Variant) + } + return nil +} + +// ParsePlatform parses a platform string in the format os[/arch[/variant] +// into an OCI image-spec platform structure. +// TODO This is a temporary function - can be replaced by parsing from +// https://github.com/containerd/containerd/pull/1403/files at a later date. +// @jhowardmsft +func ParsePlatform(in string) *specs.Platform { + p := &specs.Platform{} + elements := strings.SplitN(strings.ToLower(in), "/", 3) + if len(elements) == 3 { + p.Variant = elements[2] + } + if len(elements) >= 2 { + p.Architecture = elements[1] + } + if len(elements) >= 1 { + p.OS = elements[0] + } + return p +} diff --git a/vendor/github.com/docker/docker/pkg/system/meminfo_solaris.go b/vendor/github.com/docker/docker/pkg/system/meminfo_solaris.go deleted file mode 100644 index 925776e78..000000000 --- a/vendor/github.com/docker/docker/pkg/system/meminfo_solaris.go +++ /dev/null @@ -1,129 +0,0 @@ -// +build solaris,cgo - -package system - -import ( - "fmt" - "unsafe" -) - -// #cgo CFLAGS: -std=c99 -// #cgo LDFLAGS: -lkstat -// #include <unistd.h> -// #include <stdlib.h> -// #include <stdio.h> -// #include <kstat.h> -// #include <sys/swap.h> -// #include <sys/param.h> -// struct swaptable *allocSwaptable(int num) { -// struct swaptable *st; -// struct swapent *swapent; -// st = (struct swaptable *)malloc(num * sizeof(swapent_t) + sizeof (int)); -// swapent = st->swt_ent; -// for (int i = 0; i < num; i++,swapent++) { -// swapent->ste_path = (char *)malloc(MAXPATHLEN * sizeof (char)); -// } -// st->swt_n = num; -// return st; -//} -// void freeSwaptable (struct swaptable *st) { -// struct swapent *swapent = st->swt_ent; -// for (int i = 0; i < st->swt_n; i++,swapent++) { -// free(swapent->ste_path); -// } -// free(st); -// } -// swapent_t getSwapEnt(swapent_t *ent, int i) { -// return ent[i]; -// } -// int64_t getPpKernel() { -// int64_t pp_kernel = 0; -// kstat_ctl_t *ksc; -// kstat_t *ks; -// kstat_named_t *knp; -// kid_t kid; -// -// if ((ksc = kstat_open()) == NULL) { -// return -1; -// } -// if ((ks = kstat_lookup(ksc, "unix", 0, "system_pages")) == NULL) { -// return -1; -// } -// if (((kid = kstat_read(ksc, ks, NULL)) == -1) || -// ((knp = kstat_data_lookup(ks, "pp_kernel")) == NULL)) { -// return -1; -// } -// switch (knp->data_type) { -// case KSTAT_DATA_UINT64: -// pp_kernel = knp->value.ui64; -// break; -// case KSTAT_DATA_UINT32: -// pp_kernel = knp->value.ui32; -// break; -// } -// pp_kernel *= sysconf(_SC_PAGESIZE); -// return (pp_kernel > 0 ? pp_kernel : -1); -// } -import "C" - -// Get the system memory info using sysconf same as prtconf -func getTotalMem() int64 { - pagesize := C.sysconf(C._SC_PAGESIZE) - npages := C.sysconf(C._SC_PHYS_PAGES) - return int64(pagesize * npages) -} - -func getFreeMem() int64 { - pagesize := C.sysconf(C._SC_PAGESIZE) - npages := C.sysconf(C._SC_AVPHYS_PAGES) - return int64(pagesize * npages) -} - -// ReadMemInfo retrieves memory statistics of the host system and returns a -// MemInfo type. -func ReadMemInfo() (*MemInfo, error) { - - ppKernel := C.getPpKernel() - MemTotal := getTotalMem() - MemFree := getFreeMem() - SwapTotal, SwapFree, err := getSysSwap() - - if ppKernel < 0 || MemTotal < 0 || MemFree < 0 || SwapTotal < 0 || - SwapFree < 0 { - return nil, fmt.Errorf("error getting system memory info %v\n", err) - } - - meminfo := &MemInfo{} - // Total memory is total physical memory less than memory locked by kernel - meminfo.MemTotal = MemTotal - int64(ppKernel) - meminfo.MemFree = MemFree - meminfo.SwapTotal = SwapTotal - meminfo.SwapFree = SwapFree - - return meminfo, nil -} - -func getSysSwap() (int64, int64, error) { - var tSwap int64 - var fSwap int64 - var diskblksPerPage int64 - num, err := C.swapctl(C.SC_GETNSWP, nil) - if err != nil { - return -1, -1, err - } - st := C.allocSwaptable(num) - _, err = C.swapctl(C.SC_LIST, unsafe.Pointer(st)) - if err != nil { - C.freeSwaptable(st) - return -1, -1, err - } - - diskblksPerPage = int64(C.sysconf(C._SC_PAGESIZE) >> C.DEV_BSHIFT) - for i := 0; i < int(num); i++ { - swapent := C.getSwapEnt(&st.swt_ent[0], C.int(i)) - tSwap += int64(swapent.ste_pages) * diskblksPerPage - fSwap += int64(swapent.ste_free) * diskblksPerPage - } - C.freeSwaptable(st) - return tSwap, fSwap, nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go b/vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go index 3ce019dff..82ddd30c1 100644 --- a/vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go +++ b/vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!windows,!solaris +// +build !linux,!windows package system diff --git a/vendor/github.com/docker/docker/pkg/system/mknod.go b/vendor/github.com/docker/docker/pkg/system/mknod.go index af79a6538..2200ec42d 100644 --- a/vendor/github.com/docker/docker/pkg/system/mknod.go +++ b/vendor/github.com/docker/docker/pkg/system/mknod.go @@ -18,5 +18,5 @@ func Mknod(path string, mode uint32, dev int) error { // They are, from low to high: the lower 8 bits of the minor, then 12 bits of the major, // then the top 12 bits of the minor. func Mkdev(major int64, minor int64) uint32 { - return uint32(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff)) + return uint32(unix.Mkdev(uint32(major), uint32(minor))) } diff --git a/vendor/github.com/docker/docker/pkg/system/path.go b/vendor/github.com/docker/docker/pkg/system/path.go index f634a6be6..034c33c87 100644 --- a/vendor/github.com/docker/docker/pkg/system/path.go +++ b/vendor/github.com/docker/docker/pkg/system/path.go @@ -1,15 +1,22 @@ package system -import "runtime" +import ( + "fmt" + "path/filepath" + "runtime" + "strings" + + "github.com/containerd/continuity/pathdriver" +) const defaultUnixPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" // DefaultPathEnv is unix style list of directories to search for // executables. Each directory is separated from the next by a colon // ':' character . -func DefaultPathEnv(platform string) string { +func DefaultPathEnv(os string) string { if runtime.GOOS == "windows" { - if platform != runtime.GOOS && LCOWSupported() { + if os != runtime.GOOS { return defaultUnixPathEnv } // Deliberately empty on Windows containers on Windows as the default path will be set by @@ -19,3 +26,35 @@ func DefaultPathEnv(platform string) string { return defaultUnixPathEnv } + +// CheckSystemDriveAndRemoveDriveLetter verifies that a path, if it includes a drive letter, +// is the system drive. +// On Linux: this is a no-op. +// On Windows: this does the following> +// CheckSystemDriveAndRemoveDriveLetter verifies and manipulates a Windows path. +// This is used, for example, when validating a user provided path in docker cp. +// If a drive letter is supplied, it must be the system drive. The drive letter +// is always removed. Also, it translates it to OS semantics (IOW / to \). We +// need the path in this syntax so that it can ultimately be contatenated with +// a Windows long-path which doesn't support drive-letters. Examples: +// C: --> Fail +// C:\ --> \ +// a --> a +// /a --> \a +// d:\ --> Fail +func CheckSystemDriveAndRemoveDriveLetter(path string, driver pathdriver.PathDriver) (string, error) { + if runtime.GOOS != "windows" || LCOWSupported() { + return path, nil + } + + if len(path) == 2 && string(path[1]) == ":" { + return "", fmt.Errorf("No relative path specified in %q", path) + } + if !driver.IsAbs(path) || len(path) < 2 { + return filepath.FromSlash(path), nil + } + if string(path[1]) == ":" && !strings.EqualFold(string(path[0]), "c") { + return "", fmt.Errorf("The specified path is not on the system drive (C:)") + } + return filepath.FromSlash(path[2:]), nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/path_unix.go b/vendor/github.com/docker/docker/pkg/system/path_unix.go deleted file mode 100644 index f3762e69d..000000000 --- a/vendor/github.com/docker/docker/pkg/system/path_unix.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build !windows - -package system - -// CheckSystemDriveAndRemoveDriveLetter verifies that a path, if it includes a drive letter, -// is the system drive. This is a no-op on Linux. -func CheckSystemDriveAndRemoveDriveLetter(path string) (string, error) { - return path, nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/path_windows.go b/vendor/github.com/docker/docker/pkg/system/path_windows.go deleted file mode 100644 index aab891522..000000000 --- a/vendor/github.com/docker/docker/pkg/system/path_windows.go +++ /dev/null @@ -1,33 +0,0 @@ -// +build windows - -package system - -import ( - "fmt" - "path/filepath" - "strings" -) - -// CheckSystemDriveAndRemoveDriveLetter verifies and manipulates a Windows path. -// This is used, for example, when validating a user provided path in docker cp. -// If a drive letter is supplied, it must be the system drive. The drive letter -// is always removed. Also, it translates it to OS semantics (IOW / to \). We -// need the path in this syntax so that it can ultimately be concatenated with -// a Windows long-path which doesn't support drive-letters. Examples: -// C: --> Fail -// C:\ --> \ -// a --> a -// /a --> \a -// d:\ --> Fail -func CheckSystemDriveAndRemoveDriveLetter(path string) (string, error) { - if len(path) == 2 && string(path[1]) == ":" { - return "", fmt.Errorf("No relative path specified in %q", path) - } - if !filepath.IsAbs(path) || len(path) < 2 { - return filepath.FromSlash(path), nil - } - if string(path[1]) == ":" && !strings.EqualFold(string(path[0]), "c") { - return "", fmt.Errorf("The specified path is not on the system drive (C:)") - } - return filepath.FromSlash(path[2:]), nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/process_unix.go b/vendor/github.com/docker/docker/pkg/system/process_unix.go index 26c8b42c1..02c138235 100644 --- a/vendor/github.com/docker/docker/pkg/system/process_unix.go +++ b/vendor/github.com/docker/docker/pkg/system/process_unix.go @@ -1,4 +1,4 @@ -// +build linux freebsd solaris darwin +// +build linux freebsd darwin package system diff --git a/vendor/github.com/docker/docker/pkg/system/process_windows.go b/vendor/github.com/docker/docker/pkg/system/process_windows.go new file mode 100644 index 000000000..5973c46de --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/process_windows.go @@ -0,0 +1,18 @@ +package system + +import "os" + +// IsProcessAlive returns true if process with a given pid is running. +func IsProcessAlive(pid int) bool { + _, err := os.FindProcess(pid) + + return err == nil +} + +// KillProcess force-stops a process. +func KillProcess(pid int) { + p, err := os.FindProcess(pid) + if err == nil { + p.Kill() + } +} diff --git a/vendor/github.com/docker/docker/pkg/system/rm.go b/vendor/github.com/docker/docker/pkg/system/rm.go index 101b569a5..c453adcdb 100644 --- a/vendor/github.com/docker/docker/pkg/system/rm.go +++ b/vendor/github.com/docker/docker/pkg/system/rm.go @@ -26,7 +26,7 @@ func EnsureRemoveAll(dir string) error { // track retries exitOnErr := make(map[string]int) - maxRetry := 5 + maxRetry := 50 // Attempt to unmount anything beneath this dir first mount.RecursiveUnmount(dir) diff --git a/vendor/github.com/docker/docker/pkg/system/stat_linux.go b/vendor/github.com/docker/docker/pkg/system/stat_linux.go index 66bf6e28e..1939f9518 100644 --- a/vendor/github.com/docker/docker/pkg/system/stat_linux.go +++ b/vendor/github.com/docker/docker/pkg/system/stat_linux.go @@ -5,10 +5,10 @@ import "syscall" // fromStatT converts a syscall.Stat_t type to a system.Stat_t type func fromStatT(s *syscall.Stat_t) (*StatT, error) { return &StatT{size: s.Size, - mode: uint32(s.Mode), + mode: s.Mode, uid: s.Uid, gid: s.Gid, - rdev: uint64(s.Rdev), + rdev: s.Rdev, mtim: s.Mtim}, nil } diff --git a/vendor/github.com/docker/docker/pkg/term/ascii.go b/vendor/github.com/docker/docker/pkg/term/ascii.go index f5262bccf..55873c055 100644 --- a/vendor/github.com/docker/docker/pkg/term/ascii.go +++ b/vendor/github.com/docker/docker/pkg/term/ascii.go @@ -59,7 +59,7 @@ next: return nil, fmt.Errorf("Unknown character: '%s'", key) } } else { - codes = append(codes, byte(key[0])) + codes = append(codes, key[0]) } } return codes, nil diff --git a/vendor/github.com/docker/docker/pkg/term/tc.go b/vendor/github.com/docker/docker/pkg/term/tc.go index 6d2dfd3a8..19dbb1cb1 100644 --- a/vendor/github.com/docker/docker/pkg/term/tc.go +++ b/vendor/github.com/docker/docker/pkg/term/tc.go @@ -1,5 +1,4 @@ // +build !windows -// +build !solaris !cgo package term diff --git a/vendor/github.com/docker/docker/pkg/term/tc_solaris_cgo.go b/vendor/github.com/docker/docker/pkg/term/tc_solaris_cgo.go deleted file mode 100644 index 50234affc..000000000 --- a/vendor/github.com/docker/docker/pkg/term/tc_solaris_cgo.go +++ /dev/null @@ -1,65 +0,0 @@ -// +build solaris,cgo - -package term - -import ( - "syscall" - "unsafe" - - "golang.org/x/sys/unix" -) - -// #include <termios.h> -import "C" - -// Termios is the Unix API for terminal I/O. -// It is passthrough for unix.Termios in order to make it portable with -// other platforms where it is not available or handled differently. -type Termios unix.Termios - -// MakeRaw put the terminal connected to the given file descriptor into raw -// mode and returns the previous state of the terminal so that it can be -// restored. -func MakeRaw(fd uintptr) (*State, error) { - var oldState State - if err := tcget(fd, &oldState.termios); err != 0 { - return nil, err - } - - newState := oldState.termios - - newState.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON | unix.IXANY) - newState.Oflag &^= unix.OPOST - newState.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN) - newState.Cflag &^= (unix.CSIZE | unix.PARENB) - newState.Cflag |= unix.CS8 - - /* - VMIN is the minimum number of characters that needs to be read in non-canonical mode for it to be returned - Since VMIN is overloaded with another element in canonical mode when we switch modes it defaults to 4. It - needs to be explicitly set to 1. - */ - newState.Cc[C.VMIN] = 1 - newState.Cc[C.VTIME] = 0 - - if err := tcset(fd, &newState); err != 0 { - return nil, err - } - return &oldState, nil -} - -func tcget(fd uintptr, p *Termios) syscall.Errno { - ret, err := C.tcgetattr(C.int(fd), (*C.struct_termios)(unsafe.Pointer(p))) - if ret != 0 { - return err.(syscall.Errno) - } - return 0 -} - -func tcset(fd uintptr, p *Termios) syscall.Errno { - ret, err := C.tcsetattr(C.int(fd), C.TCSANOW, (*C.struct_termios)(unsafe.Pointer(p))) - if ret != 0 { - return err.(syscall.Errno) - } - return 0 -} diff --git a/vendor/github.com/docker/docker/pkg/term/term_windows.go b/vendor/github.com/docker/docker/pkg/term/term_windows.go index c0332c3cd..b6819b342 100644 --- a/vendor/github.com/docker/docker/pkg/term/term_windows.go +++ b/vendor/github.com/docker/docker/pkg/term/term_windows.go @@ -23,14 +23,7 @@ type Winsize struct { Width uint16 } -const ( - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx - enableVirtualTerminalInput = 0x0200 - enableVirtualTerminalProcessing = 0x0004 - disableNewlineAutoReturn = 0x0008 -) - -// vtInputSupported is true if enableVirtualTerminalInput is supported by the console +// vtInputSupported is true if winterm.ENABLE_VIRTUAL_TERMINAL_INPUT is supported by the console var vtInputSupported bool // StdStreams returns the standard streams (stdin, stdout, stderr). @@ -40,8 +33,8 @@ func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) { var emulateStdin, emulateStdout, emulateStderr bool fd := os.Stdin.Fd() if mode, err := winterm.GetConsoleMode(fd); err == nil { - // Validate that enableVirtualTerminalInput is supported, but do not set it. - if err = winterm.SetConsoleMode(fd, mode|enableVirtualTerminalInput); err != nil { + // Validate that winterm.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it. + if err = winterm.SetConsoleMode(fd, mode|winterm.ENABLE_VIRTUAL_TERMINAL_INPUT); err != nil { emulateStdin = true } else { vtInputSupported = true @@ -53,21 +46,21 @@ func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) { fd = os.Stdout.Fd() if mode, err := winterm.GetConsoleMode(fd); err == nil { - // Validate disableNewlineAutoReturn is supported, but do not set it. - if err = winterm.SetConsoleMode(fd, mode|enableVirtualTerminalProcessing|disableNewlineAutoReturn); err != nil { + // Validate winterm.DISABLE_NEWLINE_AUTO_RETURN is supported, but do not set it. + if err = winterm.SetConsoleMode(fd, mode|winterm.ENABLE_VIRTUAL_TERMINAL_PROCESSING|winterm.DISABLE_NEWLINE_AUTO_RETURN); err != nil { emulateStdout = true } else { - winterm.SetConsoleMode(fd, mode|enableVirtualTerminalProcessing) + winterm.SetConsoleMode(fd, mode|winterm.ENABLE_VIRTUAL_TERMINAL_PROCESSING) } } fd = os.Stderr.Fd() if mode, err := winterm.GetConsoleMode(fd); err == nil { - // Validate disableNewlineAutoReturn is supported, but do not set it. - if err = winterm.SetConsoleMode(fd, mode|enableVirtualTerminalProcessing|disableNewlineAutoReturn); err != nil { + // Validate winterm.DISABLE_NEWLINE_AUTO_RETURN is supported, but do not set it. + if err = winterm.SetConsoleMode(fd, mode|winterm.ENABLE_VIRTUAL_TERMINAL_PROCESSING|winterm.DISABLE_NEWLINE_AUTO_RETURN); err != nil { emulateStderr = true } else { - winterm.SetConsoleMode(fd, mode|enableVirtualTerminalProcessing) + winterm.SetConsoleMode(fd, mode|winterm.ENABLE_VIRTUAL_TERMINAL_PROCESSING) } } @@ -183,9 +176,9 @@ func SetRawTerminalOutput(fd uintptr) (*State, error) { return nil, err } - // Ignore failures, since disableNewlineAutoReturn might not be supported on this + // Ignore failures, since winterm.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this // version of Windows. - winterm.SetConsoleMode(fd, state.mode|disableNewlineAutoReturn) + winterm.SetConsoleMode(fd, state.mode|winterm.DISABLE_NEWLINE_AUTO_RETURN) return state, err } @@ -215,7 +208,7 @@ func MakeRaw(fd uintptr) (*State, error) { mode |= winterm.ENABLE_INSERT_MODE mode |= winterm.ENABLE_QUICK_EDIT_MODE if vtInputSupported { - mode |= enableVirtualTerminalInput + mode |= winterm.ENABLE_VIRTUAL_TERMINAL_INPUT } err = winterm.SetConsoleMode(fd, mode) diff --git a/vendor/github.com/docker/docker/pkg/term/termios_linux.go b/vendor/github.com/docker/docker/pkg/term/termios_linux.go index 3e25eb7a4..0f21abcc2 100644 --- a/vendor/github.com/docker/docker/pkg/term/termios_linux.go +++ b/vendor/github.com/docker/docker/pkg/term/termios_linux.go @@ -29,6 +29,8 @@ func MakeRaw(fd uintptr) (*State, error) { termios.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN) termios.Cflag &^= (unix.CSIZE | unix.PARENB) termios.Cflag |= unix.CS8 + termios.Cc[unix.VMIN] = 1 + termios.Cc[unix.VTIME] = 0 if err := unix.IoctlSetTermios(int(fd), setTermios, termios); err != nil { return nil, err diff --git a/vendor/github.com/docker/docker/pkg/term/winsize.go b/vendor/github.com/docker/docker/pkg/term/winsize.go index f58367fe6..1ef98d599 100644 --- a/vendor/github.com/docker/docker/pkg/term/winsize.go +++ b/vendor/github.com/docker/docker/pkg/term/winsize.go @@ -1,30 +1,20 @@ -// +build !solaris,!windows +// +build !windows package term import ( - "unsafe" - "golang.org/x/sys/unix" ) // GetWinsize returns the window size based on the specified file descriptor. func GetWinsize(fd uintptr) (*Winsize, error) { - ws := &Winsize{} - _, _, err := unix.Syscall(unix.SYS_IOCTL, fd, uintptr(unix.TIOCGWINSZ), uintptr(unsafe.Pointer(ws))) - // Skipp errno = 0 - if err == 0 { - return ws, nil - } + uws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ) + ws := &Winsize{Height: uws.Row, Width: uws.Col, x: uws.Xpixel, y: uws.Ypixel} return ws, err } // SetWinsize tries to set the specified window size for the specified file descriptor. func SetWinsize(fd uintptr, ws *Winsize) error { - _, _, err := unix.Syscall(unix.SYS_IOCTL, fd, uintptr(unix.TIOCSWINSZ), uintptr(unsafe.Pointer(ws))) - // Skipp errno = 0 - if err == 0 { - return nil - } - return err + uws := &unix.Winsize{Row: ws.Height, Col: ws.Width, Xpixel: ws.x, Ypixel: ws.y} + return unix.IoctlSetWinsize(int(fd), unix.TIOCSWINSZ, uws) } diff --git a/vendor/github.com/docker/docker/pkg/term/winsize_solaris_cgo.go b/vendor/github.com/docker/docker/pkg/term/winsize_solaris_cgo.go deleted file mode 100644 index 39c1d3207..000000000 --- a/vendor/github.com/docker/docker/pkg/term/winsize_solaris_cgo.go +++ /dev/null @@ -1,42 +0,0 @@ -// +build solaris,cgo - -package term - -import ( - "unsafe" - - "golang.org/x/sys/unix" -) - -/* -#include <unistd.h> -#include <stropts.h> -#include <termios.h> - -// Small wrapper to get rid of variadic args of ioctl() -int my_ioctl(int fd, int cmd, struct winsize *ws) { - return ioctl(fd, cmd, ws); -} -*/ -import "C" - -// GetWinsize returns the window size based on the specified file descriptor. -func GetWinsize(fd uintptr) (*Winsize, error) { - ws := &Winsize{} - ret, err := C.my_ioctl(C.int(fd), C.int(unix.TIOCGWINSZ), (*C.struct_winsize)(unsafe.Pointer(ws))) - // Skip retval = 0 - if ret == 0 { - return ws, nil - } - return ws, err -} - -// SetWinsize tries to set the specified window size for the specified file descriptor. -func SetWinsize(fd uintptr, ws *Winsize) error { - ret, err := C.my_ioctl(C.int(fd), C.int(unix.TIOCSWINSZ), (*C.struct_winsize)(unsafe.Pointer(ws))) - // Skip retval = 0 - if ret == 0 { - return nil - } - return err -} diff --git a/vendor/github.com/docker/docker/pkg/tlsconfig/tlsconfig_clone.go b/vendor/github.com/docker/docker/pkg/tlsconfig/tlsconfig_clone.go deleted file mode 100644 index e4dec3a5d..000000000 --- a/vendor/github.com/docker/docker/pkg/tlsconfig/tlsconfig_clone.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build go1.8 - -package tlsconfig - -import "crypto/tls" - -// Clone returns a clone of tls.Config. This function is provided for -// compatibility for go1.7 that doesn't include this method in stdlib. -func Clone(c *tls.Config) *tls.Config { - return c.Clone() -} diff --git a/vendor/github.com/docker/docker/vendor.conf b/vendor/github.com/docker/docker/vendor.conf index 7608b0e33..448792524 100644 --- a/vendor/github.com/docker/docker/vendor.conf +++ b/vendor/github.com/docker/docker/vendor.conf @@ -1,33 +1,36 @@ # the following lines are in sorted order, FYI -github.com/Azure/go-ansiterm 19f72df4d05d31cbe1c56bfc8045c96babff6c7e -github.com/Microsoft/hcsshim v0.6.2 -github.com/Microsoft/go-winio v0.4.4 -github.com/moby/buildkit da2b9dc7dab99e824b2b1067ad7d0523e32dd2d9 https://github.com/dmcgowan/buildkit.git +github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109 +github.com/Microsoft/hcsshim v0.6.7 +github.com/Microsoft/go-winio v0.4.5 github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76 github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git github.com/gorilla/context v1.1 github.com/gorilla/mux v1.1 -github.com/jhowardmsft/opengcs v0.0.12 +github.com/Microsoft/opengcs v0.3.4 github.com/kr/pty 5cf931ef8f github.com/mattn/go-shellwords v1.0.3 -github.com/sirupsen/logrus v1.0.1 +github.com/sirupsen/logrus v1.0.3 github.com/tchap/go-patricia v2.2.6 github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3 golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6 -golang.org/x/sys 739734461d1c916b6c72a63d7efda2b27edb369f +golang.org/x/sys 95c6576299259db960f6c5b9b69ea52422860fce github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1 github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756 github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987 github.com/pmezard/go-difflib v1.0.0 +github.com/gotestyourself/gotestyourself v1.1.0 github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5 github.com/imdario/mergo 0.2.1 golang.org/x/sync de49d9dcd27d4f764488181bea099dfe6179bcf0 +github.com/moby/buildkit aaff9d591ef128560018433fe61beb802e149de8 +github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2 + #get libnetwork packages -github.com/docker/libnetwork 248fd5ea6a67f8810da322e6e7441e8de96a9045 https://github.com/dmcgowan/libnetwork.git +github.com/docker/libnetwork 72fd7e5495eba86e28012e39b5ed63ef9ca9a97b github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec @@ -52,7 +55,7 @@ github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7 # get graph and distribution packages github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c -github.com/vbatts/tar-split v0.10.1 +github.com/vbatts/tar-split v0.10.2 github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb # get go-zfs packages @@ -62,20 +65,19 @@ github.com/pborman/uuid v1.0 google.golang.org/grpc v1.3.0 # When updating, also update RUNC_COMMIT in hack/dockerfile/binaries-commits accordingly -github.com/opencontainers/runc e9325d442f5979c4f79bfa9e09bdf7abb74ba03b https://github.com/dmcgowan/runc.git -github.com/opencontainers/image-spec 372ad780f63454fbbbbcc7cf80e5b90245c13e13 -github.com/opencontainers/runtime-spec d42f1eb741e6361e858d83fc75aa6893b66292c4 # specs - +github.com/opencontainers/runc b2567b37d7b75eb4cf325b77297b140ea686ce8f +github.com/opencontainers/runtime-spec v1.0.0 +github.com/opencontainers/image-spec v1.0.0 github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0 # libcontainer deps (see src/github.com/opencontainers/runc/Godeps/Godeps.json) -github.com/coreos/go-systemd v4 +github.com/coreos/go-systemd v15 github.com/godbus/dbus v4.0.0 github.com/syndtr/gocapability 2c00daeb6c3b45114c80ac44119e7b8801fdd852 github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4 # gelf logging driver deps -github.com/Graylog2/go-gelf 7029da823dad4ef3a876df61065156acb703b2ea +github.com/Graylog2/go-gelf v2 github.com/fluent/fluent-logger-golang v1.2.1 # fluent-logger-golang deps @@ -83,7 +85,7 @@ github.com/philhofer/fwd 98c11a7a6ec829d672b03833c3d69a7fae1ca972 github.com/tinylib/msgp 75ee40d2601edf122ef667e2a07d600d4c44490c # fsnotify -github.com/fsnotify/fsnotify v1.4.2 +github.com/fsnotify/fsnotify 4da3e2cfbabc9f751898f250b49f2439785783a1 # awslogs deps github.com/aws/aws-sdk-go v1.4.22 @@ -101,17 +103,21 @@ github.com/googleapis/gax-go da06d194a00e19ce00d9011a13931c3f6f6887c7 google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944 # containerd -github.com/containerd/containerd fc10004571bb9b26695ccbf2dd4a83213f60b93e https://github.com/dmcgowan/containerd.git -github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4 -github.com/stevvooe/continuity cd7a8e21e2b6f84799f5dd4b65faf49c8d3ee02d -github.com/tonistiigi/fsutil 0ac4c11b053b9c5c7c47558f81f96c7100ce50fb +github.com/containerd/containerd v1.0.0-beta.3 +github.com/containerd/fifo fbfb6a11ec671efbe94ad1c12c2e98773f19e1e6 +github.com/containerd/continuity 35d55c5e8dd23b32037d56cf97174aff3efdfa83 +github.com/containerd/cgroups f7dd103d3e4e696aa67152f6b4ddd1779a3455a9 +github.com/containerd/console 84eeaae905fa414d03e07bcd6c8d3f19e7cf180e +github.com/containerd/go-runc ed1cbe1fc31f5fb2359d3a54b6330d1a097858b7 +github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788 +github.com/dmcgowan/go-tar 2e2c51242e8993c50445dab7c03c8e7febddd0cf # cluster -github.com/docker/swarmkit 8bdecc57887ffc598b63d6433f58e0d2852112c3 https://github.com/dmcgowan/swarmkit.git +github.com/docker/swarmkit de950a7ed842c7b7e47e9451cde9bf8f96031894 github.com/gogo/protobuf v0.4 github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e -golang.org/x/crypto 3fbbcd23f1cb824e69491a5930cfeff09b12f4d2 +golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb github.com/hashicorp/go-memdb cb9a474f84cc5e41b273b20c6927680b2a8776ad github.com/hashicorp/go-immutable-radix 8e8ed81f8f0bf1bdd829593fdd5c29922c1ea990 @@ -136,7 +142,7 @@ github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github. # metrics github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18 -github.com/opencontainers/selinux v1.0.0-rc1 +github.com/opencontainers/selinux b29023b86e4a69d1b46b7e7b4e2b6fda03f0b9cd # archive/tar # mkdir -p ./vendor/archive diff --git a/vendor/github.com/fsnotify/fsnotify/LICENSE b/vendor/github.com/fsnotify/fsnotify/LICENSE deleted file mode 100644 index f21e54080..000000000 --- a/vendor/github.com/fsnotify/fsnotify/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2012 The Go Authors. All rights reserved. -Copyright (c) 2012 fsnotify Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/fsnotify/fsnotify/README.md b/vendor/github.com/fsnotify/fsnotify/README.md deleted file mode 100644 index 399320741..000000000 --- a/vendor/github.com/fsnotify/fsnotify/README.md +++ /dev/null @@ -1,79 +0,0 @@ -# File system notifications for Go - -[![GoDoc](https://godoc.org/github.com/fsnotify/fsnotify?status.svg)](https://godoc.org/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify) - -fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running: - -```console -go get -u golang.org/x/sys/... -``` - -Cross platform: Windows, Linux, BSD and macOS. - -|Adapter |OS |Status | -|----------|----------|----------| -|inotify |Linux 2.6.27 or later, Android\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)| -|kqueue |BSD, macOS, iOS\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)| -|ReadDirectoryChangesW|Windows|Supported [![Build status](https://ci.appveyor.com/api/projects/status/ivwjubaih4r0udeh/branch/master?svg=true)](https://ci.appveyor.com/project/NathanYoungman/fsnotify/branch/master)| -|FSEvents |macOS |[Planned](https://github.com/fsnotify/fsnotify/issues/11)| -|FEN |Solaris 11 |[In Progress](https://github.com/fsnotify/fsnotify/issues/12)| -|fanotify |Linux 2.6.37+ | | -|USN Journals |Windows |[Maybe](https://github.com/fsnotify/fsnotify/issues/53)| -|Polling |*All* |[Maybe](https://github.com/fsnotify/fsnotify/issues/9)| - -\* Android and iOS are untested. - -Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information. - -## API stability - -fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA). - -All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number. - -Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`. - -## Contributing - -Please refer to [CONTRIBUTING][] before opening an issue or pull request. - -## Example - -See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go). - -## FAQ - -**When a file is moved to another directory is it still being watched?** - -No (it shouldn't be, unless you are watching where it was moved to). - -**When I watch a directory, are all subdirectories watched as well?** - -No, you must add watches for any directory you want to watch (a recursive watcher is on the roadmap [#18][]). - -**Do I have to watch the Error and Event channels in a separate goroutine?** - -As of now, yes. Looking into making this single-thread friendly (see [howeyc #7][#7]) - -**Why am I receiving multiple events for the same file on OS X?** - -Spotlight indexing on OS X can result in multiple events (see [howeyc #62][#62]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#11][]). - -**How many files can be watched at once?** - -There are OS-specific limits as to how many watches can be created: -* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error. -* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error. - -[#62]: https://github.com/howeyc/fsnotify/issues/62 -[#18]: https://github.com/fsnotify/fsnotify/issues/18 -[#11]: https://github.com/fsnotify/fsnotify/issues/11 -[#7]: https://github.com/howeyc/fsnotify/issues/7 - -[contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md - -## Related Projects - -* [notify](https://github.com/rjeczalik/notify) -* [fsevents](https://github.com/fsnotify/fsevents) - diff --git a/vendor/github.com/fsnotify/fsnotify/fen.go b/vendor/github.com/fsnotify/fsnotify/fen.go deleted file mode 100644 index ced39cb88..000000000 --- a/vendor/github.com/fsnotify/fsnotify/fen.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build solaris - -package fsnotify - -import ( - "errors" -) - -// Watcher watches a set of files, delivering events to a channel. -type Watcher struct { - Events chan Event - Errors chan error -} - -// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. -func NewWatcher() (*Watcher, error) { - return nil, errors.New("FEN based watcher not yet supported for fsnotify\n") -} - -// Close removes all watches and closes the events channel. -func (w *Watcher) Close() error { - return nil -} - -// Add starts watching the named file or directory (non-recursively). -func (w *Watcher) Add(name string) error { - return nil -} - -// Remove stops watching the the named file or directory (non-recursively). -func (w *Watcher) Remove(name string) error { - return nil -} diff --git a/vendor/github.com/fsnotify/fsnotify/fsnotify.go b/vendor/github.com/fsnotify/fsnotify/fsnotify.go deleted file mode 100644 index 190bf0de5..000000000 --- a/vendor/github.com/fsnotify/fsnotify/fsnotify.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !plan9 - -// Package fsnotify provides a platform-independent interface for file system notifications. -package fsnotify - -import ( - "bytes" - "errors" - "fmt" -) - -// Event represents a single file system notification. -type Event struct { - Name string // Relative path to the file or directory. - Op Op // File operation that triggered the event. -} - -// Op describes a set of file operations. -type Op uint32 - -// These are the generalized file operations that can trigger a notification. -const ( - Create Op = 1 << iota - Write - Remove - Rename - Chmod -) - -func (op Op) String() string { - // Use a buffer for efficient string concatenation - var buffer bytes.Buffer - - if op&Create == Create { - buffer.WriteString("|CREATE") - } - if op&Remove == Remove { - buffer.WriteString("|REMOVE") - } - if op&Write == Write { - buffer.WriteString("|WRITE") - } - if op&Rename == Rename { - buffer.WriteString("|RENAME") - } - if op&Chmod == Chmod { - buffer.WriteString("|CHMOD") - } - if buffer.Len() == 0 { - return "" - } - return buffer.String()[1:] // Strip leading pipe -} - -// String returns a string representation of the event in the form -// "file: REMOVE|WRITE|..." -func (e Event) String() string { - return fmt.Sprintf("%q: %s", e.Name, e.Op.String()) -} - -// Common errors that can be reported by a watcher -var ErrEventOverflow = errors.New("fsnotify queue overflow") diff --git a/vendor/github.com/fsnotify/fsnotify/inotify.go b/vendor/github.com/fsnotify/fsnotify/inotify.go deleted file mode 100644 index bfa9dbc3c..000000000 --- a/vendor/github.com/fsnotify/fsnotify/inotify.go +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build linux - -package fsnotify - -import ( - "errors" - "fmt" - "io" - "os" - "path/filepath" - "strings" - "sync" - "unsafe" - - "golang.org/x/sys/unix" -) - -// Watcher watches a set of files, delivering events to a channel. -type Watcher struct { - Events chan Event - Errors chan error - mu sync.Mutex // Map access - cv *sync.Cond // sync removing on rm_watch with IN_IGNORE - fd int - poller *fdPoller - watches map[string]*watch // Map of inotify watches (key: path) - paths map[int]string // Map of watched paths (key: watch descriptor) - done chan struct{} // Channel for sending a "quit message" to the reader goroutine - doneResp chan struct{} // Channel to respond to Close -} - -// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. -func NewWatcher() (*Watcher, error) { - // Create inotify fd - fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC) - if fd == -1 { - return nil, errno - } - // Create epoll - poller, err := newFdPoller(fd) - if err != nil { - unix.Close(fd) - return nil, err - } - w := &Watcher{ - fd: fd, - poller: poller, - watches: make(map[string]*watch), - paths: make(map[int]string), - Events: make(chan Event), - Errors: make(chan error), - done: make(chan struct{}), - doneResp: make(chan struct{}), - } - w.cv = sync.NewCond(&w.mu) - - go w.readEvents() - return w, nil -} - -func (w *Watcher) isClosed() bool { - select { - case <-w.done: - return true - default: - return false - } -} - -// Close removes all watches and closes the events channel. -func (w *Watcher) Close() error { - if w.isClosed() { - return nil - } - - // Send 'close' signal to goroutine, and set the Watcher to closed. - close(w.done) - - // Wake up goroutine - w.poller.wake() - - // Wait for goroutine to close - <-w.doneResp - - return nil -} - -// Add starts watching the named file or directory (non-recursively). -func (w *Watcher) Add(name string) error { - name = filepath.Clean(name) - if w.isClosed() { - return errors.New("inotify instance already closed") - } - - const agnosticEvents = unix.IN_MOVED_TO | unix.IN_MOVED_FROM | - unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY | - unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF - - var flags uint32 = agnosticEvents - - w.mu.Lock() - watchEntry, found := w.watches[name] - w.mu.Unlock() - if found { - watchEntry.flags |= flags - flags |= unix.IN_MASK_ADD - } - wd, errno := unix.InotifyAddWatch(w.fd, name, flags) - if wd == -1 { - return errno - } - - w.mu.Lock() - w.watches[name] = &watch{wd: uint32(wd), flags: flags} - w.paths[wd] = name - w.mu.Unlock() - - return nil -} - -// Remove stops watching the named file or directory (non-recursively). -func (w *Watcher) Remove(name string) error { - name = filepath.Clean(name) - - // Fetch the watch. - w.mu.Lock() - defer w.mu.Unlock() - watch, ok := w.watches[name] - - // Remove it from inotify. - if !ok { - return fmt.Errorf("can't remove non-existent inotify watch for: %s", name) - } - // inotify_rm_watch will return EINVAL if the file has been deleted; - // the inotify will already have been removed. - // watches and pathes are deleted in ignoreLinux() implicitly and asynchronously - // by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE - // so that EINVAL means that the wd is being rm_watch()ed or its file removed - // by another thread and we have not received IN_IGNORE event. - success, errno := unix.InotifyRmWatch(w.fd, watch.wd) - if success == -1 { - // TODO: Perhaps it's not helpful to return an error here in every case. - // the only two possible errors are: - // EBADF, which happens when w.fd is not a valid file descriptor of any kind. - // EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor. - // Watch descriptors are invalidated when they are removed explicitly or implicitly; - // explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted. - return errno - } - - // wait until ignoreLinux() deleting maps - exists := true - for exists { - w.cv.Wait() - _, exists = w.watches[name] - } - - return nil -} - -type watch struct { - wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall) - flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags) -} - -// readEvents reads from the inotify file descriptor, converts the -// received events into Event objects and sends them via the Events channel -func (w *Watcher) readEvents() { - var ( - buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events - n int // Number of bytes read with read() - errno error // Syscall errno - ok bool // For poller.wait - ) - - defer close(w.doneResp) - defer close(w.Errors) - defer close(w.Events) - defer unix.Close(w.fd) - defer w.poller.close() - - for { - // See if we have been closed. - if w.isClosed() { - return - } - - ok, errno = w.poller.wait() - if errno != nil { - select { - case w.Errors <- errno: - case <-w.done: - return - } - continue - } - - if !ok { - continue - } - - n, errno = unix.Read(w.fd, buf[:]) - // If a signal interrupted execution, see if we've been asked to close, and try again. - // http://man7.org/linux/man-pages/man7/signal.7.html : - // "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable" - if errno == unix.EINTR { - continue - } - - // unix.Read might have been woken up by Close. If so, we're done. - if w.isClosed() { - return - } - - if n < unix.SizeofInotifyEvent { - var err error - if n == 0 { - // If EOF is received. This should really never happen. - err = io.EOF - } else if n < 0 { - // If an error occurred while reading. - err = errno - } else { - // Read was too short. - err = errors.New("notify: short read in readEvents()") - } - select { - case w.Errors <- err: - case <-w.done: - return - } - continue - } - - var offset uint32 - // We don't know how many events we just read into the buffer - // While the offset points to at least one whole event... - for offset <= uint32(n-unix.SizeofInotifyEvent) { - // Point "raw" to the event in the buffer - raw := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset])) - - mask := uint32(raw.Mask) - nameLen := uint32(raw.Len) - - if mask&unix.IN_Q_OVERFLOW != 0 { - select { - case w.Errors <- ErrEventOverflow: - case <-w.done: - return - } - } - - // If the event happened to the watched directory or the watched file, the kernel - // doesn't append the filename to the event, but we would like to always fill the - // the "Name" field with a valid filename. We retrieve the path of the watch from - // the "paths" map. - w.mu.Lock() - name := w.paths[int(raw.Wd)] - w.mu.Unlock() - if nameLen > 0 { - // Point "bytes" at the first byte of the filename - bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent])) - // The filename is padded with NULL bytes. TrimRight() gets rid of those. - name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") - } - - event := newEvent(name, mask) - - // Send the events that are not ignored on the events channel - if !event.ignoreLinux(w, raw.Wd, mask) { - select { - case w.Events <- event: - case <-w.done: - return - } - } - - // Move to the next event in the buffer - offset += unix.SizeofInotifyEvent + nameLen - } - } -} - -// Certain types of events can be "ignored" and not sent over the Events -// channel. Such as events marked ignore by the kernel, or MODIFY events -// against files that do not exist. -func (e *Event) ignoreLinux(w *Watcher, wd int32, mask uint32) bool { - // Ignore anything the inotify API says to ignore - if mask&unix.IN_IGNORED == unix.IN_IGNORED { - w.mu.Lock() - defer w.mu.Unlock() - name := w.paths[int(wd)] - delete(w.paths, int(wd)) - delete(w.watches, name) - w.cv.Broadcast() - return true - } - - // If the event is not a DELETE or RENAME, the file must exist. - // Otherwise the event is ignored. - // *Note*: this was put in place because it was seen that a MODIFY - // event was sent after the DELETE. This ignores that MODIFY and - // assumes a DELETE will come or has come if the file doesn't exist. - if !(e.Op&Remove == Remove || e.Op&Rename == Rename) { - _, statErr := os.Lstat(e.Name) - return os.IsNotExist(statErr) - } - return false -} - -// newEvent returns an platform-independent Event based on an inotify mask. -func newEvent(name string, mask uint32) Event { - e := Event{Name: name} - if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO { - e.Op |= Create - } - if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE { - e.Op |= Remove - } - if mask&unix.IN_MODIFY == unix.IN_MODIFY { - e.Op |= Write - } - if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM { - e.Op |= Rename - } - if mask&unix.IN_ATTRIB == unix.IN_ATTRIB { - e.Op |= Chmod - } - return e -} diff --git a/vendor/github.com/fsnotify/fsnotify/inotify_poller.go b/vendor/github.com/fsnotify/fsnotify/inotify_poller.go deleted file mode 100644 index cc7db4b22..000000000 --- a/vendor/github.com/fsnotify/fsnotify/inotify_poller.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build linux - -package fsnotify - -import ( - "errors" - - "golang.org/x/sys/unix" -) - -type fdPoller struct { - fd int // File descriptor (as returned by the inotify_init() syscall) - epfd int // Epoll file descriptor - pipe [2]int // Pipe for waking up -} - -func emptyPoller(fd int) *fdPoller { - poller := new(fdPoller) - poller.fd = fd - poller.epfd = -1 - poller.pipe[0] = -1 - poller.pipe[1] = -1 - return poller -} - -// Create a new inotify poller. -// This creates an inotify handler, and an epoll handler. -func newFdPoller(fd int) (*fdPoller, error) { - var errno error - poller := emptyPoller(fd) - defer func() { - if errno != nil { - poller.close() - } - }() - poller.fd = fd - - // Create epoll fd - poller.epfd, errno = unix.EpollCreate1(0) - if poller.epfd == -1 { - return nil, errno - } - // Create pipe; pipe[0] is the read end, pipe[1] the write end. - errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK) - if errno != nil { - return nil, errno - } - - // Register inotify fd with epoll - event := unix.EpollEvent{ - Fd: int32(poller.fd), - Events: unix.EPOLLIN, - } - errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.fd, &event) - if errno != nil { - return nil, errno - } - - // Register pipe fd with epoll - event = unix.EpollEvent{ - Fd: int32(poller.pipe[0]), - Events: unix.EPOLLIN, - } - errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.pipe[0], &event) - if errno != nil { - return nil, errno - } - - return poller, nil -} - -// Wait using epoll. -// Returns true if something is ready to be read, -// false if there is not. -func (poller *fdPoller) wait() (bool, error) { - // 3 possible events per fd, and 2 fds, makes a maximum of 6 events. - // I don't know whether epoll_wait returns the number of events returned, - // or the total number of events ready. - // I decided to catch both by making the buffer one larger than the maximum. - events := make([]unix.EpollEvent, 7) - for { - n, errno := unix.EpollWait(poller.epfd, events, -1) - if n == -1 { - if errno == unix.EINTR { - continue - } - return false, errno - } - if n == 0 { - // If there are no events, try again. - continue - } - if n > 6 { - // This should never happen. More events were returned than should be possible. - return false, errors.New("epoll_wait returned more events than I know what to do with") - } - ready := events[:n] - epollhup := false - epollerr := false - epollin := false - for _, event := range ready { - if event.Fd == int32(poller.fd) { - if event.Events&unix.EPOLLHUP != 0 { - // This should not happen, but if it does, treat it as a wakeup. - epollhup = true - } - if event.Events&unix.EPOLLERR != 0 { - // If an error is waiting on the file descriptor, we should pretend - // something is ready to read, and let unix.Read pick up the error. - epollerr = true - } - if event.Events&unix.EPOLLIN != 0 { - // There is data to read. - epollin = true - } - } - if event.Fd == int32(poller.pipe[0]) { - if event.Events&unix.EPOLLHUP != 0 { - // Write pipe descriptor was closed, by us. This means we're closing down the - // watcher, and we should wake up. - } - if event.Events&unix.EPOLLERR != 0 { - // If an error is waiting on the pipe file descriptor. - // This is an absolute mystery, and should never ever happen. - return false, errors.New("Error on the pipe descriptor.") - } - if event.Events&unix.EPOLLIN != 0 { - // This is a regular wakeup, so we have to clear the buffer. - err := poller.clearWake() - if err != nil { - return false, err - } - } - } - } - - if epollhup || epollerr || epollin { - return true, nil - } - return false, nil - } -} - -// Close the write end of the poller. -func (poller *fdPoller) wake() error { - buf := make([]byte, 1) - n, errno := unix.Write(poller.pipe[1], buf) - if n == -1 { - if errno == unix.EAGAIN { - // Buffer is full, poller will wake. - return nil - } - return errno - } - return nil -} - -func (poller *fdPoller) clearWake() error { - // You have to be woken up a LOT in order to get to 100! - buf := make([]byte, 100) - n, errno := unix.Read(poller.pipe[0], buf) - if n == -1 { - if errno == unix.EAGAIN { - // Buffer is empty, someone else cleared our wake. - return nil - } - return errno - } - return nil -} - -// Close all poller file descriptors, but not the one passed to it. -func (poller *fdPoller) close() { - if poller.pipe[1] != -1 { - unix.Close(poller.pipe[1]) - } - if poller.pipe[0] != -1 { - unix.Close(poller.pipe[0]) - } - if poller.epfd != -1 { - unix.Close(poller.epfd) - } -} diff --git a/vendor/github.com/fsnotify/fsnotify/kqueue.go b/vendor/github.com/fsnotify/fsnotify/kqueue.go deleted file mode 100644 index c2b4acb18..000000000 --- a/vendor/github.com/fsnotify/fsnotify/kqueue.go +++ /dev/null @@ -1,503 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build freebsd openbsd netbsd dragonfly darwin - -package fsnotify - -import ( - "errors" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "sync" - "time" - - "golang.org/x/sys/unix" -) - -// Watcher watches a set of files, delivering events to a channel. -type Watcher struct { - Events chan Event - Errors chan error - done chan bool // Channel for sending a "quit message" to the reader goroutine - - kq int // File descriptor (as returned by the kqueue() syscall). - - mu sync.Mutex // Protects access to watcher data - watches map[string]int // Map of watched file descriptors (key: path). - externalWatches map[string]bool // Map of watches added by user of the library. - dirFlags map[string]uint32 // Map of watched directories to fflags used in kqueue. - paths map[int]pathInfo // Map file descriptors to path names for processing kqueue events. - fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events). - isClosed bool // Set to true when Close() is first called -} - -type pathInfo struct { - name string - isDir bool -} - -// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. -func NewWatcher() (*Watcher, error) { - kq, err := kqueue() - if err != nil { - return nil, err - } - - w := &Watcher{ - kq: kq, - watches: make(map[string]int), - dirFlags: make(map[string]uint32), - paths: make(map[int]pathInfo), - fileExists: make(map[string]bool), - externalWatches: make(map[string]bool), - Events: make(chan Event), - Errors: make(chan error), - done: make(chan bool), - } - - go w.readEvents() - return w, nil -} - -// Close removes all watches and closes the events channel. -func (w *Watcher) Close() error { - w.mu.Lock() - if w.isClosed { - w.mu.Unlock() - return nil - } - w.isClosed = true - w.mu.Unlock() - - // copy paths to remove while locked - w.mu.Lock() - var pathsToRemove = make([]string, 0, len(w.watches)) - for name := range w.watches { - pathsToRemove = append(pathsToRemove, name) - } - w.mu.Unlock() - // unlock before calling Remove, which also locks - - var err error - for _, name := range pathsToRemove { - if e := w.Remove(name); e != nil && err == nil { - err = e - } - } - - // Send "quit" message to the reader goroutine: - w.done <- true - - return nil -} - -// Add starts watching the named file or directory (non-recursively). -func (w *Watcher) Add(name string) error { - w.mu.Lock() - w.externalWatches[name] = true - w.mu.Unlock() - _, err := w.addWatch(name, noteAllEvents) - return err -} - -// Remove stops watching the the named file or directory (non-recursively). -func (w *Watcher) Remove(name string) error { - name = filepath.Clean(name) - w.mu.Lock() - watchfd, ok := w.watches[name] - w.mu.Unlock() - if !ok { - return fmt.Errorf("can't remove non-existent kevent watch for: %s", name) - } - - const registerRemove = unix.EV_DELETE - if err := register(w.kq, []int{watchfd}, registerRemove, 0); err != nil { - return err - } - - unix.Close(watchfd) - - w.mu.Lock() - isDir := w.paths[watchfd].isDir - delete(w.watches, name) - delete(w.paths, watchfd) - delete(w.dirFlags, name) - w.mu.Unlock() - - // Find all watched paths that are in this directory that are not external. - if isDir { - var pathsToRemove []string - w.mu.Lock() - for _, path := range w.paths { - wdir, _ := filepath.Split(path.name) - if filepath.Clean(wdir) == name { - if !w.externalWatches[path.name] { - pathsToRemove = append(pathsToRemove, path.name) - } - } - } - w.mu.Unlock() - for _, name := range pathsToRemove { - // Since these are internal, not much sense in propagating error - // to the user, as that will just confuse them with an error about - // a path they did not explicitly watch themselves. - w.Remove(name) - } - } - - return nil -} - -// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE) -const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME - -// keventWaitTime to block on each read from kevent -var keventWaitTime = durationToTimespec(100 * time.Millisecond) - -// addWatch adds name to the watched file set. -// The flags are interpreted as described in kevent(2). -// Returns the real path to the file which was added, if any, which may be different from the one passed in the case of symlinks. -func (w *Watcher) addWatch(name string, flags uint32) (string, error) { - var isDir bool - // Make ./name and name equivalent - name = filepath.Clean(name) - - w.mu.Lock() - if w.isClosed { - w.mu.Unlock() - return "", errors.New("kevent instance already closed") - } - watchfd, alreadyWatching := w.watches[name] - // We already have a watch, but we can still override flags. - if alreadyWatching { - isDir = w.paths[watchfd].isDir - } - w.mu.Unlock() - - if !alreadyWatching { - fi, err := os.Lstat(name) - if err != nil { - return "", err - } - - // Don't watch sockets. - if fi.Mode()&os.ModeSocket == os.ModeSocket { - return "", nil - } - - // Don't watch named pipes. - if fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe { - return "", nil - } - - // Follow Symlinks - // Unfortunately, Linux can add bogus symlinks to watch list without - // issue, and Windows can't do symlinks period (AFAIK). To maintain - // consistency, we will act like everything is fine. There will simply - // be no file events for broken symlinks. - // Hence the returns of nil on errors. - if fi.Mode()&os.ModeSymlink == os.ModeSymlink { - name, err = filepath.EvalSymlinks(name) - if err != nil { - return "", nil - } - - w.mu.Lock() - _, alreadyWatching = w.watches[name] - w.mu.Unlock() - - if alreadyWatching { - return name, nil - } - - fi, err = os.Lstat(name) - if err != nil { - return "", nil - } - } - - watchfd, err = unix.Open(name, openMode, 0700) - if watchfd == -1 { - return "", err - } - - isDir = fi.IsDir() - } - - const registerAdd = unix.EV_ADD | unix.EV_CLEAR | unix.EV_ENABLE - if err := register(w.kq, []int{watchfd}, registerAdd, flags); err != nil { - unix.Close(watchfd) - return "", err - } - - if !alreadyWatching { - w.mu.Lock() - w.watches[name] = watchfd - w.paths[watchfd] = pathInfo{name: name, isDir: isDir} - w.mu.Unlock() - } - - if isDir { - // Watch the directory if it has not been watched before, - // or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles) - w.mu.Lock() - - watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE && - (!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE) - // Store flags so this watch can be updated later - w.dirFlags[name] = flags - w.mu.Unlock() - - if watchDir { - if err := w.watchDirectoryFiles(name); err != nil { - return "", err - } - } - } - return name, nil -} - -// readEvents reads from kqueue and converts the received kevents into -// Event values that it sends down the Events channel. -func (w *Watcher) readEvents() { - eventBuffer := make([]unix.Kevent_t, 10) - - for { - // See if there is a message on the "done" channel - select { - case <-w.done: - err := unix.Close(w.kq) - if err != nil { - w.Errors <- err - } - close(w.Events) - close(w.Errors) - return - default: - } - - // Get new events - kevents, err := read(w.kq, eventBuffer, &keventWaitTime) - // EINTR is okay, the syscall was interrupted before timeout expired. - if err != nil && err != unix.EINTR { - w.Errors <- err - continue - } - - // Flush the events we received to the Events channel - for len(kevents) > 0 { - kevent := &kevents[0] - watchfd := int(kevent.Ident) - mask := uint32(kevent.Fflags) - w.mu.Lock() - path := w.paths[watchfd] - w.mu.Unlock() - event := newEvent(path.name, mask) - - if path.isDir && !(event.Op&Remove == Remove) { - // Double check to make sure the directory exists. This can happen when - // we do a rm -fr on a recursively watched folders and we receive a - // modification event first but the folder has been deleted and later - // receive the delete event - if _, err := os.Lstat(event.Name); os.IsNotExist(err) { - // mark is as delete event - event.Op |= Remove - } - } - - if event.Op&Rename == Rename || event.Op&Remove == Remove { - w.Remove(event.Name) - w.mu.Lock() - delete(w.fileExists, event.Name) - w.mu.Unlock() - } - - if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) { - w.sendDirectoryChangeEvents(event.Name) - } else { - // Send the event on the Events channel - w.Events <- event - } - - if event.Op&Remove == Remove { - // Look for a file that may have overwritten this. - // For example, mv f1 f2 will delete f2, then create f2. - if path.isDir { - fileDir := filepath.Clean(event.Name) - w.mu.Lock() - _, found := w.watches[fileDir] - w.mu.Unlock() - if found { - // make sure the directory exists before we watch for changes. When we - // do a recursive watch and perform rm -fr, the parent directory might - // have gone missing, ignore the missing directory and let the - // upcoming delete event remove the watch from the parent directory. - if _, err := os.Lstat(fileDir); err == nil { - w.sendDirectoryChangeEvents(fileDir) - } - } - } else { - filePath := filepath.Clean(event.Name) - if fileInfo, err := os.Lstat(filePath); err == nil { - w.sendFileCreatedEventIfNew(filePath, fileInfo) - } - } - } - - // Move to next event - kevents = kevents[1:] - } - } -} - -// newEvent returns an platform-independent Event based on kqueue Fflags. -func newEvent(name string, mask uint32) Event { - e := Event{Name: name} - if mask&unix.NOTE_DELETE == unix.NOTE_DELETE { - e.Op |= Remove - } - if mask&unix.NOTE_WRITE == unix.NOTE_WRITE { - e.Op |= Write - } - if mask&unix.NOTE_RENAME == unix.NOTE_RENAME { - e.Op |= Rename - } - if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB { - e.Op |= Chmod - } - return e -} - -func newCreateEvent(name string) Event { - return Event{Name: name, Op: Create} -} - -// watchDirectoryFiles to mimic inotify when adding a watch on a directory -func (w *Watcher) watchDirectoryFiles(dirPath string) error { - // Get all files - files, err := ioutil.ReadDir(dirPath) - if err != nil { - return err - } - - for _, fileInfo := range files { - filePath := filepath.Join(dirPath, fileInfo.Name()) - filePath, err = w.internalWatch(filePath, fileInfo) - if err != nil { - return err - } - - w.mu.Lock() - w.fileExists[filePath] = true - w.mu.Unlock() - } - - return nil -} - -// sendDirectoryEvents searches the directory for newly created files -// and sends them over the event channel. This functionality is to have -// the BSD version of fsnotify match Linux inotify which provides a -// create event for files created in a watched directory. -func (w *Watcher) sendDirectoryChangeEvents(dirPath string) { - // Get all files - files, err := ioutil.ReadDir(dirPath) - if err != nil { - w.Errors <- err - } - - // Search for new files - for _, fileInfo := range files { - filePath := filepath.Join(dirPath, fileInfo.Name()) - err := w.sendFileCreatedEventIfNew(filePath, fileInfo) - - if err != nil { - return - } - } -} - -// sendFileCreatedEvent sends a create event if the file isn't already being tracked. -func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInfo) (err error) { - w.mu.Lock() - _, doesExist := w.fileExists[filePath] - w.mu.Unlock() - if !doesExist { - // Send create event - w.Events <- newCreateEvent(filePath) - } - - // like watchDirectoryFiles (but without doing another ReadDir) - filePath, err = w.internalWatch(filePath, fileInfo) - if err != nil { - return err - } - - w.mu.Lock() - w.fileExists[filePath] = true - w.mu.Unlock() - - return nil -} - -func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) (string, error) { - if fileInfo.IsDir() { - // mimic Linux providing delete events for subdirectories - // but preserve the flags used if currently watching subdirectory - w.mu.Lock() - flags := w.dirFlags[name] - w.mu.Unlock() - - flags |= unix.NOTE_DELETE | unix.NOTE_RENAME - return w.addWatch(name, flags) - } - - // watch file to mimic Linux inotify - return w.addWatch(name, noteAllEvents) -} - -// kqueue creates a new kernel event queue and returns a descriptor. -func kqueue() (kq int, err error) { - kq, err = unix.Kqueue() - if kq == -1 { - return kq, err - } - return kq, nil -} - -// register events with the queue -func register(kq int, fds []int, flags int, fflags uint32) error { - changes := make([]unix.Kevent_t, len(fds)) - - for i, fd := range fds { - // SetKevent converts int to the platform-specific types: - unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags) - changes[i].Fflags = fflags - } - - // register the events - success, err := unix.Kevent(kq, changes, nil, nil) - if success == -1 { - return err - } - return nil -} - -// read retrieves pending events, or waits until an event occurs. -// A timeout of nil blocks indefinitely, while 0 polls the queue. -func read(kq int, events []unix.Kevent_t, timeout *unix.Timespec) ([]unix.Kevent_t, error) { - n, err := unix.Kevent(kq, nil, events, timeout) - if err != nil { - return nil, err - } - return events[0:n], nil -} - -// durationToTimespec prepares a timeout value -func durationToTimespec(d time.Duration) unix.Timespec { - return unix.NsecToTimespec(d.Nanoseconds()) -} diff --git a/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go b/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go deleted file mode 100644 index 7d8de1451..000000000 --- a/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build freebsd openbsd netbsd dragonfly - -package fsnotify - -import "golang.org/x/sys/unix" - -const openMode = unix.O_NONBLOCK | unix.O_RDONLY diff --git a/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go b/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go deleted file mode 100644 index 9139e1716..000000000 --- a/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin - -package fsnotify - -import "golang.org/x/sys/unix" - -// note: this constant is not defined on BSD -const openMode = unix.O_EVTONLY diff --git a/vendor/github.com/fsnotify/fsnotify/windows.go b/vendor/github.com/fsnotify/fsnotify/windows.go deleted file mode 100644 index 09436f31d..000000000 --- a/vendor/github.com/fsnotify/fsnotify/windows.go +++ /dev/null @@ -1,561 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package fsnotify - -import ( - "errors" - "fmt" - "os" - "path/filepath" - "runtime" - "sync" - "syscall" - "unsafe" -) - -// Watcher watches a set of files, delivering events to a channel. -type Watcher struct { - Events chan Event - Errors chan error - isClosed bool // Set to true when Close() is first called - mu sync.Mutex // Map access - port syscall.Handle // Handle to completion port - watches watchMap // Map of watches (key: i-number) - input chan *input // Inputs to the reader are sent on this channel - quit chan chan<- error -} - -// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. -func NewWatcher() (*Watcher, error) { - port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0) - if e != nil { - return nil, os.NewSyscallError("CreateIoCompletionPort", e) - } - w := &Watcher{ - port: port, - watches: make(watchMap), - input: make(chan *input, 1), - Events: make(chan Event, 50), - Errors: make(chan error), - quit: make(chan chan<- error, 1), - } - go w.readEvents() - return w, nil -} - -// Close removes all watches and closes the events channel. -func (w *Watcher) Close() error { - if w.isClosed { - return nil - } - w.isClosed = true - - // Send "quit" message to the reader goroutine - ch := make(chan error) - w.quit <- ch - if err := w.wakeupReader(); err != nil { - return err - } - return <-ch -} - -// Add starts watching the named file or directory (non-recursively). -func (w *Watcher) Add(name string) error { - if w.isClosed { - return errors.New("watcher already closed") - } - in := &input{ - op: opAddWatch, - path: filepath.Clean(name), - flags: sysFSALLEVENTS, - reply: make(chan error), - } - w.input <- in - if err := w.wakeupReader(); err != nil { - return err - } - return <-in.reply -} - -// Remove stops watching the the named file or directory (non-recursively). -func (w *Watcher) Remove(name string) error { - in := &input{ - op: opRemoveWatch, - path: filepath.Clean(name), - reply: make(chan error), - } - w.input <- in - if err := w.wakeupReader(); err != nil { - return err - } - return <-in.reply -} - -const ( - // Options for AddWatch - sysFSONESHOT = 0x80000000 - sysFSONLYDIR = 0x1000000 - - // Events - sysFSACCESS = 0x1 - sysFSALLEVENTS = 0xfff - sysFSATTRIB = 0x4 - sysFSCLOSE = 0x18 - sysFSCREATE = 0x100 - sysFSDELETE = 0x200 - sysFSDELETESELF = 0x400 - sysFSMODIFY = 0x2 - sysFSMOVE = 0xc0 - sysFSMOVEDFROM = 0x40 - sysFSMOVEDTO = 0x80 - sysFSMOVESELF = 0x800 - - // Special events - sysFSIGNORED = 0x8000 - sysFSQOVERFLOW = 0x4000 -) - -func newEvent(name string, mask uint32) Event { - e := Event{Name: name} - if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO { - e.Op |= Create - } - if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF { - e.Op |= Remove - } - if mask&sysFSMODIFY == sysFSMODIFY { - e.Op |= Write - } - if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM { - e.Op |= Rename - } - if mask&sysFSATTRIB == sysFSATTRIB { - e.Op |= Chmod - } - return e -} - -const ( - opAddWatch = iota - opRemoveWatch -) - -const ( - provisional uint64 = 1 << (32 + iota) -) - -type input struct { - op int - path string - flags uint32 - reply chan error -} - -type inode struct { - handle syscall.Handle - volume uint32 - index uint64 -} - -type watch struct { - ov syscall.Overlapped - ino *inode // i-number - path string // Directory path - mask uint64 // Directory itself is being watched with these notify flags - names map[string]uint64 // Map of names being watched and their notify flags - rename string // Remembers the old name while renaming a file - buf [4096]byte -} - -type indexMap map[uint64]*watch -type watchMap map[uint32]indexMap - -func (w *Watcher) wakeupReader() error { - e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil) - if e != nil { - return os.NewSyscallError("PostQueuedCompletionStatus", e) - } - return nil -} - -func getDir(pathname string) (dir string, err error) { - attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname)) - if e != nil { - return "", os.NewSyscallError("GetFileAttributes", e) - } - if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { - dir = pathname - } else { - dir, _ = filepath.Split(pathname) - dir = filepath.Clean(dir) - } - return -} - -func getIno(path string) (ino *inode, err error) { - h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path), - syscall.FILE_LIST_DIRECTORY, - syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, - nil, syscall.OPEN_EXISTING, - syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0) - if e != nil { - return nil, os.NewSyscallError("CreateFile", e) - } - var fi syscall.ByHandleFileInformation - if e = syscall.GetFileInformationByHandle(h, &fi); e != nil { - syscall.CloseHandle(h) - return nil, os.NewSyscallError("GetFileInformationByHandle", e) - } - ino = &inode{ - handle: h, - volume: fi.VolumeSerialNumber, - index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow), - } - return ino, nil -} - -// Must run within the I/O thread. -func (m watchMap) get(ino *inode) *watch { - if i := m[ino.volume]; i != nil { - return i[ino.index] - } - return nil -} - -// Must run within the I/O thread. -func (m watchMap) set(ino *inode, watch *watch) { - i := m[ino.volume] - if i == nil { - i = make(indexMap) - m[ino.volume] = i - } - i[ino.index] = watch -} - -// Must run within the I/O thread. -func (w *Watcher) addWatch(pathname string, flags uint64) error { - dir, err := getDir(pathname) - if err != nil { - return err - } - if flags&sysFSONLYDIR != 0 && pathname != dir { - return nil - } - ino, err := getIno(dir) - if err != nil { - return err - } - w.mu.Lock() - watchEntry := w.watches.get(ino) - w.mu.Unlock() - if watchEntry == nil { - if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil { - syscall.CloseHandle(ino.handle) - return os.NewSyscallError("CreateIoCompletionPort", e) - } - watchEntry = &watch{ - ino: ino, - path: dir, - names: make(map[string]uint64), - } - w.mu.Lock() - w.watches.set(ino, watchEntry) - w.mu.Unlock() - flags |= provisional - } else { - syscall.CloseHandle(ino.handle) - } - if pathname == dir { - watchEntry.mask |= flags - } else { - watchEntry.names[filepath.Base(pathname)] |= flags - } - if err = w.startRead(watchEntry); err != nil { - return err - } - if pathname == dir { - watchEntry.mask &= ^provisional - } else { - watchEntry.names[filepath.Base(pathname)] &= ^provisional - } - return nil -} - -// Must run within the I/O thread. -func (w *Watcher) remWatch(pathname string) error { - dir, err := getDir(pathname) - if err != nil { - return err - } - ino, err := getIno(dir) - if err != nil { - return err - } - w.mu.Lock() - watch := w.watches.get(ino) - w.mu.Unlock() - if watch == nil { - return fmt.Errorf("can't remove non-existent watch for: %s", pathname) - } - if pathname == dir { - w.sendEvent(watch.path, watch.mask&sysFSIGNORED) - watch.mask = 0 - } else { - name := filepath.Base(pathname) - w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED) - delete(watch.names, name) - } - return w.startRead(watch) -} - -// Must run within the I/O thread. -func (w *Watcher) deleteWatch(watch *watch) { - for name, mask := range watch.names { - if mask&provisional == 0 { - w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED) - } - delete(watch.names, name) - } - if watch.mask != 0 { - if watch.mask&provisional == 0 { - w.sendEvent(watch.path, watch.mask&sysFSIGNORED) - } - watch.mask = 0 - } -} - -// Must run within the I/O thread. -func (w *Watcher) startRead(watch *watch) error { - if e := syscall.CancelIo(watch.ino.handle); e != nil { - w.Errors <- os.NewSyscallError("CancelIo", e) - w.deleteWatch(watch) - } - mask := toWindowsFlags(watch.mask) - for _, m := range watch.names { - mask |= toWindowsFlags(m) - } - if mask == 0 { - if e := syscall.CloseHandle(watch.ino.handle); e != nil { - w.Errors <- os.NewSyscallError("CloseHandle", e) - } - w.mu.Lock() - delete(w.watches[watch.ino.volume], watch.ino.index) - w.mu.Unlock() - return nil - } - e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0], - uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0) - if e != nil { - err := os.NewSyscallError("ReadDirectoryChanges", e) - if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 { - // Watched directory was probably removed - if w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) { - if watch.mask&sysFSONESHOT != 0 { - watch.mask = 0 - } - } - err = nil - } - w.deleteWatch(watch) - w.startRead(watch) - return err - } - return nil -} - -// readEvents reads from the I/O completion port, converts the -// received events into Event objects and sends them via the Events channel. -// Entry point to the I/O thread. -func (w *Watcher) readEvents() { - var ( - n, key uint32 - ov *syscall.Overlapped - ) - runtime.LockOSThread() - - for { - e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE) - watch := (*watch)(unsafe.Pointer(ov)) - - if watch == nil { - select { - case ch := <-w.quit: - w.mu.Lock() - var indexes []indexMap - for _, index := range w.watches { - indexes = append(indexes, index) - } - w.mu.Unlock() - for _, index := range indexes { - for _, watch := range index { - w.deleteWatch(watch) - w.startRead(watch) - } - } - var err error - if e := syscall.CloseHandle(w.port); e != nil { - err = os.NewSyscallError("CloseHandle", e) - } - close(w.Events) - close(w.Errors) - ch <- err - return - case in := <-w.input: - switch in.op { - case opAddWatch: - in.reply <- w.addWatch(in.path, uint64(in.flags)) - case opRemoveWatch: - in.reply <- w.remWatch(in.path) - } - default: - } - continue - } - - switch e { - case syscall.ERROR_MORE_DATA: - if watch == nil { - w.Errors <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer") - } else { - // The i/o succeeded but the buffer is full. - // In theory we should be building up a full packet. - // In practice we can get away with just carrying on. - n = uint32(unsafe.Sizeof(watch.buf)) - } - case syscall.ERROR_ACCESS_DENIED: - // Watched directory was probably removed - w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) - w.deleteWatch(watch) - w.startRead(watch) - continue - case syscall.ERROR_OPERATION_ABORTED: - // CancelIo was called on this handle - continue - default: - w.Errors <- os.NewSyscallError("GetQueuedCompletionPort", e) - continue - case nil: - } - - var offset uint32 - for { - if n == 0 { - w.Events <- newEvent("", sysFSQOVERFLOW) - w.Errors <- errors.New("short read in readEvents()") - break - } - - // Point "raw" to the event in the buffer - raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset])) - buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName)) - name := syscall.UTF16ToString(buf[:raw.FileNameLength/2]) - fullname := filepath.Join(watch.path, name) - - var mask uint64 - switch raw.Action { - case syscall.FILE_ACTION_REMOVED: - mask = sysFSDELETESELF - case syscall.FILE_ACTION_MODIFIED: - mask = sysFSMODIFY - case syscall.FILE_ACTION_RENAMED_OLD_NAME: - watch.rename = name - case syscall.FILE_ACTION_RENAMED_NEW_NAME: - if watch.names[watch.rename] != 0 { - watch.names[name] |= watch.names[watch.rename] - delete(watch.names, watch.rename) - mask = sysFSMOVESELF - } - } - - sendNameEvent := func() { - if w.sendEvent(fullname, watch.names[name]&mask) { - if watch.names[name]&sysFSONESHOT != 0 { - delete(watch.names, name) - } - } - } - if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME { - sendNameEvent() - } - if raw.Action == syscall.FILE_ACTION_REMOVED { - w.sendEvent(fullname, watch.names[name]&sysFSIGNORED) - delete(watch.names, name) - } - if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) { - if watch.mask&sysFSONESHOT != 0 { - watch.mask = 0 - } - } - if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME { - fullname = filepath.Join(watch.path, watch.rename) - sendNameEvent() - } - - // Move to the next event in the buffer - if raw.NextEntryOffset == 0 { - break - } - offset += raw.NextEntryOffset - - // Error! - if offset >= n { - w.Errors <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.") - break - } - } - - if err := w.startRead(watch); err != nil { - w.Errors <- err - } - } -} - -func (w *Watcher) sendEvent(name string, mask uint64) bool { - if mask == 0 { - return false - } - event := newEvent(name, uint32(mask)) - select { - case ch := <-w.quit: - w.quit <- ch - case w.Events <- event: - } - return true -} - -func toWindowsFlags(mask uint64) uint32 { - var m uint32 - if mask&sysFSACCESS != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS - } - if mask&sysFSMODIFY != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE - } - if mask&sysFSATTRIB != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES - } - if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME - } - return m -} - -func toFSnotifyFlags(action uint32) uint64 { - switch action { - case syscall.FILE_ACTION_ADDED: - return sysFSCREATE - case syscall.FILE_ACTION_REMOVED: - return sysFSDELETE - case syscall.FILE_ACTION_MODIFIED: - return sysFSMODIFY - case syscall.FILE_ACTION_RENAMED_OLD_NAME: - return sysFSMOVEDFROM - case syscall.FILE_ACTION_RENAMED_NEW_NAME: - return sysFSMOVEDTO - } - return 0 -} diff --git a/vendor/github.com/go-zoo/bone/LICENSE b/vendor/github.com/go-zoo/bone/LICENSE deleted file mode 100644 index 652583b76..000000000 --- a/vendor/github.com/go-zoo/bone/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 CodingFerret - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, Subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or Substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/vendor/github.com/go-zoo/bone/README.md b/vendor/github.com/go-zoo/bone/README.md deleted file mode 100644 index 29ea5f6de..000000000 --- a/vendor/github.com/go-zoo/bone/README.md +++ /dev/null @@ -1,81 +0,0 @@ -bone [![GoDoc](https://godoc.org/github.com/squiidz/bone?status.png)](http://godoc.org/github.com/go-zoo/bone) [![Build Status](https://travis-ci.org/go-zoo/bone.svg)](https://travis-ci.org/go-zoo/bone) [![Go Report Card](https://goreportcard.com/badge/go-zoo/bone)](https://goreportcard.com/report/go-zoo/bone) [![Sourcegraph](https://sourcegraph.com/github.com/go-zoo/bone/-/badge.svg)](https://sourcegraph.com/github.com/go-zoo/bone?badge) -======= - -## What is bone ? - -Bone is a lightweight and lightning fast HTTP Multiplexer for Golang. It support : - -- URL Parameters -- REGEX Parameters -- Wildcard routes -- Router Prefix -- Sub Router, `mux.SubRoute()`, support most standard router (bone, gorilla/mux, httpRouter etc...) -- Http method declaration -- Support for `http.Handler` and `http.HandlerFunc` -- Custom NotFound handler -- Respect the Go standard `http.Handler` interface - -![alt tag](https://c2.staticflickr.com/2/1070/540747396_5542b42cca_z.jpg) - -## Speed - -``` -- BenchmarkBoneMux 10000000 118 ns/op -- BenchmarkZeusMux 100000 144 ns/op -- BenchmarkHttpRouterMux 10000000 134 ns/op -- BenchmarkNetHttpMux 3000000 580 ns/op -- BenchmarkGorillaMux 300000 3333 ns/op -- BenchmarkGorillaPatMux 1000000 1889 ns/op -``` - - These test are just for fun, all these router are great and really efficient. - Bone do not pretend to be the fastest router for every job. - -## Example - -``` go - -package main - -import( - "net/http" - - "github.com/go-zoo/bone" -) - -func main () { - mux := bone.New() - - // mux.Get, Post, etc ... takes http.Handler - mux.Get("/home/:id", http.HandlerFunc(HomeHandler)) - mux.Get("/profil/:id/:var", http.HandlerFunc(ProfilHandler)) - mux.Post("/data", http.HandlerFunc(DataHandler)) - - // Support REGEX Route params - mux.Get("/index/#id^[0-9]$", http.HandlerFunc(IndexHandler)) - - // Handle take http.Handler - mux.Handle("/", http.HandlerFunc(RootHandler)) - - // GetFunc, PostFunc etc ... takes http.HandlerFunc - mux.GetFunc("/test", Handler) - - http.ListenAndServe(":8080", mux) -} - -func Handler(rw http.ResponseWriter, req *http.Request) { - // Get the value of the "id" parameters. - val := bone.GetValue(req, "id") - - rw.Write([]byte(val)) -} - -``` - -## Blog Posts -- http://www.peterbe.com/plog/my-favorite-go-multiplexer -- https://harshladha.xyz/my-first-library-in-go-language-hasty-791b8e2b9e69 - -## Libs -- Errors dump for Go : [Trash](https://github.com/go-zoo/trash) -- Middleware Chaining module : [Claw](https://github.com/go-zoo/claw) diff --git a/vendor/github.com/go-zoo/bone/bone.go b/vendor/github.com/go-zoo/bone/bone.go deleted file mode 100644 index d00a0b083..000000000 --- a/vendor/github.com/go-zoo/bone/bone.go +++ /dev/null @@ -1,74 +0,0 @@ -/******************************** -*** Multiplexer for Go *** -*** Bone is under MIT license *** -*** Code by CodingFerret *** -*** github.com/go-zoo *** -*********************************/ - -package bone - -import ( - "net/http" - "strings" -) - -// Mux have routes and a notFound handler -// Route: all the registred route -// notFound: 404 handler, default http.NotFound if not provided -type Mux struct { - Routes map[string][]*Route - prefix string - notFound http.Handler - Serve func(rw http.ResponseWriter, req *http.Request) - CaseSensitive bool -} - -var ( - static = "static" - method = []string{"GET", "POST", "PUT", "DELETE", "HEAD", "PATCH", "OPTIONS"} -) - -type adapter func(*Mux) *Mux - -// New create a pointer to a Mux instance -func New(adapters ...adapter) *Mux { - m := &Mux{Routes: make(map[string][]*Route), Serve: nil, CaseSensitive: true} - for _, adap := range adapters { - adap(m) - } - if m.Serve == nil { - m.Serve = m.DefaultServe - } - return m -} - -// Prefix set a default prefix for all routes registred on the router -func (m *Mux) Prefix(p string) *Mux { - m.prefix = strings.TrimSuffix(p, "/") - return m -} - -// DefaultServe is the default http request handler -func (m *Mux) DefaultServe(rw http.ResponseWriter, req *http.Request) { - // Check if a route match - if !m.parse(rw, req) { - // Check if it's a static ressource - if !m.staticRoute(rw, req) { - // Check if the request path doesn't end with / - if !m.validate(rw, req) { - // Check if same route exists for another HTTP method - if !m.otherMethods(rw, req) { - m.HandleNotFound(rw, req) - } - } - } - } -} - -// ServeHTTP pass the request to the serve method of Mux -func (m *Mux) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - if !m.CaseSensitive { - req.URL.Path = strings.ToLower(req.URL.Path) - } - m.Serve(rw, req) -} diff --git a/vendor/github.com/go-zoo/bone/helper.go b/vendor/github.com/go-zoo/bone/helper.go deleted file mode 100644 index bd7b45e95..000000000 --- a/vendor/github.com/go-zoo/bone/helper.go +++ /dev/null @@ -1,169 +0,0 @@ -/******************************** -*** Multiplexer for Go *** -*** Bone is under MIT license *** -*** Code by CodingFerret *** -*** github.com/go-zoo *** -*********************************/ - -package bone - -import ( - "net/http" - "net/url" - "strings" -) - -func (m *Mux) ListenAndServe(port string) error { - return http.ListenAndServe(port, m) -} - -func (m *Mux) parse(rw http.ResponseWriter, req *http.Request) bool { - for _, r := range m.Routes[req.Method] { - ok := r.parse(rw, req) - if ok { - return true - } - } - // If no HEAD method, default to GET - if req.Method == "HEAD" { - for _, r := range m.Routes["GET"] { - ok := r.parse(rw, req) - if ok { - return true - } - } - } - return false -} - -// StaticRoute check if the request path is for Static route -func (m *Mux) staticRoute(rw http.ResponseWriter, req *http.Request) bool { - for _, s := range m.Routes[static] { - if len(req.URL.Path) >= s.Size { - if req.URL.Path[:s.Size] == s.Path { - s.Handler.ServeHTTP(rw, req) - return true - } - } - } - return false -} - -// HandleNotFound handle when a request does not match a registered handler. -func (m *Mux) HandleNotFound(rw http.ResponseWriter, req *http.Request) { - if m.notFound != nil { - m.notFound.ServeHTTP(rw, req) - } else { - http.NotFound(rw, req) - } -} - -// Check if the path don't end with a / -func (m *Mux) validate(rw http.ResponseWriter, req *http.Request) bool { - plen := len(req.URL.Path) - if plen > 1 && req.URL.Path[plen-1:] == "/" { - cleanURL(&req.URL.Path) - rw.Header().Set("Location", req.URL.String()) - rw.WriteHeader(http.StatusFound) - return true - } - // Retry to find a route that match - return m.parse(rw, req) -} - -func valid(path string) bool { - plen := len(path) - if plen > 1 && path[plen-1:] == "/" { - return false - } - return true -} - -// Clean url path -func cleanURL(url *string) { - ulen := len((*url)) - if ulen > 1 { - if (*url)[ulen-1:] == "/" { - *url = (*url)[:ulen-1] - cleanURL(url) - } - } -} - -// GetValue return the key value, of the current *http.Request -func GetValue(req *http.Request, key string) string { - return GetAllValues(req)[key] -} - -// GetRequestRoute returns the route of given Request -func (m *Mux) GetRequestRoute(req *http.Request) string { - cleanURL(&req.URL.Path) - for _, r := range m.Routes[req.Method] { - if r.Atts != 0 { - if r.Atts&SUB != 0 { - return r.Handler.(*Mux).GetRequestRoute(req) - } - if r.Match(req) { - return r.Path - } - } - if req.URL.Path == r.Path { - return r.Path - } - } - - for _, s := range m.Routes[static] { - if len(req.URL.Path) >= s.Size { - if req.URL.Path[:s.Size] == s.Path { - return s.Path - } - } - } - - return "NotFound" -} - -// GetQuery return the key value, of the current *http.Request query -func GetQuery(req *http.Request, key string) []string { - if ok, value := extractQueries(req); ok { - return value[key] - } - return nil -} - -// GetAllQueries return all queries of the current *http.Request -func GetAllQueries(req *http.Request) map[string][]string { - if ok, values := extractQueries(req); ok { - return values - } - return nil -} - -func extractQueries(req *http.Request) (bool, map[string][]string) { - if q, err := url.ParseQuery(req.URL.RawQuery); err == nil { - var queries = make(map[string][]string) - for k, v := range q { - for _, item := range v { - values := strings.Split(item, ",") - queries[k] = append(queries[k], values...) - } - } - return true, queries - } - return false, nil -} - -func (m *Mux) otherMethods(rw http.ResponseWriter, req *http.Request) bool { - for _, met := range method { - if met != req.Method { - for _, r := range m.Routes[met] { - ok := r.exists(rw, req) - if ok { - rw.WriteHeader(http.StatusMethodNotAllowed) - return true - } - } - } - } - return false -} diff --git a/vendor/github.com/go-zoo/bone/helper_15.go b/vendor/github.com/go-zoo/bone/helper_15.go deleted file mode 100644 index 068ce18e0..000000000 --- a/vendor/github.com/go-zoo/bone/helper_15.go +++ /dev/null @@ -1,45 +0,0 @@ -// +build !go1.7 - -/******************************** -*** Multiplexer for Go *** -*** Bone is under MIT license *** -*** Code by CodingFerret *** -*** github.com/go-zoo *** -*********************************/ - -package bone - -import ( - "net/http" - "sync" -) - -var globalVars = struct { - sync.RWMutex - v map[*http.Request]map[string]string -}{v: make(map[*http.Request]map[string]string)} - -// GetAllValues return the req PARAMs -func GetAllValues(req *http.Request) map[string]string { - globalVars.RLock() - values := globalVars.v[req] - globalVars.RUnlock() - return values -} - -// serveMatchedRequest is an extension point for Route which allows us to conditionally compile for -// go1.7 and <go1.7 -func (r *Route) serveMatchedRequest(rw http.ResponseWriter, req *http.Request, vars map[string]string) { - globalVars.Lock() - globalVars.v[req] = vars - globalVars.Unlock() - - // Regardless if ServeHTTP panics (and potentially recovers) we can make sure to not leak - // memory in globalVars for this request - defer func() { - globalVars.Lock() - delete(globalVars.v, req) - globalVars.Unlock() - }() - r.Handler.ServeHTTP(rw, req) -} diff --git a/vendor/github.com/go-zoo/bone/helper_17.go b/vendor/github.com/go-zoo/bone/helper_17.go deleted file mode 100644 index 2e41ea4be..000000000 --- a/vendor/github.com/go-zoo/bone/helper_17.go +++ /dev/null @@ -1,39 +0,0 @@ -// +build go1.7 - -/******************************** -*** Multiplexer for Go *** -*** Bone is under MIT license *** -*** Code by CodingFerret *** -*** github.com/go-zoo *** -*********************************/ - -package bone - -import ( - "context" - "net/http" -) - -// contextKeyType is a private struct that is used for storing bone values in net.Context -type contextKeyType struct{} - -// contextKey is the key that is used to store bone values in the net.Context for each request -var contextKey = contextKeyType{} - -// GetAllValues return the req PARAMs -func GetAllValues(req *http.Request) map[string]string { - values, ok := req.Context().Value(contextKey).(map[string]string) - if ok { - return values - } - - return map[string]string{} -} - -// serveMatchedRequest is an extension point for Route which allows us to conditionally compile for -// go1.7 and <go1.7 -func (r *Route) serveMatchedRequest(rw http.ResponseWriter, req *http.Request, vars map[string]string) { - ctx := context.WithValue(req.Context(), contextKey, vars) - newReq := req.WithContext(ctx) - r.Handler.ServeHTTP(rw, newReq) -} diff --git a/vendor/github.com/go-zoo/bone/mux.go b/vendor/github.com/go-zoo/bone/mux.go deleted file mode 100644 index 0ec29a338..000000000 --- a/vendor/github.com/go-zoo/bone/mux.go +++ /dev/null @@ -1,137 +0,0 @@ -/******************************** -*** Multiplexer for Go *** -*** Bone is under MIT license *** -*** Code by CodingFerret *** -*** github.com/go-zoo *** -*********************************/ - -package bone - -import "net/http" - -// Router is the same as a http.Handler -type Router interface { - ServeHTTP(http.ResponseWriter, *http.Request) -} - -// Register the route in the router -func (m *Mux) Register(method string, path string, handler http.Handler) *Route { - return m.register(method, path, handler) -} - -// GetFunc add a new route to the Mux with the Get method -func (m *Mux) GetFunc(path string, handler http.HandlerFunc) *Route { - return m.register("GET", path, handler) -} - -// PostFunc add a new route to the Mux with the Post method -func (m *Mux) PostFunc(path string, handler http.HandlerFunc) *Route { - return m.register("POST", path, handler) -} - -// PutFunc add a new route to the Mux with the Put method -func (m *Mux) PutFunc(path string, handler http.HandlerFunc) *Route { - return m.register("PUT", path, handler) -} - -// DeleteFunc add a new route to the Mux with the Delete method -func (m *Mux) DeleteFunc(path string, handler http.HandlerFunc) *Route { - return m.register("DELETE", path, handler) -} - -// HeadFunc add a new route to the Mux with the Head method -func (m *Mux) HeadFunc(path string, handler http.HandlerFunc) *Route { - return m.register("HEAD", path, handler) -} - -// PatchFunc add a new route to the Mux with the Patch method -func (m *Mux) PatchFunc(path string, handler http.HandlerFunc) *Route { - return m.register("PATCH", path, handler) -} - -// OptionsFunc add a new route to the Mux with the Options method -func (m *Mux) OptionsFunc(path string, handler http.HandlerFunc) *Route { - return m.register("OPTIONS", path, handler) -} - -// NotFoundFunc the mux custom 404 handler -func (m *Mux) NotFoundFunc(handler http.HandlerFunc) { - m.notFound = handler -} - -// Handle add a new route to the Mux without a HTTP method -func (m *Mux) Handle(path string, handler http.Handler) { - for _, mt := range method { - m.register(mt, path, handler) - } -} - -// HandleFunc is use to pass a func(http.ResponseWriter, *Http.Request) instead of http.Handler -func (m *Mux) HandleFunc(path string, handler http.HandlerFunc) { - m.Handle(path, handler) -} - -// Get add a new route to the Mux with the Get method -func (m *Mux) Get(path string, handler http.Handler) *Route { - return m.register("GET", path, handler) -} - -// Post add a new route to the Mux with the Post method -func (m *Mux) Post(path string, handler http.Handler) *Route { - return m.register("POST", path, handler) -} - -// Put add a new route to the Mux with the Put method -func (m *Mux) Put(path string, handler http.Handler) *Route { - return m.register("PUT", path, handler) -} - -// Delete add a new route to the Mux with the Delete method -func (m *Mux) Delete(path string, handler http.Handler) *Route { - return m.register("DELETE", path, handler) -} - -// Head add a new route to the Mux with the Head method -func (m *Mux) Head(path string, handler http.Handler) *Route { - return m.register("HEAD", path, handler) -} - -// Patch add a new route to the Mux with the Patch method -func (m *Mux) Patch(path string, handler http.Handler) *Route { - return m.register("PATCH", path, handler) -} - -// Options add a new route to the Mux with the Options method -func (m *Mux) Options(path string, handler http.Handler) *Route { - return m.register("OPTIONS", path, handler) -} - -// NotFound the mux custom 404 handler -func (m *Mux) NotFound(handler http.Handler) { - m.notFound = handler -} - -// Register the new route in the router with the provided method and handler -func (m *Mux) register(method string, path string, handler http.Handler) *Route { - r := NewRoute(m.prefix+path, handler) - r.Method = method - if valid(path) { - m.Routes[method] = append(m.Routes[method], r) - return r - } - m.Routes[static] = append(m.Routes[static], r) - return r -} - -// SubRoute register a router as a SubRouter of bone -func (m *Mux) SubRoute(path string, router Router) *Route { - r := NewRoute(m.prefix+path, router) - if valid(path) { - r.Atts += SUB - for _, mt := range method { - m.Routes[mt] = append(m.Routes[mt], r) - } - return r - } - return nil -} diff --git a/vendor/github.com/go-zoo/bone/route.go b/vendor/github.com/go-zoo/bone/route.go deleted file mode 100644 index 7f6c1b1d0..000000000 --- a/vendor/github.com/go-zoo/bone/route.go +++ /dev/null @@ -1,245 +0,0 @@ -/******************************** -*** Multiplexer for Go *** -*** Bone is under MIT license *** -*** Code by CodingFerret *** -*** github.com/go-zoo *** -*********************************/ - -package bone - -import ( - "net/http" - "regexp" - "strings" -) - -const ( - //PARAM value store in Atts if the route have parameters - PARAM = 2 - //SUB value store in Atts if the route is a sub router - SUB = 4 - //WC value store in Atts if the route have wildcard - WC = 8 - //REGEX value store in Atts if the route contains regex - REGEX = 16 -) - -// Route content the required information for a valid route -// Path: is the Route URL -// Size: is the length of the path -// Token: is the value of each part of the path, split by / -// Pattern: is content information about the route, if it's have a route variable -// handler: is the handler who handle this route -// Method: define HTTP method on the route -type Route struct { - Path string - Method string - Size int - Atts int - wildPos int - Token Token - Pattern map[int]string - Compile map[int]*regexp.Regexp - Tag map[int]string - Handler http.Handler -} - -// Token content all value of a spliting route path -// Tokens: string value of each token -// size: number of token -type Token struct { - raw []int - Tokens []string - Size int -} - -// NewRoute return a pointer to a Route instance and call save() on it -func NewRoute(url string, h http.Handler) *Route { - r := &Route{Path: url, Handler: h} - r.save() - return r -} - -// Save, set automatically the the Route.Size and Route.Pattern value -func (r *Route) save() { - r.Size = len(r.Path) - r.Token.Tokens = strings.Split(r.Path, "/") - for i, s := range r.Token.Tokens { - if len(s) >= 1 { - switch s[:1] { - case ":": - if r.Pattern == nil { - r.Pattern = make(map[int]string) - } - r.Pattern[i] = s[1:] - r.Atts |= PARAM - case "#": - if r.Compile == nil { - r.Compile = make(map[int]*regexp.Regexp) - r.Tag = make(map[int]string) - } - tmp := strings.Split(s, "^") - r.Tag[i] = tmp[0][1:] - r.Compile[i] = regexp.MustCompile("^" + tmp[1][:len(tmp[1])-1]) - r.Atts |= REGEX - case "*": - r.wildPos = i - r.Atts |= WC - default: - r.Token.raw = append(r.Token.raw, i) - } - } - r.Token.Size++ - } -} - -// Match check if the request match the route Pattern -func (r *Route) Match(req *http.Request) bool { - ok, _ := r.matchAndParse(req) - return ok -} - -// matchAndParse check if the request matches the route Pattern and returns a map of the parsed -// variables if it matches -func (r *Route) matchAndParse(req *http.Request) (bool, map[string]string) { - ss := strings.Split(req.URL.EscapedPath(), "/") - if r.matchRawTokens(&ss) { - if len(ss) == r.Token.Size || r.Atts&WC != 0 { - totalSize := len(r.Pattern) - if r.Atts®EX != 0 { - totalSize += len(r.Compile) - } - - vars := make(map[string]string, totalSize) - for k, v := range r.Pattern { - vars[v] = ss[k] - } - - if r.Atts®EX != 0 { - for k, v := range r.Compile { - if !v.MatchString(ss[k]) { - return false, nil - } - vars[r.Tag[k]] = ss[k] - } - } - - return true, vars - } - } - - return false, nil -} - -func (r *Route) parse(rw http.ResponseWriter, req *http.Request) bool { - if r.Atts != 0 { - if r.Atts&SUB != 0 { - if len(req.URL.Path) >= r.Size { - if req.URL.Path[:r.Size] == r.Path { - req.URL.Path = req.URL.Path[r.Size:] - r.Handler.ServeHTTP(rw, req) - return true - } - } - } - - if ok, vars := r.matchAndParse(req); ok { - r.serveMatchedRequest(rw, req, vars) - return true - } - } - if req.URL.Path == r.Path { - r.Handler.ServeHTTP(rw, req) - return true - } - return false -} - -func (r *Route) matchRawTokens(ss *[]string) bool { - if len(*ss) >= r.Token.Size { - for i, v := range r.Token.raw { - if (*ss)[v] != r.Token.Tokens[v] { - if r.Atts&WC != 0 && r.wildPos == i { - return true - } - return false - } - } - return true - } - return false -} - -func (r *Route) exists(rw http.ResponseWriter, req *http.Request) bool { - if r.Atts != 0 { - if r.Atts&SUB != 0 { - if len(req.URL.Path) >= r.Size { - if req.URL.Path[:r.Size] == r.Path { - return true - } - } - } - - if ok, _ := r.matchAndParse(req); ok { - return true - } - } - if req.URL.Path == r.Path { - return true - } - return false -} - -// Get set the route method to Get -func (r *Route) Get() *Route { - r.Method = "GET" - return r -} - -// Post set the route method to Post -func (r *Route) Post() *Route { - r.Method = "POST" - return r -} - -// Put set the route method to Put -func (r *Route) Put() *Route { - r.Method = "PUT" - return r -} - -// Delete set the route method to Delete -func (r *Route) Delete() *Route { - r.Method = "DELETE" - return r -} - -// Head set the route method to Head -func (r *Route) Head() *Route { - r.Method = "HEAD" - return r -} - -// Patch set the route method to Patch -func (r *Route) Patch() *Route { - r.Method = "PATCH" - return r -} - -// Options set the route method to Options -func (r *Route) Options() *Route { - r.Method = "OPTIONS" - return r -} - -func (r *Route) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - if r.Method != "" { - if req.Method == r.Method { - r.Handler.ServeHTTP(rw, req) - return - } - http.NotFound(rw, req) - return - } - r.Handler.ServeHTTP(rw, req) -} diff --git a/vendor/github.com/kubernetes-incubator/cri-o/LICENSE b/vendor/github.com/kubernetes-incubator/cri-o/LICENSE new file mode 100644 index 000000000..8dada3eda --- /dev/null +++ b/vendor/github.com/kubernetes-incubator/cri-o/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/kubernetes-incubator/cri-o/README.md b/vendor/github.com/kubernetes-incubator/cri-o/README.md new file mode 100644 index 000000000..dd2881142 --- /dev/null +++ b/vendor/github.com/kubernetes-incubator/cri-o/README.md @@ -0,0 +1,263 @@ +![CRI-O logo](https://cdn.rawgit.com/kubernetes-incubator/cri-o/master/logo/crio-logo.svg) +# CRI-O - OCI-based implementation of Kubernetes Container Runtime Interface + +[![Build Status](https://img.shields.io/travis/kubernetes-incubator/cri-o.svg?maxAge=2592000&style=flat-square)](https://travis-ci.org/kubernetes-incubator/cri-o) +[![Go Report Card](https://goreportcard.com/badge/github.com/kubernetes-incubator/cri-o?style=flat-square)](https://goreportcard.com/report/github.com/kubernetes-incubator/cri-o) + +### Status: Stable + +## What is the scope of this project? + +CRI-O is meant to provide an integration path between OCI conformant runtimes and the kubelet. +Specifically, it implements the Kubelet [Container Runtime Interface (CRI)](https://github.com/kubernetes/community/blob/master/contributors/devel/container-runtime-interface.md) using OCI conformant runtimes. +The scope of CRI-O is tied to the scope of the CRI. + +At a high level, we expect the scope of CRI-O to be restricted to the following functionalities: + +* Support multiple image formats including the existing Docker image format +* Support for multiple means to download images including trust & image verification +* Container image management (managing image layers, overlay filesystems, etc) +* Container process lifecycle management +* Monitoring and logging required to satisfy the CRI +* Resource isolation as required by the CRI + +## What is not in scope for this project? + +* Building, signing and pushing images to various image storages +* A CLI utility for interacting with CRI-O. Any CLIs built as part of this project are only meant for testing this project and there will be no guarantees on the backward compatibility with it. + +This is an implementation of the Kubernetes Container Runtime Interface (CRI) that will allow Kubernetes to directly launch and manage Open Container Initiative (OCI) containers. + +The plan is to use OCI projects and best of breed libraries for different aspects: +- Runtime: [runc](https://github.com/opencontainers/runc) (or any OCI runtime-spec implementation) and [oci runtime tools](https://github.com/opencontainers/runtime-tools) +- Images: Image management using [containers/image](https://github.com/containers/image) +- Storage: Storage and management of image layers using [containers/storage](https://github.com/containers/storage) +- Networking: Networking support through use of [CNI](https://github.com/containernetworking/cni) + +It is currently in active development in the Kubernetes community through the [design proposal](https://github.com/kubernetes/kubernetes/pull/26788). Questions and issues should be raised in the Kubernetes [sig-node Slack channel](https://kubernetes.slack.com/archives/sig-node). + +## Commands +| Command | Description | Demo| +| ---------------------------------------------------- | --------------------------------------------------------------------------|-----| +| [crio(8)](/docs/crio.8.md) | OCI Kubernetes Container Runtime daemon || +| [kpod(1)](/docs/kpod.1.md) | Simple management tool for pods and images || +| [kpod-attach(1)](/docs/kpod-attach.1.md) | Instead of providing a `kpod attach` command, the man page `kpod-attach` describes how to use the `kpod logs` and `kpod exec` commands to achieve the same goals as `kpod attach`.|| +| [kpod-cp(1)](/docs/kpod-cp.1.md) | Instead of providing a `kpod cp` command, the man page `kpod-cp` describes how to use the `kpod mount` command to have even more flexibility and functionality.|| +| [kpod-create(1)](/docs/kpod-create.1.md) | Create a new container || +| [kpod-diff(1)](/docs/kpod-diff.1.md) | Inspect changes on a container or image's filesystem || +| [kpod-export(1)](/docs/kpod-export.1.md) | Export container's filesystem contents as a tar archive |[![...](/docs/play.png)](https://asciinema.org/a/913lBIRAg5hK8asyIhhkQVLtV)| +| [kpod-history(1)](/docs/kpod-history.1.md) | Shows the history of an image |[![...](/docs/play.png)](https://asciinema.org/a/bCvUQJ6DkxInMELZdc5DinNSx)| +| [kpod-images(1)](/docs/kpod-images.1.md) | List images in local storage |[![...](/docs/play.png)](https://asciinema.org/a/133649)| +| [kpod-info(1)](/docs/kpod-info.1.md) | Display system information || +| [kpod-inspect(1)](/docs/kpod-inspect.1.md) | Display the configuration of a container or image |[![...](/docs/play.png)](https://asciinema.org/a/133418)| +| [kpod-kill(1)](/docs/kpod-kill.1.md) | Kill the main process in one or more running containers |[![...](/docs/play.png)](https://asciinema.org/a/3jNos0A5yzO4hChu7ddKkUPw7)| +| [kpod-load(1)](/docs/kpod-load.1.md) | Load an image from docker archive or oci |[![...](/docs/play.png)](https://asciinema.org/a/kp8kOaexEhEa20P1KLZ3L5X4g)| +| [kpod-login(1)](/docs/kpod-login.1.md) | Login to a container registry |[![...](/docs/play.png)](https://asciinema.org/a/oNiPgmfo1FjV2YdesiLpvihtV)| +| [kpod-logout(1)](/docs/kpod-logout.1.md) | Logout of a container registry |[![...](/docs/play.png)](https://asciinema.org/a/oNiPgmfo1FjV2YdesiLpvihtV)| +| [kpod-logs(1)](/docs/kpod-logs.1.md) | Display the logs of a container || +| [kpod-mount(1)](/docs/kpod-mount.1.md) | Mount a working container's root filesystem || +| [kpod-pause(1)](/docs/kpod-pause.1.md) | Pause one or more running containers |[![...](/docs/play.png)](https://asciinema.org/a/141292)| +| [kpod-ps(1)](/docs/kpod-ps.1.md) | Prints out information about containers |[![...](/docs/play.png)](https://asciinema.org/a/bbT41kac6CwZ5giESmZLIaTLR)| +| [kpod-pull(1)](/docs/kpod-pull.1.md) | Pull an image from a registry |[![...](/docs/play.png)](https://asciinema.org/a/lr4zfoynHJOUNu1KaXa1dwG2X)| +| [kpod-push(1)](/docs/kpod-push.1.md) | Push an image to a specified destination |[![...](/docs/play.png)](https://asciinema.org/a/133276)| +| [kpod-rename(1)](/docs/kpod-rename.1.md) | Rename a container || +| [kpod-rm(1)](/docs/kpod-rm.1.md) | Removes one or more containers |[![...](/docs/play.png)](https://asciinema.org/a/7EMk22WrfGtKWmgHJX9Nze1Qp)| +| [kpod-rmi(1)](/docs/kpod-rmi.1.md) | Removes one or more images |[![...](/docs/play.png)](https://asciinema.org/a/133799)| +| [kpod-run(1)](/docs/kpod-run.1.md) | Run a command in a new container || +| [kpod-save(1)](/docs/kpod-save.1.md) | Saves an image to an archive |[![...](/docs/play.png)](https://asciinema.org/a/kp8kOaexEhEa20P1KLZ3L5X4g)| +| [kpod-stats(1)](/docs/kpod-stats.1.md) | Display a live stream of one or more containers' resource usage statistics|| +| [kpod-stop(1)](/docs/kpod-stop.1.md) | Stops one or more running containers || +| [kpod-tag(1)](/docs/kpod-tag.1.md) | Add an additional name to a local image |[![...](/docs/play.png)](https://asciinema.org/a/133803)| +| [kpod-umount(1)](/docs/kpod-umount.1.md) | Unmount a working container's root filesystem || +| [kpod-unpause(1)](/docs/kpod-unpause.1.md) | Unpause one or more running containers |[![...](/docs/play.png)](https://asciinema.org/a/141292)| +| [kpod-version(1)](/docs/kpod-version.1.md) | Display the version information |[![...](/docs/play.png)](https://asciinema.org/a/mfrn61pjZT9Fc8L4NbfdSqfgu)| +| [kpod-wait(1)](/docs/kpod-wait.1.md) | Wait on one or more containers to stop and print their exit codes|| + +## Configuration +| File | Description | +| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | +| [crio.conf(5)](/docs/crio.conf.5.md) | CRI-O Configuation file | + +## OCI Hooks Support + +[CRI-O configures OCI Hooks to run when launching a container](./hooks.md) + +## CRI-O Usage Transfer + +[Useful information for ops and dev transfer as it relates to infrastructure that utilizes CRI-O](/transfer.md) + +## Communication + +For async communication and long running discussions please use issues and pull requests on the github repo. This will be the best place to discuss design and implementation. + +For sync communication we have an IRC channel #CRI-O, on chat.freenode.net, that everyone is welcome to join and chat about development. + +## Getting started + +### Prerequisites + +Latest version of `runc` is expected to be installed on the system. It is picked up as the default runtime by CRI-O. + +### Build and Run Dependencies + +**Required** + +Fedora, CentOS, RHEL, and related distributions: + +```bash +yum install -y \ + btrfs-progs-devel \ + device-mapper-devel \ + git \ + glib2-devel \ + glibc-devel \ + glibc-static \ + go \ + golang-github-cpuguy83-go-md2man \ + gpgme-devel \ + libassuan-devel \ + libgpg-error-devel \ + libseccomp-devel \ + libselinux-devel \ + ostree-devel \ + pkgconfig \ + runc \ + skopeo-containers +``` + +Debian, Ubuntu, and related distributions: + +```bash +apt-get install -y \ + btrfs-tools \ + git \ + golang-go \ + libassuan-dev \ + libdevmapper-dev \ + libglib2.0-dev \ + libc6-dev \ + libgpgme11-dev \ + libgpg-error-dev \ + libseccomp-dev \ + libselinux1-dev \ + pkg-config \ + go-md2man \ + runc \ + skopeo-containers +``` + +Debian, Ubuntu, and related distributions will also need a copy of the development libraries for `ostree`, either in the form of the `libostree-dev` package from the [flatpak](https://launchpad.net/~alexlarsson/+archive/ubuntu/flatpak) PPA, or built [from source](https://github.com/ostreedev/ostree) (more on that [here](https://ostree.readthedocs.io/en/latest/#building)). + +If using an older release or a long-term support release, be careful to double-check that the version of `runc` is new enough (running `runc --version` should produce `spec: 1.0.0`), or else build your own. + +**NOTE** + +Be careful to double-check that the version of golang is new enough, version 1.8.x or higher is required. If needed, golang kits are avaliable at https://golang.org/dl/ + +**Optional** + +Fedora, CentOS, RHEL, and related distributions: + +(no optional packages) + +Debian, Ubuntu, and related distributions: + +```bash +apt-get install -y \ + libapparmor-dev +``` + +### Get Source Code + +As with other Go projects, CRI-O must be cloned into a directory structure like: + +``` +GOPATH +└── src + └── github.com + └── kubernetes-incubator + └── cri-o +``` + +First, configure a `GOPATH` (if you are using go1.8 or later, this defaults to `~/go`). + +```bash +export GOPATH=~/go +mkdir -p $GOPATH +``` + +Next, clone the source code using: + +```bash +mkdir -p $GOPATH/src/github.com/kubernetes-incubator +cd $_ # or cd $GOPATH/src/github.com/kubernetes-incubator +git clone https://github.com/kubernetes-incubator/cri-o # or your fork +cd cri-o +``` + +### Build + +```bash +make install.tools +make +sudo make install +``` + +Otherwise, if you do not want to build `CRI-O` with seccomp support you can add `BUILDTAGS=""` when running make. + +```bash +make BUILDTAGS="" +sudo make install +``` + +#### Build Tags + +`CRI-O` supports optional build tags for compiling support of various features. +To add build tags to the make option the `BUILDTAGS` variable must be set. + +```bash +make BUILDTAGS='seccomp apparmor' +``` + +| Build Tag | Feature | Dependency | +|-----------|------------------------------------|-------------| +| seccomp | syscall filtering | libseccomp | +| selinux | selinux process and mount labeling | libselinux | +| apparmor | apparmor profile support | libapparmor | + +### Running pods and containers + +Follow this [tutorial](tutorial.md) to get started with CRI-O. + +### Setup CNI networking + +A proper description of setting up CNI networking is given in the +[`contrib/cni` README](contrib/cni/README.md). But the gist is that you need to +have some basic network configurations enabled and CNI plugins installed on +your system. + +### Running with kubernetes + +You can run a local version of kubernetes with CRI-O using `local-up-cluster.sh`: + +1. Clone the [kubernetes repository](https://github.com/kubernetes/kubernetes) +1. Start the CRI-O daemon (`crio`) +1. From the kubernetes project directory, run: +```shell +CGROUP_DRIVER=systemd \ +CONTAINER_RUNTIME=remote \ +CONTAINER_RUNTIME_ENDPOINT='/var/run/crio.sock --runtime-request-timeout=15m' \ +./hack/local-up-cluster.sh +``` + +To run a full cluster, see [the instructions](kubernetes.md). + +### Current Roadmap + +1. Basic pod/container lifecycle, basic image pull (done) +1. Support for tty handling and state management (done) +1. Basic integration with kubelet once client side changes are ready (done) +1. Support for log management, networking integration using CNI, pluggable image/storage management (done) +1. Support for exec/attach (done) +1. Target fully automated kubernetes testing without failures [e2e status](https://github.com/kubernetes-incubator/cri-o/issues/533) +1. Track upstream k8s releases diff --git a/vendor/github.com/kubernetes-incubator/cri-o/conmon/cmsg.c b/vendor/github.com/kubernetes-incubator/cri-o/conmon/cmsg.c new file mode 100644 index 000000000..c44db2ef1 --- /dev/null +++ b/vendor/github.com/kubernetes-incubator/cri-o/conmon/cmsg.c @@ -0,0 +1,149 @@ +/* + * Copyright 2016 SUSE LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* NOTE: This code comes directly from runc/libcontainer/utils/cmsg.c. */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> + +#include "cmsg.h" + +#define error(fmt, ...) \ + ({ \ + fprintf(stderr, "nsenter: " fmt ": %m\n", ##__VA_ARGS__); \ + errno = ECOMM; \ + goto err; /* return value */ \ + }) + +/* + * Sends a file descriptor along the sockfd provided. Returns the return + * value of sendmsg(2). Any synchronisation and preparation of state + * should be done external to this (we expect the other side to be in + * recvfd() in the code). + */ +ssize_t sendfd(int sockfd, struct file_t file) +{ + struct msghdr msg = {0}; + struct iovec iov[1] = {0}; + struct cmsghdr *cmsg; + int *fdptr; + + union { + char buf[CMSG_SPACE(sizeof(file.fd))]; + struct cmsghdr align; + } u; + + /* + * We need to send some other data along with the ancillary data, + * otherwise the other side won't recieve any data. This is very + * well-hidden in the documentation (and only applies to + * SOCK_STREAM). See the bottom part of unix(7). + */ + iov[0].iov_base = file.name; + iov[0].iov_len = strlen(file.name) + 1; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_control = u.buf; + msg.msg_controllen = sizeof(u.buf); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + + fdptr = (int *) CMSG_DATA(cmsg); + memcpy(fdptr, &file.fd, sizeof(int)); + + return sendmsg(sockfd, &msg, 0); +} + +/* + * Receives a file descriptor from the sockfd provided. Returns the file + * descriptor as sent from sendfd(). It will return the file descriptor + * or die (literally) trying. Any synchronisation and preparation of + * state should be done external to this (we expect the other side to be + * in sendfd() in the code). + */ +struct file_t recvfd(int sockfd) +{ + struct msghdr msg = {0}; + struct iovec iov[1] = {0}; + struct cmsghdr *cmsg; + struct file_t file = {0}; + int *fdptr; + int olderrno; + + union { + char buf[CMSG_SPACE(sizeof(file.fd))]; + struct cmsghdr align; + } u; + + /* Allocate a buffer. */ + /* TODO: Make this dynamic with MSG_PEEK. */ + file.name = malloc(TAG_BUFFER); + if (!file.name) + error("recvfd: failed to allocate file.tag buffer\n"); + + /* + * We need to "recieve" the non-ancillary data even though we don't + * plan to use it at all. Otherwise, things won't work as expected. + * See unix(7) and other well-hidden documentation. + */ + iov[0].iov_base = file.name; + iov[0].iov_len = TAG_BUFFER; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_control = u.buf; + msg.msg_controllen = sizeof(u.buf); + + ssize_t ret = recvmsg(sockfd, &msg, 0); + if (ret < 0) + goto err; + + cmsg = CMSG_FIRSTHDR(&msg); + if (!cmsg) + error("recvfd: got NULL from CMSG_FIRSTHDR"); + if (cmsg->cmsg_level != SOL_SOCKET) + error("recvfd: expected SOL_SOCKET in cmsg: %d", cmsg->cmsg_level); + if (cmsg->cmsg_type != SCM_RIGHTS) + error("recvfd: expected SCM_RIGHTS in cmsg: %d", cmsg->cmsg_type); + if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) + error("recvfd: expected correct CMSG_LEN in cmsg: %lu", cmsg->cmsg_len); + + fdptr = (int *) CMSG_DATA(cmsg); + if (!fdptr || *fdptr < 0) + error("recvfd: recieved invalid pointer"); + + file.fd = *fdptr; + return file; + +err: + olderrno = errno; + free(file.name); + errno = olderrno; + return (struct file_t){0}; +} diff --git a/vendor/github.com/kubernetes-incubator/cri-o/conmon/cmsg.h b/vendor/github.com/kubernetes-incubator/cri-o/conmon/cmsg.h new file mode 100644 index 000000000..7c7aefe6e --- /dev/null +++ b/vendor/github.com/kubernetes-incubator/cri-o/conmon/cmsg.h @@ -0,0 +1,38 @@ +/* + * Copyright 2016 SUSE LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* NOTE: This code comes directly from runc/libcontainer/utils/cmsg.h. */ + +#pragma once + +#if !defined(CMSG_H) +#define CMSG_H + +#include <sys/types.h> + +/* TODO: Implement this properly with MSG_PEEK. */ +#define TAG_BUFFER 4096 + +/* This mirrors Go's (*os.File). */ +struct file_t { + char *name; + int fd; +}; + +struct file_t recvfd(int sockfd); +ssize_t sendfd(int sockfd, struct file_t file); + +#endif /* !defined(CMSG_H) */ diff --git a/vendor/github.com/kubernetes-incubator/cri-o/conmon/conmon.c b/vendor/github.com/kubernetes-incubator/cri-o/conmon/conmon.c new file mode 100644 index 000000000..66d1bbe08 --- /dev/null +++ b/vendor/github.com/kubernetes-incubator/cri-o/conmon/conmon.c @@ -0,0 +1,1474 @@ +#define _GNU_SOURCE +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <sys/prctl.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/un.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/eventfd.h> +#include <sys/stat.h> +#include <sys/uio.h> +#include <sys/ioctl.h> +#include <termios.h> +#include <syslog.h> +#include <unistd.h> +#include <inttypes.h> + +#include <glib.h> +#include <glib-unix.h> + +#include "cmsg.h" + +#define pexit(fmt, ...) \ + do { \ + fprintf(stderr, "[conmon:e]: " fmt " %m\n", ##__VA_ARGS__); \ + syslog(LOG_ERR, "conmon <error>: " fmt ": %m\n", ##__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } while (0) + +#define nexit(fmt, ...) \ + do { \ + fprintf(stderr, "[conmon:e]: " fmt "\n", ##__VA_ARGS__); \ + syslog(LOG_ERR, "conmon <error>: " fmt " \n", ##__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } while (0) + +#define nwarn(fmt, ...) \ + do { \ + fprintf(stderr, "[conmon:w]: " fmt "\n", ##__VA_ARGS__); \ + syslog(LOG_INFO, "conmon <nwarn>: " fmt " \n", ##__VA_ARGS__); \ + } while (0) + +#define ninfo(fmt, ...) \ + do { \ + fprintf(stderr, "[conmon:i]: " fmt "\n", ##__VA_ARGS__); \ + syslog(LOG_INFO, "conmon <ninfo>: " fmt " \n", ##__VA_ARGS__); \ + } while (0) + +#define _cleanup_(x) __attribute__((cleanup(x))) + +static inline void freep(void *p) +{ + free(*(void **)p); +} + +static inline void closep(int *fd) +{ + if (*fd >= 0) + close(*fd); + *fd = -1; +} + +static inline void fclosep(FILE **fp) { + if (*fp) + fclose(*fp); + *fp = NULL; +} + +static inline void gstring_free_cleanup(GString **string) +{ + if (*string) + g_string_free(*string, TRUE); +} + +static inline void strv_cleanup(char ***strv) +{ + if (strv) + g_strfreev (*strv); +} + +#define _cleanup_free_ _cleanup_(freep) +#define _cleanup_close_ _cleanup_(closep) +#define _cleanup_fclose_ _cleanup_(fclosep) +#define _cleanup_gstring_ _cleanup_(gstring_free_cleanup) +#define _cleanup_strv_ _cleanup_(strv_cleanup) + +#define BUF_SIZE 8192 +#define CMD_SIZE 1024 +#define MAX_EVENTS 10 + +#define DEFAULT_SOCKET_PATH "/var/lib/crio" + +static bool opt_terminal = false; +static bool opt_stdin = false; +static char *opt_cid = NULL; +static char *opt_cuuid = NULL; +static char *opt_runtime_path = NULL; +static char *opt_bundle_path = NULL; +static char *opt_pid_file = NULL; +static bool opt_systemd_cgroup = false; +static bool opt_no_pivot = false; +static char *opt_exec_process_spec = NULL; +static bool opt_exec = false; +static char *opt_log_path = NULL; +static char *opt_exit_dir = NULL; +static int opt_timeout = 0; +static int64_t opt_log_size_max = -1; +static char *opt_socket_path = DEFAULT_SOCKET_PATH; +static GOptionEntry opt_entries[] = +{ + { "terminal", 't', 0, G_OPTION_ARG_NONE, &opt_terminal, "Terminal", NULL }, + { "stdin", 'i', 0, G_OPTION_ARG_NONE, &opt_stdin, "Stdin", NULL }, + { "cid", 'c', 0, G_OPTION_ARG_STRING, &opt_cid, "Container ID", NULL }, + { "cuuid", 'u', 0, G_OPTION_ARG_STRING, &opt_cuuid, "Container UUID", NULL }, + { "runtime", 'r', 0, G_OPTION_ARG_STRING, &opt_runtime_path, "Runtime path", NULL }, + { "no-pivot", 0, 0, G_OPTION_ARG_NONE, &opt_no_pivot, "do not use pivot_root", NULL }, + { "bundle", 'b', 0, G_OPTION_ARG_STRING, &opt_bundle_path, "Bundle path", NULL }, + { "pidfile", 'p', 0, G_OPTION_ARG_STRING, &opt_pid_file, "PID file", NULL }, + { "systemd-cgroup", 's', 0, G_OPTION_ARG_NONE, &opt_systemd_cgroup, "Enable systemd cgroup manager", NULL }, + { "exec", 'e', 0, G_OPTION_ARG_NONE, &opt_exec, "Exec a command in a running container", NULL }, + { "exec-process-spec", 0, 0, G_OPTION_ARG_STRING, &opt_exec_process_spec, "Path to the process spec for exec", NULL }, + { "exit-dir", 0, 0, G_OPTION_ARG_STRING, &opt_exit_dir, "Path to the directory where exit files are written", NULL }, + { "log-path", 'l', 0, G_OPTION_ARG_STRING, &opt_log_path, "Log file path", NULL }, + { "timeout", 'T', 0, G_OPTION_ARG_INT, &opt_timeout, "Timeout in seconds", NULL }, + { "log-size-max", 0, 0, G_OPTION_ARG_INT64, &opt_log_size_max, "Maximum size of log file", NULL }, + { "socket-dir-path", 0, 0, G_OPTION_ARG_STRING, &opt_socket_path, "Location of container attach sockets", NULL }, + { NULL } +}; + +/* strlen("1997-03-25T13:20:42.999999999+01:00 stdout ") + 1 */ +#define TSBUFLEN 44 + +#define CGROUP_ROOT "/sys/fs/cgroup" + +static int log_fd = -1; + +static ssize_t write_all(int fd, const void *buf, size_t count) +{ + size_t remaining = count; + const char *p = buf; + ssize_t res; + + while (remaining > 0) { + do { + res = write(fd, p, remaining); + } while (res == -1 && errno == EINTR); + + if (res <= 0) + return -1; + + remaining -= res; + p += res; + } + + return count; +} + +#define WRITEV_BUFFER_N_IOV 128 + +typedef struct { + int iovcnt; + struct iovec iov[WRITEV_BUFFER_N_IOV]; +} writev_buffer_t; + +static ssize_t writev_buffer_flush (int fd, writev_buffer_t *buf) +{ + size_t count = 0; + ssize_t res; + struct iovec *iov; + int iovcnt; + + iovcnt = buf->iovcnt; + iov = buf->iov; + + while (iovcnt > 0) { + do { + res = writev(fd, iov, iovcnt); + } while (res == -1 && errno == EINTR); + + if (res <= 0) + return -1; + + count += res; + + while (res > 0) { + size_t from_this = MIN((size_t)res, iov->iov_len); + iov->iov_len -= from_this; + res -= from_this; + + if (iov->iov_len == 0) { + iov++; + iovcnt--; + } + } + } + + buf->iovcnt = 0; + + return count; +} + +ssize_t writev_buffer_append_segment(int fd, writev_buffer_t *buf, const void *data, ssize_t len) +{ + if (data == NULL) + return 1; + + if (len < 0) + len = strlen ((char *)data); + + if (buf->iovcnt == WRITEV_BUFFER_N_IOV && + writev_buffer_flush (fd, buf) < 0) + return -1; + + if (len > 0) { + buf->iov[buf->iovcnt].iov_base = (void *)data; + buf->iov[buf->iovcnt].iov_len = (size_t)len; + buf->iovcnt++; + } + + return 1; +} + +int set_k8s_timestamp(char *buf, ssize_t buflen, const char *pipename) +{ + struct tm *tm; + struct timespec ts; + char off_sign = '+'; + int off, len, err = -1; + + if (clock_gettime(CLOCK_REALTIME, &ts) < 0) { + /* If CLOCK_REALTIME is not supported, we set nano seconds to 0 */ + if (errno == EINVAL) { + ts.tv_nsec = 0; + } else { + return err; + } + } + + if ((tm = localtime(&ts.tv_sec)) == NULL) + return err; + + + off = (int) tm->tm_gmtoff; + if (tm->tm_gmtoff < 0) { + off_sign = '-'; + off = -off; + } + + len = snprintf(buf, buflen, "%d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d %s ", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, ts.tv_nsec, + off_sign, off / 3600, off % 3600, pipename); + + if (len < buflen) + err = 0; + return err; +} + +/* stdpipe_t represents one of the std pipes (or NONE). + * Sync with const in container_attach.go */ +typedef enum { + NO_PIPE, + STDIN_PIPE, /* unused */ + STDOUT_PIPE, + STDERR_PIPE, +} stdpipe_t; + +const char *stdpipe_name(stdpipe_t pipe) +{ + switch (pipe) { + case STDIN_PIPE: + return "stdin"; + case STDOUT_PIPE: + return "stdout"; + case STDERR_PIPE: + return "stderr"; + default: + return "NONE"; + } +} + +/* + * The CRI requires us to write logs with a (timestamp, stream, line) format + * for every newline-separated line. write_k8s_log writes said format for every + * line in buf, and will partially write the final line of the log if buf is + * not terminated by a newline. + */ +static int write_k8s_log(int fd, stdpipe_t pipe, const char *buf, ssize_t buflen) +{ + char tsbuf[TSBUFLEN]; + static stdpipe_t trailing_line = NO_PIPE; + writev_buffer_t bufv = {0}; + static int64_t bytes_written = 0; + int64_t bytes_to_be_written = 0; + + /* + * Use the same timestamp for every line of the log in this buffer. + * There is no practical difference in the output since write(2) is + * fast. + */ + if (set_k8s_timestamp(tsbuf, sizeof tsbuf, stdpipe_name(pipe))) + /* TODO: We should handle failures much more cleanly than this. */ + return -1; + + while (buflen > 0) { + const char *line_end = NULL; + ptrdiff_t line_len = 0; + bool insert_newline = FALSE; + bool insert_timestamp = FALSE; + + /* Find the end of the line, or alternatively the end of the buffer. */ + line_end = memchr(buf, '\n', buflen); + if (line_end == NULL) + line_end = &buf[buflen-1]; + line_len = line_end - buf + 1; + + bytes_to_be_written = line_len; + if (trailing_line != pipe) { + /* + * Write the (timestamp, stream) tuple if there isn't any trailing + * output from the previous line (or if there is trailing output but + * the current buffer being printed is from a different pipe). + */ + insert_timestamp = TRUE; + bytes_to_be_written += (TSBUFLEN - 1); + /* + * If there was a trailing line from a different pipe, prepend a + * newline to split it properly. This technically breaks the flow + * of the previous line (adding a newline in the log where there + * wasn't one output) but without modifying the file in a + * non-append-only way there's not much we can do. + */ + if (trailing_line != NO_PIPE) { + insert_newline = TRUE; + bytes_to_be_written += 1; + } + } + + /* + * We re-open the log file if writing out the bytes will exceed the max + * log size. We also reset the state so that the new file is started with + * a timestamp. + */ + if ((opt_log_size_max > 0) && (bytes_written + bytes_to_be_written) > opt_log_size_max) { + ninfo("Creating new log file"); + insert_newline = FALSE; + insert_timestamp = TRUE; + bytes_written = 0; + + /* Close the existing fd */ + close(fd); + + /* Unlink the file */ + if (unlink(opt_log_path) < 0) { + pexit("Failed to unlink log file"); + } + + /* Open the log path file again */ + log_fd = open(opt_log_path, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0600); + if (log_fd < 0) + pexit("Failed to open log file"); + fd = log_fd; + } + + /* Output a newline */ + if (insert_newline) { + if (writev_buffer_append_segment(fd, &bufv, "\n", -1) < 0) { + nwarn("failed to write newline to log"); + goto next; + } + } + + /* Output a timestamp */ + if (insert_timestamp) { + if (writev_buffer_append_segment(fd, &bufv, tsbuf, -1) < 0) { + nwarn("failed to write (timestamp, stream) to log"); + goto next; + } + } + + /* Output the actual contents. */ + if (writev_buffer_append_segment(fd, &bufv, buf, line_len) < 0) { + nwarn("failed to write buffer to log"); + goto next; + } + + bytes_written += bytes_to_be_written; + + /* If we did not output a full line, then we are a trailing_line. */ + trailing_line = (*line_end == '\n') ? NO_PIPE : pipe; + +next: + /* Update the head of the buffer remaining to output. */ + buf += line_len; + buflen -= line_len; + } + + if (writev_buffer_flush (fd, &bufv) < 0) { + nwarn("failed to flush buffer to log"); + } + + ninfo("Total bytes written: %"PRId64"", bytes_written); + + return 0; +} + +/* + * Returns the path for specified controller name for a pid. + * Returns NULL on error. + */ +static char *process_cgroup_subsystem_path(int pid, const char *subsystem) { + _cleanup_free_ char *cgroups_file_path = g_strdup_printf("/proc/%d/cgroup", pid); + _cleanup_fclose_ FILE *fp = NULL; + fp = fopen(cgroups_file_path, "re"); + if (fp == NULL) { + nwarn("Failed to open cgroups file: %s", cgroups_file_path); + return NULL; + } + + _cleanup_free_ char *line = NULL; + ssize_t read; + size_t len = 0; + char *ptr, *path; + char *subsystem_path = NULL; + int i; + while ((read = getline(&line, &len, fp)) != -1) { + _cleanup_strv_ char **subsystems = NULL; + ptr = strchr(line, ':'); + if (ptr == NULL) { + nwarn("Error parsing cgroup, ':' not found: %s", line); + return NULL; + } + ptr++; + path = strchr(ptr, ':'); + if (path == NULL) { + nwarn("Error parsing cgroup, second ':' not found: %s", line); + return NULL; + } + *path = 0; + path++; + subsystems = g_strsplit (ptr, ",", -1); + for (i = 0; subsystems[i] != NULL; i++) { + if (strcmp (subsystems[i], subsystem) == 0) { + char *subpath = strchr(subsystems[i], '='); + if (subpath == NULL) { + subpath = ptr; + } else { + *subpath = 0; + } + + subsystem_path = g_strdup_printf("%s/%s%s", CGROUP_ROOT, subpath, path); + subsystem_path[strlen(subsystem_path) - 1] = '\0'; + return subsystem_path; + } + } + } + + return NULL; +} + +static char *escape_json_string(const char *str) +{ + GString *escaped; + const char *p; + + p = str; + escaped = g_string_sized_new(strlen(str)); + + while (*p != 0) { + char c = *p++; + if (c == '\\' || c == '"') { + g_string_append_c(escaped, '\\'); + g_string_append_c(escaped, c); + } else if (c == '\n') { + g_string_append_printf (escaped, "\\n"); + } else if (c == '\t') { + g_string_append_printf (escaped, "\\t"); + } else if ((c > 0 && c < 0x1f) || c == 0x7f) { + g_string_append_printf (escaped, "\\u00%02x", (guint)c); + } else { + g_string_append_c (escaped, c); + } + } + + return g_string_free (escaped, FALSE); +} + +static int get_pipe_fd_from_env(const char *envname) +{ + char *pipe_str, *endptr; + int pipe_fd; + + pipe_str = getenv(envname); + if (pipe_str == NULL) + return -1; + + errno = 0; + pipe_fd = strtol(pipe_str, &endptr, 10); + if (errno != 0 || *endptr != '\0') + pexit("unable to parse %s", envname); + if (fcntl(pipe_fd, F_SETFD, FD_CLOEXEC) == -1) + pexit("unable to make %s CLOEXEC", envname); + + return pipe_fd; +} + +static void add_argv(GPtrArray *argv_array, ...) G_GNUC_NULL_TERMINATED; + +static void add_argv(GPtrArray *argv_array, ...) +{ + va_list args; + char *arg; + + va_start (args, argv_array); + while ((arg = va_arg (args, char *))) + g_ptr_array_add (argv_array, arg); + va_end (args); +} + +static void end_argv(GPtrArray *argv_array) +{ + g_ptr_array_add(argv_array, NULL); +} + +/* Global state */ + +static int runtime_status = -1; +static int container_status = -1; + +static int masterfd_stdin = -1; +static int masterfd_stdout = -1; +static int masterfd_stderr = -1; + +/* Used for attach */ +static int conn_sock = -1; +static int conn_sock_readable; +static int conn_sock_writable; + +static int oom_event_fd = -1; +static int attach_socket_fd = -1; +static int console_socket_fd = -1; +static int terminal_ctrl_fd = -1; + +static bool timed_out = FALSE; + +static GMainLoop *main_loop = NULL; + +static void conn_sock_shutdown(int how) +{ + if (conn_sock == -1) + return; + shutdown(conn_sock, how); + if (how & SHUT_RD) + conn_sock_readable = false; + if (how & SHUT_WR) + conn_sock_writable = false; + if (!conn_sock_writable && !conn_sock_readable) { + close(conn_sock); + conn_sock = -1; + } +} + +static gboolean stdio_cb(int fd, GIOCondition condition, gpointer user_data); + +static gboolean tty_hup_timeout_scheduled = false; + +static gboolean tty_hup_timeout_cb (G_GNUC_UNUSED gpointer user_data) +{ + tty_hup_timeout_scheduled = false; + g_unix_fd_add (masterfd_stdout, G_IO_IN, stdio_cb, GINT_TO_POINTER(STDOUT_PIPE)); + return G_SOURCE_REMOVE; +} + +static bool read_stdio(int fd, stdpipe_t pipe, bool *eof) +{ + #define STDIO_BUF_SIZE 8192 /* Sync with redirectResponseToOutputStreams() */ + /* We use one extra byte at the start, which we don't read into, instead + we use that for marking the pipe when we write to the attached socket */ + char real_buf[STDIO_BUF_SIZE + 1]; + char *buf = real_buf + 1; + ssize_t num_read = 0; + + if (eof) + *eof = false; + + num_read = read(fd, buf, STDIO_BUF_SIZE); + if (num_read == 0) { + if (eof) + *eof = true; + return false; + } else if (num_read < 0) { + nwarn("stdio_input read failed %s", strerror(errno)); + return false; + } else { + if (write_k8s_log(log_fd, pipe, buf, num_read) < 0) { + nwarn("write_k8s_log failed"); + return G_SOURCE_CONTINUE; + } + + real_buf[0] = pipe; + if (conn_sock_writable && write_all(conn_sock, real_buf, num_read+1) < 0) { + nwarn("Failed to write to socket"); + conn_sock_shutdown(SHUT_WR); + } + return true; + } +} + +static void on_sigchld(G_GNUC_UNUSED int signal) +{ + raise (SIGUSR1); +} + +static void check_child_processes(GHashTable *pid_to_handler) +{ + void (*cb) (GPid, int, gpointer); + + for (;;) { + int status; + pid_t pid = waitpid(-1, &status, WNOHANG); + + if (pid < 0 && errno == EINTR) + continue; + if (pid < 0 && errno == ECHILD) { + g_main_loop_quit (main_loop); + return; + } + if (pid < 0) + pexit("Failed to read child process status"); + + if (pid == 0) + return; + + /* If we got here, pid > 0, so we have a valid pid to check. */ + cb = g_hash_table_lookup(pid_to_handler, &pid); + if (cb) + cb(pid, status, 0); + } +} + +static gboolean on_sigusr1_cb(gpointer user_data) +{ + GHashTable *pid_to_handler = (GHashTable *) user_data; + check_child_processes (pid_to_handler); + return G_SOURCE_CONTINUE; +} + +static gboolean stdio_cb(int fd, GIOCondition condition, gpointer user_data) +{ + stdpipe_t pipe = GPOINTER_TO_INT(user_data); + bool read_eof = false; + bool has_input = (condition & G_IO_IN) != 0; + bool has_hup = (condition & G_IO_HUP) != 0; + + /* When we get here, condition can be G_IO_IN and/or G_IO_HUP. + IN means there is some data to read. + HUP means the other side closed the fd. In the case of a pine + this in final, and we will never get more data. However, in the + terminal case this just means that nobody has the terminal + open at this point, and this can be change whenever someone + opens the tty */ + + /* Read any data before handling hup */ + if (has_input) { + read_stdio(fd, pipe, &read_eof); + } + + if (has_hup && opt_terminal && pipe == STDOUT_PIPE) { + /* We got a HUP from the terminal master this means there + are no open slaves ptys atm, and we will get a lot + of wakeups until we have one, switch to polling + mode. */ + + /* If we read some data this cycle, wait one more, maybe there + is more in the buffer before we handle the hup */ + if (has_input && !read_eof) { + return G_SOURCE_CONTINUE; + } + + if (!tty_hup_timeout_scheduled) { + g_timeout_add (100, tty_hup_timeout_cb, NULL); + } + tty_hup_timeout_scheduled = true; + return G_SOURCE_REMOVE; + } + + if (read_eof || (has_hup && !has_input)) { + /* End of input */ + if (pipe == STDOUT_PIPE) + masterfd_stdout = -1; + if (pipe == STDERR_PIPE) + masterfd_stderr = -1; + + close (fd); + return G_SOURCE_REMOVE; + } + + return G_SOURCE_CONTINUE; +} + +static gboolean timeout_cb (G_GNUC_UNUSED gpointer user_data) +{ + timed_out = TRUE; + ninfo ("Timed out, killing main loop"); + g_main_loop_quit (main_loop); + return G_SOURCE_REMOVE; +} + +static gboolean oom_cb(int fd, GIOCondition condition, G_GNUC_UNUSED gpointer user_data) +{ + uint64_t oom_event; + ssize_t num_read = 0; + + if ((condition & G_IO_IN) != 0) { + num_read = read(fd, &oom_event, sizeof(uint64_t)); + if (num_read < 0) { + nwarn("Failed to read oom event from eventfd"); + return G_SOURCE_CONTINUE; + } + + if (num_read > 0) { + if (num_read != sizeof(uint64_t)) + nwarn("Failed to read full oom event from eventfd"); + ninfo("OOM received"); + if (open("oom", O_CREAT, 0666) < 0) { + nwarn("Failed to write oom file"); + } + return G_SOURCE_CONTINUE; + } + } + + /* End of input */ + close (fd); + oom_event_fd = -1; + return G_SOURCE_REMOVE; +} + +static gboolean conn_sock_cb(int fd, GIOCondition condition, G_GNUC_UNUSED gpointer user_data) +{ + #define CONN_SOCK_BUF_SIZE 32*1024 /* Match the write size in CopyDetachable */ + char buf[CONN_SOCK_BUF_SIZE]; + ssize_t num_read = 0; + + if ((condition & G_IO_IN) != 0) { + num_read = read(fd, buf, CONN_SOCK_BUF_SIZE); + if (num_read < 0) + return G_SOURCE_CONTINUE; + + if (num_read > 0 && masterfd_stdin >= 0) { + if (write_all(masterfd_stdin, buf, num_read) < 0) { + nwarn("Failed to write to container stdin"); + } + return G_SOURCE_CONTINUE; + } + } + + /* End of input */ + conn_sock_shutdown(SHUT_RD); + if (masterfd_stdin >= 0 && opt_stdin) { + close(masterfd_stdin); + masterfd_stdin = -1; + } + return G_SOURCE_REMOVE; +} + +static gboolean attach_cb(int fd, G_GNUC_UNUSED GIOCondition condition, G_GNUC_UNUSED gpointer user_data) +{ + conn_sock = accept(fd, NULL, NULL); + if (conn_sock == -1) { + if (errno != EWOULDBLOCK) + nwarn("Failed to accept client connection on attach socket"); + } else { + conn_sock_readable = true; + conn_sock_writable = true; + g_unix_fd_add (conn_sock, G_IO_IN|G_IO_HUP|G_IO_ERR, conn_sock_cb, GINT_TO_POINTER(STDOUT_PIPE)); + ninfo("Accepted connection %d", conn_sock); + } + + return G_SOURCE_CONTINUE; +} + +static gboolean ctrl_cb(int fd, G_GNUC_UNUSED GIOCondition condition, G_GNUC_UNUSED gpointer user_data) +{ + #define CTLBUFSZ 200 + static char ctlbuf[CTLBUFSZ]; + static int readsz = CTLBUFSZ - 1; + static char *readptr = ctlbuf; + ssize_t num_read = 0; + int ctl_msg_type = -1; + int height = -1; + int width = -1; + struct winsize ws; + int ret; + + num_read = read(fd, readptr, readsz); + if (num_read <= 0) { + nwarn("Failed to read from control fd"); + return G_SOURCE_CONTINUE; + } + + readptr[num_read] = '\0'; + ninfo("Got ctl message: %s\n", ctlbuf); + + char *beg = ctlbuf; + char *newline = strchrnul(beg, '\n'); + /* Process each message which ends with a line */ + while (*newline != '\0') { + ret = sscanf(ctlbuf, "%d %d %d\n", &ctl_msg_type, &height, &width); + if (ret != 3) { + nwarn("Failed to sscanf message"); + return G_SOURCE_CONTINUE; + } + ninfo("Message type: %d, Height: %d, Width: %d", ctl_msg_type, height, width); + ret = ioctl(masterfd_stdout, TIOCGWINSZ, &ws); + ninfo("Existing size: %d %d", ws.ws_row, ws.ws_col); + ws.ws_row = height; + ws.ws_col = width; + ret = ioctl(masterfd_stdout, TIOCSWINSZ, &ws); + if (ret == -1) { + nwarn("Failed to set process pty terminal size"); + } + beg = newline + 1; + newline = strchrnul(beg, '\n'); + } + if (num_read == (CTLBUFSZ - 1) && beg == ctlbuf) { + /* + * We did not find a newline in the entire buffer. + * This shouldn't happen as our buffer is larger than + * the message that we expect to receive. + */ + nwarn("Could not find newline in entire buffer\n"); + } else if (*beg == '\0') { + /* We exhausted all messages that were complete */ + readptr = ctlbuf; + readsz = CTLBUFSZ - 1; + } else { + /* + * We copy remaining data to beginning of buffer + * and advance readptr after that. + */ + int cp_rem = 0; + do { + ctlbuf[cp_rem++] = *beg++; + } while (*beg != '\0'); + readptr = ctlbuf + cp_rem; + readsz = CTLBUFSZ - 1 - cp_rem; + } + + return G_SOURCE_CONTINUE; +} + +static gboolean terminal_accept_cb(int fd, G_GNUC_UNUSED GIOCondition condition, G_GNUC_UNUSED gpointer user_data) +{ + const char *csname = user_data; + struct file_t console; + int connfd = -1; + struct termios tset; + + ninfo("about to accept from console_socket_fd: %d", fd); + connfd = accept4(fd, NULL, NULL, SOCK_CLOEXEC); + if (connfd < 0) { + nwarn("Failed to accept console-socket connection"); + return G_SOURCE_CONTINUE; + } + + /* Not accepting anything else. */ + close(fd); + unlink(csname); + + /* We exit if this fails. */ + ninfo("about to recvfd from connfd: %d", connfd); + console = recvfd(connfd); + + ninfo("console = {.name = '%s'; .fd = %d}", console.name, console.fd); + free(console.name); + + /* We change the terminal settings to match kube settings */ + if (tcgetattr(console.fd, &tset) == -1) + pexit("Failed to get console terminal settings"); + + tset.c_oflag |= ONLCR; + + if (tcsetattr(console.fd, TCSANOW, &tset) == -1) + pexit("Failed to set console terminal settings"); + + /* We only have a single fd for both pipes, so we just treat it as + * stdout. stderr is ignored. */ + masterfd_stdin = console.fd; + masterfd_stdout = console.fd; + + /* Clean up everything */ + close(connfd); + + return G_SOURCE_CONTINUE; +} + +static void +runtime_exit_cb (G_GNUC_UNUSED GPid pid, int status, G_GNUC_UNUSED gpointer user_data) +{ + runtime_status = status; + g_main_loop_quit (main_loop); +} + +static void +container_exit_cb (G_GNUC_UNUSED GPid pid, int status, G_GNUC_UNUSED gpointer user_data) +{ + ninfo("container %d exited with status %d\n", pid, status); + container_status = status; + g_main_loop_quit (main_loop); +} + +static void write_sync_fd(int sync_pipe_fd, int res, const char *message) +{ + _cleanup_free_ char *escaped_message = NULL; + _cleanup_free_ char *json = NULL; + const char *res_key; + ssize_t len; + + if (sync_pipe_fd == -1) + return; + + if (opt_exec) + res_key = "exit_code"; + else + res_key = "pid"; + + if (message) { + escaped_message = escape_json_string(message); + json = g_strdup_printf ("{\"%s\": %d, \"message\": \"%s\"}\n", res_key, res, escaped_message); + } else { + json = g_strdup_printf ("{\"%s\": %d}\n", res_key, res); + } + + len = strlen(json); + if (write_all(sync_pipe_fd, json, len) != len) { + pexit("Unable to send container stderr message to parent"); + } +} + +static char *setup_console_socket(void) +{ + struct sockaddr_un addr = {0}; + _cleanup_free_ const char *tmpdir = g_get_tmp_dir(); + _cleanup_free_ char *csname = g_build_filename(tmpdir, "conmon-term.XXXXXX", NULL); + /* + * Generate a temporary name. Is this unsafe? Probably, but we can + * replace it with a rename(2) setup if necessary. + */ + + int unusedfd = g_mkstemp(csname); + if (unusedfd < 0) + pexit("Failed to generate random path for console-socket"); + close(unusedfd); + + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, csname, sizeof(addr.sun_path)-1); + + ninfo("addr{sun_family=AF_UNIX, sun_path=%s}", addr.sun_path); + + /* Bind to the console socket path. */ + console_socket_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); + if (console_socket_fd < 0) + pexit("Failed to create console-socket"); + if (fchmod(console_socket_fd, 0700)) + pexit("Failed to change console-socket permissions"); + /* XXX: This should be handled with a rename(2). */ + if (unlink(csname) < 0) + pexit("Failed to unlink temporary random path"); + if (bind(console_socket_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) + pexit("Failed to bind to console-socket"); + if (listen(console_socket_fd, 128) < 0) + pexit("Failed to listen on console-socket"); + + return g_strdup(csname); +} + +static char *setup_attach_socket(void) +{ + _cleanup_free_ char *attach_sock_path = NULL; + char *attach_symlink_dir_path; + struct sockaddr_un attach_addr = {0}; + attach_addr.sun_family = AF_UNIX; + + /* + * Create a symlink so we don't exceed unix domain socket + * path length limit. + */ + attach_symlink_dir_path = g_build_filename(opt_socket_path, opt_cuuid, NULL); + if (unlink(attach_symlink_dir_path) == -1 && errno != ENOENT) + pexit("Failed to remove existing symlink for attach socket directory"); + + if (symlink(opt_bundle_path, attach_symlink_dir_path) == -1) + pexit("Failed to create symlink for attach socket"); + + attach_sock_path = g_build_filename(opt_socket_path, opt_cuuid, "attach", NULL); + ninfo("attach sock path: %s", attach_sock_path); + + strncpy(attach_addr.sun_path, attach_sock_path, sizeof(attach_addr.sun_path) - 1); + ninfo("addr{sun_family=AF_UNIX, sun_path=%s}", attach_addr.sun_path); + + /* + * We make the socket non-blocking to avoid a race where client aborts connection + * before the server gets a chance to call accept. In that scenario, the server + * accept blocks till a new client connection comes in. + */ + attach_socket_fd = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0); + if (attach_socket_fd == -1) + pexit("Failed to create attach socket"); + + if (fchmod(attach_socket_fd, 0700)) + pexit("Failed to change attach socket permissions"); + + if (bind(attach_socket_fd, (struct sockaddr *)&attach_addr, sizeof(struct sockaddr_un)) == -1) + pexit("Failed to bind attach socket: %s", attach_sock_path); + + if (listen(attach_socket_fd, 10) == -1) + pexit("Failed to listen on attach socket: %s", attach_sock_path); + + g_unix_fd_add (attach_socket_fd, G_IO_IN, attach_cb, NULL); + + return attach_symlink_dir_path; +} + +static void setup_terminal_control_fifo() +{ + _cleanup_free_ char *ctl_fifo_path = g_build_filename(opt_bundle_path, "ctl", NULL); + ninfo("ctl fifo path: %s", ctl_fifo_path); + + /* Setup fifo for reading in terminal resize and other stdio control messages */ + + if (mkfifo(ctl_fifo_path, 0666) == -1) + pexit("Failed to mkfifo at %s", ctl_fifo_path); + + terminal_ctrl_fd = open(ctl_fifo_path, O_RDONLY|O_NONBLOCK|O_CLOEXEC); + if (terminal_ctrl_fd == -1) + pexit("Failed to open control fifo"); + + /* + * Open a dummy writer to prevent getting flood of POLLHUPs when + * last writer closes. + */ + int dummyfd = open(ctl_fifo_path, O_WRONLY|O_CLOEXEC); + if (dummyfd == -1) + pexit("Failed to open dummy writer for fifo"); + + g_unix_fd_add (terminal_ctrl_fd, G_IO_IN, ctrl_cb, NULL); + + ninfo("terminal_ctrl_fd: %d", terminal_ctrl_fd); +} + +static void setup_oom_handling(int container_pid) +{ + /* Setup OOM notification for container process */ + _cleanup_free_ char *memory_cgroup_path = process_cgroup_subsystem_path(container_pid, "memory"); + _cleanup_close_ int cfd = -1; + int ofd = -1; /* Not closed */ + if (!memory_cgroup_path) { + nexit("Failed to get memory cgroup path"); + } + + _cleanup_free_ char *memory_cgroup_file_path = g_build_filename(memory_cgroup_path, "cgroup.event_control", NULL); + + if ((cfd = open(memory_cgroup_file_path, O_WRONLY | O_CLOEXEC)) == -1) { + nwarn("Failed to open %s", memory_cgroup_file_path); + return; + } + + _cleanup_free_ char *memory_cgroup_file_oom_path = g_build_filename(memory_cgroup_path, "memory.oom_control", NULL); + if ((ofd = open(memory_cgroup_file_oom_path, O_RDONLY | O_CLOEXEC)) == -1) + pexit("Failed to open %s", memory_cgroup_file_oom_path); + + if ((oom_event_fd = eventfd(0, EFD_CLOEXEC)) == -1) + pexit("Failed to create eventfd"); + + _cleanup_free_ char *data = g_strdup_printf("%d %d", oom_event_fd, ofd); + if (write_all(cfd, data, strlen(data)) < 0) + pexit("Failed to write to cgroup.event_control"); + + g_unix_fd_add (oom_event_fd, G_IO_IN, oom_cb, NULL); +} + +int main(int argc, char *argv[]) +{ + int ret; + char cwd[PATH_MAX]; + _cleanup_free_ char *default_pid_file = NULL; + _cleanup_free_ char *csname = NULL; + GError *err = NULL; + _cleanup_free_ char *contents = NULL; + int container_pid = -1; + pid_t main_pid, create_pid; + /* Used for !terminal cases. */ + int slavefd_stdin = -1; + int slavefd_stdout = -1; + int slavefd_stderr = -1; + char buf[BUF_SIZE]; + int num_read; + int sync_pipe_fd = -1; + int start_pipe_fd = -1; + GError *error = NULL; + GOptionContext *context; + GPtrArray *runtime_argv = NULL; + _cleanup_close_ int dev_null_r = -1; + _cleanup_close_ int dev_null_w = -1; + int fds[2]; + + main_loop = g_main_loop_new (NULL, FALSE); + + /* Command line parameters */ + context = g_option_context_new("- conmon utility"); + g_option_context_add_main_entries(context, opt_entries, "conmon"); + if (!g_option_context_parse(context, &argc, &argv, &error)) { + g_print("option parsing failed: %s\n", error->message); + exit(1); + } + + if (opt_cid == NULL) + nexit("Container ID not provided. Use --cid"); + + if (!opt_exec && opt_cuuid == NULL) + nexit("Container UUID not provided. Use --cuuid"); + + if (opt_runtime_path == NULL) + nexit("Runtime path not provided. Use --runtime"); + + if (!opt_exec && opt_exit_dir == NULL) + nexit("Container exit directory not provided. Use --exit-dir"); + + if (opt_bundle_path == NULL && !opt_exec) { + if (getcwd(cwd, sizeof(cwd)) == NULL) { + nexit("Failed to get working directory"); + } + opt_bundle_path = cwd; + } + + dev_null_r = open("/dev/null", O_RDONLY | O_CLOEXEC); + if (dev_null_r < 0) + pexit("Failed to open /dev/null"); + + dev_null_w = open("/dev/null", O_WRONLY | O_CLOEXEC); + if (dev_null_w < 0) + pexit("Failed to open /dev/null"); + + if (opt_exec && opt_exec_process_spec == NULL) { + nexit("Exec process spec path not provided. Use --exec-process-spec"); + } + + if (opt_pid_file == NULL) { + default_pid_file = g_strdup_printf ("%s/pidfile-%s", cwd, opt_cid); + opt_pid_file = default_pid_file; + } + + if (opt_log_path == NULL) + nexit("Log file path not provided. Use --log-path"); + + start_pipe_fd = get_pipe_fd_from_env("_OCI_STARTPIPE"); + if (start_pipe_fd >= 0) { + /* Block for an initial write to the start pipe before + spawning any childred or exiting, to ensure the + parent can put us in the right cgroup. */ + read(start_pipe_fd, buf, BUF_SIZE); + close(start_pipe_fd); + } + + /* In the create-container case we double-fork in + order to disconnect from the parent, as we want to + continue in a daemon-like way */ + main_pid = fork(); + if (main_pid < 0) { + pexit("Failed to fork the create command"); + } else if (main_pid != 0) { + exit(0); + } + + /* Disconnect stdio from parent. We need to do this, because + the parent is waiting for the stdout to end when the intermediate + child dies */ + if (dup2(dev_null_r, STDIN_FILENO) < 0) + pexit("Failed to dup over stdin"); + if (dup2(dev_null_w, STDOUT_FILENO) < 0) + pexit("Failed to dup over stdout"); + if (dup2(dev_null_w, STDERR_FILENO) < 0) + pexit("Failed to dup over stderr"); + + /* Create a new session group */ + setsid(); + + /* Environment variables */ + sync_pipe_fd = get_pipe_fd_from_env("_OCI_SYNCPIPE"); + + /* Open the log path file. */ + log_fd = open(opt_log_path, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0600); + if (log_fd < 0) + pexit("Failed to open log file"); + + /* + * Set self as subreaper so we can wait for container process + * and return its exit code. + */ + ret = prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0); + if (ret != 0) { + pexit("Failed to set as subreaper"); + } + + if (opt_terminal) { + csname = setup_console_socket(); + } else { + + /* + * Create a "fake" master fd so that we can use the same epoll code in + * both cases. The slavefd_*s will be closed after we dup over + * everything. + * + * We use pipes here because open(/dev/std{out,err}) will fail if we + * used anything else (and it wouldn't be a good idea to create a new + * pty pair in the host). + */ + + if (opt_stdin) { + if (pipe2(fds, O_CLOEXEC) < 0) + pexit("Failed to create !terminal stdin pipe"); + + masterfd_stdin = fds[1]; + slavefd_stdin = fds[0]; + } + + if (pipe2(fds, O_CLOEXEC) < 0) + pexit("Failed to create !terminal stdout pipe"); + + masterfd_stdout = fds[0]; + slavefd_stdout = fds[1]; + } + + /* We always create a stderr pipe, because that way we can capture + runc stderr messages before the tty is created */ + if (pipe2(fds, O_CLOEXEC) < 0) + pexit("Failed to create stderr pipe"); + + masterfd_stderr = fds[0]; + slavefd_stderr = fds[1]; + + runtime_argv = g_ptr_array_new(); + add_argv(runtime_argv, + opt_runtime_path, + NULL); + + /* Generate the cmdline. */ + if (!opt_exec && opt_systemd_cgroup) + add_argv(runtime_argv, + "--systemd-cgroup", + NULL); + + if (opt_exec) { + add_argv(runtime_argv, + "exec", "-d", + "--pid-file", opt_pid_file, + NULL); + } else { + add_argv(runtime_argv, + "create", + "--bundle", opt_bundle_path, + "--pid-file", opt_pid_file, + NULL); + } + + if (!opt_exec && opt_no_pivot) { + add_argv(runtime_argv, + "--no-pivot", + NULL); + } + + if (csname != NULL) { + add_argv(runtime_argv, + "--console-socket", csname, + NULL); + } + + /* Set the exec arguments. */ + if (opt_exec) { + add_argv(runtime_argv, + "--process", opt_exec_process_spec, + NULL); + } + + /* Container name comes last. */ + add_argv(runtime_argv, opt_cid, NULL); + end_argv(runtime_argv); + + /* + * We have to fork here because the current runC API dups the stdio of the + * calling process over the container's fds. This is actually *very bad* + * but is currently being discussed for change in + * https://github.com/opencontainers/runtime-spec/pull/513. Hopefully this + * won't be the case for very long. + */ + + /* Create our container. */ + create_pid = fork(); + if (create_pid < 0) { + pexit("Failed to fork the create command"); + } else if (!create_pid) { + /* FIXME: This results in us not outputting runc error messages to crio's log. */ + if (slavefd_stdin < 0) + slavefd_stdin = dev_null_r; + if (dup2(slavefd_stdin, STDIN_FILENO) < 0) + pexit("Failed to dup over stdout"); + + if (slavefd_stdout < 0) + slavefd_stdout = dev_null_w; + if (dup2(slavefd_stdout, STDOUT_FILENO) < 0) + pexit("Failed to dup over stdout"); + + if (slavefd_stderr < 0) + slavefd_stderr = slavefd_stdout; + if (dup2(slavefd_stderr, STDERR_FILENO) < 0) + pexit("Failed to dup over stderr"); + + execv(g_ptr_array_index(runtime_argv,0), (char **)runtime_argv->pdata); + exit(127); + } + + g_ptr_array_free (runtime_argv, TRUE); + + /* The runtime has that fd now. We don't need to touch it anymore. */ + close(slavefd_stdin); + close(slavefd_stdout); + close(slavefd_stderr); + + /* Map pid to its handler. */ + GHashTable *pid_to_handler = g_hash_table_new (g_int_hash, g_int_equal); + g_hash_table_insert (pid_to_handler, &create_pid, runtime_exit_cb); + + /* + * Glib does not support SIGCHLD so use SIGUSR1 with the same semantic. We will + * catch SIGCHLD and raise(SIGUSR1) in the signal handler. + */ + g_unix_signal_add (SIGUSR1, on_sigusr1_cb, pid_to_handler); + + if (signal(SIGCHLD, on_sigchld) == SIG_ERR) + pexit("Failed to set handler for SIGCHLD"); + + ninfo("about to waitpid: %d", create_pid); + if (csname != NULL) { + guint terminal_watch = g_unix_fd_add (console_socket_fd, G_IO_IN, terminal_accept_cb, csname); + /* Process any SIGCHLD we may have missed before the signal handler was in place. */ + check_child_processes (pid_to_handler); + g_main_loop_run (main_loop); + g_source_remove (terminal_watch); + } else { + int ret; + /* Wait for our create child to exit with the return code. */ + do + ret = waitpid(create_pid, &runtime_status, 0); + while (ret < 0 && errno == EINTR); + if (ret < 0) { + int old_errno = errno; + kill(create_pid, SIGKILL); + errno = old_errno; + pexit("Failed to wait for `runtime %s`", opt_exec ? "exec" : "create"); + } + + } + + if (!WIFEXITED(runtime_status) || WEXITSTATUS(runtime_status) != 0) { + if (sync_pipe_fd > 0) { + /* + * Read from container stderr for any error and send it to parent + * We send -1 as pid to signal to parent that create container has failed. + */ + num_read = read(masterfd_stderr, buf, BUF_SIZE); + if (num_read > 0) { + buf[num_read] = '\0'; + write_sync_fd(sync_pipe_fd, -1, buf); + } + } + nexit("Failed to create container: exit status %d", WEXITSTATUS(runtime_status)); + } + + if (opt_terminal && masterfd_stdout == -1) + nexit("Runtime did not set up terminal"); + + /* Read the pid so we can wait for the process to exit */ + g_file_get_contents(opt_pid_file, &contents, NULL, &err); + if (err) { + nwarn("Failed to read pidfile: %s", err->message); + g_error_free(err); + exit(1); + } + + container_pid = atoi(contents); + ninfo("container PID: %d", container_pid); + + g_hash_table_insert (pid_to_handler, &container_pid, container_exit_cb); + + /* Setup endpoint for attach */ + _cleanup_free_ char *attach_symlink_dir_path = NULL; + if (!opt_exec) { + attach_symlink_dir_path = setup_attach_socket(); + } + + if (!opt_exec) { + setup_terminal_control_fifo(); + } + + /* Send the container pid back to parent */ + if (!opt_exec) { + write_sync_fd(sync_pipe_fd, container_pid, NULL); + } + + setup_oom_handling(container_pid); + + if (masterfd_stdout >= 0) { + g_unix_fd_add (masterfd_stdout, G_IO_IN, stdio_cb, GINT_TO_POINTER(STDOUT_PIPE)); + } + if (masterfd_stderr >= 0) { + g_unix_fd_add (masterfd_stderr, G_IO_IN, stdio_cb, GINT_TO_POINTER(STDERR_PIPE)); + } + + if (opt_timeout > 0) { + g_timeout_add_seconds (opt_timeout, timeout_cb, NULL); + } + + check_child_processes(pid_to_handler); + + g_main_loop_run (main_loop); + + /* Drain stdout and stderr */ + if (masterfd_stdout != -1) { + g_unix_set_fd_nonblocking(masterfd_stdout, TRUE, NULL); + while (read_stdio(masterfd_stdout, STDOUT_PIPE, NULL)) + ; + } + if (masterfd_stderr != -1) { + g_unix_set_fd_nonblocking(masterfd_stderr, TRUE, NULL); + while (read_stdio(masterfd_stderr, STDERR_PIPE, NULL)) + ; + } + + int exit_status = -1; + const char *exit_message = NULL; + + if (timed_out) { + kill(container_pid, SIGKILL); + exit_message = "command timed out"; + } else { + exit_status = WEXITSTATUS(container_status); + } + + if (!opt_exec) { + _cleanup_free_ char *status_str = g_strdup_printf("%d", exit_status); + _cleanup_free_ char *exit_file_path = g_build_filename(opt_exit_dir, opt_cid, NULL); + if (!g_file_set_contents(exit_file_path, status_str, -1, &err)) + nexit("Failed to write %s to exit file: %s\n", + status_str, err->message); + } else { + /* Send the command exec exit code back to the parent */ + write_sync_fd(sync_pipe_fd, exit_status, exit_message); + } + + if (attach_symlink_dir_path != NULL && + unlink(attach_symlink_dir_path) == -1 && errno != ENOENT) { + pexit("Failed to remove symlink for attach socket directory"); + } + + return EXIT_SUCCESS; +} diff --git a/vendor/github.com/kubernetes-incubator/cri-o/vendor.conf b/vendor/github.com/kubernetes-incubator/cri-o/vendor.conf new file mode 100644 index 000000000..c2f3d452a --- /dev/null +++ b/vendor/github.com/kubernetes-incubator/cri-o/vendor.conf @@ -0,0 +1,113 @@ +k8s.io/kubernetes v1.8.1 https://github.com/kubernetes/kubernetes +k8s.io/client-go release-5.0 https://github.com/kubernetes/client-go +k8s.io/apimachinery release-1.8 https://github.com/kubernetes/apimachinery +k8s.io/apiserver release-1.8 https://github.com/kubernetes/apiserver +k8s.io/utils 4fe312863be2155a7b68acd2aff1c9221b24e68c https://github.com/kubernetes/utils +k8s.io/api release-1.8 https://github.com/kubernetes/api +k8s.io/kube-openapi abfc5fbe1cf87ee697db107fdfd24c32fe4397a8 https://github.com/kubernetes/kube-openapi +k8s.io/apiextensions-apiserver release-1.8 https://github.com/kubernetes/apiextensions-apiserver +# +github.com/googleapis/gnostic 0c5108395e2debce0d731cf0287ddf7242066aba +github.com/gregjones/httpcache 787624de3eb7bd915c329cba748687a3b22666a6 +github.com/json-iterator/go 1.0.0 +github.com/peterbourgon/diskv v2.0.1 +github.com/sirupsen/logrus v1.0.0 +github.com/containers/image storage-update https://github.com/nalind/image +github.com/docker/docker-credential-helpers d68f9aeca33f5fd3f08eeae5e9d175edf4e731d1 +github.com/ostreedev/ostree-go master +github.com/containers/storage 9e0c323a4b425557f8310ee8d125634acd39d8f5 +github.com/containernetworking/cni v0.4.0 +google.golang.org/grpc v1.0.4 https://github.com/grpc/grpc-go +github.com/opencontainers/selinux b29023b86e4a69d1b46b7e7b4e2b6fda03f0b9cd +github.com/opencontainers/go-digest v1.0.0-rc0 +github.com/opencontainers/runtime-tools d3f7e9e9e631c7e87552d67dc7c86de33c3fb68a +github.com/opencontainers/runc 45bde006ca8c90e089894508708bcf0e2cdf9e13 +github.com/mrunalp/fileutils master +github.com/vishvananda/netlink master +github.com/vishvananda/netns master +github.com/opencontainers/image-spec v1.0.0 +github.com/opencontainers/runtime-spec v1.0.0 +github.com/juju/ratelimit 5b9ff866471762aa2ab2dced63c9fb6f53921342 +github.com/tchap/go-patricia v2.2.6 +gopkg.in/cheggaaa/pb.v1 v1.0.7 +gopkg.in/inf.v0 v0.9.0 +gopkg.in/yaml.v2 v2 +github.com/docker/docker d4f6db83c21cfc6af54fffb1f13e8acb7199f96a +github.com/docker/spdystream ed496381df8283605c435b86d4fdd6f4f20b8c6e +github.com/docker/distribution 7a8efe719e55bbfaff7bc5718cdf0ed51ca821df +github.com/docker/go-units v0.3.1 +github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d +github.com/docker/libtrust aabc10ec26b754e797f9028f4589c5b7bd90dc20 +github.com/mistifyio/go-zfs v2.1.1 +github.com/ghodss/yaml 04f313413ffd65ce25f2541bfd2b2ceec5c0908c +github.com/imdario/mergo 0.2.2 +github.com/gorilla/mux v1.3.0 +github.com/gorilla/context v1.1 +github.com/mtrmac/gpgme b2432428689ca58c2b8e8dea9449d3295cf96fc9 +github.com/mattn/go-runewidth v0.0.1 +github.com/seccomp/libseccomp-golang v0.9.0 +github.com/syndtr/gocapability e7cb7fa329f456b3855136a2642b197bad7366ba +github.com/blang/semver v3.5.0 +github.com/BurntSushi/toml v0.2.0 +github.com/mitchellh/go-wordwrap ad45545899c7b13c020ea92b2072220eefad42b8 +github.com/golang/glog 23def4e6c14b4da8ac2ed8007337bc5eb5007998 +github.com/davecgh/go-spew v1.1.0 +github.com/go-openapi/spec 6aced65f8501fe1217321abf0749d354824ba2ff +github.com/go-openapi/jsonpointer 779f45308c19820f1a69e9a4cd965f496e0da10f +github.com/go-openapi/jsonreference 36d33bfe519efae5632669801b180bf1a245da3b +github.com/go-openapi/swag 1d0bd113de87027671077d3c71eb3ac5d7dbba72 +github.com/google/gofuzz 44d81051d367757e1c7c6a5a86423ece9afcf63c +github.com/mailru/easyjson 99e922cf9de1bc0ab38310c277cff32c2147e747 +github.com/PuerkitoBio/purell v1.1.0 +github.com/PuerkitoBio/urlesc 5bd2802263f21d8788851d5305584c82a5c75d7e +github.com/ugorji/go d23841a297e5489e787e72fceffabf9d2994b52a +github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7 +golang.org/x/crypto 3fbbcd23f1cb824e69491a5930cfeff09b12f4d2 +golang.org/x/net c427ad74c6d7a814201695e9ffde0c5d400a7674 +golang.org/x/sys 9aade4d3a3b7e6d876cd3823ad20ec45fc035402 +golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756 +github.com/kr/pty v1.0.0 +github.com/google/btree 7d79101e329e5a3adf994758c578dab82b90c017 +github.com/gogo/protobuf c0656edd0d9eab7c66d1eb0c568f9039345796f7 +github.com/golang/protobuf 4bd1920723d7b7c925de087aa32e2187708897f7 +github.com/coreos/go-systemd v14 +github.com/coreos/pkg v3 +github.com/golang/groupcache b710c8433bd175204919eb38776e944233235d03 +github.com/fsnotify/fsnotify 7d7316ed6e1ed2de075aab8dfc76de5d158d66e1 +github.com/Azure/go-ansiterm 19f72df4d05d31cbe1c56bfc8045c96babff6c7e +github.com/Microsoft/go-winio 78439966b38d69bf38227fbf57ac8a6fee70f69a +github.com/Microsoft/hcsshim 43f9725307998e09f2e3816c2c0c36dc98f0c982 +github.com/emicklei/go-restful ff4f55a206334ef123e4f79bbf348980da81ca46 +github.com/emicklei/go-restful-swagger12 1.0.1 +github.com/pkg/errors v0.8.0 +github.com/godbus/dbus a389bdde4dd695d414e47b755e95e72b7826432c +github.com/urfave/cli v1.20.0 +github.com/vbatts/tar-split v0.10.1 +github.com/renstrom/dedent v1.0.0 +github.com/hpcloud/tail v1.0.0 +gopkg.in/fsnotify.v1 v1.4.2 +gopkg.in/tomb.v1 v1 +github.com/fatih/camelcase f6a740d52f961c60348ebb109adde9f4635d7540 +github.com/buger/goterm 2f8dfbc7dbbff5dd1d391ed91482c24df243b2d3 +github.com/dgrijalva/jwt-go v3.0.0 +github.com/exponent-io/jsonpath d6023ce2651d8eafb5c75bb0c7167536102ec9f5 +github.com/hashicorp/golang-lru 0a025b7e63adc15a622f29b0b2c4c3848243bbf6 +github.com/go-openapi/loads 18441dfa706d924a39a030ee2c3b1d8d81917b38 +github.com/go-openapi/analysis b44dc874b601d9e4e2f6e19140e794ba24bead3b +github.com/go-openapi/strfmt 93a31ef21ac23f317792fff78f9539219dd74619 +github.com/asaskevich/govalidator v6 +github.com/go-openapi/errors d24ebc2075bad502fac3a8ae27aa6dd58e1952dc +github.com/mitchellh/mapstructure d0303fe809921458f417bcf828397a65db30a7e4 +gopkg.in/mgo.v2 v2 +github.com/prometheus/client_golang e7e903064f5e9eb5da98208bae10b475d4db0f8c +github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6 +github.com/prometheus/common 13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207 +github.com/prometheus/procfs 65c1f6f8f0fc1e2185eb9863a3bc751496404259 +github.com/matttproud/golang_protobuf_extensions fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a +github.com/beorn7/perks 3ac7bf7a47d159a033b107610db8a1b6575507a4 +github.com/containerd/cgroups 7a5fdd8330119dc70d850260db8f3594d89d6943 +github.com/go-zoo/bone 031b4005dfe248ccba241a0c9de0f9e112fd6b7c +github.com/soheilhy/cmux v0.1.3 +github.com/hashicorp/go-multierror 83588e72410abfbe4df460eeb6f30841ae47d4c4 +github.com/hashicorp/errwrap 7554cd9344cec97297fa6649b055a8c98c2a1e55 +github.com/pquerna/ffjson d49c2bc1aa135aad0c6f4fc2056623ec78f5d5ac diff --git a/vendor/github.com/mitchellh/go-wordwrap/LICENSE.md b/vendor/github.com/mitchellh/go-wordwrap/LICENSE.md deleted file mode 100644 index 229851590..000000000 --- a/vendor/github.com/mitchellh/go-wordwrap/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Mitchell Hashimoto - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/mitchellh/go-wordwrap/README.md b/vendor/github.com/mitchellh/go-wordwrap/README.md deleted file mode 100644 index 60ae31170..000000000 --- a/vendor/github.com/mitchellh/go-wordwrap/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# go-wordwrap - -`go-wordwrap` (Golang package: `wordwrap`) is a package for Go that -automatically wraps words into multiple lines. The primary use case for this -is in formatting CLI output, but of course word wrapping is a generally useful -thing to do. - -## Installation and Usage - -Install using `go get github.com/mitchellh/go-wordwrap`. - -Full documentation is available at -http://godoc.org/github.com/mitchellh/go-wordwrap - -Below is an example of its usage ignoring errors: - -```go -wrapped := wordwrap.WrapString("foo bar baz", 3) -fmt.Println(wrapped) -``` - -Would output: - -``` -foo -bar -baz -``` - -## Word Wrap Algorithm - -This library doesn't use any clever algorithm for word wrapping. The wrapping -is actually very naive: whenever there is whitespace or an explicit linebreak. -The goal of this library is for word wrapping CLI output, so the input is -typically pretty well controlled human language. Because of this, the naive -approach typically works just fine. - -In the future, we'd like to make the algorithm more advanced. We would do -so without breaking the API. diff --git a/vendor/github.com/mitchellh/go-wordwrap/wordwrap.go b/vendor/github.com/mitchellh/go-wordwrap/wordwrap.go deleted file mode 100644 index ac67205bc..000000000 --- a/vendor/github.com/mitchellh/go-wordwrap/wordwrap.go +++ /dev/null @@ -1,73 +0,0 @@ -package wordwrap - -import ( - "bytes" - "unicode" -) - -// WrapString wraps the given string within lim width in characters. -// -// Wrapping is currently naive and only happens at white-space. A future -// version of the library will implement smarter wrapping. This means that -// pathological cases can dramatically reach past the limit, such as a very -// long word. -func WrapString(s string, lim uint) string { - // Initialize a buffer with a slightly larger size to account for breaks - init := make([]byte, 0, len(s)) - buf := bytes.NewBuffer(init) - - var current uint - var wordBuf, spaceBuf bytes.Buffer - - for _, char := range s { - if char == '\n' { - if wordBuf.Len() == 0 { - if current+uint(spaceBuf.Len()) > lim { - current = 0 - } else { - current += uint(spaceBuf.Len()) - spaceBuf.WriteTo(buf) - } - spaceBuf.Reset() - } else { - current += uint(spaceBuf.Len() + wordBuf.Len()) - spaceBuf.WriteTo(buf) - spaceBuf.Reset() - wordBuf.WriteTo(buf) - wordBuf.Reset() - } - buf.WriteRune(char) - current = 0 - } else if unicode.IsSpace(char) { - if spaceBuf.Len() == 0 || wordBuf.Len() > 0 { - current += uint(spaceBuf.Len() + wordBuf.Len()) - spaceBuf.WriteTo(buf) - spaceBuf.Reset() - wordBuf.WriteTo(buf) - wordBuf.Reset() - } - - spaceBuf.WriteRune(char) - } else { - - wordBuf.WriteRune(char) - - if current+uint(spaceBuf.Len()+wordBuf.Len()) > lim && uint(wordBuf.Len()) < lim { - buf.WriteRune('\n') - current = 0 - spaceBuf.Reset() - } - } - } - - if wordBuf.Len() == 0 { - if current+uint(spaceBuf.Len()) <= lim { - spaceBuf.WriteTo(buf) - } - } else { - spaceBuf.WriteTo(buf) - wordBuf.WriteTo(buf) - } - - return buf.String() -} diff --git a/vendor/golang.org/x/net/websocket/client.go b/vendor/golang.org/x/net/websocket/client.go deleted file mode 100644 index 69a4ac7ee..000000000 --- a/vendor/golang.org/x/net/websocket/client.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bufio" - "io" - "net" - "net/http" - "net/url" -) - -// DialError is an error that occurs while dialling a websocket server. -type DialError struct { - *Config - Err error -} - -func (e *DialError) Error() string { - return "websocket.Dial " + e.Config.Location.String() + ": " + e.Err.Error() -} - -// NewConfig creates a new WebSocket config for client connection. -func NewConfig(server, origin string) (config *Config, err error) { - config = new(Config) - config.Version = ProtocolVersionHybi13 - config.Location, err = url.ParseRequestURI(server) - if err != nil { - return - } - config.Origin, err = url.ParseRequestURI(origin) - if err != nil { - return - } - config.Header = http.Header(make(map[string][]string)) - return -} - -// NewClient creates a new WebSocket client connection over rwc. -func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) { - br := bufio.NewReader(rwc) - bw := bufio.NewWriter(rwc) - err = hybiClientHandshake(config, br, bw) - if err != nil { - return - } - buf := bufio.NewReadWriter(br, bw) - ws = newHybiClientConn(config, buf, rwc) - return -} - -// Dial opens a new client connection to a WebSocket. -func Dial(url_, protocol, origin string) (ws *Conn, err error) { - config, err := NewConfig(url_, origin) - if err != nil { - return nil, err - } - if protocol != "" { - config.Protocol = []string{protocol} - } - return DialConfig(config) -} - -var portMap = map[string]string{ - "ws": "80", - "wss": "443", -} - -func parseAuthority(location *url.URL) string { - if _, ok := portMap[location.Scheme]; ok { - if _, _, err := net.SplitHostPort(location.Host); err != nil { - return net.JoinHostPort(location.Host, portMap[location.Scheme]) - } - } - return location.Host -} - -// DialConfig opens a new client connection to a WebSocket with a config. -func DialConfig(config *Config) (ws *Conn, err error) { - var client net.Conn - if config.Location == nil { - return nil, &DialError{config, ErrBadWebSocketLocation} - } - if config.Origin == nil { - return nil, &DialError{config, ErrBadWebSocketOrigin} - } - dialer := config.Dialer - if dialer == nil { - dialer = &net.Dialer{} - } - client, err = dialWithDialer(dialer, config) - if err != nil { - goto Error - } - ws, err = NewClient(config, client) - if err != nil { - client.Close() - goto Error - } - return - -Error: - return nil, &DialError{config, err} -} diff --git a/vendor/golang.org/x/net/websocket/dial.go b/vendor/golang.org/x/net/websocket/dial.go deleted file mode 100644 index 2dab943a4..000000000 --- a/vendor/golang.org/x/net/websocket/dial.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "crypto/tls" - "net" -) - -func dialWithDialer(dialer *net.Dialer, config *Config) (conn net.Conn, err error) { - switch config.Location.Scheme { - case "ws": - conn, err = dialer.Dial("tcp", parseAuthority(config.Location)) - - case "wss": - conn, err = tls.DialWithDialer(dialer, "tcp", parseAuthority(config.Location), config.TlsConfig) - - default: - err = ErrBadScheme - } - return -} diff --git a/vendor/golang.org/x/net/websocket/hybi.go b/vendor/golang.org/x/net/websocket/hybi.go deleted file mode 100644 index 8cffdd16c..000000000 --- a/vendor/golang.org/x/net/websocket/hybi.go +++ /dev/null @@ -1,583 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -// This file implements a protocol of hybi draft. -// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17 - -import ( - "bufio" - "bytes" - "crypto/rand" - "crypto/sha1" - "encoding/base64" - "encoding/binary" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "strings" -) - -const ( - websocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - - closeStatusNormal = 1000 - closeStatusGoingAway = 1001 - closeStatusProtocolError = 1002 - closeStatusUnsupportedData = 1003 - closeStatusFrameTooLarge = 1004 - closeStatusNoStatusRcvd = 1005 - closeStatusAbnormalClosure = 1006 - closeStatusBadMessageData = 1007 - closeStatusPolicyViolation = 1008 - closeStatusTooBigData = 1009 - closeStatusExtensionMismatch = 1010 - - maxControlFramePayloadLength = 125 -) - -var ( - ErrBadMaskingKey = &ProtocolError{"bad masking key"} - ErrBadPongMessage = &ProtocolError{"bad pong message"} - ErrBadClosingStatus = &ProtocolError{"bad closing status"} - ErrUnsupportedExtensions = &ProtocolError{"unsupported extensions"} - ErrNotImplemented = &ProtocolError{"not implemented"} - - handshakeHeader = map[string]bool{ - "Host": true, - "Upgrade": true, - "Connection": true, - "Sec-Websocket-Key": true, - "Sec-Websocket-Origin": true, - "Sec-Websocket-Version": true, - "Sec-Websocket-Protocol": true, - "Sec-Websocket-Accept": true, - } -) - -// A hybiFrameHeader is a frame header as defined in hybi draft. -type hybiFrameHeader struct { - Fin bool - Rsv [3]bool - OpCode byte - Length int64 - MaskingKey []byte - - data *bytes.Buffer -} - -// A hybiFrameReader is a reader for hybi frame. -type hybiFrameReader struct { - reader io.Reader - - header hybiFrameHeader - pos int64 - length int -} - -func (frame *hybiFrameReader) Read(msg []byte) (n int, err error) { - n, err = frame.reader.Read(msg) - if frame.header.MaskingKey != nil { - for i := 0; i < n; i++ { - msg[i] = msg[i] ^ frame.header.MaskingKey[frame.pos%4] - frame.pos++ - } - } - return n, err -} - -func (frame *hybiFrameReader) PayloadType() byte { return frame.header.OpCode } - -func (frame *hybiFrameReader) HeaderReader() io.Reader { - if frame.header.data == nil { - return nil - } - if frame.header.data.Len() == 0 { - return nil - } - return frame.header.data -} - -func (frame *hybiFrameReader) TrailerReader() io.Reader { return nil } - -func (frame *hybiFrameReader) Len() (n int) { return frame.length } - -// A hybiFrameReaderFactory creates new frame reader based on its frame type. -type hybiFrameReaderFactory struct { - *bufio.Reader -} - -// NewFrameReader reads a frame header from the connection, and creates new reader for the frame. -// See Section 5.2 Base Framing protocol for detail. -// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5.2 -func (buf hybiFrameReaderFactory) NewFrameReader() (frame frameReader, err error) { - hybiFrame := new(hybiFrameReader) - frame = hybiFrame - var header []byte - var b byte - // First byte. FIN/RSV1/RSV2/RSV3/OpCode(4bits) - b, err = buf.ReadByte() - if err != nil { - return - } - header = append(header, b) - hybiFrame.header.Fin = ((header[0] >> 7) & 1) != 0 - for i := 0; i < 3; i++ { - j := uint(6 - i) - hybiFrame.header.Rsv[i] = ((header[0] >> j) & 1) != 0 - } - hybiFrame.header.OpCode = header[0] & 0x0f - - // Second byte. Mask/Payload len(7bits) - b, err = buf.ReadByte() - if err != nil { - return - } - header = append(header, b) - mask := (b & 0x80) != 0 - b &= 0x7f - lengthFields := 0 - switch { - case b <= 125: // Payload length 7bits. - hybiFrame.header.Length = int64(b) - case b == 126: // Payload length 7+16bits - lengthFields = 2 - case b == 127: // Payload length 7+64bits - lengthFields = 8 - } - for i := 0; i < lengthFields; i++ { - b, err = buf.ReadByte() - if err != nil { - return - } - if lengthFields == 8 && i == 0 { // MSB must be zero when 7+64 bits - b &= 0x7f - } - header = append(header, b) - hybiFrame.header.Length = hybiFrame.header.Length*256 + int64(b) - } - if mask { - // Masking key. 4 bytes. - for i := 0; i < 4; i++ { - b, err = buf.ReadByte() - if err != nil { - return - } - header = append(header, b) - hybiFrame.header.MaskingKey = append(hybiFrame.header.MaskingKey, b) - } - } - hybiFrame.reader = io.LimitReader(buf.Reader, hybiFrame.header.Length) - hybiFrame.header.data = bytes.NewBuffer(header) - hybiFrame.length = len(header) + int(hybiFrame.header.Length) - return -} - -// A HybiFrameWriter is a writer for hybi frame. -type hybiFrameWriter struct { - writer *bufio.Writer - - header *hybiFrameHeader -} - -func (frame *hybiFrameWriter) Write(msg []byte) (n int, err error) { - var header []byte - var b byte - if frame.header.Fin { - b |= 0x80 - } - for i := 0; i < 3; i++ { - if frame.header.Rsv[i] { - j := uint(6 - i) - b |= 1 << j - } - } - b |= frame.header.OpCode - header = append(header, b) - if frame.header.MaskingKey != nil { - b = 0x80 - } else { - b = 0 - } - lengthFields := 0 - length := len(msg) - switch { - case length <= 125: - b |= byte(length) - case length < 65536: - b |= 126 - lengthFields = 2 - default: - b |= 127 - lengthFields = 8 - } - header = append(header, b) - for i := 0; i < lengthFields; i++ { - j := uint((lengthFields - i - 1) * 8) - b = byte((length >> j) & 0xff) - header = append(header, b) - } - if frame.header.MaskingKey != nil { - if len(frame.header.MaskingKey) != 4 { - return 0, ErrBadMaskingKey - } - header = append(header, frame.header.MaskingKey...) - frame.writer.Write(header) - data := make([]byte, length) - for i := range data { - data[i] = msg[i] ^ frame.header.MaskingKey[i%4] - } - frame.writer.Write(data) - err = frame.writer.Flush() - return length, err - } - frame.writer.Write(header) - frame.writer.Write(msg) - err = frame.writer.Flush() - return length, err -} - -func (frame *hybiFrameWriter) Close() error { return nil } - -type hybiFrameWriterFactory struct { - *bufio.Writer - needMaskingKey bool -} - -func (buf hybiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameWriter, err error) { - frameHeader := &hybiFrameHeader{Fin: true, OpCode: payloadType} - if buf.needMaskingKey { - frameHeader.MaskingKey, err = generateMaskingKey() - if err != nil { - return nil, err - } - } - return &hybiFrameWriter{writer: buf.Writer, header: frameHeader}, nil -} - -type hybiFrameHandler struct { - conn *Conn - payloadType byte -} - -func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (frameReader, error) { - if handler.conn.IsServerConn() { - // The client MUST mask all frames sent to the server. - if frame.(*hybiFrameReader).header.MaskingKey == nil { - handler.WriteClose(closeStatusProtocolError) - return nil, io.EOF - } - } else { - // The server MUST NOT mask all frames. - if frame.(*hybiFrameReader).header.MaskingKey != nil { - handler.WriteClose(closeStatusProtocolError) - return nil, io.EOF - } - } - if header := frame.HeaderReader(); header != nil { - io.Copy(ioutil.Discard, header) - } - switch frame.PayloadType() { - case ContinuationFrame: - frame.(*hybiFrameReader).header.OpCode = handler.payloadType - case TextFrame, BinaryFrame: - handler.payloadType = frame.PayloadType() - case CloseFrame: - return nil, io.EOF - case PingFrame, PongFrame: - b := make([]byte, maxControlFramePayloadLength) - n, err := io.ReadFull(frame, b) - if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF { - return nil, err - } - io.Copy(ioutil.Discard, frame) - if frame.PayloadType() == PingFrame { - if _, err := handler.WritePong(b[:n]); err != nil { - return nil, err - } - } - return nil, nil - } - return frame, nil -} - -func (handler *hybiFrameHandler) WriteClose(status int) (err error) { - handler.conn.wio.Lock() - defer handler.conn.wio.Unlock() - w, err := handler.conn.frameWriterFactory.NewFrameWriter(CloseFrame) - if err != nil { - return err - } - msg := make([]byte, 2) - binary.BigEndian.PutUint16(msg, uint16(status)) - _, err = w.Write(msg) - w.Close() - return err -} - -func (handler *hybiFrameHandler) WritePong(msg []byte) (n int, err error) { - handler.conn.wio.Lock() - defer handler.conn.wio.Unlock() - w, err := handler.conn.frameWriterFactory.NewFrameWriter(PongFrame) - if err != nil { - return 0, err - } - n, err = w.Write(msg) - w.Close() - return n, err -} - -// newHybiConn creates a new WebSocket connection speaking hybi draft protocol. -func newHybiConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { - if buf == nil { - br := bufio.NewReader(rwc) - bw := bufio.NewWriter(rwc) - buf = bufio.NewReadWriter(br, bw) - } - ws := &Conn{config: config, request: request, buf: buf, rwc: rwc, - frameReaderFactory: hybiFrameReaderFactory{buf.Reader}, - frameWriterFactory: hybiFrameWriterFactory{ - buf.Writer, request == nil}, - PayloadType: TextFrame, - defaultCloseStatus: closeStatusNormal} - ws.frameHandler = &hybiFrameHandler{conn: ws} - return ws -} - -// generateMaskingKey generates a masking key for a frame. -func generateMaskingKey() (maskingKey []byte, err error) { - maskingKey = make([]byte, 4) - if _, err = io.ReadFull(rand.Reader, maskingKey); err != nil { - return - } - return -} - -// generateNonce generates a nonce consisting of a randomly selected 16-byte -// value that has been base64-encoded. -func generateNonce() (nonce []byte) { - key := make([]byte, 16) - if _, err := io.ReadFull(rand.Reader, key); err != nil { - panic(err) - } - nonce = make([]byte, 24) - base64.StdEncoding.Encode(nonce, key) - return -} - -// removeZone removes IPv6 zone identifer from host. -// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080" -func removeZone(host string) string { - if !strings.HasPrefix(host, "[") { - return host - } - i := strings.LastIndex(host, "]") - if i < 0 { - return host - } - j := strings.LastIndex(host[:i], "%") - if j < 0 { - return host - } - return host[:j] + host[i:] -} - -// getNonceAccept computes the base64-encoded SHA-1 of the concatenation of -// the nonce ("Sec-WebSocket-Key" value) with the websocket GUID string. -func getNonceAccept(nonce []byte) (expected []byte, err error) { - h := sha1.New() - if _, err = h.Write(nonce); err != nil { - return - } - if _, err = h.Write([]byte(websocketGUID)); err != nil { - return - } - expected = make([]byte, 28) - base64.StdEncoding.Encode(expected, h.Sum(nil)) - return -} - -// Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17 -func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) { - bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n") - - // According to RFC 6874, an HTTP client, proxy, or other - // intermediary must remove any IPv6 zone identifier attached - // to an outgoing URI. - bw.WriteString("Host: " + removeZone(config.Location.Host) + "\r\n") - bw.WriteString("Upgrade: websocket\r\n") - bw.WriteString("Connection: Upgrade\r\n") - nonce := generateNonce() - if config.handshakeData != nil { - nonce = []byte(config.handshakeData["key"]) - } - bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n") - bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n") - - if config.Version != ProtocolVersionHybi13 { - return ErrBadProtocolVersion - } - - bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n") - if len(config.Protocol) > 0 { - bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n") - } - // TODO(ukai): send Sec-WebSocket-Extensions. - err = config.Header.WriteSubset(bw, handshakeHeader) - if err != nil { - return err - } - - bw.WriteString("\r\n") - if err = bw.Flush(); err != nil { - return err - } - - resp, err := http.ReadResponse(br, &http.Request{Method: "GET"}) - if err != nil { - return err - } - if resp.StatusCode != 101 { - return ErrBadStatus - } - if strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" || - strings.ToLower(resp.Header.Get("Connection")) != "upgrade" { - return ErrBadUpgrade - } - expectedAccept, err := getNonceAccept(nonce) - if err != nil { - return err - } - if resp.Header.Get("Sec-WebSocket-Accept") != string(expectedAccept) { - return ErrChallengeResponse - } - if resp.Header.Get("Sec-WebSocket-Extensions") != "" { - return ErrUnsupportedExtensions - } - offeredProtocol := resp.Header.Get("Sec-WebSocket-Protocol") - if offeredProtocol != "" { - protocolMatched := false - for i := 0; i < len(config.Protocol); i++ { - if config.Protocol[i] == offeredProtocol { - protocolMatched = true - break - } - } - if !protocolMatched { - return ErrBadWebSocketProtocol - } - config.Protocol = []string{offeredProtocol} - } - - return nil -} - -// newHybiClientConn creates a client WebSocket connection after handshake. -func newHybiClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn { - return newHybiConn(config, buf, rwc, nil) -} - -// A HybiServerHandshaker performs a server handshake using hybi draft protocol. -type hybiServerHandshaker struct { - *Config - accept []byte -} - -func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) { - c.Version = ProtocolVersionHybi13 - if req.Method != "GET" { - return http.StatusMethodNotAllowed, ErrBadRequestMethod - } - // HTTP version can be safely ignored. - - if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" || - !strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") { - return http.StatusBadRequest, ErrNotWebSocket - } - - key := req.Header.Get("Sec-Websocket-Key") - if key == "" { - return http.StatusBadRequest, ErrChallengeResponse - } - version := req.Header.Get("Sec-Websocket-Version") - switch version { - case "13": - c.Version = ProtocolVersionHybi13 - default: - return http.StatusBadRequest, ErrBadWebSocketVersion - } - var scheme string - if req.TLS != nil { - scheme = "wss" - } else { - scheme = "ws" - } - c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI()) - if err != nil { - return http.StatusBadRequest, err - } - protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol")) - if protocol != "" { - protocols := strings.Split(protocol, ",") - for i := 0; i < len(protocols); i++ { - c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i])) - } - } - c.accept, err = getNonceAccept([]byte(key)) - if err != nil { - return http.StatusInternalServerError, err - } - return http.StatusSwitchingProtocols, nil -} - -// Origin parses the Origin header in req. -// If the Origin header is not set, it returns nil and nil. -func Origin(config *Config, req *http.Request) (*url.URL, error) { - var origin string - switch config.Version { - case ProtocolVersionHybi13: - origin = req.Header.Get("Origin") - } - if origin == "" { - return nil, nil - } - return url.ParseRequestURI(origin) -} - -func (c *hybiServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) { - if len(c.Protocol) > 0 { - if len(c.Protocol) != 1 { - // You need choose a Protocol in Handshake func in Server. - return ErrBadWebSocketProtocol - } - } - buf.WriteString("HTTP/1.1 101 Switching Protocols\r\n") - buf.WriteString("Upgrade: websocket\r\n") - buf.WriteString("Connection: Upgrade\r\n") - buf.WriteString("Sec-WebSocket-Accept: " + string(c.accept) + "\r\n") - if len(c.Protocol) > 0 { - buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r\n") - } - // TODO(ukai): send Sec-WebSocket-Extensions. - if c.Header != nil { - err := c.Header.WriteSubset(buf, handshakeHeader) - if err != nil { - return err - } - } - buf.WriteString("\r\n") - return buf.Flush() -} - -func (c *hybiServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { - return newHybiServerConn(c.Config, buf, rwc, request) -} - -// newHybiServerConn returns a new WebSocket connection speaking hybi draft protocol. -func newHybiServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { - return newHybiConn(config, buf, rwc, request) -} diff --git a/vendor/golang.org/x/net/websocket/server.go b/vendor/golang.org/x/net/websocket/server.go deleted file mode 100644 index 0895dea19..000000000 --- a/vendor/golang.org/x/net/websocket/server.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bufio" - "fmt" - "io" - "net/http" -) - -func newServerConn(rwc io.ReadWriteCloser, buf *bufio.ReadWriter, req *http.Request, config *Config, handshake func(*Config, *http.Request) error) (conn *Conn, err error) { - var hs serverHandshaker = &hybiServerHandshaker{Config: config} - code, err := hs.ReadHandshake(buf.Reader, req) - if err == ErrBadWebSocketVersion { - fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) - fmt.Fprintf(buf, "Sec-WebSocket-Version: %s\r\n", SupportedProtocolVersion) - buf.WriteString("\r\n") - buf.WriteString(err.Error()) - buf.Flush() - return - } - if err != nil { - fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) - buf.WriteString("\r\n") - buf.WriteString(err.Error()) - buf.Flush() - return - } - if handshake != nil { - err = handshake(config, req) - if err != nil { - code = http.StatusForbidden - fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) - buf.WriteString("\r\n") - buf.Flush() - return - } - } - err = hs.AcceptHandshake(buf.Writer) - if err != nil { - code = http.StatusBadRequest - fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) - buf.WriteString("\r\n") - buf.Flush() - return - } - conn = hs.NewServerConn(buf, rwc, req) - return -} - -// Server represents a server of a WebSocket. -type Server struct { - // Config is a WebSocket configuration for new WebSocket connection. - Config - - // Handshake is an optional function in WebSocket handshake. - // For example, you can check, or don't check Origin header. - // Another example, you can select config.Protocol. - Handshake func(*Config, *http.Request) error - - // Handler handles a WebSocket connection. - Handler -} - -// ServeHTTP implements the http.Handler interface for a WebSocket -func (s Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { - s.serveWebSocket(w, req) -} - -func (s Server) serveWebSocket(w http.ResponseWriter, req *http.Request) { - rwc, buf, err := w.(http.Hijacker).Hijack() - if err != nil { - panic("Hijack failed: " + err.Error()) - } - // The server should abort the WebSocket connection if it finds - // the client did not send a handshake that matches with protocol - // specification. - defer rwc.Close() - conn, err := newServerConn(rwc, buf, req, &s.Config, s.Handshake) - if err != nil { - return - } - if conn == nil { - panic("unexpected nil conn") - } - s.Handler(conn) -} - -// Handler is a simple interface to a WebSocket browser client. -// It checks if Origin header is valid URL by default. -// You might want to verify websocket.Conn.Config().Origin in the func. -// If you use Server instead of Handler, you could call websocket.Origin and -// check the origin in your Handshake func. So, if you want to accept -// non-browser clients, which do not send an Origin header, set a -// Server.Handshake that does not check the origin. -type Handler func(*Conn) - -func checkOrigin(config *Config, req *http.Request) (err error) { - config.Origin, err = Origin(config, req) - if err == nil && config.Origin == nil { - return fmt.Errorf("null origin") - } - return err -} - -// ServeHTTP implements the http.Handler interface for a WebSocket -func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - s := Server{Handler: h, Handshake: checkOrigin} - s.serveWebSocket(w, req) -} diff --git a/vendor/golang.org/x/net/websocket/websocket.go b/vendor/golang.org/x/net/websocket/websocket.go deleted file mode 100644 index e242c89a7..000000000 --- a/vendor/golang.org/x/net/websocket/websocket.go +++ /dev/null @@ -1,448 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package websocket implements a client and server for the WebSocket protocol -// as specified in RFC 6455. -// -// This package currently lacks some features found in an alternative -// and more actively maintained WebSocket package: -// -// https://godoc.org/github.com/gorilla/websocket -// -package websocket // import "golang.org/x/net/websocket" - -import ( - "bufio" - "crypto/tls" - "encoding/json" - "errors" - "io" - "io/ioutil" - "net" - "net/http" - "net/url" - "sync" - "time" -) - -const ( - ProtocolVersionHybi13 = 13 - ProtocolVersionHybi = ProtocolVersionHybi13 - SupportedProtocolVersion = "13" - - ContinuationFrame = 0 - TextFrame = 1 - BinaryFrame = 2 - CloseFrame = 8 - PingFrame = 9 - PongFrame = 10 - UnknownFrame = 255 - - DefaultMaxPayloadBytes = 32 << 20 // 32MB -) - -// ProtocolError represents WebSocket protocol errors. -type ProtocolError struct { - ErrorString string -} - -func (err *ProtocolError) Error() string { return err.ErrorString } - -var ( - ErrBadProtocolVersion = &ProtocolError{"bad protocol version"} - ErrBadScheme = &ProtocolError{"bad scheme"} - ErrBadStatus = &ProtocolError{"bad status"} - ErrBadUpgrade = &ProtocolError{"missing or bad upgrade"} - ErrBadWebSocketOrigin = &ProtocolError{"missing or bad WebSocket-Origin"} - ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"} - ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"} - ErrBadWebSocketVersion = &ProtocolError{"missing or bad WebSocket Version"} - ErrChallengeResponse = &ProtocolError{"mismatch challenge/response"} - ErrBadFrame = &ProtocolError{"bad frame"} - ErrBadFrameBoundary = &ProtocolError{"not on frame boundary"} - ErrNotWebSocket = &ProtocolError{"not websocket protocol"} - ErrBadRequestMethod = &ProtocolError{"bad method"} - ErrNotSupported = &ProtocolError{"not supported"} -) - -// ErrFrameTooLarge is returned by Codec's Receive method if payload size -// exceeds limit set by Conn.MaxPayloadBytes -var ErrFrameTooLarge = errors.New("websocket: frame payload size exceeds limit") - -// Addr is an implementation of net.Addr for WebSocket. -type Addr struct { - *url.URL -} - -// Network returns the network type for a WebSocket, "websocket". -func (addr *Addr) Network() string { return "websocket" } - -// Config is a WebSocket configuration -type Config struct { - // A WebSocket server address. - Location *url.URL - - // A Websocket client origin. - Origin *url.URL - - // WebSocket subprotocols. - Protocol []string - - // WebSocket protocol version. - Version int - - // TLS config for secure WebSocket (wss). - TlsConfig *tls.Config - - // Additional header fields to be sent in WebSocket opening handshake. - Header http.Header - - // Dialer used when opening websocket connections. - Dialer *net.Dialer - - handshakeData map[string]string -} - -// serverHandshaker is an interface to handle WebSocket server side handshake. -type serverHandshaker interface { - // ReadHandshake reads handshake request message from client. - // Returns http response code and error if any. - ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) - - // AcceptHandshake accepts the client handshake request and sends - // handshake response back to client. - AcceptHandshake(buf *bufio.Writer) (err error) - - // NewServerConn creates a new WebSocket connection. - NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn) -} - -// frameReader is an interface to read a WebSocket frame. -type frameReader interface { - // Reader is to read payload of the frame. - io.Reader - - // PayloadType returns payload type. - PayloadType() byte - - // HeaderReader returns a reader to read header of the frame. - HeaderReader() io.Reader - - // TrailerReader returns a reader to read trailer of the frame. - // If it returns nil, there is no trailer in the frame. - TrailerReader() io.Reader - - // Len returns total length of the frame, including header and trailer. - Len() int -} - -// frameReaderFactory is an interface to creates new frame reader. -type frameReaderFactory interface { - NewFrameReader() (r frameReader, err error) -} - -// frameWriter is an interface to write a WebSocket frame. -type frameWriter interface { - // Writer is to write payload of the frame. - io.WriteCloser -} - -// frameWriterFactory is an interface to create new frame writer. -type frameWriterFactory interface { - NewFrameWriter(payloadType byte) (w frameWriter, err error) -} - -type frameHandler interface { - HandleFrame(frame frameReader) (r frameReader, err error) - WriteClose(status int) (err error) -} - -// Conn represents a WebSocket connection. -// -// Multiple goroutines may invoke methods on a Conn simultaneously. -type Conn struct { - config *Config - request *http.Request - - buf *bufio.ReadWriter - rwc io.ReadWriteCloser - - rio sync.Mutex - frameReaderFactory - frameReader - - wio sync.Mutex - frameWriterFactory - - frameHandler - PayloadType byte - defaultCloseStatus int - - // MaxPayloadBytes limits the size of frame payload received over Conn - // by Codec's Receive method. If zero, DefaultMaxPayloadBytes is used. - MaxPayloadBytes int -} - -// Read implements the io.Reader interface: -// it reads data of a frame from the WebSocket connection. -// if msg is not large enough for the frame data, it fills the msg and next Read -// will read the rest of the frame data. -// it reads Text frame or Binary frame. -func (ws *Conn) Read(msg []byte) (n int, err error) { - ws.rio.Lock() - defer ws.rio.Unlock() -again: - if ws.frameReader == nil { - frame, err := ws.frameReaderFactory.NewFrameReader() - if err != nil { - return 0, err - } - ws.frameReader, err = ws.frameHandler.HandleFrame(frame) - if err != nil { - return 0, err - } - if ws.frameReader == nil { - goto again - } - } - n, err = ws.frameReader.Read(msg) - if err == io.EOF { - if trailer := ws.frameReader.TrailerReader(); trailer != nil { - io.Copy(ioutil.Discard, trailer) - } - ws.frameReader = nil - goto again - } - return n, err -} - -// Write implements the io.Writer interface: -// it writes data as a frame to the WebSocket connection. -func (ws *Conn) Write(msg []byte) (n int, err error) { - ws.wio.Lock() - defer ws.wio.Unlock() - w, err := ws.frameWriterFactory.NewFrameWriter(ws.PayloadType) - if err != nil { - return 0, err - } - n, err = w.Write(msg) - w.Close() - return n, err -} - -// Close implements the io.Closer interface. -func (ws *Conn) Close() error { - err := ws.frameHandler.WriteClose(ws.defaultCloseStatus) - err1 := ws.rwc.Close() - if err != nil { - return err - } - return err1 -} - -func (ws *Conn) IsClientConn() bool { return ws.request == nil } -func (ws *Conn) IsServerConn() bool { return ws.request != nil } - -// LocalAddr returns the WebSocket Origin for the connection for client, or -// the WebSocket location for server. -func (ws *Conn) LocalAddr() net.Addr { - if ws.IsClientConn() { - return &Addr{ws.config.Origin} - } - return &Addr{ws.config.Location} -} - -// RemoteAddr returns the WebSocket location for the connection for client, or -// the Websocket Origin for server. -func (ws *Conn) RemoteAddr() net.Addr { - if ws.IsClientConn() { - return &Addr{ws.config.Location} - } - return &Addr{ws.config.Origin} -} - -var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn") - -// SetDeadline sets the connection's network read & write deadlines. -func (ws *Conn) SetDeadline(t time.Time) error { - if conn, ok := ws.rwc.(net.Conn); ok { - return conn.SetDeadline(t) - } - return errSetDeadline -} - -// SetReadDeadline sets the connection's network read deadline. -func (ws *Conn) SetReadDeadline(t time.Time) error { - if conn, ok := ws.rwc.(net.Conn); ok { - return conn.SetReadDeadline(t) - } - return errSetDeadline -} - -// SetWriteDeadline sets the connection's network write deadline. -func (ws *Conn) SetWriteDeadline(t time.Time) error { - if conn, ok := ws.rwc.(net.Conn); ok { - return conn.SetWriteDeadline(t) - } - return errSetDeadline -} - -// Config returns the WebSocket config. -func (ws *Conn) Config() *Config { return ws.config } - -// Request returns the http request upgraded to the WebSocket. -// It is nil for client side. -func (ws *Conn) Request() *http.Request { return ws.request } - -// Codec represents a symmetric pair of functions that implement a codec. -type Codec struct { - Marshal func(v interface{}) (data []byte, payloadType byte, err error) - Unmarshal func(data []byte, payloadType byte, v interface{}) (err error) -} - -// Send sends v marshaled by cd.Marshal as single frame to ws. -func (cd Codec) Send(ws *Conn, v interface{}) (err error) { - data, payloadType, err := cd.Marshal(v) - if err != nil { - return err - } - ws.wio.Lock() - defer ws.wio.Unlock() - w, err := ws.frameWriterFactory.NewFrameWriter(payloadType) - if err != nil { - return err - } - _, err = w.Write(data) - w.Close() - return err -} - -// Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores -// in v. The whole frame payload is read to an in-memory buffer; max size of -// payload is defined by ws.MaxPayloadBytes. If frame payload size exceeds -// limit, ErrFrameTooLarge is returned; in this case frame is not read off wire -// completely. The next call to Receive would read and discard leftover data of -// previous oversized frame before processing next frame. -func (cd Codec) Receive(ws *Conn, v interface{}) (err error) { - ws.rio.Lock() - defer ws.rio.Unlock() - if ws.frameReader != nil { - _, err = io.Copy(ioutil.Discard, ws.frameReader) - if err != nil { - return err - } - ws.frameReader = nil - } -again: - frame, err := ws.frameReaderFactory.NewFrameReader() - if err != nil { - return err - } - frame, err = ws.frameHandler.HandleFrame(frame) - if err != nil { - return err - } - if frame == nil { - goto again - } - maxPayloadBytes := ws.MaxPayloadBytes - if maxPayloadBytes == 0 { - maxPayloadBytes = DefaultMaxPayloadBytes - } - if hf, ok := frame.(*hybiFrameReader); ok && hf.header.Length > int64(maxPayloadBytes) { - // payload size exceeds limit, no need to call Unmarshal - // - // set frameReader to current oversized frame so that - // the next call to this function can drain leftover - // data before processing the next frame - ws.frameReader = frame - return ErrFrameTooLarge - } - payloadType := frame.PayloadType() - data, err := ioutil.ReadAll(frame) - if err != nil { - return err - } - return cd.Unmarshal(data, payloadType, v) -} - -func marshal(v interface{}) (msg []byte, payloadType byte, err error) { - switch data := v.(type) { - case string: - return []byte(data), TextFrame, nil - case []byte: - return data, BinaryFrame, nil - } - return nil, UnknownFrame, ErrNotSupported -} - -func unmarshal(msg []byte, payloadType byte, v interface{}) (err error) { - switch data := v.(type) { - case *string: - *data = string(msg) - return nil - case *[]byte: - *data = msg - return nil - } - return ErrNotSupported -} - -/* -Message is a codec to send/receive text/binary data in a frame on WebSocket connection. -To send/receive text frame, use string type. -To send/receive binary frame, use []byte type. - -Trivial usage: - - import "websocket" - - // receive text frame - var message string - websocket.Message.Receive(ws, &message) - - // send text frame - message = "hello" - websocket.Message.Send(ws, message) - - // receive binary frame - var data []byte - websocket.Message.Receive(ws, &data) - - // send binary frame - data = []byte{0, 1, 2} - websocket.Message.Send(ws, data) - -*/ -var Message = Codec{marshal, unmarshal} - -func jsonMarshal(v interface{}) (msg []byte, payloadType byte, err error) { - msg, err = json.Marshal(v) - return msg, TextFrame, err -} - -func jsonUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) { - return json.Unmarshal(msg, v) -} - -/* -JSON is a codec to send/receive JSON data in a frame from a WebSocket connection. - -Trivial usage: - - import "websocket" - - type T struct { - Msg string - Count int - } - - // receive JSON type T - var data T - websocket.JSON.Receive(ws, &data) - - // send JSON type T - websocket.JSON.Send(ws, data) -*/ -var JSON = Codec{jsonMarshal, jsonUnmarshal} diff --git a/vendor/k8s.io/apiserver/pkg/server/httplog/doc.go b/vendor/k8s.io/apiserver/pkg/server/httplog/doc.go deleted file mode 100644 index caa6572c7..000000000 --- a/vendor/k8s.io/apiserver/pkg/server/httplog/doc.go +++ /dev/null @@ -1,19 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package httplog contains a helper object and functions to maintain a log -// along with an http response. -package httplog // import "k8s.io/apiserver/pkg/server/httplog" diff --git a/vendor/k8s.io/apiserver/pkg/server/httplog/log.go b/vendor/k8s.io/apiserver/pkg/server/httplog/log.go deleted file mode 100644 index 4a4894cee..000000000 --- a/vendor/k8s.io/apiserver/pkg/server/httplog/log.go +++ /dev/null @@ -1,225 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package httplog - -import ( - "bufio" - "fmt" - "net" - "net/http" - "runtime" - "time" - - "github.com/golang/glog" -) - -// Handler wraps all HTTP calls to delegate with nice logging. -// delegate may use LogOf(w).Addf(...) to write additional info to -// the per-request log message. -// -// Intended to wrap calls to your ServeMux. -func Handler(delegate http.Handler, pred StacktracePred) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - defer NewLogged(req, &w).StacktraceWhen(pred).Log() - delegate.ServeHTTP(w, req) - }) -} - -// StacktracePred returns true if a stacktrace should be logged for this status. -type StacktracePred func(httpStatus int) (logStacktrace bool) - -type logger interface { - Addf(format string, data ...interface{}) -} - -// Add a layer on top of ResponseWriter, so we can track latency and error -// message sources. -// -// TODO now that we're using go-restful, we shouldn't need to be wrapping -// the http.ResponseWriter. We can recover panics from go-restful, and -// the logging value is questionable. -type respLogger struct { - hijacked bool - statusRecorded bool - status int - statusStack string - addedInfo string - startTime time.Time - - captureErrorOutput bool - - req *http.Request - w http.ResponseWriter - - logStacktracePred StacktracePred -} - -// Simple logger that logs immediately when Addf is called -type passthroughLogger struct{} - -// Addf logs info immediately. -func (passthroughLogger) Addf(format string, data ...interface{}) { - glog.V(2).Info(fmt.Sprintf(format, data...)) -} - -// DefaultStacktracePred is the default implementation of StacktracePred. -func DefaultStacktracePred(status int) bool { - return (status < http.StatusOK || status >= http.StatusInternalServerError) && status != http.StatusSwitchingProtocols -} - -// NewLogged turns a normal response writer into a logged response writer. -// -// Usage: -// -// defer NewLogged(req, &w).StacktraceWhen(StatusIsNot(200, 202)).Log() -// -// (Only the call to Log() is deferred, so you can set everything up in one line!) -// -// Note that this *changes* your writer, to route response writing actions -// through the logger. -// -// Use LogOf(w).Addf(...) to log something along with the response result. -func NewLogged(req *http.Request, w *http.ResponseWriter) *respLogger { - if _, ok := (*w).(*respLogger); ok { - // Don't double-wrap! - panic("multiple NewLogged calls!") - } - rl := &respLogger{ - startTime: time.Now(), - req: req, - w: *w, - logStacktracePred: DefaultStacktracePred, - } - *w = rl // hijack caller's writer! - return rl -} - -// LogOf returns the logger hiding in w. If there is not an existing logger -// then a passthroughLogger will be created which will log to stdout immediately -// when Addf is called. -func LogOf(req *http.Request, w http.ResponseWriter) logger { - if _, exists := w.(*respLogger); !exists { - pl := &passthroughLogger{} - return pl - } - if rl, ok := w.(*respLogger); ok { - return rl - } - panic("Unable to find or create the logger!") -} - -// Unlogged returns the original ResponseWriter, or w if it is not our inserted logger. -func Unlogged(w http.ResponseWriter) http.ResponseWriter { - if rl, ok := w.(*respLogger); ok { - return rl.w - } - return w -} - -// StacktraceWhen sets the stacktrace logging predicate, which decides when to log a stacktrace. -// There's a default, so you don't need to call this unless you don't like the default. -func (rl *respLogger) StacktraceWhen(pred StacktracePred) *respLogger { - rl.logStacktracePred = pred - return rl -} - -// StatusIsNot returns a StacktracePred which will cause stacktraces to be logged -// for any status *not* in the given list. -func StatusIsNot(statuses ...int) StacktracePred { - return func(status int) bool { - for _, s := range statuses { - if status == s { - return false - } - } - return true - } -} - -// Addf adds additional data to be logged with this request. -func (rl *respLogger) Addf(format string, data ...interface{}) { - rl.addedInfo += "\n" + fmt.Sprintf(format, data...) -} - -// Log is intended to be called once at the end of your request handler, via defer -func (rl *respLogger) Log() { - latency := time.Since(rl.startTime) - if glog.V(2) { - if !rl.hijacked { - glog.InfoDepth(1, fmt.Sprintf("%s %s: (%v) %v%v%v [%s %s]", rl.req.Method, rl.req.RequestURI, latency, rl.status, rl.statusStack, rl.addedInfo, rl.req.Header["User-Agent"], rl.req.RemoteAddr)) - } else { - glog.InfoDepth(1, fmt.Sprintf("%s %s: (%v) hijacked [%s %s]", rl.req.Method, rl.req.RequestURI, latency, rl.req.Header["User-Agent"], rl.req.RemoteAddr)) - } - } -} - -// Header implements http.ResponseWriter. -func (rl *respLogger) Header() http.Header { - return rl.w.Header() -} - -// Write implements http.ResponseWriter. -func (rl *respLogger) Write(b []byte) (int, error) { - if !rl.statusRecorded { - rl.recordStatus(http.StatusOK) // Default if WriteHeader hasn't been called - } - if rl.captureErrorOutput { - rl.Addf("logging error output: %q\n", string(b)) - } - return rl.w.Write(b) -} - -// Flush implements http.Flusher even if the underlying http.Writer doesn't implement it. -// Flush is used for streaming purposes and allows to flush buffered data to the client. -func (rl *respLogger) Flush() { - if flusher, ok := rl.w.(http.Flusher); ok { - flusher.Flush() - } else if glog.V(2) { - glog.InfoDepth(1, fmt.Sprintf("Unable to convert %+v into http.Flusher", rl.w)) - } -} - -// WriteHeader implements http.ResponseWriter. -func (rl *respLogger) WriteHeader(status int) { - rl.recordStatus(status) - rl.w.WriteHeader(status) -} - -// Hijack implements http.Hijacker. -func (rl *respLogger) Hijack() (net.Conn, *bufio.ReadWriter, error) { - rl.hijacked = true - return rl.w.(http.Hijacker).Hijack() -} - -// CloseNotify implements http.CloseNotifier -func (rl *respLogger) CloseNotify() <-chan bool { - return rl.w.(http.CloseNotifier).CloseNotify() -} - -func (rl *respLogger) recordStatus(status int) { - rl.status = status - rl.statusRecorded = true - if rl.logStacktracePred(status) { - // Only log stacks for errors - stack := make([]byte, 50*1024) - stack = stack[:runtime.Stack(stack, false)] - rl.statusStack = "\n" + string(stack) - rl.captureErrorOutput = true - } else { - rl.statusStack = "" - } -} diff --git a/vendor/k8s.io/apiserver/pkg/util/wsstream/conn.go b/vendor/k8s.io/apiserver/pkg/util/wsstream/conn.go deleted file mode 100644 index f01638ad6..000000000 --- a/vendor/k8s.io/apiserver/pkg/util/wsstream/conn.go +++ /dev/null @@ -1,349 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package wsstream - -import ( - "encoding/base64" - "fmt" - "io" - "net/http" - "regexp" - "strings" - "time" - - "github.com/golang/glog" - "golang.org/x/net/websocket" - - "k8s.io/apimachinery/pkg/util/runtime" -) - -// The Websocket subprotocol "channel.k8s.io" prepends each binary message with a byte indicating -// the channel number (zero indexed) the message was sent on. Messages in both directions should -// prefix their messages with this channel byte. When used for remote execution, the channel numbers -// are by convention defined to match the POSIX file-descriptors assigned to STDIN, STDOUT, and STDERR -// (0, 1, and 2). No other conversion is performed on the raw subprotocol - writes are sent as they -// are received by the server. -// -// Example client session: -// -// CONNECT http://server.com with subprotocol "channel.k8s.io" -// WRITE []byte{0, 102, 111, 111, 10} # send "foo\n" on channel 0 (STDIN) -// READ []byte{1, 10} # receive "\n" on channel 1 (STDOUT) -// CLOSE -// -const ChannelWebSocketProtocol = "channel.k8s.io" - -// The Websocket subprotocol "base64.channel.k8s.io" base64 encodes each message with a character -// indicating the channel number (zero indexed) the message was sent on. Messages in both directions -// should prefix their messages with this channel char. When used for remote execution, the channel -// numbers are by convention defined to match the POSIX file-descriptors assigned to STDIN, STDOUT, -// and STDERR ('0', '1', and '2'). The data received on the server is base64 decoded (and must be -// be valid) and data written by the server to the client is base64 encoded. -// -// Example client session: -// -// CONNECT http://server.com with subprotocol "base64.channel.k8s.io" -// WRITE []byte{48, 90, 109, 57, 118, 67, 103, 111, 61} # send "foo\n" (base64: "Zm9vCgo=") on channel '0' (STDIN) -// READ []byte{49, 67, 103, 61, 61} # receive "\n" (base64: "Cg==") on channel '1' (STDOUT) -// CLOSE -// -const Base64ChannelWebSocketProtocol = "base64.channel.k8s.io" - -type codecType int - -const ( - rawCodec codecType = iota - base64Codec -) - -type ChannelType int - -const ( - IgnoreChannel ChannelType = iota - ReadChannel - WriteChannel - ReadWriteChannel -) - -var ( - // connectionUpgradeRegex matches any Connection header value that includes upgrade - connectionUpgradeRegex = regexp.MustCompile("(^|.*,\\s*)upgrade($|\\s*,)") -) - -// IsWebSocketRequest returns true if the incoming request contains connection upgrade headers -// for WebSockets. -func IsWebSocketRequest(req *http.Request) bool { - return connectionUpgradeRegex.MatchString(strings.ToLower(req.Header.Get("Connection"))) && strings.ToLower(req.Header.Get("Upgrade")) == "websocket" -} - -// IgnoreReceives reads from a WebSocket until it is closed, then returns. If timeout is set, the -// read and write deadlines are pushed every time a new message is received. -func IgnoreReceives(ws *websocket.Conn, timeout time.Duration) { - defer runtime.HandleCrash() - var data []byte - for { - resetTimeout(ws, timeout) - if err := websocket.Message.Receive(ws, &data); err != nil { - return - } - } -} - -// handshake ensures the provided user protocol matches one of the allowed protocols. It returns -// no error if no protocol is specified. -func handshake(config *websocket.Config, req *http.Request, allowed []string) error { - protocols := config.Protocol - if len(protocols) == 0 { - protocols = []string{""} - } - - for _, protocol := range protocols { - for _, allow := range allowed { - if allow == protocol { - config.Protocol = []string{protocol} - return nil - } - } - } - - return fmt.Errorf("requested protocol(s) are not supported: %v; supports %v", config.Protocol, allowed) -} - -// ChannelProtocolConfig describes a websocket subprotocol with channels. -type ChannelProtocolConfig struct { - Binary bool - Channels []ChannelType -} - -// NewDefaultChannelProtocols returns a channel protocol map with the -// subprotocols "", "channel.k8s.io", "base64.channel.k8s.io" and the given -// channels. -func NewDefaultChannelProtocols(channels []ChannelType) map[string]ChannelProtocolConfig { - return map[string]ChannelProtocolConfig{ - "": {Binary: true, Channels: channels}, - ChannelWebSocketProtocol: {Binary: true, Channels: channels}, - Base64ChannelWebSocketProtocol: {Binary: false, Channels: channels}, - } -} - -// Conn supports sending multiple binary channels over a websocket connection. -type Conn struct { - protocols map[string]ChannelProtocolConfig - selectedProtocol string - channels []*websocketChannel - codec codecType - ready chan struct{} - ws *websocket.Conn - timeout time.Duration -} - -// NewConn creates a WebSocket connection that supports a set of channels. Channels begin each -// web socket message with a single byte indicating the channel number (0-N). 255 is reserved for -// future use. The channel types for each channel are passed as an array, supporting the different -// duplex modes. Read and Write refer to whether the channel can be used as a Reader or Writer. -// -// The protocols parameter maps subprotocol names to ChannelProtocols. The empty string subprotocol -// name is used if websocket.Config.Protocol is empty. -func NewConn(protocols map[string]ChannelProtocolConfig) *Conn { - return &Conn{ - ready: make(chan struct{}), - protocols: protocols, - } -} - -// SetIdleTimeout sets the interval for both reads and writes before timeout. If not specified, -// there is no timeout on the connection. -func (conn *Conn) SetIdleTimeout(duration time.Duration) { - conn.timeout = duration -} - -// Open the connection and create channels for reading and writing. It returns -// the selected subprotocol, a slice of channels and an error. -func (conn *Conn) Open(w http.ResponseWriter, req *http.Request) (string, []io.ReadWriteCloser, error) { - go func() { - defer runtime.HandleCrash() - defer conn.Close() - websocket.Server{Handshake: conn.handshake, Handler: conn.handle}.ServeHTTP(w, req) - }() - <-conn.ready - rwc := make([]io.ReadWriteCloser, len(conn.channels)) - for i := range conn.channels { - rwc[i] = conn.channels[i] - } - return conn.selectedProtocol, rwc, nil -} - -func (conn *Conn) initialize(ws *websocket.Conn) { - negotiated := ws.Config().Protocol - conn.selectedProtocol = negotiated[0] - p := conn.protocols[conn.selectedProtocol] - if p.Binary { - conn.codec = rawCodec - } else { - conn.codec = base64Codec - } - conn.ws = ws - conn.channels = make([]*websocketChannel, len(p.Channels)) - for i, t := range p.Channels { - switch t { - case ReadChannel: - conn.channels[i] = newWebsocketChannel(conn, byte(i), true, false) - case WriteChannel: - conn.channels[i] = newWebsocketChannel(conn, byte(i), false, true) - case ReadWriteChannel: - conn.channels[i] = newWebsocketChannel(conn, byte(i), true, true) - case IgnoreChannel: - conn.channels[i] = newWebsocketChannel(conn, byte(i), false, false) - } - } - - close(conn.ready) -} - -func (conn *Conn) handshake(config *websocket.Config, req *http.Request) error { - supportedProtocols := make([]string, 0, len(conn.protocols)) - for p := range conn.protocols { - supportedProtocols = append(supportedProtocols, p) - } - return handshake(config, req, supportedProtocols) -} - -func (conn *Conn) resetTimeout() { - if conn.timeout > 0 { - conn.ws.SetDeadline(time.Now().Add(conn.timeout)) - } -} - -// Close is only valid after Open has been called -func (conn *Conn) Close() error { - <-conn.ready - for _, s := range conn.channels { - s.Close() - } - conn.ws.Close() - return nil -} - -// handle implements a websocket handler. -func (conn *Conn) handle(ws *websocket.Conn) { - defer conn.Close() - conn.initialize(ws) - - for { - conn.resetTimeout() - var data []byte - if err := websocket.Message.Receive(ws, &data); err != nil { - if err != io.EOF { - glog.Errorf("Error on socket receive: %v", err) - } - break - } - if len(data) == 0 { - continue - } - channel := data[0] - if conn.codec == base64Codec { - channel = channel - '0' - } - data = data[1:] - if int(channel) >= len(conn.channels) { - glog.V(6).Infof("Frame is targeted for a reader %d that is not valid, possible protocol error", channel) - continue - } - if _, err := conn.channels[channel].DataFromSocket(data); err != nil { - glog.Errorf("Unable to write frame to %d: %v\n%s", channel, err, string(data)) - continue - } - } -} - -// write multiplexes the specified channel onto the websocket -func (conn *Conn) write(num byte, data []byte) (int, error) { - conn.resetTimeout() - switch conn.codec { - case rawCodec: - frame := make([]byte, len(data)+1) - frame[0] = num - copy(frame[1:], data) - if err := websocket.Message.Send(conn.ws, frame); err != nil { - return 0, err - } - case base64Codec: - frame := string('0'+num) + base64.StdEncoding.EncodeToString(data) - if err := websocket.Message.Send(conn.ws, frame); err != nil { - return 0, err - } - } - return len(data), nil -} - -// websocketChannel represents a channel in a connection -type websocketChannel struct { - conn *Conn - num byte - r io.Reader - w io.WriteCloser - - read, write bool -} - -// newWebsocketChannel creates a pipe for writing to a websocket. Do not write to this pipe -// prior to the connection being opened. It may be no, half, or full duplex depending on -// read and write. -func newWebsocketChannel(conn *Conn, num byte, read, write bool) *websocketChannel { - r, w := io.Pipe() - return &websocketChannel{conn, num, r, w, read, write} -} - -func (p *websocketChannel) Write(data []byte) (int, error) { - if !p.write { - return len(data), nil - } - return p.conn.write(p.num, data) -} - -// DataFromSocket is invoked by the connection receiver to move data from the connection -// into a specific channel. -func (p *websocketChannel) DataFromSocket(data []byte) (int, error) { - if !p.read { - return len(data), nil - } - - switch p.conn.codec { - case rawCodec: - return p.w.Write(data) - case base64Codec: - dst := make([]byte, len(data)) - n, err := base64.StdEncoding.Decode(dst, data) - if err != nil { - return 0, err - } - return p.w.Write(dst[:n]) - } - return 0, nil -} - -func (p *websocketChannel) Read(data []byte) (int, error) { - if !p.read { - return 0, io.EOF - } - return p.r.Read(data) -} - -func (p *websocketChannel) Close() error { - return p.w.Close() -} diff --git a/vendor/k8s.io/apiserver/pkg/util/wsstream/doc.go b/vendor/k8s.io/apiserver/pkg/util/wsstream/doc.go deleted file mode 100644 index 694ce81d2..000000000 --- a/vendor/k8s.io/apiserver/pkg/util/wsstream/doc.go +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package wsstream contains utilities for streaming content over WebSockets. -// The Conn type allows callers to multiplex multiple read/write channels over -// a single websocket. The Reader type allows an io.Reader to be copied over -// a websocket channel as binary content. -package wsstream // import "k8s.io/apiserver/pkg/util/wsstream" diff --git a/vendor/k8s.io/apiserver/pkg/util/wsstream/stream.go b/vendor/k8s.io/apiserver/pkg/util/wsstream/stream.go deleted file mode 100644 index 9dd165bfa..000000000 --- a/vendor/k8s.io/apiserver/pkg/util/wsstream/stream.go +++ /dev/null @@ -1,177 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package wsstream - -import ( - "encoding/base64" - "io" - "net/http" - "sync" - "time" - - "golang.org/x/net/websocket" - - "k8s.io/apimachinery/pkg/util/runtime" -) - -// The WebSocket subprotocol "binary.k8s.io" will only send messages to the -// client and ignore messages sent to the server. The received messages are -// the exact bytes written to the stream. Zero byte messages are possible. -const binaryWebSocketProtocol = "binary.k8s.io" - -// The WebSocket subprotocol "base64.binary.k8s.io" will only send messages to the -// client and ignore messages sent to the server. The received messages are -// a base64 version of the bytes written to the stream. Zero byte messages are -// possible. -const base64BinaryWebSocketProtocol = "base64.binary.k8s.io" - -// ReaderProtocolConfig describes a websocket subprotocol with one stream. -type ReaderProtocolConfig struct { - Binary bool -} - -// NewDefaultReaderProtocols returns a stream protocol map with the -// subprotocols "", "channel.k8s.io", "base64.channel.k8s.io". -func NewDefaultReaderProtocols() map[string]ReaderProtocolConfig { - return map[string]ReaderProtocolConfig{ - "": {Binary: true}, - binaryWebSocketProtocol: {Binary: true}, - base64BinaryWebSocketProtocol: {Binary: false}, - } -} - -// Reader supports returning an arbitrary byte stream over a websocket channel. -type Reader struct { - err chan error - r io.Reader - ping bool - timeout time.Duration - protocols map[string]ReaderProtocolConfig - selectedProtocol string - - handleCrash func() // overridable for testing -} - -// NewReader creates a WebSocket pipe that will copy the contents of r to a provided -// WebSocket connection. If ping is true, a zero length message will be sent to the client -// before the stream begins reading. -// -// The protocols parameter maps subprotocol names to StreamProtocols. The empty string -// subprotocol name is used if websocket.Config.Protocol is empty. -func NewReader(r io.Reader, ping bool, protocols map[string]ReaderProtocolConfig) *Reader { - return &Reader{ - r: r, - err: make(chan error), - ping: ping, - protocols: protocols, - handleCrash: func() { runtime.HandleCrash() }, - } -} - -// SetIdleTimeout sets the interval for both reads and writes before timeout. If not specified, -// there is no timeout on the reader. -func (r *Reader) SetIdleTimeout(duration time.Duration) { - r.timeout = duration -} - -func (r *Reader) handshake(config *websocket.Config, req *http.Request) error { - supportedProtocols := make([]string, 0, len(r.protocols)) - for p := range r.protocols { - supportedProtocols = append(supportedProtocols, p) - } - return handshake(config, req, supportedProtocols) -} - -// Copy the reader to the response. The created WebSocket is closed after this -// method completes. -func (r *Reader) Copy(w http.ResponseWriter, req *http.Request) error { - go func() { - defer r.handleCrash() - websocket.Server{Handshake: r.handshake, Handler: r.handle}.ServeHTTP(w, req) - }() - return <-r.err -} - -// handle implements a WebSocket handler. -func (r *Reader) handle(ws *websocket.Conn) { - // Close the connection when the client requests it, or when we finish streaming, whichever happens first - closeConnOnce := &sync.Once{} - closeConn := func() { - closeConnOnce.Do(func() { - ws.Close() - }) - } - - negotiated := ws.Config().Protocol - r.selectedProtocol = negotiated[0] - defer close(r.err) - defer closeConn() - - go func() { - defer runtime.HandleCrash() - // This blocks until the connection is closed. - // Client should not send anything. - IgnoreReceives(ws, r.timeout) - // Once the client closes, we should also close - closeConn() - }() - - r.err <- messageCopy(ws, r.r, !r.protocols[r.selectedProtocol].Binary, r.ping, r.timeout) -} - -func resetTimeout(ws *websocket.Conn, timeout time.Duration) { - if timeout > 0 { - ws.SetDeadline(time.Now().Add(timeout)) - } -} - -func messageCopy(ws *websocket.Conn, r io.Reader, base64Encode, ping bool, timeout time.Duration) error { - buf := make([]byte, 2048) - if ping { - resetTimeout(ws, timeout) - if base64Encode { - if err := websocket.Message.Send(ws, ""); err != nil { - return err - } - } else { - if err := websocket.Message.Send(ws, []byte{}); err != nil { - return err - } - } - } - for { - resetTimeout(ws, timeout) - n, err := r.Read(buf) - if err != nil { - if err == io.EOF { - return nil - } - return err - } - if n > 0 { - if base64Encode { - if err := websocket.Message.Send(ws, base64.StdEncoding.EncodeToString(buf[:n])); err != nil { - return err - } - } else { - if err := websocket.Message.Send(ws, buf[:n]); err != nil { - return err - } - } - } - } -} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/leaky/leaky.go b/vendor/k8s.io/kubernetes/pkg/kubelet/leaky/leaky.go deleted file mode 100644 index 4e3e1e1f2..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/leaky/leaky.go +++ /dev/null @@ -1,25 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package leaky holds bits of kubelet that should be internal but have leaked -// out through bad abstractions. TODO: delete all of this. -package leaky - -const ( - // This is used in a few places outside of Kubelet, such as indexing - // into the container info. - PodInfraContainerName = "POD" -) diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/portforward/constants.go b/vendor/k8s.io/kubernetes/pkg/kubelet/server/portforward/constants.go deleted file mode 100644 index e7ccd58ae..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/server/portforward/constants.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// package portforward contains server-side logic for handling port forwarding requests. -package portforward - -// The subprotocol "portforward.k8s.io" is used for port forwarding. -const ProtocolV1Name = "portforward.k8s.io" - -var SupportedProtocols = []string{ProtocolV1Name} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/portforward/httpstream.go b/vendor/k8s.io/kubernetes/pkg/kubelet/server/portforward/httpstream.go deleted file mode 100644 index 5f872c820..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/server/portforward/httpstream.go +++ /dev/null @@ -1,309 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package portforward - -import ( - "errors" - "fmt" - "net/http" - "strconv" - "sync" - "time" - - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/httpstream" - "k8s.io/apimachinery/pkg/util/httpstream/spdy" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/kubernetes/pkg/api" - - "github.com/golang/glog" -) - -func handleHttpStreams(req *http.Request, w http.ResponseWriter, portForwarder PortForwarder, podName string, uid types.UID, supportedPortForwardProtocols []string, idleTimeout, streamCreationTimeout time.Duration) error { - _, err := httpstream.Handshake(req, w, supportedPortForwardProtocols) - // negotiated protocol isn't currently used server side, but could be in the future - if err != nil { - // Handshake writes the error to the client - return err - } - streamChan := make(chan httpstream.Stream, 1) - - glog.V(5).Infof("Upgrading port forward response") - upgrader := spdy.NewResponseUpgrader() - conn := upgrader.UpgradeResponse(w, req, httpStreamReceived(streamChan)) - if conn == nil { - return errors.New("Unable to upgrade websocket connection") - } - defer conn.Close() - - glog.V(5).Infof("(conn=%p) setting port forwarding streaming connection idle timeout to %v", conn, idleTimeout) - conn.SetIdleTimeout(idleTimeout) - - h := &httpStreamHandler{ - conn: conn, - streamChan: streamChan, - streamPairs: make(map[string]*httpStreamPair), - streamCreationTimeout: streamCreationTimeout, - pod: podName, - uid: uid, - forwarder: portForwarder, - } - h.run() - - return nil -} - -// httpStreamReceived is the httpstream.NewStreamHandler for port -// forward streams. It checks each stream's port and stream type headers, -// rejecting any streams that with missing or invalid values. Each valid -// stream is sent to the streams channel. -func httpStreamReceived(streams chan httpstream.Stream) func(httpstream.Stream, <-chan struct{}) error { - return func(stream httpstream.Stream, replySent <-chan struct{}) error { - // make sure it has a valid port header - portString := stream.Headers().Get(api.PortHeader) - if len(portString) == 0 { - return fmt.Errorf("%q header is required", api.PortHeader) - } - port, err := strconv.ParseUint(portString, 10, 16) - if err != nil { - return fmt.Errorf("unable to parse %q as a port: %v", portString, err) - } - if port < 1 { - return fmt.Errorf("port %q must be > 0", portString) - } - - // make sure it has a valid stream type header - streamType := stream.Headers().Get(api.StreamType) - if len(streamType) == 0 { - return fmt.Errorf("%q header is required", api.StreamType) - } - if streamType != api.StreamTypeError && streamType != api.StreamTypeData { - return fmt.Errorf("invalid stream type %q", streamType) - } - - streams <- stream - return nil - } -} - -// httpStreamHandler is capable of processing multiple port forward -// requests over a single httpstream.Connection. -type httpStreamHandler struct { - conn httpstream.Connection - streamChan chan httpstream.Stream - streamPairsLock sync.RWMutex - streamPairs map[string]*httpStreamPair - streamCreationTimeout time.Duration - pod string - uid types.UID - forwarder PortForwarder -} - -// getStreamPair returns a httpStreamPair for requestID. This creates a -// new pair if one does not yet exist for the requestID. The returned bool is -// true if the pair was created. -func (h *httpStreamHandler) getStreamPair(requestID string) (*httpStreamPair, bool) { - h.streamPairsLock.Lock() - defer h.streamPairsLock.Unlock() - - if p, ok := h.streamPairs[requestID]; ok { - glog.V(5).Infof("(conn=%p, request=%s) found existing stream pair", h.conn, requestID) - return p, false - } - - glog.V(5).Infof("(conn=%p, request=%s) creating new stream pair", h.conn, requestID) - - p := newPortForwardPair(requestID) - h.streamPairs[requestID] = p - - return p, true -} - -// monitorStreamPair waits for the pair to receive both its error and data -// streams, or for the timeout to expire (whichever happens first), and then -// removes the pair. -func (h *httpStreamHandler) monitorStreamPair(p *httpStreamPair, timeout <-chan time.Time) { - select { - case <-timeout: - err := fmt.Errorf("(conn=%v, request=%s) timed out waiting for streams", h.conn, p.requestID) - utilruntime.HandleError(err) - p.printError(err.Error()) - case <-p.complete: - glog.V(5).Infof("(conn=%v, request=%s) successfully received error and data streams", h.conn, p.requestID) - } - h.removeStreamPair(p.requestID) -} - -// hasStreamPair returns a bool indicating if a stream pair for requestID -// exists. -func (h *httpStreamHandler) hasStreamPair(requestID string) bool { - h.streamPairsLock.RLock() - defer h.streamPairsLock.RUnlock() - - _, ok := h.streamPairs[requestID] - return ok -} - -// removeStreamPair removes the stream pair identified by requestID from streamPairs. -func (h *httpStreamHandler) removeStreamPair(requestID string) { - h.streamPairsLock.Lock() - defer h.streamPairsLock.Unlock() - - delete(h.streamPairs, requestID) -} - -// requestID returns the request id for stream. -func (h *httpStreamHandler) requestID(stream httpstream.Stream) string { - requestID := stream.Headers().Get(api.PortForwardRequestIDHeader) - if len(requestID) == 0 { - glog.V(5).Infof("(conn=%p) stream received without %s header", h.conn, api.PortForwardRequestIDHeader) - // If we get here, it's because the connection came from an older client - // that isn't generating the request id header - // (https://github.com/kubernetes/kubernetes/blob/843134885e7e0b360eb5441e85b1410a8b1a7a0c/pkg/client/unversioned/portforward/portforward.go#L258-L287) - // - // This is a best-effort attempt at supporting older clients. - // - // When there aren't concurrent new forwarded connections, each connection - // will have a pair of streams (data, error), and the stream IDs will be - // consecutive odd numbers, e.g. 1 and 3 for the first connection. Convert - // the stream ID into a pseudo-request id by taking the stream type and - // using id = stream.Identifier() when the stream type is error, - // and id = stream.Identifier() - 2 when it's data. - // - // NOTE: this only works when there are not concurrent new streams from - // multiple forwarded connections; it's a best-effort attempt at supporting - // old clients that don't generate request ids. If there are concurrent - // new connections, it's possible that 1 connection gets streams whose IDs - // are not consecutive (e.g. 5 and 9 instead of 5 and 7). - streamType := stream.Headers().Get(api.StreamType) - switch streamType { - case api.StreamTypeError: - requestID = strconv.Itoa(int(stream.Identifier())) - case api.StreamTypeData: - requestID = strconv.Itoa(int(stream.Identifier()) - 2) - } - - glog.V(5).Infof("(conn=%p) automatically assigning request ID=%q from stream type=%s, stream ID=%d", h.conn, requestID, streamType, stream.Identifier()) - } - return requestID -} - -// run is the main loop for the httpStreamHandler. It processes new -// streams, invoking portForward for each complete stream pair. The loop exits -// when the httpstream.Connection is closed. -func (h *httpStreamHandler) run() { - glog.V(5).Infof("(conn=%p) waiting for port forward streams", h.conn) -Loop: - for { - select { - case <-h.conn.CloseChan(): - glog.V(5).Infof("(conn=%p) upgraded connection closed", h.conn) - break Loop - case stream := <-h.streamChan: - requestID := h.requestID(stream) - streamType := stream.Headers().Get(api.StreamType) - glog.V(5).Infof("(conn=%p, request=%s) received new stream of type %s", h.conn, requestID, streamType) - - p, created := h.getStreamPair(requestID) - if created { - go h.monitorStreamPair(p, time.After(h.streamCreationTimeout)) - } - if complete, err := p.add(stream); err != nil { - msg := fmt.Sprintf("error processing stream for request %s: %v", requestID, err) - utilruntime.HandleError(errors.New(msg)) - p.printError(msg) - } else if complete { - go h.portForward(p) - } - } - } -} - -// portForward invokes the httpStreamHandler's forwarder.PortForward -// function for the given stream pair. -func (h *httpStreamHandler) portForward(p *httpStreamPair) { - defer p.dataStream.Close() - defer p.errorStream.Close() - - portString := p.dataStream.Headers().Get(api.PortHeader) - port, _ := strconv.ParseInt(portString, 10, 32) - - glog.V(5).Infof("(conn=%p, request=%s) invoking forwarder.PortForward for port %s", h.conn, p.requestID, portString) - err := h.forwarder.PortForward(h.pod, h.uid, int32(port), p.dataStream) - glog.V(5).Infof("(conn=%p, request=%s) done invoking forwarder.PortForward for port %s", h.conn, p.requestID, portString) - - if err != nil { - msg := fmt.Errorf("error forwarding port %d to pod %s, uid %v: %v", port, h.pod, h.uid, err) - utilruntime.HandleError(msg) - fmt.Fprint(p.errorStream, msg.Error()) - } -} - -// httpStreamPair represents the error and data streams for a port -// forwarding request. -type httpStreamPair struct { - lock sync.RWMutex - requestID string - dataStream httpstream.Stream - errorStream httpstream.Stream - complete chan struct{} -} - -// newPortForwardPair creates a new httpStreamPair. -func newPortForwardPair(requestID string) *httpStreamPair { - return &httpStreamPair{ - requestID: requestID, - complete: make(chan struct{}), - } -} - -// add adds the stream to the httpStreamPair. If the pair already -// contains a stream for the new stream's type, an error is returned. add -// returns true if both the data and error streams for this pair have been -// received. -func (p *httpStreamPair) add(stream httpstream.Stream) (bool, error) { - p.lock.Lock() - defer p.lock.Unlock() - - switch stream.Headers().Get(api.StreamType) { - case api.StreamTypeError: - if p.errorStream != nil { - return false, errors.New("error stream already assigned") - } - p.errorStream = stream - case api.StreamTypeData: - if p.dataStream != nil { - return false, errors.New("data stream already assigned") - } - p.dataStream = stream - } - - complete := p.errorStream != nil && p.dataStream != nil - if complete { - close(p.complete) - } - return complete, nil -} - -// printError writes s to p.errorStream if p.errorStream has been set. -func (p *httpStreamPair) printError(s string) { - p.lock.RLock() - defer p.lock.RUnlock() - if p.errorStream != nil { - fmt.Fprint(p.errorStream, s) - } -} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/portforward/portforward.go b/vendor/k8s.io/kubernetes/pkg/kubelet/server/portforward/portforward.go deleted file mode 100644 index 60a96e51a..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/server/portforward/portforward.go +++ /dev/null @@ -1,53 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package portforward - -import ( - "io" - "net/http" - "time" - - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apiserver/pkg/util/wsstream" -) - -// PortForwarder knows how to forward content from a data stream to/from a port -// in a pod. -type PortForwarder interface { - // PortForwarder copies data between a data stream and a port in a pod. - PortForward(name string, uid types.UID, port int32, stream io.ReadWriteCloser) error -} - -// ServePortForward handles a port forwarding request. A single request is -// kept alive as long as the client is still alive and the connection has not -// been timed out due to idleness. This function handles multiple forwarded -// connections; i.e., multiple `curl http://localhost:8888/` requests will be -// handled by a single invocation of ServePortForward. -func ServePortForward(w http.ResponseWriter, req *http.Request, portForwarder PortForwarder, podName string, uid types.UID, portForwardOptions *V4Options, idleTimeout time.Duration, streamCreationTimeout time.Duration, supportedProtocols []string) { - var err error - if wsstream.IsWebSocketRequest(req) { - err = handleWebSocketStreams(req, w, portForwarder, podName, uid, portForwardOptions, supportedProtocols, idleTimeout, streamCreationTimeout) - } else { - err = handleHttpStreams(req, w, portForwarder, podName, uid, supportedProtocols, idleTimeout, streamCreationTimeout) - } - - if err != nil { - runtime.HandleError(err) - return - } -} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/portforward/websocket.go b/vendor/k8s.io/kubernetes/pkg/kubelet/server/portforward/websocket.go deleted file mode 100644 index 22d5add06..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/server/portforward/websocket.go +++ /dev/null @@ -1,198 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package portforward - -import ( - "encoding/binary" - "fmt" - "io" - "net/http" - "strconv" - "strings" - "sync" - "time" - - "github.com/golang/glog" - - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apiserver/pkg/server/httplog" - "k8s.io/apiserver/pkg/util/wsstream" - "k8s.io/kubernetes/pkg/api" -) - -const ( - dataChannel = iota - errorChannel - - v4BinaryWebsocketProtocol = "v4." + wsstream.ChannelWebSocketProtocol - v4Base64WebsocketProtocol = "v4." + wsstream.Base64ChannelWebSocketProtocol -) - -// options contains details about which streams are required for -// port forwarding. -// All fields incldued in V4Options need to be expressed explicilty in the -// CRI (pkg/kubelet/apis/cri/{version}/api.proto) PortForwardRequest. -type V4Options struct { - Ports []int32 -} - -// newOptions creates a new options from the Request. -func NewV4Options(req *http.Request) (*V4Options, error) { - if !wsstream.IsWebSocketRequest(req) { - return &V4Options{}, nil - } - - portStrings := req.URL.Query()[api.PortHeader] - if len(portStrings) == 0 { - return nil, fmt.Errorf("query parameter %q is required", api.PortHeader) - } - - ports := make([]int32, 0, len(portStrings)) - for _, portString := range portStrings { - if len(portString) == 0 { - return nil, fmt.Errorf("query parameter %q cannot be empty", api.PortHeader) - } - for _, p := range strings.Split(portString, ",") { - port, err := strconv.ParseUint(p, 10, 16) - if err != nil { - return nil, fmt.Errorf("unable to parse %q as a port: %v", portString, err) - } - if port < 1 { - return nil, fmt.Errorf("port %q must be > 0", portString) - } - ports = append(ports, int32(port)) - } - } - - return &V4Options{ - Ports: ports, - }, nil -} - -// BuildV4Options returns a V4Options based on the given information. -func BuildV4Options(ports []int32) (*V4Options, error) { - return &V4Options{Ports: ports}, nil -} - -// handleWebSocketStreams handles requests to forward ports to a pod via -// a PortForwarder. A pair of streams are created per port (DATA n, -// ERROR n+1). The associated port is written to each stream as a unsigned 16 -// bit integer in little endian format. -func handleWebSocketStreams(req *http.Request, w http.ResponseWriter, portForwarder PortForwarder, podName string, uid types.UID, opts *V4Options, supportedPortForwardProtocols []string, idleTimeout, streamCreationTimeout time.Duration) error { - channels := make([]wsstream.ChannelType, 0, len(opts.Ports)*2) - for i := 0; i < len(opts.Ports); i++ { - channels = append(channels, wsstream.ReadWriteChannel, wsstream.WriteChannel) - } - conn := wsstream.NewConn(map[string]wsstream.ChannelProtocolConfig{ - "": { - Binary: true, - Channels: channels, - }, - v4BinaryWebsocketProtocol: { - Binary: true, - Channels: channels, - }, - v4Base64WebsocketProtocol: { - Binary: false, - Channels: channels, - }, - }) - conn.SetIdleTimeout(idleTimeout) - _, streams, err := conn.Open(httplog.Unlogged(w), req) - if err != nil { - err = fmt.Errorf("Unable to upgrade websocket connection: %v", err) - return err - } - defer conn.Close() - streamPairs := make([]*websocketStreamPair, len(opts.Ports)) - for i := range streamPairs { - streamPair := websocketStreamPair{ - port: opts.Ports[i], - dataStream: streams[i*2+dataChannel], - errorStream: streams[i*2+errorChannel], - } - streamPairs[i] = &streamPair - - portBytes := make([]byte, 2) - // port is always positive so conversion is allowable - binary.LittleEndian.PutUint16(portBytes, uint16(streamPair.port)) - streamPair.dataStream.Write(portBytes) - streamPair.errorStream.Write(portBytes) - } - h := &websocketStreamHandler{ - conn: conn, - streamPairs: streamPairs, - pod: podName, - uid: uid, - forwarder: portForwarder, - } - h.run() - - return nil -} - -// websocketStreamPair represents the error and data streams for a port -// forwarding request. -type websocketStreamPair struct { - port int32 - dataStream io.ReadWriteCloser - errorStream io.WriteCloser -} - -// websocketStreamHandler is capable of processing a single port forward -// request over a websocket connection -type websocketStreamHandler struct { - conn *wsstream.Conn - ports []int32 - streamPairs []*websocketStreamPair - pod string - uid types.UID - forwarder PortForwarder -} - -// run invokes the websocketStreamHandler's forwarder.PortForward -// function for the given stream pair. -func (h *websocketStreamHandler) run() { - wg := sync.WaitGroup{} - wg.Add(len(h.streamPairs)) - - for _, pair := range h.streamPairs { - p := pair - go func() { - defer wg.Done() - h.portForward(p) - }() - } - - wg.Wait() -} - -func (h *websocketStreamHandler) portForward(p *websocketStreamPair) { - defer p.dataStream.Close() - defer p.errorStream.Close() - - glog.V(5).Infof("(conn=%p) invoking forwarder.PortForward for port %d", h.conn, p.port) - err := h.forwarder.PortForward(h.pod, h.uid, p.port, p.dataStream) - glog.V(5).Infof("(conn=%p) done invoking forwarder.PortForward for port %d", h.conn, p.port) - - if err != nil { - msg := fmt.Errorf("error forwarding port %d to pod %s, uid %v: %v", p.port, h.pod, h.uid, err) - runtime.HandleError(msg) - fmt.Fprint(p.errorStream, msg.Error()) - } -} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/remotecommand/attach.go b/vendor/k8s.io/kubernetes/pkg/kubelet/server/remotecommand/attach.go deleted file mode 100644 index e266f34fe..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/server/remotecommand/attach.go +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package remotecommand - -import ( - "fmt" - "io" - "net/http" - "time" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/client-go/tools/remotecommand" -) - -// Attacher knows how to attach to a running container in a pod. -type Attacher interface { - // AttachContainer attaches to the running container in the pod, copying data between in/out/err - // and the container's stdin/stdout/stderr. - AttachContainer(name string, uid types.UID, container string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error -} - -// ServeAttach handles requests to attach to a container. After creating/receiving the required -// streams, it delegates the actual attaching to attacher. -func ServeAttach(w http.ResponseWriter, req *http.Request, attacher Attacher, podName string, uid types.UID, container string, streamOpts *Options, idleTimeout, streamCreationTimeout time.Duration, supportedProtocols []string) { - ctx, ok := createStreams(req, w, streamOpts, supportedProtocols, idleTimeout, streamCreationTimeout) - if !ok { - // error is handled by createStreams - return - } - defer ctx.conn.Close() - - err := attacher.AttachContainer(podName, uid, container, ctx.stdinStream, ctx.stdoutStream, ctx.stderrStream, ctx.tty, ctx.resizeChan) - if err != nil { - err = fmt.Errorf("error attaching to container: %v", err) - runtime.HandleError(err) - ctx.writeStatus(apierrors.NewInternalError(err)) - } else { - ctx.writeStatus(&apierrors.StatusError{ErrStatus: metav1.Status{ - Status: metav1.StatusSuccess, - }}) - } -} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/remotecommand/doc.go b/vendor/k8s.io/kubernetes/pkg/kubelet/server/remotecommand/doc.go deleted file mode 100644 index 24f9393ab..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/server/remotecommand/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// package remotecommand contains functions related to executing commands in and attaching to pods. -package remotecommand // import "k8s.io/kubernetes/pkg/kubelet/server/remotecommand" diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/remotecommand/exec.go b/vendor/k8s.io/kubernetes/pkg/kubelet/server/remotecommand/exec.go deleted file mode 100644 index 8d14a937a..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/server/remotecommand/exec.go +++ /dev/null @@ -1,79 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package remotecommand - -import ( - "fmt" - "io" - "net/http" - "time" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - remotecommandconsts "k8s.io/apimachinery/pkg/util/remotecommand" - "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/client-go/tools/remotecommand" - utilexec "k8s.io/kubernetes/pkg/util/exec" -) - -// Executor knows how to execute a command in a container in a pod. -type Executor interface { - // ExecInContainer executes a command in a container in the pod, copying data - // between in/out/err and the container's stdin/stdout/stderr. - ExecInContainer(name string, uid types.UID, container string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize, timeout time.Duration) error -} - -// ServeExec handles requests to execute a command in a container. After -// creating/receiving the required streams, it delegates the actual execution -// to the executor. -func ServeExec(w http.ResponseWriter, req *http.Request, executor Executor, podName string, uid types.UID, container string, cmd []string, streamOpts *Options, idleTimeout, streamCreationTimeout time.Duration, supportedProtocols []string) { - ctx, ok := createStreams(req, w, streamOpts, supportedProtocols, idleTimeout, streamCreationTimeout) - if !ok { - // error is handled by createStreams - return - } - defer ctx.conn.Close() - - err := executor.ExecInContainer(podName, uid, container, cmd, ctx.stdinStream, ctx.stdoutStream, ctx.stderrStream, ctx.tty, ctx.resizeChan, 0) - if err != nil { - if exitErr, ok := err.(utilexec.ExitError); ok && exitErr.Exited() { - rc := exitErr.ExitStatus() - ctx.writeStatus(&apierrors.StatusError{ErrStatus: metav1.Status{ - Status: metav1.StatusFailure, - Reason: remotecommandconsts.NonZeroExitCodeReason, - Details: &metav1.StatusDetails{ - Causes: []metav1.StatusCause{ - { - Type: remotecommandconsts.ExitCodeCauseType, - Message: fmt.Sprintf("%d", rc), - }, - }, - }, - Message: fmt.Sprintf("command terminated with non-zero exit code: %v", exitErr), - }}) - } else { - err = fmt.Errorf("error executing command in container: %v", err) - runtime.HandleError(err) - ctx.writeStatus(apierrors.NewInternalError(err)) - } - } else { - ctx.writeStatus(&apierrors.StatusError{ErrStatus: metav1.Status{ - Status: metav1.StatusSuccess, - }}) - } -} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/remotecommand/httpstream.go b/vendor/k8s.io/kubernetes/pkg/kubelet/server/remotecommand/httpstream.go deleted file mode 100644 index f09b5e400..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/server/remotecommand/httpstream.go +++ /dev/null @@ -1,447 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package remotecommand - -import ( - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "time" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/httpstream" - "k8s.io/apimachinery/pkg/util/httpstream/spdy" - remotecommandconsts "k8s.io/apimachinery/pkg/util/remotecommand" - "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apiserver/pkg/util/wsstream" - "k8s.io/client-go/tools/remotecommand" - "k8s.io/kubernetes/pkg/api" - - "github.com/golang/glog" -) - -// Options contains details about which streams are required for -// remote command execution. -type Options struct { - Stdin bool - Stdout bool - Stderr bool - TTY bool -} - -// NewOptions creates a new Options from the Request. -func NewOptions(req *http.Request) (*Options, error) { - tty := req.FormValue(api.ExecTTYParam) == "1" - stdin := req.FormValue(api.ExecStdinParam) == "1" - stdout := req.FormValue(api.ExecStdoutParam) == "1" - stderr := req.FormValue(api.ExecStderrParam) == "1" - if tty && stderr { - // TODO: make this an error before we reach this method - glog.V(4).Infof("Access to exec with tty and stderr is not supported, bypassing stderr") - stderr = false - } - - if !stdin && !stdout && !stderr { - return nil, fmt.Errorf("you must specify at least 1 of stdin, stdout, stderr") - } - - return &Options{ - Stdin: stdin, - Stdout: stdout, - Stderr: stderr, - TTY: tty, - }, nil -} - -// context contains the connection and streams used when -// forwarding an attach or execute session into a container. -type context struct { - conn io.Closer - stdinStream io.ReadCloser - stdoutStream io.WriteCloser - stderrStream io.WriteCloser - writeStatus func(status *apierrors.StatusError) error - resizeStream io.ReadCloser - resizeChan chan remotecommand.TerminalSize - tty bool -} - -// streamAndReply holds both a Stream and a channel that is closed when the stream's reply frame is -// enqueued. Consumers can wait for replySent to be closed prior to proceeding, to ensure that the -// replyFrame is enqueued before the connection's goaway frame is sent (e.g. if a stream was -// received and right after, the connection gets closed). -type streamAndReply struct { - httpstream.Stream - replySent <-chan struct{} -} - -// waitStreamReply waits until either replySent or stop is closed. If replySent is closed, it sends -// an empty struct to the notify channel. -func waitStreamReply(replySent <-chan struct{}, notify chan<- struct{}, stop <-chan struct{}) { - select { - case <-replySent: - notify <- struct{}{} - case <-stop: - } -} - -func createStreams(req *http.Request, w http.ResponseWriter, opts *Options, supportedStreamProtocols []string, idleTimeout, streamCreationTimeout time.Duration) (*context, bool) { - var ctx *context - var ok bool - if wsstream.IsWebSocketRequest(req) { - ctx, ok = createWebSocketStreams(req, w, opts, idleTimeout) - } else { - ctx, ok = createHttpStreamStreams(req, w, opts, supportedStreamProtocols, idleTimeout, streamCreationTimeout) - } - if !ok { - return nil, false - } - - if ctx.resizeStream != nil { - ctx.resizeChan = make(chan remotecommand.TerminalSize) - go handleResizeEvents(ctx.resizeStream, ctx.resizeChan) - } - - return ctx, true -} - -func createHttpStreamStreams(req *http.Request, w http.ResponseWriter, opts *Options, supportedStreamProtocols []string, idleTimeout, streamCreationTimeout time.Duration) (*context, bool) { - protocol, err := httpstream.Handshake(req, w, supportedStreamProtocols) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - fmt.Fprint(w, err.Error()) - return nil, false - } - - streamCh := make(chan streamAndReply) - - upgrader := spdy.NewResponseUpgrader() - conn := upgrader.UpgradeResponse(w, req, func(stream httpstream.Stream, replySent <-chan struct{}) error { - streamCh <- streamAndReply{Stream: stream, replySent: replySent} - return nil - }) - // from this point on, we can no longer call methods on response - if conn == nil { - // The upgrader is responsible for notifying the client of any errors that - // occurred during upgrading. All we can do is return here at this point - // if we weren't successful in upgrading. - return nil, false - } - - conn.SetIdleTimeout(idleTimeout) - - var handler protocolHandler - switch protocol { - case remotecommandconsts.StreamProtocolV4Name: - handler = &v4ProtocolHandler{} - case remotecommandconsts.StreamProtocolV3Name: - handler = &v3ProtocolHandler{} - case remotecommandconsts.StreamProtocolV2Name: - handler = &v2ProtocolHandler{} - case "": - glog.V(4).Infof("Client did not request protocol negotiaion. Falling back to %q", remotecommandconsts.StreamProtocolV1Name) - fallthrough - case remotecommandconsts.StreamProtocolV1Name: - handler = &v1ProtocolHandler{} - } - - // count the streams client asked for, starting with 1 - expectedStreams := 1 - if opts.Stdin { - expectedStreams++ - } - if opts.Stdout { - expectedStreams++ - } - if opts.Stderr { - expectedStreams++ - } - if opts.TTY && handler.supportsTerminalResizing() { - expectedStreams++ - } - - expired := time.NewTimer(streamCreationTimeout) - defer expired.Stop() - - ctx, err := handler.waitForStreams(streamCh, expectedStreams, expired.C) - if err != nil { - runtime.HandleError(err) - return nil, false - } - - ctx.conn = conn - ctx.tty = opts.TTY - - return ctx, true -} - -type protocolHandler interface { - // waitForStreams waits for the expected streams or a timeout, returning a - // remoteCommandContext if all the streams were received, or an error if not. - waitForStreams(streams <-chan streamAndReply, expectedStreams int, expired <-chan time.Time) (*context, error) - // supportsTerminalResizing returns true if the protocol handler supports terminal resizing - supportsTerminalResizing() bool -} - -// v4ProtocolHandler implements the V4 protocol version for streaming command execution. It only differs -// in from v3 in the error stream format using an json-marshaled metav1.Status which carries -// the process' exit code. -type v4ProtocolHandler struct{} - -func (*v4ProtocolHandler) waitForStreams(streams <-chan streamAndReply, expectedStreams int, expired <-chan time.Time) (*context, error) { - ctx := &context{} - receivedStreams := 0 - replyChan := make(chan struct{}) - stop := make(chan struct{}) - defer close(stop) -WaitForStreams: - for { - select { - case stream := <-streams: - streamType := stream.Headers().Get(api.StreamType) - switch streamType { - case api.StreamTypeError: - ctx.writeStatus = v4WriteStatusFunc(stream) // write json errors - go waitStreamReply(stream.replySent, replyChan, stop) - case api.StreamTypeStdin: - ctx.stdinStream = stream - go waitStreamReply(stream.replySent, replyChan, stop) - case api.StreamTypeStdout: - ctx.stdoutStream = stream - go waitStreamReply(stream.replySent, replyChan, stop) - case api.StreamTypeStderr: - ctx.stderrStream = stream - go waitStreamReply(stream.replySent, replyChan, stop) - case api.StreamTypeResize: - ctx.resizeStream = stream - go waitStreamReply(stream.replySent, replyChan, stop) - default: - runtime.HandleError(fmt.Errorf("Unexpected stream type: %q", streamType)) - } - case <-replyChan: - receivedStreams++ - if receivedStreams == expectedStreams { - break WaitForStreams - } - case <-expired: - // TODO find a way to return the error to the user. Maybe use a separate - // stream to report errors? - return nil, errors.New("timed out waiting for client to create streams") - } - } - - return ctx, nil -} - -// supportsTerminalResizing returns true because v4ProtocolHandler supports it -func (*v4ProtocolHandler) supportsTerminalResizing() bool { return true } - -// v3ProtocolHandler implements the V3 protocol version for streaming command execution. -type v3ProtocolHandler struct{} - -func (*v3ProtocolHandler) waitForStreams(streams <-chan streamAndReply, expectedStreams int, expired <-chan time.Time) (*context, error) { - ctx := &context{} - receivedStreams := 0 - replyChan := make(chan struct{}) - stop := make(chan struct{}) - defer close(stop) -WaitForStreams: - for { - select { - case stream := <-streams: - streamType := stream.Headers().Get(api.StreamType) - switch streamType { - case api.StreamTypeError: - ctx.writeStatus = v1WriteStatusFunc(stream) - go waitStreamReply(stream.replySent, replyChan, stop) - case api.StreamTypeStdin: - ctx.stdinStream = stream - go waitStreamReply(stream.replySent, replyChan, stop) - case api.StreamTypeStdout: - ctx.stdoutStream = stream - go waitStreamReply(stream.replySent, replyChan, stop) - case api.StreamTypeStderr: - ctx.stderrStream = stream - go waitStreamReply(stream.replySent, replyChan, stop) - case api.StreamTypeResize: - ctx.resizeStream = stream - go waitStreamReply(stream.replySent, replyChan, stop) - default: - runtime.HandleError(fmt.Errorf("Unexpected stream type: %q", streamType)) - } - case <-replyChan: - receivedStreams++ - if receivedStreams == expectedStreams { - break WaitForStreams - } - case <-expired: - // TODO find a way to return the error to the user. Maybe use a separate - // stream to report errors? - return nil, errors.New("timed out waiting for client to create streams") - } - } - - return ctx, nil -} - -// supportsTerminalResizing returns true because v3ProtocolHandler supports it -func (*v3ProtocolHandler) supportsTerminalResizing() bool { return true } - -// v2ProtocolHandler implements the V2 protocol version for streaming command execution. -type v2ProtocolHandler struct{} - -func (*v2ProtocolHandler) waitForStreams(streams <-chan streamAndReply, expectedStreams int, expired <-chan time.Time) (*context, error) { - ctx := &context{} - receivedStreams := 0 - replyChan := make(chan struct{}) - stop := make(chan struct{}) - defer close(stop) -WaitForStreams: - for { - select { - case stream := <-streams: - streamType := stream.Headers().Get(api.StreamType) - switch streamType { - case api.StreamTypeError: - ctx.writeStatus = v1WriteStatusFunc(stream) - go waitStreamReply(stream.replySent, replyChan, stop) - case api.StreamTypeStdin: - ctx.stdinStream = stream - go waitStreamReply(stream.replySent, replyChan, stop) - case api.StreamTypeStdout: - ctx.stdoutStream = stream - go waitStreamReply(stream.replySent, replyChan, stop) - case api.StreamTypeStderr: - ctx.stderrStream = stream - go waitStreamReply(stream.replySent, replyChan, stop) - default: - runtime.HandleError(fmt.Errorf("Unexpected stream type: %q", streamType)) - } - case <-replyChan: - receivedStreams++ - if receivedStreams == expectedStreams { - break WaitForStreams - } - case <-expired: - // TODO find a way to return the error to the user. Maybe use a separate - // stream to report errors? - return nil, errors.New("timed out waiting for client to create streams") - } - } - - return ctx, nil -} - -// supportsTerminalResizing returns false because v2ProtocolHandler doesn't support it. -func (*v2ProtocolHandler) supportsTerminalResizing() bool { return false } - -// v1ProtocolHandler implements the V1 protocol version for streaming command execution. -type v1ProtocolHandler struct{} - -func (*v1ProtocolHandler) waitForStreams(streams <-chan streamAndReply, expectedStreams int, expired <-chan time.Time) (*context, error) { - ctx := &context{} - receivedStreams := 0 - replyChan := make(chan struct{}) - stop := make(chan struct{}) - defer close(stop) -WaitForStreams: - for { - select { - case stream := <-streams: - streamType := stream.Headers().Get(api.StreamType) - switch streamType { - case api.StreamTypeError: - ctx.writeStatus = v1WriteStatusFunc(stream) - - // This defer statement shouldn't be here, but due to previous refactoring, it ended up in - // here. This is what 1.0.x kubelets do, so we're retaining that behavior. This is fixed in - // the v2ProtocolHandler. - defer stream.Reset() - - go waitStreamReply(stream.replySent, replyChan, stop) - case api.StreamTypeStdin: - ctx.stdinStream = stream - go waitStreamReply(stream.replySent, replyChan, stop) - case api.StreamTypeStdout: - ctx.stdoutStream = stream - go waitStreamReply(stream.replySent, replyChan, stop) - case api.StreamTypeStderr: - ctx.stderrStream = stream - go waitStreamReply(stream.replySent, replyChan, stop) - default: - runtime.HandleError(fmt.Errorf("Unexpected stream type: %q", streamType)) - } - case <-replyChan: - receivedStreams++ - if receivedStreams == expectedStreams { - break WaitForStreams - } - case <-expired: - // TODO find a way to return the error to the user. Maybe use a separate - // stream to report errors? - return nil, errors.New("timed out waiting for client to create streams") - } - } - - if ctx.stdinStream != nil { - ctx.stdinStream.Close() - } - - return ctx, nil -} - -// supportsTerminalResizing returns false because v1ProtocolHandler doesn't support it. -func (*v1ProtocolHandler) supportsTerminalResizing() bool { return false } - -func handleResizeEvents(stream io.Reader, channel chan<- remotecommand.TerminalSize) { - defer runtime.HandleCrash() - - decoder := json.NewDecoder(stream) - for { - size := remotecommand.TerminalSize{} - if err := decoder.Decode(&size); err != nil { - break - } - channel <- size - } -} - -func v1WriteStatusFunc(stream io.WriteCloser) func(status *apierrors.StatusError) error { - return func(status *apierrors.StatusError) error { - if status.Status().Status == metav1.StatusSuccess { - return nil // send error messages - } - _, err := stream.Write([]byte(status.Error())) - return err - } -} - -// v4WriteStatusFunc returns a WriteStatusFunc that marshals a given api Status -// as json in the error channel. -func v4WriteStatusFunc(stream io.WriteCloser) func(status *apierrors.StatusError) error { - return func(status *apierrors.StatusError) error { - bs, err := json.Marshal(status.Status()) - if err != nil { - return err - } - _, err = stream.Write(bs) - return err - } -} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/remotecommand/websocket.go b/vendor/k8s.io/kubernetes/pkg/kubelet/server/remotecommand/websocket.go deleted file mode 100644 index c60012b21..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/server/remotecommand/websocket.go +++ /dev/null @@ -1,132 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package remotecommand - -import ( - "fmt" - "net/http" - "time" - - "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apiserver/pkg/server/httplog" - "k8s.io/apiserver/pkg/util/wsstream" -) - -const ( - stdinChannel = iota - stdoutChannel - stderrChannel - errorChannel - resizeChannel - - preV4BinaryWebsocketProtocol = wsstream.ChannelWebSocketProtocol - preV4Base64WebsocketProtocol = wsstream.Base64ChannelWebSocketProtocol - v4BinaryWebsocketProtocol = "v4." + wsstream.ChannelWebSocketProtocol - v4Base64WebsocketProtocol = "v4." + wsstream.Base64ChannelWebSocketProtocol -) - -// createChannels returns the standard channel types for a shell connection (STDIN 0, STDOUT 1, STDERR 2) -// along with the approximate duplex value. It also creates the error (3) and resize (4) channels. -func createChannels(opts *Options) []wsstream.ChannelType { - // open the requested channels, and always open the error channel - channels := make([]wsstream.ChannelType, 5) - channels[stdinChannel] = readChannel(opts.Stdin) - channels[stdoutChannel] = writeChannel(opts.Stdout) - channels[stderrChannel] = writeChannel(opts.Stderr) - channels[errorChannel] = wsstream.WriteChannel - channels[resizeChannel] = wsstream.ReadChannel - return channels -} - -// readChannel returns wsstream.ReadChannel if real is true, or wsstream.IgnoreChannel. -func readChannel(real bool) wsstream.ChannelType { - if real { - return wsstream.ReadChannel - } - return wsstream.IgnoreChannel -} - -// writeChannel returns wsstream.WriteChannel if real is true, or wsstream.IgnoreChannel. -func writeChannel(real bool) wsstream.ChannelType { - if real { - return wsstream.WriteChannel - } - return wsstream.IgnoreChannel -} - -// createWebSocketStreams returns a context containing the websocket connection and -// streams needed to perform an exec or an attach. -func createWebSocketStreams(req *http.Request, w http.ResponseWriter, opts *Options, idleTimeout time.Duration) (*context, bool) { - channels := createChannels(opts) - conn := wsstream.NewConn(map[string]wsstream.ChannelProtocolConfig{ - "": { - Binary: true, - Channels: channels, - }, - preV4BinaryWebsocketProtocol: { - Binary: true, - Channels: channels, - }, - preV4Base64WebsocketProtocol: { - Binary: false, - Channels: channels, - }, - v4BinaryWebsocketProtocol: { - Binary: true, - Channels: channels, - }, - v4Base64WebsocketProtocol: { - Binary: false, - Channels: channels, - }, - }) - conn.SetIdleTimeout(idleTimeout) - negotiatedProtocol, streams, err := conn.Open(httplog.Unlogged(w), req) - if err != nil { - runtime.HandleError(fmt.Errorf("Unable to upgrade websocket connection: %v", err)) - return nil, false - } - - // Send an empty message to the lowest writable channel to notify the client the connection is established - // TODO: make generic to SPDY and WebSockets and do it outside of this method? - switch { - case opts.Stdout: - streams[stdoutChannel].Write([]byte{}) - case opts.Stderr: - streams[stderrChannel].Write([]byte{}) - default: - streams[errorChannel].Write([]byte{}) - } - - ctx := &context{ - conn: conn, - stdinStream: streams[stdinChannel], - stdoutStream: streams[stdoutChannel], - stderrStream: streams[stderrChannel], - tty: opts.TTY, - resizeStream: streams[resizeChannel], - } - - switch negotiatedProtocol { - case v4BinaryWebsocketProtocol, v4Base64WebsocketProtocol: - ctx.writeStatus = v4WriteStatusFunc(streams[errorChannel]) - default: - ctx.writeStatus = v1WriteStatusFunc(streams[errorChannel]) - } - - return ctx, true -} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/streaming/errors.go b/vendor/k8s.io/kubernetes/pkg/kubelet/server/streaming/errors.go deleted file mode 100644 index 9f16b4eb2..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/server/streaming/errors.go +++ /dev/null @@ -1,55 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package streaming - -import ( - "fmt" - "net/http" - "strconv" - - "google.golang.org/grpc" - "google.golang.org/grpc/codes" -) - -func ErrorStreamingDisabled(method string) error { - return grpc.Errorf(codes.NotFound, fmt.Sprintf("streaming method %s disabled", method)) -} - -// The error returned when the maximum number of in-flight requests is exceeded. -func ErrorTooManyInFlight() error { - return grpc.Errorf(codes.ResourceExhausted, "maximum number of in-flight requests exceeded") -} - -// Translates a CRI streaming error into an appropriate HTTP response. -func WriteError(err error, w http.ResponseWriter) error { - var status int - switch grpc.Code(err) { - case codes.NotFound: - status = http.StatusNotFound - case codes.ResourceExhausted: - // We only expect to hit this if there is a DoS, so we just wait the full TTL. - // If this is ever hit in steady-state operations, consider increasing the MaxInFlight requests, - // or plumbing through the time to next expiration. - w.Header().Set("Retry-After", strconv.Itoa(int(CacheTTL.Seconds()))) - status = http.StatusTooManyRequests - default: - status = http.StatusInternalServerError - } - w.WriteHeader(status) - _, writeErr := w.Write([]byte(err.Error())) - return writeErr -} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/streaming/request_cache.go b/vendor/k8s.io/kubernetes/pkg/kubelet/server/streaming/request_cache.go deleted file mode 100644 index f68f640be..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/server/streaming/request_cache.go +++ /dev/null @@ -1,146 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package streaming - -import ( - "container/list" - "crypto/rand" - "encoding/base64" - "fmt" - "math" - "sync" - "time" - - "k8s.io/apimachinery/pkg/util/clock" -) - -var ( - // Timeout after which tokens become invalid. - CacheTTL = 1 * time.Minute - // The maximum number of in-flight requests to allow. - MaxInFlight = 1000 - // Length of the random base64 encoded token identifying the request. - TokenLen = 8 -) - -// requestCache caches streaming (exec/attach/port-forward) requests and generates a single-use -// random token for their retrieval. The requestCache is used for building streaming URLs without -// the need to encode every request parameter in the URL. -type requestCache struct { - // clock is used to obtain the current time - clock clock.Clock - - // tokens maps the generate token to the request for fast retrieval. - tokens map[string]*list.Element - // ll maintains an age-ordered request list for faster garbage collection of expired requests. - ll *list.List - - lock sync.Mutex -} - -// Type representing an *ExecRequest, *AttachRequest, or *PortForwardRequest. -type request interface{} - -type cacheEntry struct { - token string - req request - expireTime time.Time -} - -func newRequestCache() *requestCache { - return &requestCache{ - clock: clock.RealClock{}, - ll: list.New(), - tokens: make(map[string]*list.Element), - } -} - -// Insert the given request into the cache and returns the token used for fetching it out. -func (c *requestCache) Insert(req request) (token string, err error) { - c.lock.Lock() - defer c.lock.Unlock() - - // Remove expired entries. - c.gc() - // If the cache is full, reject the request. - if c.ll.Len() == MaxInFlight { - return "", ErrorTooManyInFlight() - } - token, err = c.uniqueToken() - if err != nil { - return "", err - } - ele := c.ll.PushFront(&cacheEntry{token, req, c.clock.Now().Add(CacheTTL)}) - - c.tokens[token] = ele - return token, nil -} - -// Consume the token (remove it from the cache) and return the cached request, if found. -func (c *requestCache) Consume(token string) (req request, found bool) { - c.lock.Lock() - defer c.lock.Unlock() - ele, ok := c.tokens[token] - if !ok { - return nil, false - } - c.ll.Remove(ele) - delete(c.tokens, token) - - entry := ele.Value.(*cacheEntry) - if c.clock.Now().After(entry.expireTime) { - // Entry already expired. - return nil, false - } - return entry.req, true -} - -// uniqueToken generates a random URL-safe token and ensures uniqueness. -func (c *requestCache) uniqueToken() (string, error) { - const maxTries = 10 - // Number of bytes to be TokenLen when base64 encoded. - tokenSize := math.Ceil(float64(TokenLen) * 6 / 8) - rawToken := make([]byte, int(tokenSize)) - for i := 0; i < maxTries; i++ { - if _, err := rand.Read(rawToken); err != nil { - return "", err - } - encoded := base64.RawURLEncoding.EncodeToString(rawToken) - token := encoded[:TokenLen] - // If it's unique, return it. Otherwise retry. - if _, exists := c.tokens[encoded]; !exists { - return token, nil - } - } - return "", fmt.Errorf("failed to generate unique token") -} - -// Must be write-locked prior to calling. -func (c *requestCache) gc() { - now := c.clock.Now() - for c.ll.Len() > 0 { - oldest := c.ll.Back() - entry := oldest.Value.(*cacheEntry) - if !now.After(entry.expireTime) { - return - } - - // Oldest value is expired; remove it. - c.ll.Remove(oldest) - delete(c.tokens, entry.token) - } -} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/streaming/server.go b/vendor/k8s.io/kubernetes/pkg/kubelet/server/streaming/server.go deleted file mode 100644 index 875e44462..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/server/streaming/server.go +++ /dev/null @@ -1,344 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package streaming - -import ( - "crypto/tls" - "errors" - "io" - "net/http" - "net/url" - "path" - "time" - - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - - restful "github.com/emicklei/go-restful" - - "k8s.io/apimachinery/pkg/types" - remotecommandconsts "k8s.io/apimachinery/pkg/util/remotecommand" - "k8s.io/client-go/tools/remotecommand" - runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime" - "k8s.io/kubernetes/pkg/kubelet/server/portforward" - remotecommandserver "k8s.io/kubernetes/pkg/kubelet/server/remotecommand" -) - -// The library interface to serve the stream requests. -type Server interface { - http.Handler - - // Get the serving URL for the requests. - // Requests must not be nil. Responses may be nil iff an error is returned. - GetExec(*runtimeapi.ExecRequest) (*runtimeapi.ExecResponse, error) - GetAttach(req *runtimeapi.AttachRequest) (*runtimeapi.AttachResponse, error) - GetPortForward(*runtimeapi.PortForwardRequest) (*runtimeapi.PortForwardResponse, error) - - // Start the server. - // addr is the address to serve on (address:port) stayUp indicates whether the server should - // listen until Stop() is called, or automatically stop after all expected connections are - // closed. Calling Get{Exec,Attach,PortForward} increments the expected connection count. - // Function does not return until the server is stopped. - Start(stayUp bool) error - // Stop the server, and terminate any open connections. - Stop() error -} - -// The interface to execute the commands and provide the streams. -type Runtime interface { - Exec(containerID string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error - Attach(containerID string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error - PortForward(podSandboxID string, port int32, stream io.ReadWriteCloser) error -} - -// Config defines the options used for running the stream server. -type Config struct { - // The host:port address the server will listen on. - Addr string - // The optional base URL for constructing streaming URLs. If empty, the baseURL will be - // constructed from the serve address. - BaseURL *url.URL - - // How long to leave idle connections open for. - StreamIdleTimeout time.Duration - // How long to wait for clients to create streams. Only used for SPDY streaming. - StreamCreationTimeout time.Duration - - // The streaming protocols the server supports (understands and permits). See - // k8s.io/kubernetes/pkg/kubelet/server/remotecommand/constants.go for available protocols. - // Only used for SPDY streaming. - SupportedRemoteCommandProtocols []string - - // The streaming protocols the server supports (understands and permits). See - // k8s.io/kubernetes/pkg/kubelet/server/portforward/constants.go for available protocols. - // Only used for SPDY streaming. - SupportedPortForwardProtocols []string - - // The config for serving over TLS. If nil, TLS will not be used. - TLSConfig *tls.Config -} - -// DefaultConfig provides default values for server Config. The DefaultConfig is partial, so -// some fields like Addr must still be provided. -var DefaultConfig = Config{ - StreamIdleTimeout: 4 * time.Hour, - StreamCreationTimeout: remotecommandconsts.DefaultStreamCreationTimeout, - SupportedRemoteCommandProtocols: remotecommandconsts.SupportedStreamingProtocols, - SupportedPortForwardProtocols: portforward.SupportedProtocols, -} - -// TODO(timstclair): Add auth(n/z) interface & handling. -func NewServer(config Config, runtime Runtime) (Server, error) { - s := &server{ - config: config, - runtime: &criAdapter{runtime}, - cache: newRequestCache(), - } - - if s.config.BaseURL == nil { - s.config.BaseURL = &url.URL{ - Scheme: "http", - Host: s.config.Addr, - } - if s.config.TLSConfig != nil { - s.config.BaseURL.Scheme = "https" - } - } - - ws := &restful.WebService{} - endpoints := []struct { - path string - handler restful.RouteFunction - }{ - {"/exec/{token}", s.serveExec}, - {"/attach/{token}", s.serveAttach}, - {"/portforward/{token}", s.servePortForward}, - } - // If serving relative to a base path, set that here. - pathPrefix := path.Dir(s.config.BaseURL.Path) - for _, e := range endpoints { - for _, method := range []string{"GET", "POST"} { - ws.Route(ws. - Method(method). - Path(path.Join(pathPrefix, e.path)). - To(e.handler)) - } - } - handler := restful.NewContainer() - handler.Add(ws) - s.handler = handler - - return s, nil -} - -type server struct { - config Config - runtime *criAdapter - handler http.Handler - cache *requestCache -} - -func (s *server) GetExec(req *runtimeapi.ExecRequest) (*runtimeapi.ExecResponse, error) { - if req.ContainerId == "" { - return nil, grpc.Errorf(codes.InvalidArgument, "missing required container_id") - } - token, err := s.cache.Insert(req) - if err != nil { - return nil, err - } - return &runtimeapi.ExecResponse{ - Url: s.buildURL("exec", token), - }, nil -} - -func (s *server) GetAttach(req *runtimeapi.AttachRequest) (*runtimeapi.AttachResponse, error) { - if req.ContainerId == "" { - return nil, grpc.Errorf(codes.InvalidArgument, "missing required container_id") - } - token, err := s.cache.Insert(req) - if err != nil { - return nil, err - } - return &runtimeapi.AttachResponse{ - Url: s.buildURL("attach", token), - }, nil -} - -func (s *server) GetPortForward(req *runtimeapi.PortForwardRequest) (*runtimeapi.PortForwardResponse, error) { - if req.PodSandboxId == "" { - return nil, grpc.Errorf(codes.InvalidArgument, "missing required pod_sandbox_id") - } - token, err := s.cache.Insert(req) - if err != nil { - return nil, err - } - return &runtimeapi.PortForwardResponse{ - Url: s.buildURL("portforward", token), - }, nil -} - -func (s *server) Start(stayUp bool) error { - if !stayUp { - // TODO(timstclair): Implement this. - return errors.New("stayUp=false is not yet implemented") - } - - server := &http.Server{ - Addr: s.config.Addr, - Handler: s.handler, - TLSConfig: s.config.TLSConfig, - } - if s.config.TLSConfig != nil { - return server.ListenAndServeTLS("", "") // Use certs from TLSConfig. - } else { - return server.ListenAndServe() - } -} - -func (s *server) Stop() error { - // TODO(timstclair): Implement this. - return errors.New("not yet implemented") -} - -func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { - s.handler.ServeHTTP(w, r) -} - -func (s *server) buildURL(method, token string) string { - return s.config.BaseURL.ResolveReference(&url.URL{ - Path: path.Join(method, token), - }).String() -} - -func (s *server) serveExec(req *restful.Request, resp *restful.Response) { - token := req.PathParameter("token") - cachedRequest, ok := s.cache.Consume(token) - if !ok { - http.NotFound(resp.ResponseWriter, req.Request) - return - } - exec, ok := cachedRequest.(*runtimeapi.ExecRequest) - if !ok { - http.NotFound(resp.ResponseWriter, req.Request) - return - } - - streamOpts := &remotecommandserver.Options{ - Stdin: exec.Stdin, - Stdout: true, - Stderr: !exec.Tty, - TTY: exec.Tty, - } - - remotecommandserver.ServeExec( - resp.ResponseWriter, - req.Request, - s.runtime, - "", // unused: podName - "", // unusued: podUID - exec.ContainerId, - exec.Cmd, - streamOpts, - s.config.StreamIdleTimeout, - s.config.StreamCreationTimeout, - s.config.SupportedRemoteCommandProtocols) -} - -func (s *server) serveAttach(req *restful.Request, resp *restful.Response) { - token := req.PathParameter("token") - cachedRequest, ok := s.cache.Consume(token) - if !ok { - http.NotFound(resp.ResponseWriter, req.Request) - return - } - attach, ok := cachedRequest.(*runtimeapi.AttachRequest) - if !ok { - http.NotFound(resp.ResponseWriter, req.Request) - return - } - - streamOpts := &remotecommandserver.Options{ - Stdin: attach.Stdin, - Stdout: true, - Stderr: !attach.Tty, - TTY: attach.Tty, - } - remotecommandserver.ServeAttach( - resp.ResponseWriter, - req.Request, - s.runtime, - "", // unused: podName - "", // unusued: podUID - attach.ContainerId, - streamOpts, - s.config.StreamIdleTimeout, - s.config.StreamCreationTimeout, - s.config.SupportedRemoteCommandProtocols) -} - -func (s *server) servePortForward(req *restful.Request, resp *restful.Response) { - token := req.PathParameter("token") - cachedRequest, ok := s.cache.Consume(token) - if !ok { - http.NotFound(resp.ResponseWriter, req.Request) - return - } - pf, ok := cachedRequest.(*runtimeapi.PortForwardRequest) - if !ok { - http.NotFound(resp.ResponseWriter, req.Request) - return - } - - portForwardOptions, err := portforward.BuildV4Options(pf.Port) - if err != nil { - resp.WriteError(http.StatusBadRequest, err) - return - } - - portforward.ServePortForward( - resp.ResponseWriter, - req.Request, - s.runtime, - pf.PodSandboxId, - "", // unused: podUID - portForwardOptions, - s.config.StreamIdleTimeout, - s.config.StreamCreationTimeout, - s.config.SupportedPortForwardProtocols) -} - -// criAdapter wraps the Runtime functions to conform to the remotecommand interfaces. -// The adapter binds the container ID to the container name argument, and the pod sandbox ID to the pod name. -type criAdapter struct { - Runtime -} - -var _ remotecommandserver.Executor = &criAdapter{} -var _ remotecommandserver.Attacher = &criAdapter{} -var _ portforward.PortForwarder = &criAdapter{} - -func (a *criAdapter) ExecInContainer(podName string, podUID types.UID, container string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize, timeout time.Duration) error { - return a.Exec(container, cmd, in, out, err, tty, resize) -} - -func (a *criAdapter) AttachContainer(podName string, podUID types.UID, container string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error { - return a.Attach(container, in, out, err, tty, resize) -} - -func (a *criAdapter) PortForward(podName string, podUID types.UID, port int32, stream io.ReadWriteCloser) error { - return a.Runtime.PortForward(podName, port, stream) -} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/types/constants.go b/vendor/k8s.io/kubernetes/pkg/kubelet/types/constants.go deleted file mode 100644 index eeabba017..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/types/constants.go +++ /dev/null @@ -1,22 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package types - -const ( - // system default DNS resolver configuration - ResolvConfDefault = "/etc/resolv.conf" -) diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/types/doc.go b/vendor/k8s.io/kubernetes/pkg/kubelet/types/doc.go deleted file mode 100644 index 88e345636..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/types/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Common types in the Kubelet. -package types // import "k8s.io/kubernetes/pkg/kubelet/types" diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/types/labels.go b/vendor/k8s.io/kubernetes/pkg/kubelet/types/labels.go deleted file mode 100644 index c4dad6302..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/types/labels.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package types - -const ( - KubernetesPodNameLabel = "io.kubernetes.pod.name" - KubernetesPodNamespaceLabel = "io.kubernetes.pod.namespace" - KubernetesPodUIDLabel = "io.kubernetes.pod.uid" - KubernetesContainerNameLabel = "io.kubernetes.container.name" -) - -func GetContainerName(labels map[string]string) string { - return labels[KubernetesContainerNameLabel] -} - -func GetPodName(labels map[string]string) string { - return labels[KubernetesPodNameLabel] -} - -func GetPodUID(labels map[string]string) string { - return labels[KubernetesPodUIDLabel] -} - -func GetPodNamespace(labels map[string]string) string { - return labels[KubernetesPodNamespaceLabel] -} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/types/pod_update.go b/vendor/k8s.io/kubernetes/pkg/kubelet/types/pod_update.go deleted file mode 100644 index 2c2dbb8a0..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/types/pod_update.go +++ /dev/null @@ -1,153 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package types - -import ( - "fmt" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - kubeapi "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/v1" -) - -const ( - ConfigSourceAnnotationKey = "kubernetes.io/config.source" - ConfigMirrorAnnotationKey = v1.MirrorPodAnnotationKey - ConfigFirstSeenAnnotationKey = "kubernetes.io/config.seen" - ConfigHashAnnotationKey = "kubernetes.io/config.hash" - CriticalPodAnnotationKey = "scheduler.alpha.kubernetes.io/critical-pod" -) - -// PodOperation defines what changes will be made on a pod configuration. -type PodOperation int - -const ( - // This is the current pod configuration - SET PodOperation = iota - // Pods with the given ids are new to this source - ADD - // Pods with the given ids are gracefully deleted from this source - DELETE - // Pods with the given ids have been removed from this source - REMOVE - // Pods with the given ids have been updated in this source - UPDATE - // Pods with the given ids have unexpected status in this source, - // kubelet should reconcile status with this source - RECONCILE - - // These constants identify the sources of pods - // Updates from a file - FileSource = "file" - // Updates from querying a web page - HTTPSource = "http" - // Updates from Kubernetes API Server - ApiserverSource = "api" - // Updates from all sources - AllSource = "*" - - NamespaceDefault = metav1.NamespaceDefault -) - -// PodUpdate defines an operation sent on the channel. You can add or remove single services by -// sending an array of size one and Op == ADD|REMOVE (with REMOVE, only the ID is required). -// For setting the state of the system to a given state for this source configuration, set -// Pods as desired and Op to SET, which will reset the system state to that specified in this -// operation for this source channel. To remove all pods, set Pods to empty object and Op to SET. -// -// Additionally, Pods should never be nil - it should always point to an empty slice. While -// functionally similar, this helps our unit tests properly check that the correct PodUpdates -// are generated. -type PodUpdate struct { - Pods []*v1.Pod - Op PodOperation - Source string -} - -// Gets all validated sources from the specified sources. -func GetValidatedSources(sources []string) ([]string, error) { - validated := make([]string, 0, len(sources)) - for _, source := range sources { - switch source { - case AllSource: - return []string{FileSource, HTTPSource, ApiserverSource}, nil - case FileSource, HTTPSource, ApiserverSource: - validated = append(validated, source) - break - case "": - break - default: - return []string{}, fmt.Errorf("unknown pod source %q", source) - } - } - return validated, nil -} - -// GetPodSource returns the source of the pod based on the annotation. -func GetPodSource(pod *v1.Pod) (string, error) { - if pod.Annotations != nil { - if source, ok := pod.Annotations[ConfigSourceAnnotationKey]; ok { - return source, nil - } - } - return "", fmt.Errorf("cannot get source of pod %q", pod.UID) -} - -// SyncPodType classifies pod updates, eg: create, update. -type SyncPodType int - -const ( - // SyncPodSync is when the pod is synced to ensure desired state - SyncPodSync SyncPodType = iota - // SyncPodUpdate is when the pod is updated from source - SyncPodUpdate - // SyncPodCreate is when the pod is created from source - SyncPodCreate - // SyncPodKill is when the pod is killed based on a trigger internal to the kubelet for eviction. - // If a SyncPodKill request is made to pod workers, the request is never dropped, and will always be processed. - SyncPodKill -) - -func (sp SyncPodType) String() string { - switch sp { - case SyncPodCreate: - return "create" - case SyncPodUpdate: - return "update" - case SyncPodSync: - return "sync" - case SyncPodKill: - return "kill" - default: - return "unknown" - } -} - -// IsCriticalPod returns true if the pod bears the critical pod annotation -// key. Both the rescheduler and the kubelet use this key to make admission -// and scheduling decisions. -func IsCriticalPod(pod *v1.Pod) bool { - // Critical pods are restricted to "kube-system" namespace as of now. - if pod.Namespace != kubeapi.NamespaceSystem { - return false - } - val, ok := pod.Annotations[CriticalPodAnnotationKey] - if ok && val == "" { - return true - } - return false -} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/types/types.go b/vendor/k8s.io/kubernetes/pkg/kubelet/types/types.go deleted file mode 100644 index 35359c7aa..000000000 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/types/types.go +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package types - -import ( - "net/http" - "time" - - "k8s.io/kubernetes/pkg/api/v1" -) - -// TODO: Reconcile custom types in kubelet/types and this subpackage - -type HttpGetter interface { - Get(url string) (*http.Response, error) -} - -// Timestamp wraps around time.Time and offers utilities to format and parse -// the time using RFC3339Nano -type Timestamp struct { - time time.Time -} - -// NewTimestamp returns a Timestamp object using the current time. -func NewTimestamp() *Timestamp { - return &Timestamp{time.Now()} -} - -// ConvertToTimestamp takes a string, parses it using the RFC3339Nano layout, -// and converts it to a Timestamp object. -func ConvertToTimestamp(timeString string) *Timestamp { - parsed, _ := time.Parse(time.RFC3339Nano, timeString) - return &Timestamp{parsed} -} - -// Get returns the time as time.Time. -func (t *Timestamp) Get() time.Time { - return t.time -} - -// GetString returns the time in the string format using the RFC3339Nano -// layout. -func (t *Timestamp) GetString() string { - return t.time.Format(time.RFC3339Nano) -} - -// A type to help sort container statuses based on container names. -type SortedContainerStatuses []v1.ContainerStatus - -func (s SortedContainerStatuses) Len() int { return len(s) } -func (s SortedContainerStatuses) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -func (s SortedContainerStatuses) Less(i, j int) bool { - return s[i].Name < s[j].Name -} - -// SortInitContainerStatuses ensures that statuses are in the order that their -// init container appears in the pod spec -func SortInitContainerStatuses(p *v1.Pod, statuses []v1.ContainerStatus) { - containers := p.Spec.InitContainers - current := 0 - for _, container := range containers { - for j := current; j < len(statuses); j++ { - if container.Name == statuses[j].Name { - statuses[current], statuses[j] = statuses[j], statuses[current] - current++ - break - } - } - } -} - -// Reservation represents reserved resources for non-pod components. -type Reservation struct { - // System represents resources reserved for non-kubernetes components. - System v1.ResourceList - // Kubernetes represents resources reserved for kubernetes system components. - Kubernetes v1.ResourceList -} diff --git a/vendor/k8s.io/kubernetes/pkg/util/interrupt/interrupt.go b/vendor/k8s.io/kubernetes/pkg/util/interrupt/interrupt.go deleted file mode 100644 index 0265b9fb1..000000000 --- a/vendor/k8s.io/kubernetes/pkg/util/interrupt/interrupt.go +++ /dev/null @@ -1,104 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package interrupt - -import ( - "os" - "os/signal" - "sync" - "syscall" -) - -// terminationSignals are signals that cause the program to exit in the -// supported platforms (linux, darwin, windows). -var terminationSignals = []os.Signal{syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT} - -// Handler guarantees execution of notifications after a critical section (the function passed -// to a Run method), even in the presence of process termination. It guarantees exactly once -// invocation of the provided notify functions. -type Handler struct { - notify []func() - final func(os.Signal) - once sync.Once -} - -// Chain creates a new handler that invokes all notify functions when the critical section exits -// and then invokes the optional handler's notifications. This allows critical sections to be -// nested without losing exactly once invocations. Notify functions can invoke any cleanup needed -// but should not exit (which is the responsibility of the parent handler). -func Chain(handler *Handler, notify ...func()) *Handler { - if handler == nil { - return New(nil, notify...) - } - return New(handler.Signal, append(notify, handler.Close)...) -} - -// New creates a new handler that guarantees all notify functions are run after the critical -// section exits (or is interrupted by the OS), then invokes the final handler. If no final -// handler is specified, the default final is `os.Exit(1)`. A handler can only be used for -// one critical section. -func New(final func(os.Signal), notify ...func()) *Handler { - return &Handler{ - final: final, - notify: notify, - } -} - -// Close executes all the notification handlers if they have not yet been executed. -func (h *Handler) Close() { - h.once.Do(func() { - for _, fn := range h.notify { - fn() - } - }) -} - -// Signal is called when an os.Signal is received, and guarantees that all notifications -// are executed, then the final handler is executed. This function should only be called once -// per Handler instance. -func (h *Handler) Signal(s os.Signal) { - h.once.Do(func() { - for _, fn := range h.notify { - fn() - } - if h.final == nil { - os.Exit(1) - } - h.final(s) - }) -} - -// Run ensures that any notifications are invoked after the provided fn exits (even if the -// process is interrupted by an OS termination signal). Notifications are only invoked once -// per Handler instance, so calling Run more than once will not behave as the user expects. -func (h *Handler) Run(fn func() error) error { - ch := make(chan os.Signal, 1) - signal.Notify(ch, terminationSignals...) - defer func() { - signal.Stop(ch) - close(ch) - }() - go func() { - sig, ok := <-ch - if !ok { - return - } - h.Signal(sig) - }() - defer h.Close() - return fn() -} diff --git a/vendor/k8s.io/kubernetes/pkg/util/term/resize.go b/vendor/k8s.io/kubernetes/pkg/util/term/resize.go deleted file mode 100644 index 7ca09a858..000000000 --- a/vendor/k8s.io/kubernetes/pkg/util/term/resize.go +++ /dev/null @@ -1,132 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package term - -import ( - "fmt" - - "github.com/docker/docker/pkg/term" - "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/client-go/tools/remotecommand" -) - -// GetSize returns the current size of the user's terminal. If it isn't a terminal, -// nil is returned. -func (t TTY) GetSize() *remotecommand.TerminalSize { - outFd, isTerminal := term.GetFdInfo(t.Out) - if !isTerminal { - return nil - } - return GetSize(outFd) -} - -// GetSize returns the current size of the terminal associated with fd. -func GetSize(fd uintptr) *remotecommand.TerminalSize { - winsize, err := term.GetWinsize(fd) - if err != nil { - runtime.HandleError(fmt.Errorf("unable to get terminal size: %v", err)) - return nil - } - - return &remotecommand.TerminalSize{Width: winsize.Width, Height: winsize.Height} -} - -// MonitorSize monitors the terminal's size. It returns a TerminalSizeQueue primed with -// initialSizes, or nil if there's no TTY present. -func (t *TTY) MonitorSize(initialSizes ...*remotecommand.TerminalSize) remotecommand.TerminalSizeQueue { - outFd, isTerminal := term.GetFdInfo(t.Out) - if !isTerminal { - return nil - } - - t.sizeQueue = &sizeQueue{ - t: *t, - // make it buffered so we can send the initial terminal sizes without blocking, prior to starting - // the streaming below - resizeChan: make(chan remotecommand.TerminalSize, len(initialSizes)), - stopResizing: make(chan struct{}), - } - - t.sizeQueue.monitorSize(outFd, initialSizes...) - - return t.sizeQueue -} - -// sizeQueue implements remotecommand.TerminalSizeQueue -type sizeQueue struct { - t TTY - // resizeChan receives a Size each time the user's terminal is resized. - resizeChan chan remotecommand.TerminalSize - stopResizing chan struct{} -} - -// make sure sizeQueue implements the resize.TerminalSizeQueue interface -var _ remotecommand.TerminalSizeQueue = &sizeQueue{} - -// monitorSize primes resizeChan with initialSizes and then monitors for resize events. With each -// new event, it sends the current terminal size to resizeChan. -func (s *sizeQueue) monitorSize(outFd uintptr, initialSizes ...*remotecommand.TerminalSize) { - // send the initial sizes - for i := range initialSizes { - if initialSizes[i] != nil { - s.resizeChan <- *initialSizes[i] - } - } - - resizeEvents := make(chan remotecommand.TerminalSize, 1) - - monitorResizeEvents(outFd, resizeEvents, s.stopResizing) - - // listen for resize events in the background - go func() { - defer runtime.HandleCrash() - - for { - select { - case size, ok := <-resizeEvents: - if !ok { - return - } - - select { - // try to send the size to resizeChan, but don't block - case s.resizeChan <- size: - // send successful - default: - // unable to send / no-op - } - case <-s.stopResizing: - return - } - } - }() -} - -// Next returns the new terminal size after the terminal has been resized. It returns nil when -// monitoring has been stopped. -func (s *sizeQueue) Next() *remotecommand.TerminalSize { - size, ok := <-s.resizeChan - if !ok { - return nil - } - return &size -} - -// stop stops the background goroutine that is monitoring for terminal resizes. -func (s *sizeQueue) stop() { - close(s.stopResizing) -} diff --git a/vendor/k8s.io/kubernetes/pkg/util/term/resizeevents.go b/vendor/k8s.io/kubernetes/pkg/util/term/resizeevents.go deleted file mode 100644 index 75e9690df..000000000 --- a/vendor/k8s.io/kubernetes/pkg/util/term/resizeevents.go +++ /dev/null @@ -1,61 +0,0 @@ -// +build !windows - -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package term - -import ( - "os" - "os/signal" - "syscall" - - "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/client-go/tools/remotecommand" -) - -// monitorResizeEvents spawns a goroutine that waits for SIGWINCH signals (these indicate the -// terminal has resized). After receiving a SIGWINCH, this gets the terminal size and tries to send -// it to the resizeEvents channel. The goroutine stops when the stop channel is closed. -func monitorResizeEvents(fd uintptr, resizeEvents chan<- remotecommand.TerminalSize, stop chan struct{}) { - go func() { - defer runtime.HandleCrash() - - winch := make(chan os.Signal, 1) - signal.Notify(winch, syscall.SIGWINCH) - defer signal.Stop(winch) - - for { - select { - case <-winch: - size := GetSize(fd) - if size == nil { - return - } - - // try to send size - select { - case resizeEvents <- *size: - // success - default: - // not sent - } - case <-stop: - return - } - } - }() -} diff --git a/vendor/k8s.io/kubernetes/pkg/util/term/resizeevents_windows.go b/vendor/k8s.io/kubernetes/pkg/util/term/resizeevents_windows.go deleted file mode 100644 index adccf8734..000000000 --- a/vendor/k8s.io/kubernetes/pkg/util/term/resizeevents_windows.go +++ /dev/null @@ -1,62 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package term - -import ( - "time" - - "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/client-go/tools/remotecommand" -) - -// monitorResizeEvents spawns a goroutine that periodically gets the terminal size and tries to send -// it to the resizeEvents channel if the size has changed. The goroutine stops when the stop channel -// is closed. -func monitorResizeEvents(fd uintptr, resizeEvents chan<- remotecommand.TerminalSize, stop chan struct{}) { - go func() { - defer runtime.HandleCrash() - - size := GetSize(fd) - if size == nil { - return - } - lastSize := *size - - for { - // see if we need to stop running - select { - case <-stop: - return - default: - } - - size := GetSize(fd) - if size == nil { - return - } - - if size.Height != lastSize.Height || size.Width != lastSize.Width { - lastSize.Height = size.Height - lastSize.Width = size.Width - resizeEvents <- *size - } - - // sleep to avoid hot looping - time.Sleep(250 * time.Millisecond) - } - }() -} diff --git a/vendor/k8s.io/kubernetes/pkg/util/term/setsize.go b/vendor/k8s.io/kubernetes/pkg/util/term/setsize.go deleted file mode 100644 index 8cccd431a..000000000 --- a/vendor/k8s.io/kubernetes/pkg/util/term/setsize.go +++ /dev/null @@ -1,29 +0,0 @@ -// +build !windows - -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package term - -import ( - "github.com/docker/docker/pkg/term" - "k8s.io/client-go/tools/remotecommand" -) - -// SetSize sets the terminal size associated with fd. -func SetSize(fd uintptr, size remotecommand.TerminalSize) error { - return term.SetWinsize(fd, &term.Winsize{Height: size.Height, Width: size.Width}) -} diff --git a/vendor/k8s.io/kubernetes/pkg/util/term/setsize_unsupported.go b/vendor/k8s.io/kubernetes/pkg/util/term/setsize_unsupported.go deleted file mode 100644 index 82220217a..000000000 --- a/vendor/k8s.io/kubernetes/pkg/util/term/setsize_unsupported.go +++ /dev/null @@ -1,28 +0,0 @@ -// +build windows - -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package term - -import ( - "k8s.io/client-go/tools/remotecommand" -) - -func SetSize(fd uintptr, size remotecommand.TerminalSize) error { - // NOP - return nil -} diff --git a/vendor/k8s.io/kubernetes/pkg/util/term/term.go b/vendor/k8s.io/kubernetes/pkg/util/term/term.go deleted file mode 100644 index 58baee831..000000000 --- a/vendor/k8s.io/kubernetes/pkg/util/term/term.go +++ /dev/null @@ -1,110 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package term - -import ( - "io" - "os" - - "github.com/docker/docker/pkg/term" - - "k8s.io/kubernetes/pkg/util/interrupt" -) - -// SafeFunc is a function to be invoked by TTY. -type SafeFunc func() error - -// TTY helps invoke a function and preserve the state of the terminal, even if the process is -// terminated during execution. It also provides support for terminal resizing for remote command -// execution/attachment. -type TTY struct { - // In is a reader representing stdin. It is a required field. - In io.Reader - // Out is a writer representing stdout. It must be set to support terminal resizing. It is an - // optional field. - Out io.Writer - // Raw is true if the terminal should be set raw. - Raw bool - // TryDev indicates the TTY should try to open /dev/tty if the provided input - // is not a file descriptor. - TryDev bool - // Parent is an optional interrupt handler provided to this function - if provided - // it will be invoked after the terminal state is restored. If it is not provided, - // a signal received during the TTY will result in os.Exit(0) being invoked. - Parent *interrupt.Handler - - // sizeQueue is set after a call to MonitorSize() and is used to monitor SIGWINCH signals when the - // user's terminal resizes. - sizeQueue *sizeQueue -} - -// IsTerminalIn returns true if t.In is a terminal. Does not check /dev/tty -// even if TryDev is set. -func (t TTY) IsTerminalIn() bool { - return IsTerminal(t.In) -} - -// IsTerminalOut returns true if t.Out is a terminal. Does not check /dev/tty -// even if TryDev is set. -func (t TTY) IsTerminalOut() bool { - return IsTerminal(t.Out) -} - -// IsTerminal returns whether the passed object is a terminal or not -func IsTerminal(i interface{}) bool { - _, terminal := term.GetFdInfo(i) - return terminal -} - -// Safe invokes the provided function and will attempt to ensure that when the -// function returns (or a termination signal is sent) that the terminal state -// is reset to the condition it was in prior to the function being invoked. If -// t.Raw is true the terminal will be put into raw mode prior to calling the function. -// If the input file descriptor is not a TTY and TryDev is true, the /dev/tty file -// will be opened (if available). -func (t TTY) Safe(fn SafeFunc) error { - inFd, isTerminal := term.GetFdInfo(t.In) - - if !isTerminal && t.TryDev { - if f, err := os.Open("/dev/tty"); err == nil { - defer f.Close() - inFd = f.Fd() - isTerminal = term.IsTerminal(inFd) - } - } - if !isTerminal { - return fn() - } - - var state *term.State - var err error - if t.Raw { - state, err = term.MakeRaw(inFd) - } else { - state, err = term.SaveState(inFd) - } - if err != nil { - return err - } - return interrupt.Chain(t.Parent, func() { - if t.sizeQueue != nil { - t.sizeQueue.stop() - } - - term.RestoreTerminal(inFd, state) - }).Run(fn) -} diff --git a/vendor/k8s.io/kubernetes/pkg/util/term/term_writer.go b/vendor/k8s.io/kubernetes/pkg/util/term/term_writer.go deleted file mode 100644 index 2d72d1e45..000000000 --- a/vendor/k8s.io/kubernetes/pkg/util/term/term_writer.go +++ /dev/null @@ -1,124 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package term - -import ( - "io" - "os" - - "github.com/docker/docker/pkg/term" - wordwrap "github.com/mitchellh/go-wordwrap" -) - -type wordWrapWriter struct { - limit uint - writer io.Writer -} - -// NewResponsiveWriter creates a Writer that detects the column width of the -// terminal we are in, and adjusts every line width to fit and use recommended -// terminal sizes for better readability. Does proper word wrapping automatically. -// if terminal width >= 120 columns use 120 columns -// if terminal width >= 100 columns use 100 columns -// if terminal width >= 80 columns use 80 columns -// In case we're not in a terminal or if it's smaller than 80 columns width, -// doesn't do any wrapping. -func NewResponsiveWriter(w io.Writer) io.Writer { - file, ok := w.(*os.File) - if !ok { - return w - } - fd := file.Fd() - if !term.IsTerminal(fd) { - return w - } - - terminalSize := GetSize(fd) - if terminalSize == nil { - return w - } - - var limit uint - switch { - case terminalSize.Width >= 120: - limit = 120 - case terminalSize.Width >= 100: - limit = 100 - case terminalSize.Width >= 80: - limit = 80 - } - - return NewWordWrapWriter(w, limit) -} - -// NewWordWrapWriter is a Writer that supports a limit of characters on every line -// and does auto word wrapping that respects that limit. -func NewWordWrapWriter(w io.Writer, limit uint) io.Writer { - return &wordWrapWriter{ - limit: limit, - writer: w, - } -} - -func (w wordWrapWriter) Write(p []byte) (nn int, err error) { - if w.limit == 0 { - return w.writer.Write(p) - } - original := string(p) - wrapped := wordwrap.WrapString(original, w.limit) - return w.writer.Write([]byte(wrapped)) -} - -// NewPunchCardWriter is a NewWordWrapWriter that limits the line width to 80 columns. -func NewPunchCardWriter(w io.Writer) io.Writer { - return NewWordWrapWriter(w, 80) -} - -type maxWidthWriter struct { - maxWidth uint - currentWidth uint - written uint - writer io.Writer -} - -// NewMaxWidthWriter is a Writer that supports a limit of characters on every -// line, but doesn't do any word wrapping automatically. -func NewMaxWidthWriter(w io.Writer, maxWidth uint) io.Writer { - return &maxWidthWriter{ - maxWidth: maxWidth, - writer: w, - } -} - -func (m maxWidthWriter) Write(p []byte) (nn int, err error) { - for _, b := range p { - if m.currentWidth == m.maxWidth { - m.writer.Write([]byte{'\n'}) - m.currentWidth = 0 - } - if b == '\n' { - m.currentWidth = 0 - } - _, err := m.writer.Write([]byte{b}) - if err != nil { - return int(m.written), err - } - m.written++ - m.currentWidth++ - } - return len(p), nil -} |