4
vendor/github.com/containerd/containerd/.gitignore
generated
vendored
Normal file
4
vendor/github.com/containerd/containerd/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/bin/
|
||||
**/coverage.txt
|
||||
**/coverage.out
|
||||
containerd.test
|
||||
61
vendor/github.com/containerd/containerd/.travis.yml
generated
vendored
Normal file
61
vendor/github.com/containerd/containerd/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
dist: trusty
|
||||
sudo: required
|
||||
# setup travis so that we can run containers for integration tests
|
||||
services:
|
||||
- docker
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.8.x
|
||||
|
||||
go_import_path: github.com/containerd/containerd
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- btrfs-tools
|
||||
- libseccomp-dev
|
||||
- libapparmor-dev
|
||||
- libnl-3-dev
|
||||
- libnet-dev
|
||||
- protobuf-c-compiler
|
||||
- protobuf-compiler
|
||||
- python-minimal
|
||||
- libcap-dev
|
||||
- libaio-dev
|
||||
- libprotobuf-c0-dev
|
||||
- libprotobuf-dev
|
||||
|
||||
env:
|
||||
- TRAVIS_GOOS=windows TRAVIS_CGO_ENABLED=1
|
||||
- TRAVIS_GOOS=linux TRAVIS_CGO_ENABLED=1
|
||||
- TRAVIS_GOOS=darwin TRAVIS_CGO_ENABLED=0
|
||||
|
||||
install:
|
||||
- if [ "$TRAVIS_GOOS" = "windows" ] ; then sudo apt-get install -y gcc-multilib gcc-mingw-w64; export CC=x86_64-w64-mingw32-gcc ; export CXX=x86_64-w64-mingw32-g++ ; fi
|
||||
- wget https://github.com/google/protobuf/releases/download/v3.1.0/protoc-3.1.0-linux-x86_64.zip -O /tmp/protoc-3.1.0-linux-x86_64.zip
|
||||
- unzip -o -d /tmp/protobuf /tmp/protoc-3.1.0-linux-x86_64.zip
|
||||
- export PATH=$PATH:/tmp/protobuf/bin/
|
||||
- go get -u github.com/vbatts/git-validation
|
||||
- sudo wget https://github.com/crosbymichael/runc/releases/download/ctd-1/runc -O /bin/runc; sudo chmod +x /bin/runc
|
||||
- wget https://github.com/xemul/criu/archive/v3.0.tar.gz -O /tmp/criu.tar.gz
|
||||
- tar -C /tmp/ -zxf /tmp/criu.tar.gz
|
||||
- cd /tmp/criu-3.0 && sudo make install-criu
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
|
||||
script:
|
||||
- export GOOS=$TRAVIS_GOOS
|
||||
- export CGO_ENABLED=$TRAVIS_CGO_ENABLED
|
||||
- GIT_CHECK_EXCLUDE="./vendor" TRAVIS_COMMIT_RANGE="${TRAVIS_COMMIT_RANGE/.../..}" make dco
|
||||
- make fmt
|
||||
- make vet
|
||||
- make build
|
||||
- make binaries
|
||||
- if [ "$GOOS" = "linux" ]; then sudo make install ; fi
|
||||
- if [ "$GOOS" = "linux" ]; then make coverage ; fi
|
||||
- if [ "$GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH make root-coverage ; fi
|
||||
- if [ "$GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH make integration ; fi
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
71
vendor/github.com/containerd/containerd/BUILDING.md
generated
vendored
Normal file
71
vendor/github.com/containerd/containerd/BUILDING.md
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
# Build containerd from source
|
||||
|
||||
This guide is useful if you intend to contribute on containerd. Thanks for your
|
||||
effort. Every contribution is very appreciated.
|
||||
|
||||
## Build the development environment
|
||||
|
||||
In first you need to setup your Go development environment. You can follow this
|
||||
guideline [How to write go code](https://golang.org/doc/code.html) and at the
|
||||
end you need to have `GOPATH` and `GOROOT` set in your environment.
|
||||
|
||||
At this point you can use `go` to checkout `containerd` in your `GOPATH`:
|
||||
|
||||
```sh
|
||||
go get github.com/containerd/containerd
|
||||
```
|
||||
|
||||
`containerd` uses [Btrfs](https://en.wikipedia.org/wiki/Btrfs) it means that you
|
||||
need to satisfy this dependencies in your system:
|
||||
|
||||
* CentOS/Fedora: `yum install btrfs-progs-devel`
|
||||
* Debian/Ubuntu: `apt-get install btrfs-tools`
|
||||
|
||||
At this point you are ready to build `containerd` yourself.
|
||||
|
||||
## In your local environment
|
||||
|
||||
`containerd` uses `make` to create a repeatable build flow. It means that you
|
||||
can run:
|
||||
|
||||
```sudo
|
||||
make
|
||||
```
|
||||
|
||||
This is going to build all the binaries provided by this project in the `./bin`
|
||||
directory.
|
||||
|
||||
You can move them in your global path with:
|
||||
|
||||
```sudo
|
||||
sudo make install
|
||||
```
|
||||
|
||||
## Via Docker Container
|
||||
|
||||
You can build `containerd` via Docker container. You can build an image from
|
||||
this `Dockerfile`:
|
||||
|
||||
```
|
||||
FROM golang
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install btrfs-tools
|
||||
```
|
||||
|
||||
Let's suppose that you built an image called `containerd/build` and you are into
|
||||
the containerd root directory you can run the following command:
|
||||
|
||||
```sh
|
||||
docker run -it --rm \
|
||||
-v ${PWD}:/go/src/github.com/containerd/containerd \
|
||||
-e GOPATH=/go \
|
||||
-w /go/src/github.com/containerd/containerd containerd/build make
|
||||
```
|
||||
|
||||
At this point you can find your binaries in the `./bin` directory in your host.
|
||||
You can move the binaries in your `$PATH` with the command:
|
||||
|
||||
```sh
|
||||
sudo make install
|
||||
```
|
||||
115
vendor/github.com/containerd/containerd/CONTRIBUTING.md
generated
vendored
Normal file
115
vendor/github.com/containerd/containerd/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
# Contributing
|
||||
|
||||
Contributions should be made via pull requests. Pull requests will be reviewed
|
||||
by one or more maintainers and merged when acceptable.
|
||||
|
||||
This project is in an early state, making the impact of contributions much
|
||||
greater than at other stages. In this respect, it is important to consider any
|
||||
changes or additions for their future impact more so than their current impact.
|
||||
|
||||
## Successful Changes
|
||||
|
||||
We ask that before contributing, please make the effort to coordinate with the
|
||||
maintainers of the project before submitting large or high impact PRs. This
|
||||
will prevent you from doing extra work that may or may not be merged.
|
||||
|
||||
PRs that are just submitted without any prior communication will likely be
|
||||
summarily closed.
|
||||
|
||||
While pull requests are the methodology for submitting changes to code, changes
|
||||
are much more likely to be accepted if they are accompanied by additional
|
||||
engineering work. While we don't define this explicitly, most of these goals
|
||||
are accomplished through communication of the design goals and subsequent
|
||||
solutions. Often times, it helps to first state the problem before presenting
|
||||
solutions.
|
||||
|
||||
Typically, the best methods of accomplishing this are to submit an issue,
|
||||
stating the problem. This issue can include a problem statement and a
|
||||
checklist with requirements. If solutions are proposed, alternatives should be
|
||||
listed and eliminated. Even if the criteria for elimination of a solution is
|
||||
frivolous, say so.
|
||||
|
||||
Larger changes typically work best with design documents, similar to those found
|
||||
in `design/`. These are focused on providing context to the design at the time
|
||||
the feature was conceived and can inform future documentation contributions.
|
||||
|
||||
## Commit Messages
|
||||
|
||||
There are times for one line commit messages and this is not one of them.
|
||||
Commit messages should follow best practices, including explaining the context
|
||||
of the problem and how it was solved, including in caveats or follow up changes
|
||||
required. They should tell the story of the change and provide readers
|
||||
understanding of what led to it.
|
||||
|
||||
If you're lost about what this even means, please see [How to Write a Git
|
||||
Commit Message](http://chris.beams.io/posts/git-commit/) for a start.
|
||||
|
||||
In practice, the best approach to maintaining a nice commit message is to
|
||||
leverage a `git add -p` and `git commit --amend` to formulate a solid
|
||||
changeset. This allows one to piece together a change, as information becomes
|
||||
available.
|
||||
|
||||
If you squash a series of commits, don't just submit that. Re-write the commit
|
||||
message, as if the series of commits was a single stroke of brilliance.
|
||||
|
||||
That said, there is no requirement to have a single commit for a PR, as long as
|
||||
each commit tells the story. For example, if there is a feature that requires a
|
||||
package, it might make sense to have the package in a separate commit then have
|
||||
a subsequent commit that uses it.
|
||||
|
||||
Remember, you're telling part of the story with the commit message. Don't make
|
||||
your chapter weird.
|
||||
|
||||
## Sign your work
|
||||
|
||||
The sign-off is a simple line at the end of the explanation for the patch. Your
|
||||
signature certifies that you wrote the patch or otherwise have the right to pass
|
||||
it on as an open-source patch. The rules are pretty simple: if you can certify
|
||||
the below (from [developercertificate.org](http://developercertificate.org/)):
|
||||
|
||||
```
|
||||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||
660 York Street, Suite 102,
|
||||
San Francisco, CA 94110 USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
```
|
||||
|
||||
Then you just add a line to every git commit message:
|
||||
|
||||
Signed-off-by: Joe Smith <joe.smith@email.com>
|
||||
|
||||
Use your real name (sorry, no pseudonyms or anonymous contributions.)
|
||||
|
||||
If you set your `user.name` and `user.email` git configs, you can sign your
|
||||
commit automatically with `git commit -s`.
|
||||
300
vendor/github.com/containerd/containerd/MAINTAINERS
generated
vendored
Normal file
300
vendor/github.com/containerd/containerd/MAINTAINERS
generated
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
# containerd project maintainers file
|
||||
#
|
||||
# This file describes who runs the containerd project and how.
|
||||
# This is a living document - if you see something out of date or missing,
|
||||
# speak up!
|
||||
#
|
||||
# It is structured to be consumable by both humans and programs.
|
||||
# To extract its contents programmatically, use any TOML-compliant
|
||||
# parser.
|
||||
|
||||
[Rules]
|
||||
|
||||
[Rules.maintainers]
|
||||
|
||||
title = "What is a maintainer?"
|
||||
|
||||
text = """
|
||||
There are different types of maintainers, with different responsibilities, but
|
||||
all maintainers have 3 things in common:
|
||||
|
||||
1) They share responsibility in the project's success.
|
||||
2) They have made a long-term, recurring time investment to improve the project.
|
||||
3) They spend that time doing whatever needs to be done, not necessarily what
|
||||
is the most interesting or fun.
|
||||
|
||||
Maintainers are often under-appreciated, because their work is harder to appreciate.
|
||||
It's easy to appreciate a really cool and technically advanced feature. It's harder
|
||||
to appreciate the absence of bugs, the slow but steady improvement in stability,
|
||||
or the reliability of a release process. But those things distinguish a good
|
||||
project from a great one.
|
||||
"""
|
||||
|
||||
[Rules.adding-maintainers]
|
||||
|
||||
title = "How are maintainers added?"
|
||||
|
||||
text = """
|
||||
Maintainers are first and foremost contributors that have shown they are
|
||||
committed to the long term success of a project. Contributors wanting to become
|
||||
maintainers are expected to be deeply involved in contributing code, pull
|
||||
request review, and triage of issues in the project for more than three months.
|
||||
|
||||
Just contributing does not make you a maintainer, it is about building trust
|
||||
with the current maintainers of the project and being a person that they can
|
||||
depend on and trust to make decisions in the best interest of the project.
|
||||
|
||||
Periodically, the existing maintainers curate a list of contributors that have
|
||||
shown regular activity on the project over the prior months. From this list,
|
||||
maintainer candidates are selected and proposed on the maintainers mailing list.
|
||||
|
||||
After a candidate has been announced on the maintainers mailing list, the
|
||||
existing maintainers are given five business days to discuss the candidate,
|
||||
raise objections and cast their vote. Candidates must be approved by the BDFL
|
||||
and at least 66% of the current maintainers by adding their vote on the mailing
|
||||
list. Only maintainers of the repository that the candidate is proposed for are
|
||||
allowed to vote. The BDFL's vote is mandatory.
|
||||
|
||||
If a candidate is approved, a maintainer will contact the candidate to invite
|
||||
the candidate to open a pull request that adds the contributor to the
|
||||
MAINTAINERS file. The candidate becomes a maintainer once the pull request is
|
||||
merged.
|
||||
"""
|
||||
|
||||
[Rules.adding-sub-projects]
|
||||
|
||||
title = "How are sub projects added?"
|
||||
|
||||
text = """
|
||||
Similar to adding maintainers, new sub projects can be added to containerd
|
||||
GitHub organization as long as they adhere to the CNCF
|
||||
[charter](https://www.cncf.io/about/charter/) and mission. After a project
|
||||
proposal has been announced on a public forum (GitHub issue or mailing list),
|
||||
the existing maintainers are given five business days to discuss the new
|
||||
project, raise objections and cast their vote. Projects must be approved by at
|
||||
least 66% of the current maintainers by adding their vote.
|
||||
|
||||
If a project is approved, a maintainer will add the project to the containerd
|
||||
GitHub organization, and make an announcement on a public forum.
|
||||
"""
|
||||
|
||||
[Rules.stepping-down-policy]
|
||||
|
||||
title = "Stepping down policy"
|
||||
|
||||
text = """
|
||||
Life priorities, interests, and passions can change. If you're a maintainer but
|
||||
feel you must remove yourself from the list, inform other maintainers that you
|
||||
intend to step down, and if possible, help find someone to pick up your work.
|
||||
At the very least, ensure your work can be continued where you left off.
|
||||
|
||||
After you've informed other maintainers, create a pull request to remove
|
||||
yourself from the MAINTAINERS file.
|
||||
"""
|
||||
|
||||
[Rules.inactive-maintainers]
|
||||
|
||||
title = "Removal of inactive maintainers"
|
||||
|
||||
text = """
|
||||
Similar to the procedure for adding new maintainers, existing maintainers can
|
||||
be removed from the list if they do not show significant activity on the
|
||||
project. Periodically, the maintainers review the list of maintainers and their
|
||||
activity over the last three months.
|
||||
|
||||
If a maintainer has shown insufficient activity over this period, a neutral
|
||||
person will contact the maintainer to ask if they want to continue being
|
||||
a maintainer. If the maintainer decides to step down as a maintainer, they
|
||||
open a pull request to be removed from the MAINTAINERS file.
|
||||
|
||||
If the maintainer wants to remain a maintainer, but is unable to perform the
|
||||
required duties they can be removed with a vote by the BDFL and at least 66% of
|
||||
the current maintainers. The BDFL's vote is mandatory. An e-mail is sent to the
|
||||
mailing list, inviting maintainers of the project to vote. The voting period is
|
||||
five business days. Issues related to a maintainer's performance should be
|
||||
discussed with them among the other maintainers so that they are not surprised
|
||||
by a pull request removing them.
|
||||
"""
|
||||
|
||||
[Rules.bdfl]
|
||||
|
||||
title = "The Benevolent dictator for life (BDFL)"
|
||||
|
||||
text = """
|
||||
containerd follows the timeless, highly efficient and totally unfair system
|
||||
known as [Benevolent dictator for
|
||||
life](https://en.wikipedia.org/wiki/Benevolent_Dictator_for_Life), with yours
|
||||
truly, Solomon Hykes, in the role of BDFL. This means that all decisions are
|
||||
made, by default, by Solomon. Since making every decision himself would be
|
||||
highly un-scalable, in practice decisions are spread across multiple
|
||||
maintainers.
|
||||
|
||||
Ideally, the BDFL role is like the Queen of England: awesome crown, but not an
|
||||
actual operational role day-to-day. The real job of a BDFL is to NEVER GO AWAY.
|
||||
Every other rule can change, perhaps drastically so, but the BDFL will always be
|
||||
there, preserving the philosophy and principles of the project, and keeping
|
||||
ultimate authority over its fate. This gives us great flexibility in
|
||||
experimenting with various governance models, knowing that we can always press
|
||||
the "reset" button without fear of fragmentation or deadlock. See the US
|
||||
congress for a counter-example.
|
||||
|
||||
BDFL daily routine:
|
||||
|
||||
* Is the project governance stuck in a deadlock or irreversibly fragmented?
|
||||
* If yes: refactor the project governance
|
||||
* Are there issues or conflicts escalated by maintainers?
|
||||
* If yes: resolve them
|
||||
* Go back to polishing that crown.
|
||||
"""
|
||||
|
||||
[Rules.decisions]
|
||||
|
||||
title = "How are decisions made?"
|
||||
|
||||
text = """
|
||||
Short answer: EVERYTHING IS A PULL REQUEST.
|
||||
|
||||
containerd is an open-source project with an open design philosophy. This means
|
||||
that the repository is the source of truth for EVERY aspect of the project,
|
||||
including its philosophy, design, road map, and APIs. *If it's part of the
|
||||
project, it's in the repo. If it's in the repo, it's part of the project.*
|
||||
|
||||
As a result, all decisions can be expressed as changes to the repository. An
|
||||
implementation change is a change to the source code. An API change is a change
|
||||
to the API specification. A philosophy change is a change to the philosophy
|
||||
manifesto, and so on.
|
||||
|
||||
All decisions affecting containerd, big and small, follow the same 3 steps:
|
||||
|
||||
* Step 1: Open a pull request. Anyone can do this.
|
||||
|
||||
* Step 2: Discuss the pull request. Anyone can do this.
|
||||
|
||||
* Step 3: Merge or refuse the pull request. Who does this depends on the nature
|
||||
of the pull request and which areas of the project it affects.
|
||||
"""
|
||||
|
||||
[Rules.DCO]
|
||||
|
||||
title = "Helping contributors with the DCO"
|
||||
|
||||
text = """
|
||||
The [DCO or `Sign your work`](
|
||||
https://github.com/containerd/containerd/blob/master/CONTRIBUTING.md#sign-your-work)
|
||||
requirement is not intended as a roadblock or speed bump.
|
||||
|
||||
Some containerd contributors are not as familiar with `git`, or have used a web
|
||||
based editor, and thus asking them to `git commit --amend -s` is not the best
|
||||
way forward.
|
||||
|
||||
In this case, maintainers can update the commits based on clause (c) of the DCO.
|
||||
The most trivial way for a contributor to allow the maintainer to do this, is to
|
||||
add a DCO signature in a pull requests's comment, or a maintainer can simply
|
||||
note that the change is sufficiently trivial that it does not substantially
|
||||
change the existing contribution - i.e., a spelling change.
|
||||
|
||||
When you add someone's DCO, please also add your own to keep a log.
|
||||
"""
|
||||
|
||||
[Rules."no direct push"]
|
||||
|
||||
title = "I'm a maintainer. Should I make pull requests too?"
|
||||
|
||||
text = """
|
||||
Yes. Nobody should ever push to master directly. All changes should be
|
||||
made through a pull request.
|
||||
"""
|
||||
|
||||
[Rules.meta]
|
||||
|
||||
title = "How is this process changed?"
|
||||
|
||||
text = "Just like everything else: by making a pull request :)"
|
||||
|
||||
# Current project roles
|
||||
[Roles]
|
||||
|
||||
[Roles.bdfl]
|
||||
|
||||
person = "shykes"
|
||||
|
||||
[Roles."Chief Architect"]
|
||||
|
||||
person = "crosbymichael"
|
||||
|
||||
text = """
|
||||
The chief architect is responsible for the overall integrity of the technical
|
||||
architecture across all subsystems, and the consistency of APIs and UI.
|
||||
|
||||
Changes to UI, public APIs and overall architecture must be approved by the
|
||||
chief architect.
|
||||
"""
|
||||
|
||||
[Roles."Chief Maintainer"]
|
||||
|
||||
person = "crosbymichael"
|
||||
|
||||
text = """
|
||||
The chief maintainer is responsible for all aspects of quality for the project
|
||||
including code reviews, usability, stability, security, performance, etc. The
|
||||
most important function of the chief maintainer is to lead by example. On the
|
||||
first day of a new maintainer, the best advice should be "follow the C.M.'s
|
||||
example and you'll be fine".
|
||||
"""
|
||||
|
||||
# Current project organization
|
||||
[Org]
|
||||
|
||||
[Org.Maintainers]
|
||||
people = [
|
||||
"crosbymichael",
|
||||
"dqminh",
|
||||
"dmcgowan",
|
||||
"estesp",
|
||||
"hqhq",
|
||||
"jhowardmsft",
|
||||
"mlaventure",
|
||||
"stevvooe",
|
||||
]
|
||||
|
||||
[People]
|
||||
|
||||
[People.crosbymichael]
|
||||
Name = "Michael Crosby"
|
||||
Email = "crosbymichael@gmail.com"
|
||||
GitHub = "crosbymichael"
|
||||
|
||||
[People.dqminh]
|
||||
Name = "Daniel, Dao Quang Minh"
|
||||
Email = "dqminh89@gmail.com"
|
||||
GitHub = "dqminh"
|
||||
|
||||
[people.dmcgowan]
|
||||
Name = "Derek McGowan"
|
||||
Email = "derek@mcgstyle.net"
|
||||
GitHub = "dmcgowan"
|
||||
|
||||
[People.estesp]
|
||||
Name = "Phil Estes"
|
||||
Email = "estesp@gmail.com"
|
||||
GitHub = "estesp"
|
||||
|
||||
[People.hqhq]
|
||||
Name = "Qiang Huang"
|
||||
Email = "h.huangqiang@huawei.com"
|
||||
GitHub = "hqhq"
|
||||
|
||||
[People.jhowardmsft]
|
||||
Name = "John Howard"
|
||||
Email = "jhoward@microsoft.com"
|
||||
GitHub = "jhowardmsft"
|
||||
|
||||
[People.mlaventure]
|
||||
Name = "Kenfe-Mickaël Laventure"
|
||||
Email = "mickael.laventure@docker.com"
|
||||
GitHub = "mlaventure"
|
||||
|
||||
[People.stevvooe]
|
||||
Name = "Stephen Day"
|
||||
Email = "stephen.day@docker.com"
|
||||
GitHub = "stevvooe"
|
||||
186
vendor/github.com/containerd/containerd/Makefile
generated
vendored
Normal file
186
vendor/github.com/containerd/containerd/Makefile
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
# Root directory of the project (absolute path).
|
||||
ROOTDIR=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
||||
|
||||
# Base path used to install.
|
||||
DESTDIR=/usr/local
|
||||
|
||||
# Used to populate variables in version package.
|
||||
VERSION=$(shell git describe --match 'v[0-9]*' --dirty='.m' --always)
|
||||
REVISION=$(shell git rev-parse HEAD)$(shell if ! git diff --no-ext-diff --quiet --exit-code; then echo .m; fi)
|
||||
|
||||
PKG=github.com/containerd/containerd
|
||||
|
||||
ifneq "$(strip $(shell command -v go 2>/dev/null))" ""
|
||||
GOOS ?= $(shell go env GOOS)
|
||||
else
|
||||
GOOS ?= $$GOOS
|
||||
endif
|
||||
WHALE = "🐳"
|
||||
ONI = "👹"
|
||||
ifeq ("$(OS)", "Windows_NT")
|
||||
WHALE="+"
|
||||
ONI="-"
|
||||
endif
|
||||
|
||||
# Project packages.
|
||||
PACKAGES=$(shell go list ./... | grep -v /vendor/)
|
||||
INTEGRATION_PACKAGE=${PKG}/integration
|
||||
SNAPSHOT_PACKAGES=$(shell go list ./snapshot/...)
|
||||
|
||||
# Project binaries.
|
||||
COMMANDS=ctr containerd protoc-gen-gogoctrd dist ctrd-protobuild
|
||||
ifneq ("$(GOOS)", "windows")
|
||||
COMMANDS += containerd-shim
|
||||
endif
|
||||
BINARIES=$(addprefix bin/,$(COMMANDS))
|
||||
ifeq ("$(GOOS)", "windows")
|
||||
BINARY_SUFFIX=".exe"
|
||||
endif
|
||||
|
||||
GO_TAGS=$(if $(BUILDTAGS),-tags "$(BUILDTAGS)",)
|
||||
GO_LDFLAGS=-ldflags "-X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PKG) $(EXTRA_LDFLAGS)"
|
||||
|
||||
# Flags passed to `go test`
|
||||
TESTFLAGS ?=-parallel 8 -race
|
||||
|
||||
.PHONY: clean all AUTHORS fmt vet lint dco build binaries test integration setup generate protos checkprotos coverage ci check help install uninstall vendor
|
||||
.DEFAULT: default
|
||||
|
||||
all: binaries
|
||||
|
||||
check: fmt vet lint ineffassign ## run fmt, vet, lint, ineffassign
|
||||
|
||||
ci: check binaries checkprotos coverage coverage-integration ## to be used by the CI
|
||||
|
||||
AUTHORS: .mailmap .git/HEAD
|
||||
git log --format='%aN <%aE>' | sort -fu > $@
|
||||
|
||||
setup: ## install dependencies
|
||||
@echo "$(WHALE) $@"
|
||||
# TODO(stevvooe): Install these from the vendor directory
|
||||
@go get -u github.com/golang/lint/golint
|
||||
#@go get -u github.com/kisielk/errcheck
|
||||
@go get -u github.com/gordonklaus/ineffassign
|
||||
|
||||
generate: protos
|
||||
@echo "$(WHALE) $@"
|
||||
@PATH=${ROOTDIR}/bin:${PATH} go generate -x ${PACKAGES}
|
||||
|
||||
protos: bin/protoc-gen-gogoctrd bin/ctrd-protobuild ## generate protobuf
|
||||
@echo "$(WHALE) $@"
|
||||
@PATH=${ROOTDIR}/bin:${PATH} ctrd-protobuild ${PACKAGES}
|
||||
|
||||
checkprotos: protos ## check if protobufs needs to be generated again
|
||||
@echo "$(WHALE) $@"
|
||||
@test -z "$$(git status --short | grep ".pb.go" | tee /dev/stderr)" || \
|
||||
((git diff | cat) && \
|
||||
(echo "$(ONI) please run 'make generate' when making changes to proto files" && false))
|
||||
|
||||
# Depends on binaries because vet will silently fail if it can't load compiled
|
||||
# imports
|
||||
vet: binaries ## run go vet
|
||||
@echo "$(WHALE) $@"
|
||||
@test -z "$$(go vet ${PACKAGES} 2>&1 | grep -v 'constant [0-9]* not a string in call to Errorf' | grep -v 'unrecognized printf verb 'r'' | egrep -v '(timestamp_test.go|duration_test.go|fetch.go|exit status 1)' | tee /dev/stderr)"
|
||||
|
||||
fmt: ## run go fmt
|
||||
@echo "$(WHALE) $@"
|
||||
@test -z "$$(gofmt -s -l . | grep -v vendor/ | grep -v ".pb.go$$" | tee /dev/stderr)" || \
|
||||
(echo "$(ONI) please format Go code with 'gofmt -s -w'" && false)
|
||||
@test -z "$$(find . -path ./vendor -prune -o ! -name timestamp.proto ! -name duration.proto -name '*.proto' -type f -exec grep -Hn -e "^ " {} \; | tee /dev/stderr)" || \
|
||||
(echo "$(ONI) please indent proto files with tabs only" && false)
|
||||
@test -z "$$(find . -path ./vendor -prune -o -name '*.proto' -type f -exec grep -Hn "Meta meta = " {} \; | grep -v '(gogoproto.nullable) = false' | tee /dev/stderr)" || \
|
||||
(echo "$(ONI) meta fields in proto files must have option (gogoproto.nullable) = false" && false)
|
||||
|
||||
lint: ## run go lint
|
||||
@echo "$(WHALE) $@"
|
||||
@test -z "$$(golint ./... | grep -v vendor/ | grep -v ".pb.go:" | tee /dev/stderr)"
|
||||
|
||||
dco: ## dco check
|
||||
@which git-validation > /dev/null 2>/dev/null || (echo "ERROR: git-validation not found" && false)
|
||||
ifdef TRAVIS_COMMIT_RANGE
|
||||
git-validation -q -run DCO,short-subject,dangling-whitespace
|
||||
else
|
||||
git-validation -v -run DCO,short-subject,dangling-whitespace -range $(EPOCH_TEST_COMMIT)..HEAD
|
||||
endif
|
||||
|
||||
ineffassign: ## run ineffassign
|
||||
@echo "$(WHALE) $@"
|
||||
@test -z "$$(ineffassign . | grep -v vendor/ | grep -v ".pb.go:" | tee /dev/stderr)"
|
||||
|
||||
#errcheck: ## run go errcheck
|
||||
# @echo "$(WHALE) $@"
|
||||
# @test -z "$$(errcheck ./... | grep -v vendor/ | grep -v ".pb.go:" | tee /dev/stderr)"
|
||||
|
||||
build: ## build the go packages
|
||||
@echo "$(WHALE) $@"
|
||||
@go build -i -v ${EXTRA_FLAGS} ${GO_LDFLAGS} ${GO_GCFLAGS} ${PACKAGES}
|
||||
|
||||
test: ## run tests, except integration tests and tests that require root
|
||||
@echo "$(WHALE) $@"
|
||||
@go test ${TESTFLAGS} $(filter-out ${INTEGRATION_PACKAGE},${PACKAGES})
|
||||
|
||||
root-test: ## run tests, except integration tests
|
||||
@echo "$(WHALE) $@"
|
||||
@go test ${TESTFLAGS} ${SNAPSHOT_PACKAGES} -test.root
|
||||
|
||||
integration: ## run integration tests
|
||||
@echo "$(WHALE) $@"
|
||||
@go test ${TESTFLAGS}
|
||||
|
||||
FORCE:
|
||||
|
||||
# Build a binary from a cmd.
|
||||
bin/%: cmd/% FORCE
|
||||
@echo "$(WHALE) $@${BINARY_SUFFIX}"
|
||||
@go build -i -o $@${BINARY_SUFFIX} ${GO_LDFLAGS} ${GO_TAGS} ${GO_GCFLAGS} ./$<
|
||||
|
||||
binaries: $(BINARIES) ## build binaries
|
||||
@echo "$(WHALE) $@"
|
||||
|
||||
clean: ## clean up binaries
|
||||
@echo "$(WHALE) $@"
|
||||
@rm -f $(BINARIES)
|
||||
|
||||
install: ## install binaries
|
||||
@echo "$(WHALE) $@ $(BINARIES)"
|
||||
@mkdir -p $(DESTDIR)/bin
|
||||
@install $(BINARIES) $(DESTDIR)/bin
|
||||
|
||||
uninstall:
|
||||
@echo "$(WHALE) $@"
|
||||
@rm -f $(addprefix $(DESTDIR)/bin/,$(notdir $(BINARIES)))
|
||||
|
||||
|
||||
coverage: ## generate coverprofiles from the unit tests, except tests that require root
|
||||
@echo "$(WHALE) $@"
|
||||
@rm -f coverage.txt
|
||||
( for pkg in $(filter-out ${INTEGRATION_PACKAGE},${PACKAGES}); do \
|
||||
go test -i ${TESTFLAGS} -test.short -coverprofile=coverage.out -covermode=atomic $$pkg || exit; \
|
||||
if [ -f profile.out ]; then \
|
||||
cat profile.out >> coverage.txt; \
|
||||
rm profile.out; \
|
||||
fi; \
|
||||
go test ${TESTFLAGS} -test.short -coverprofile=coverage.out -covermode=atomic $$pkg || exit; \
|
||||
if [ -f profile.out ]; then \
|
||||
cat profile.out >> coverage.txt; \
|
||||
rm profile.out; \
|
||||
fi; \
|
||||
done )
|
||||
|
||||
root-coverage: ## generae coverage profiles for the unit tests
|
||||
@echo "$(WHALE) $@"
|
||||
@( for pkg in ${SNAPSHOT_PACKAGES}; do \
|
||||
go test -i ${TESTFLAGS} -test.short -coverprofile="../../../$$pkg/coverage.txt" -covermode=atomic $$pkg -test.root || exit; \
|
||||
go test ${TESTFLAGS} -test.short -coverprofile="../../../$$pkg/coverage.txt" -covermode=atomic $$pkg -test.root || exit; \
|
||||
done )
|
||||
|
||||
coverage-integration: ## generate coverprofiles from the integration tests
|
||||
@echo "$(WHALE) $@"
|
||||
go test ${TESTFLAGS} -test.short -coverprofile="../../../${INTEGRATION_PACKAGE}/coverage.txt" -covermode=atomic ${INTEGRATION_PACKAGE}
|
||||
|
||||
vendor:
|
||||
@echo "$(WHALE) $@"
|
||||
@vndr
|
||||
|
||||
help: ## this help
|
||||
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort
|
||||
142
vendor/github.com/containerd/containerd/README.md
generated
vendored
Normal file
142
vendor/github.com/containerd/containerd/README.md
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||

|
||||
|
||||
[](https://travis-ci.org/containerd/containerd)
|
||||
[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fcontainerd%2Fcontainerd?ref=badge_shield)
|
||||
|
||||
containerd is an industry-standard container runtime with an emphasis on simplicity, robustness and portability. It is available as a daemon for Linux and Windows, which can manage the complete container lifecycle of its host system: image transfer and storage, container execution and supervision, low-level storage and network attachments, etc..
|
||||
|
||||
containerd is designed to be embedded into a larger system, rather than being used directly by developers or end-users.
|
||||
|
||||
### State of the Project
|
||||
|
||||
containerd currently has two active branches.
|
||||
There is a [v0.2.x](https://github.com/containerd/containerd/tree/v0.2.x) branch for the current release of containerd that is being consumed by Docker and others and the master branch is the development branch for the 1.0 roadmap and feature set.
|
||||
Any PR or issue that is intended for the current v0.2.x release should be tagged with the same `v0.2.x` tag.
|
||||
|
||||
### 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 a community slack with a #containerd channel that everyone is welcome to join and chat about development.
|
||||
|
||||
**Slack:** https://dockr.ly/community
|
||||
|
||||
### Developer Quick-Start
|
||||
|
||||
To build the daemon and `ctr` simple test client, the following build system dependencies are required:
|
||||
|
||||
* Go 1.8.x or above (requires 1.8 due to use of golang plugin(s))
|
||||
* Protoc 3.x compiler and headers (download at the [Google protobuf releases page](https://github.com/google/protobuf/releases))
|
||||
* Btrfs headers and libraries for your distribution. Note that building the btrfs driver can be disabled via build tag removing this dependency.
|
||||
|
||||
For proper results, install the `protoc` release into `/usr/local` on your build system. For example, the following commands will download and install the 3.1.0 release for a 64-bit Linux host:
|
||||
|
||||
```
|
||||
$ wget -c https://github.com/google/protobuf/releases/download/v3.1.0/protoc-3.1.0-linux-x86_64.zip
|
||||
$ sudo unzip protoc-3.1.0-linux-x86_64.zip -d /usr/local
|
||||
```
|
||||
|
||||
With the required dependencies installed, the `Makefile` target named **binaries** will compile the `ctr` and `containerd` binaries and place them in the `bin/` directory. Using `sudo make install` will place the binaries in `/usr/local/bin`. When making any changes to the gRPC API, `make generate` will use the installed `protoc` compiler to regenerate the API generated code packages.
|
||||
|
||||
> *Note*: A build tag is currently available to disable building the btrfs snapshot driver.
|
||||
> Adding `BUILDTAGS=no_btrfs` to your environment before calling the **binaries**
|
||||
> Makefile target will disable the btrfs driver within the containerd Go build.
|
||||
|
||||
Vendoring of external imports uses the [`vndr` tool](https://github.com/LK4D4/vndr) which uses a simple config file, `vendor.conf`, to provide the URL and version or hash details for each vendored import. After modifying `vendor.conf` run the `vndr` tool to update the `vendor/` directory contents. Combining the `vendor.conf` update with the changeset in `vendor/` after running `vndr` should become a single commit for a PR which relies on vendored updates.
|
||||
|
||||
Please refer to [RUNC.md](/RUNC.md) for the currently supported version of `runc` that is used by containerd.
|
||||
|
||||
## Features
|
||||
|
||||
* OCI Image Spec support
|
||||
* OCI Runtime Spec support
|
||||
* Image push and pull support
|
||||
* Container runtime and lifecycle support
|
||||
* Management of network namespaces containers to join existing namespaces
|
||||
* Multi-tenant supported with CAS storage for global images
|
||||
|
||||
## Scope and Principles
|
||||
|
||||
Having a clearly defined scope of a project is important for ensuring consistency and focus.
|
||||
These following criteria will be used when reviewing pull requests, features, and changes for the project before being accepted.
|
||||
|
||||
### Components
|
||||
|
||||
Components should not have tight dependencies on each other so that they are able to be used independently.
|
||||
The APIs for images and containers should be designed in a way that when used together the components have a natural flow but still be useful independently.
|
||||
|
||||
An example for this design can be seen with the overlay filesystems and the container execution layer.
|
||||
The execution layer and overlay filesystems can be used independently but if you were to use both, they share a common `Mount` struct that the filesystems produce and the execution layer consumes.
|
||||
|
||||
### Primitives
|
||||
|
||||
containerd should expose primitives to solve problems instead of building high level abstractions in the API.
|
||||
A common example of this is how build would be implemented.
|
||||
Instead of having a build API in containerd we should expose the lower level primitives that allow things required in build to work.
|
||||
Breaking up the filesystem APIs to allow snapshots, copy functionality, and mounts allow people implementing build at the higher levels more flexibility.
|
||||
|
||||
### Extensibility and Defaults
|
||||
|
||||
For the various components in containerd there should be defined extension points where implementations can be swapped for alternatives.
|
||||
The best example of this is that containerd will use `runc` from OCI as the default runtime in the execution layer but other runtimes conforming to the OCI Runtime specification they can be easily added to containerd.
|
||||
|
||||
containerd will come with a default implementation for the various components.
|
||||
These defaults will be chosen by the maintainers of the project and should not change unless better tech for that component comes out.
|
||||
Additional implementations will not be accepted into the core repository and should be developed in a separate repository not maintained by the containerd maintainers.
|
||||
|
||||
### Releases
|
||||
|
||||
containerd will be released with a 1.0 when feature complete and this version will be supported for 1 year with security and bug fixes applied and released.
|
||||
|
||||
The upgrade path for containerd is that the 0.0.x patch releases are always backward compatible with its major and minor version.
|
||||
Minor (0.x.0) version will always be compatible with the previous minor release. i.e. 1.2.0 is backwards compatible with 1.1.0 and 1.1.0 is compatible with 1.0.0.
|
||||
There is no compatibility guarantees with upgrades from two minor releases. i.e. 1.0.0 to 1.2.0.
|
||||
|
||||
There are not backwards compatibility guarantees with upgrades to major versions. i.e 1.0.0 to 2.0.0.
|
||||
Each major version will be supported for 1 year with bug fixes and security patches.
|
||||
|
||||
### Scope
|
||||
|
||||
The following table specifies the various components of containerd and general features of container runtimes.
|
||||
The table specifies whether or not the feature/component is in or out of scope.
|
||||
|
||||
| Name | Description | In/Out | Reason |
|
||||
|------------------------------|--------------------------------------------------------------------------------------------------------|--------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| execution | Provide an extensible execution layer for executing a container | in | Create,start, stop pause, resume exec, signal, delete |
|
||||
| cow filesystem | Built in functionality for overlay, aufs, and other copy on write filesystems for containers | in | |
|
||||
| distribution | Having the ability to push and pull images as well as operations on images as a first class API object | in | containerd will fully support the management and retrieval of images |
|
||||
| metrics | container-level metrics, cgroup stats, and OOM events | in |
|
||||
| networking | creation and management of network interfaces | out | Networking will be handled and provided to containerd via higher level systems. |
|
||||
| build | Building images as a first class API | out | Build is a higher level tooling feature and can be implemented in many different ways on top of containerd |
|
||||
| volumes | Volume management for external data | out | The API supports mounts, binds, etc where all volumes type systems can be built on top of containerd. |
|
||||
| logging | Persisting container logs | out | Logging can be build on top of containerd because the container’s STDIO will be provided to the clients and they can persist any way they see fit. There is no io copying of container STDIO in containerd. |
|
||||
|
||||
|
||||
containerd is scoped to a single host and makes assumptions based on that fact.
|
||||
It can be used to build things like a node agent that launches containers but does not have any concepts of a distributed system.
|
||||
|
||||
containerd is designed to be embedded into a larger system, hence it only includes a barebone CLI (`ctr`) specifically for development and debugging purpose, with no mandate to be human-friendly, and no guarantee of interface stability over time.
|
||||
|
||||
Also things like service discovery are out of scope even though networking is in scope.
|
||||
containerd should provide the primitives to create, add, remove, or manage network interfaces and network namespaces for a container but IP allocation, discovery, and DNS should be handled at higher layers.
|
||||
|
||||
### How is the scope changed?
|
||||
|
||||
The scope of this project is a whitelist.
|
||||
If it's not mentioned as being in scope, it is out of scope.
|
||||
For the scope of this project to change it requires a 100% vote from all maintainers of the project.
|
||||
|
||||
### Development reports.
|
||||
|
||||
Weekly summary on the progress and what is being worked on.
|
||||
https://github.com/containerd/containerd/tree/master/reports
|
||||
|
||||
## Copyright and license
|
||||
|
||||
Copyright © 2016 Docker, Inc. All rights reserved, except as follows. Code
|
||||
is released under the Apache 2.0 license. The README.md file, and files in the
|
||||
"docs" folder are licensed under the Creative Commons Attribution 4.0
|
||||
International License under the terms and conditions set forth in the file
|
||||
"LICENSE.docs". You may obtain a duplicate copy of the same license, titled
|
||||
CC-BY-SA-4.0, at http://creativecommons.org/licenses/by/4.0/.
|
||||
78
vendor/github.com/containerd/containerd/ROADMAP.md
generated
vendored
Normal file
78
vendor/github.com/containerd/containerd/ROADMAP.md
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
# containerd roadmap
|
||||
|
||||
This is a high level roadmap for the project that outlines what is currently being worked on, what comes next, and where you can help.
|
||||
|
||||
For a more up to date look please review the milestones on [github](https://github.com/containerd/containerd/milestones).
|
||||
|
||||
The following are the different status the various phases of development can be in:
|
||||
* Not Started - no work or thinking has been done towards the goal
|
||||
* In Design - design work has started for the component and you can find design documents in the `design` folder
|
||||
* In Progress - design has mostly finished and development has started
|
||||
* Completed - the development work has been completed
|
||||
* Stable - the apis for the phase are feature complete and considered stable
|
||||
|
||||
We would like to follow the roadmap and develop the components one by one to completion before starting the next phase. If PRs are opened for another phase before the previous phase has been completed they will be closed as we are not ready for them at that time.
|
||||
|
||||
## Phase 1
|
||||
|
||||
**Status:** In Progress
|
||||
|
||||
### GRPC API
|
||||
|
||||
**Documents:**
|
||||
|
||||
We are going from a top down design for filling out this missing pieces of containerd and design of the API.
|
||||
|
||||
### Design
|
||||
|
||||
**Documents:**
|
||||
|
||||
The high level design work is needed so that the architecture of containerd stays consistent throughout the development process.
|
||||
|
||||
### Build & Test Process
|
||||
|
||||
**Documents:**
|
||||
|
||||
We need to have a simple build and test process for new developers to bootstrap their environments.
|
||||
Because containerd will be the base of many high level systems we need to have a simple build process that does
|
||||
not require high level tooling.
|
||||
|
||||
## Phase 2
|
||||
|
||||
Phase 2 includes most of the design and development work for the execution and storage layers of containerd.
|
||||
It will include porting over existing "graph drivers" from Docker Engine and finding a common model for representing snapshots for layered filesystems.
|
||||
|
||||
This will also include moving the existing execution code support OCI's Runtime Spec and the existing containerd execution code.
|
||||
|
||||
**Status:** In Design
|
||||
|
||||
### Runtime
|
||||
|
||||
The runtime layer is responsible for the creation of containers and their management, and supervision of the processes inside those containers.
|
||||
|
||||
### Storage
|
||||
|
||||
**Documents:** https://github.com/containerd/containerd/blob/master/design/snapshots.md
|
||||
|
||||
The current graph drivers were built when we only had overlay filesystems like aufs.
|
||||
We forced the model to be designed around overlay filesystems and this introduced a lot of complexity for snapshotting graph drivers like btrfs and devicemapper thin-p.
|
||||
Our current approach is to model our storage layer after snapshotting drivers instead of overlay drivers as we can get the same results and its cleaner and more robust to have an overlay filesytem model snapshots than it is to have a snapshot filesystem model overlay filesystems.
|
||||
|
||||
## Phase 3
|
||||
|
||||
This phase includes getting support for the OCI Image spec built into containerd.
|
||||
|
||||
**Status:** Not Started
|
||||
|
||||
### Distribution
|
||||
|
||||
## Phase 4
|
||||
|
||||
Phase 4 involves graduating to version 1.0, and shifting the focus from features to maintenance. Graduating to 1.0 implies:
|
||||
|
||||
- Completing all of the above phases.
|
||||
- Covering the functionalities required by a majority of container-centric platforms.
|
||||
- Offering feature parity, to the extent of technical possibilities, across Linux and Windows.
|
||||
- Demonstrating that containerd fulfills the requirements of at least one higher-level platforms through its complete integration as an upstream.
|
||||
|
||||
**Status:** Not Started
|
||||
21
vendor/github.com/containerd/containerd/RUNC.md
generated
vendored
Normal file
21
vendor/github.com/containerd/containerd/RUNC.md
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
containerd is built with OCI support and with support for advanced features provided by `runc`.
|
||||
|
||||
We depend on a specific runc version when dealing with advanced features. You should have a specific build for development. The current supported runc commit is:
|
||||
|
||||
RUNC_COMMIT = 50401b5b4c2e01e4f1372b73a021742deeaf4e2d
|
||||
|
||||
## building
|
||||
|
||||
### apparmor
|
||||
|
||||
```bash
|
||||
make BUILDTAGS='seccomp apparmor' && sudo make install
|
||||
```
|
||||
|
||||
### selinux
|
||||
|
||||
```bash
|
||||
make BUILDTAGS='seccomp selinux' && sudo make install
|
||||
```
|
||||
|
||||
After an official runc release we will start pinning containerd support to a specific version but various development and testing features may require a newer runc version than the latest release. If you encounter any runtime errors, please make sure your runc is in sync with the commit/tag provided in this document.
|
||||
2008
vendor/github.com/containerd/containerd/api/services/namespaces/namespace.pb.go
generated
vendored
Normal file
2008
vendor/github.com/containerd/containerd/api/services/namespaces/namespace.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
88
vendor/github.com/containerd/containerd/api/services/namespaces/namespace.proto
generated
vendored
Normal file
88
vendor/github.com/containerd/containerd/api/services/namespaces/namespace.proto
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package containerd.v1.namespaces;
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
import "google/protobuf/empty.proto";
|
||||
import "google/protobuf/field_mask.proto";
|
||||
|
||||
// Namespaces provides the ability to manipulate containerd namespaces.
|
||||
//
|
||||
// All objects in the system are required to be a member of a namespace. If a
|
||||
// namespace is deleted, all objects, including containers, images and
|
||||
// snapshots, will be deleted, as well.
|
||||
//
|
||||
// Unless otherwise noted, operations in containerd apply only to the namespace
|
||||
// supplied per request.
|
||||
//
|
||||
// I hope this goes without saying, but namespaces are themselves NOT
|
||||
// namespaced.
|
||||
service Namespaces {
|
||||
rpc Get(GetNamespaceRequest) returns (GetNamespaceResponse);
|
||||
rpc List(ListNamespacesRequest) returns (ListNamespacesResponse);
|
||||
rpc Create(CreateNamespaceRequest) returns (CreateNamespaceResponse);
|
||||
rpc Update(UpdateNamespaceRequest) returns (UpdateNamespaceResponse);
|
||||
rpc Delete(DeleteNamespaceRequest) returns (google.protobuf.Empty);
|
||||
}
|
||||
|
||||
message Namespace {
|
||||
string name = 1;
|
||||
|
||||
// Labels provides an area to include arbitrary data on namespaces.
|
||||
//
|
||||
// Note that to add a new value to this field, read the existing set and
|
||||
// include the entire result in the update call.
|
||||
map<string, string> labels = 2;
|
||||
}
|
||||
|
||||
message GetNamespaceRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message GetNamespaceResponse {
|
||||
Namespace namespace = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message ListNamespacesRequest {
|
||||
string filter = 1; // TODO(stevvooe): Define a filtering syntax to make these queries.
|
||||
}
|
||||
|
||||
message ListNamespacesResponse {
|
||||
repeated Namespace namespaces = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message CreateNamespaceRequest {
|
||||
Namespace namespace = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message CreateNamespaceResponse {
|
||||
Namespace namespace = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// UpdateNamespaceRequest updates the metadata for a namespace.
|
||||
//
|
||||
// The operation should follow semantics described in
|
||||
// https://developers.google.com/protocol-buffers/docs/reference/csharp/class/google/protobuf/well-known-types/field-mask,
|
||||
// unless otherwise qualified.
|
||||
message UpdateNamespaceRequest {
|
||||
// Namespace provides the target value, as declared by the mask, for the update.
|
||||
//
|
||||
// The namespace field must be set.
|
||||
Namespace namespace = 1 [(gogoproto.nullable) = false];
|
||||
|
||||
// UpdateMask specifies which fields to perform the update on. If empty,
|
||||
// the operation applies to all fields.
|
||||
//
|
||||
// For the most part, this applies only to selectively updating labels on
|
||||
// the namespace. While field masks are typically limited to ascii alphas
|
||||
// and digits, we just take everything after the "labels." as the map key.
|
||||
google.protobuf.FieldMask update_mask = 2;
|
||||
}
|
||||
|
||||
message UpdateNamespaceResponse {
|
||||
Namespace namespace = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message DeleteNamespaceRequest {
|
||||
string name = 1;
|
||||
}
|
||||
482
vendor/github.com/containerd/containerd/client.go
generated
vendored
Normal file
482
vendor/github.com/containerd/containerd/client.go
generated
vendored
Normal file
@@ -0,0 +1,482 @@
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/api/services/containers"
|
||||
contentapi "github.com/containerd/containerd/api/services/content"
|
||||
diffapi "github.com/containerd/containerd/api/services/diff"
|
||||
"github.com/containerd/containerd/api/services/execution"
|
||||
imagesapi "github.com/containerd/containerd/api/services/images"
|
||||
namespacesapi "github.com/containerd/containerd/api/services/namespaces"
|
||||
snapshotapi "github.com/containerd/containerd/api/services/snapshot"
|
||||
versionservice "github.com/containerd/containerd/api/services/version"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
"github.com/containerd/containerd/remotes/docker/schema1"
|
||||
contentservice "github.com/containerd/containerd/services/content"
|
||||
"github.com/containerd/containerd/services/diff"
|
||||
diffservice "github.com/containerd/containerd/services/diff"
|
||||
imagesservice "github.com/containerd/containerd/services/images"
|
||||
snapshotservice "github.com/containerd/containerd/services/snapshot"
|
||||
"github.com/containerd/containerd/snapshot"
|
||||
pempty "github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/opencontainers/image-spec/identity"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/health/grpc_health_v1"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// reset the grpc logger so that it does not output in the STDIO of the calling process
|
||||
grpclog.SetLogger(log.New(ioutil.Discard, "", log.LstdFlags))
|
||||
}
|
||||
|
||||
type clientOpts struct {
|
||||
defaultns string
|
||||
}
|
||||
|
||||
type ClientOpt func(c *clientOpts) error
|
||||
|
||||
func WithDefaultNamespace(ns string) ClientOpt {
|
||||
return func(c *clientOpts) error {
|
||||
c.defaultns = ns
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// New returns a new containerd client that is connected to the containerd
|
||||
// instance provided by address
|
||||
func New(address string, opts ...ClientOpt) (*Client, error) {
|
||||
var copts clientOpts
|
||||
for _, o := range opts {
|
||||
if err := o(&copts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
gopts := []grpc.DialOption{
|
||||
grpc.WithInsecure(),
|
||||
grpc.WithTimeout(100 * time.Second),
|
||||
grpc.WithDialer(dialer),
|
||||
}
|
||||
if copts.defaultns != "" {
|
||||
unary, stream := newNSInterceptors(copts.defaultns)
|
||||
gopts = append(gopts,
|
||||
grpc.WithUnaryInterceptor(unary),
|
||||
grpc.WithStreamInterceptor(stream),
|
||||
)
|
||||
}
|
||||
|
||||
conn, err := grpc.Dial(dialAddress(address), gopts...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to dial %q", address)
|
||||
}
|
||||
return &Client{
|
||||
conn: conn,
|
||||
runtime: runtime.GOOS,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Client is the client to interact with containerd and its various services
|
||||
// using a uniform interface
|
||||
type Client struct {
|
||||
conn *grpc.ClientConn
|
||||
|
||||
defaultns string
|
||||
runtime string
|
||||
}
|
||||
|
||||
func (c *Client) IsServing(ctx context.Context) (bool, error) {
|
||||
r, err := c.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return r.Status == grpc_health_v1.HealthCheckResponse_SERVING, nil
|
||||
}
|
||||
|
||||
// Containers returns all containers created in containerd
|
||||
func (c *Client) Containers(ctx context.Context) ([]Container, error) {
|
||||
r, err := c.ContainerService().List(ctx, &containers.ListContainersRequest{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out []Container
|
||||
for _, container := range r.Containers {
|
||||
out = append(out, containerFromProto(c, container))
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
type NewContainerOpts func(ctx context.Context, client *Client, c *containers.Container) error
|
||||
|
||||
// WithContainerLabels adds the provided labels to the container
|
||||
func WithContainerLabels(labels map[string]string) NewContainerOpts {
|
||||
return func(_ context.Context, _ *Client, c *containers.Container) error {
|
||||
c.Labels = labels
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithExistingRootFS uses an existing root filesystem for the container
|
||||
func WithExistingRootFS(id string) NewContainerOpts {
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
// check that the snapshot exists, if not, fail on creation
|
||||
if _, err := client.SnapshotService().Mounts(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
c.RootFS = id
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithNewRootFS allocates a new snapshot to be used by the container as the
|
||||
// root filesystem in read-write mode
|
||||
func WithNewRootFS(id string, i Image) NewContainerOpts {
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := client.SnapshotService().Prepare(ctx, id, identity.ChainID(diffIDs).String()); err != nil {
|
||||
return err
|
||||
}
|
||||
c.RootFS = id
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithNewReadonlyRootFS allocates a new snapshot to be used by the container as the
|
||||
// root filesystem in read-only mode
|
||||
func WithNewReadonlyRootFS(id string, i Image) NewContainerOpts {
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := client.SnapshotService().View(ctx, id, identity.ChainID(diffIDs).String()); err != nil {
|
||||
return err
|
||||
}
|
||||
c.RootFS = id
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithRuntime(name string) NewContainerOpts {
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
c.Runtime = name
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithImage(i Image) NewContainerOpts {
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
c.Image = i.Name()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewContainer will create a new container in container with the provided id
|
||||
// the id must be unique within the namespace
|
||||
func (c *Client) NewContainer(ctx context.Context, id string, opts ...NewContainerOpts) (Container, error) {
|
||||
container := containers.Container{
|
||||
ID: id,
|
||||
Runtime: c.runtime,
|
||||
}
|
||||
for _, o := range opts {
|
||||
if err := o(ctx, c, &container); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
r, err := c.ContainerService().Create(ctx, &containers.CreateContainerRequest{
|
||||
Container: container,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return containerFromProto(c, r.Container), nil
|
||||
}
|
||||
|
||||
func (c *Client) LoadContainer(ctx context.Context, id string) (Container, error) {
|
||||
response, err := c.ContainerService().Get(ctx, &containers.GetContainerRequest{
|
||||
ID: id,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return containerFromProto(c, response.Container), nil
|
||||
}
|
||||
|
||||
type RemoteOpts func(*Client, *RemoteContext) error
|
||||
|
||||
// RemoteContext is used to configure object resolutions and transfers with
|
||||
// remote content stores and image providers.
|
||||
type RemoteContext struct {
|
||||
// Resolver is used to resolve names to objects, fetchers, and pushers.
|
||||
// If no resolver is provided, defaults to Docker registry resolver.
|
||||
Resolver remotes.Resolver
|
||||
|
||||
// Unpack is done after an image is pulled to extract into a snapshotter.
|
||||
// If an image is not unpacked on pull, it can be unpacked any time
|
||||
// afterwards. Unpacking is required to run an image.
|
||||
Unpack bool
|
||||
|
||||
// BaseHandlers are a set of handlers which get are called on dispatch.
|
||||
// These handlers always get called before any operation specific
|
||||
// handlers.
|
||||
BaseHandlers []images.Handler
|
||||
|
||||
// ConvertSchema1 is whether to convert Docker registry schema 1
|
||||
// manifests. If this option is false then any image which resolves
|
||||
// to schema 1 will return an error since schema 1 is not supported.
|
||||
ConvertSchema1 bool
|
||||
}
|
||||
|
||||
func defaultRemoteContext() *RemoteContext {
|
||||
return &RemoteContext{
|
||||
Resolver: docker.NewResolver(docker.ResolverOptions{
|
||||
Client: http.DefaultClient,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// WithPullUnpack is used to unpack an image after pull. This
|
||||
// uses the snapshotter, content store, and diff service
|
||||
// configured for the client.
|
||||
func WithPullUnpack(client *Client, c *RemoteContext) error {
|
||||
c.Unpack = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithSchema1Conversion is used to convert Docker registry schema 1
|
||||
// manifests to oci manifests on pull. Without this option schema 1
|
||||
// manifests will return a not supported error.
|
||||
func WithSchema1Conversion(client *Client, c *RemoteContext) error {
|
||||
c.ConvertSchema1 = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithResolver specifies the resolver to use.
|
||||
func WithResolver(resolver remotes.Resolver) RemoteOpts {
|
||||
return func(client *Client, c *RemoteContext) error {
|
||||
c.Resolver = resolver
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithImageHandler adds a base handler to be called on dispatch.
|
||||
func WithImageHandler(h images.Handler) RemoteOpts {
|
||||
return func(client *Client, c *RemoteContext) error {
|
||||
c.BaseHandlers = append(c.BaseHandlers, h)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpts) (Image, error) {
|
||||
pullCtx := defaultRemoteContext()
|
||||
for _, o := range opts {
|
||||
if err := o(c, pullCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
store := c.ContentStore()
|
||||
|
||||
name, desc, err := pullCtx.Resolver.Resolve(ctx, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fetcher, err := pullCtx.Resolver.Fetcher(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
schema1Converter *schema1.Converter
|
||||
handler images.Handler
|
||||
)
|
||||
if desc.MediaType == images.MediaTypeDockerSchema1Manifest && pullCtx.ConvertSchema1 {
|
||||
schema1Converter = schema1.NewConverter(store, fetcher)
|
||||
handler = images.Handlers(append(pullCtx.BaseHandlers, schema1Converter)...)
|
||||
} else {
|
||||
handler = images.Handlers(append(pullCtx.BaseHandlers,
|
||||
remotes.FetchHandler(store, fetcher),
|
||||
images.ChildrenHandler(store))...,
|
||||
)
|
||||
}
|
||||
|
||||
if err := images.Dispatch(ctx, handler, desc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if schema1Converter != nil {
|
||||
desc, err = schema1Converter.Convert(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
is := c.ImageService()
|
||||
if err := is.Put(ctx, name, desc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i, err := is.Get(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
img := &image{
|
||||
client: c,
|
||||
i: i,
|
||||
}
|
||||
if pullCtx.Unpack {
|
||||
if err := img.Unpack(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return img, nil
|
||||
}
|
||||
|
||||
func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor, opts ...RemoteOpts) error {
|
||||
pushCtx := defaultRemoteContext()
|
||||
for _, o := range opts {
|
||||
if err := o(c, pushCtx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
pusher, err := pushCtx.Resolver.Pusher(ctx, ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var m sync.Mutex
|
||||
manifestStack := []ocispec.Descriptor{}
|
||||
|
||||
filterHandler := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
switch desc.MediaType {
|
||||
case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest,
|
||||
images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
|
||||
m.Lock()
|
||||
manifestStack = append(manifestStack, desc)
|
||||
m.Unlock()
|
||||
return nil, images.StopHandler
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
})
|
||||
|
||||
cs := c.ContentStore()
|
||||
pushHandler := remotes.PushHandler(cs, pusher)
|
||||
|
||||
handlers := append(pushCtx.BaseHandlers,
|
||||
images.ChildrenHandler(cs),
|
||||
filterHandler,
|
||||
pushHandler,
|
||||
)
|
||||
|
||||
if err := images.Dispatch(ctx, images.Handlers(handlers...), desc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Iterate in reverse order as seen, parent always uploaded after child
|
||||
for i := len(manifestStack) - 1; i >= 0; i-- {
|
||||
_, err := pushHandler(ctx, manifestStack[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetImage returns an existing image
|
||||
func (c *Client) GetImage(ctx context.Context, ref string) (Image, error) {
|
||||
i, err := c.ImageService().Get(ctx, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &image{
|
||||
client: c,
|
||||
i: i,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ListImages returns all existing images
|
||||
func (c *Client) ListImages(ctx context.Context) ([]Image, error) {
|
||||
imgs, err := c.ImageService().List(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
images := make([]Image, len(imgs))
|
||||
for i, img := range imgs {
|
||||
images[i] = &image{
|
||||
client: c,
|
||||
i: img,
|
||||
}
|
||||
}
|
||||
return images, nil
|
||||
}
|
||||
|
||||
// Close closes the clients connection to containerd
|
||||
func (c *Client) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
func (c *Client) NamespaceService() namespacesapi.NamespacesClient {
|
||||
return namespacesapi.NewNamespacesClient(c.conn)
|
||||
}
|
||||
|
||||
func (c *Client) ContainerService() containers.ContainersClient {
|
||||
return containers.NewContainersClient(c.conn)
|
||||
}
|
||||
|
||||
func (c *Client) ContentStore() content.Store {
|
||||
return contentservice.NewStoreFromClient(contentapi.NewContentClient(c.conn))
|
||||
}
|
||||
|
||||
func (c *Client) SnapshotService() snapshot.Snapshotter {
|
||||
return snapshotservice.NewSnapshotterFromClient(snapshotapi.NewSnapshotClient(c.conn))
|
||||
}
|
||||
|
||||
func (c *Client) TaskService() execution.TasksClient {
|
||||
return execution.NewTasksClient(c.conn)
|
||||
}
|
||||
|
||||
func (c *Client) ImageService() images.Store {
|
||||
return imagesservice.NewStoreFromClient(imagesapi.NewImagesClient(c.conn))
|
||||
}
|
||||
|
||||
func (c *Client) DiffService() diff.DiffService {
|
||||
return diffservice.NewDiffServiceFromClient(diffapi.NewDiffClient(c.conn))
|
||||
}
|
||||
|
||||
func (c *Client) HealthService() grpc_health_v1.HealthClient {
|
||||
return grpc_health_v1.NewHealthClient(c.conn)
|
||||
}
|
||||
|
||||
func (c *Client) VersionService() versionservice.VersionClient {
|
||||
return versionservice.NewVersionClient(c.conn)
|
||||
}
|
||||
|
||||
type Version struct {
|
||||
Version string
|
||||
Revision string
|
||||
}
|
||||
|
||||
func (c *Client) Version(ctx context.Context) (Version, error) {
|
||||
response, err := c.VersionService().Version(ctx, &pempty.Empty{})
|
||||
if err != nil {
|
||||
return Version{}, err
|
||||
}
|
||||
return Version{
|
||||
Version: response.Version,
|
||||
Revision: response.Revision,
|
||||
}, nil
|
||||
}
|
||||
19
vendor/github.com/containerd/containerd/client_unix.go
generated
vendored
Normal file
19
vendor/github.com/containerd/containerd/client_unix.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// +build !windows
|
||||
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func dialer(address string, timeout time.Duration) (net.Conn, error) {
|
||||
address = strings.TrimPrefix(address, "unix://")
|
||||
return net.DialTimeout("unix", address, timeout)
|
||||
}
|
||||
|
||||
func dialAddress(address string) string {
|
||||
return fmt.Sprintf("unix://%s", address)
|
||||
}
|
||||
16
vendor/github.com/containerd/containerd/client_windows.go
generated
vendored
Normal file
16
vendor/github.com/containerd/containerd/client_windows.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
winio "github.com/Microsoft/go-winio"
|
||||
)
|
||||
|
||||
func dialer(address string, timeout time.Duration) (net.Conn, error) {
|
||||
return winio.DialPipe(address, &timeout)
|
||||
}
|
||||
|
||||
func dialAddress(address string) string {
|
||||
return address
|
||||
}
|
||||
3
vendor/github.com/containerd/containerd/code-of-conduct.md
generated
vendored
Normal file
3
vendor/github.com/containerd/containerd/code-of-conduct.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
## containerd Community Code of Conduct
|
||||
|
||||
containerd follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
|
||||
222
vendor/github.com/containerd/containerd/container.go
generated
vendored
Normal file
222
vendor/github.com/containerd/containerd/container.go
generated
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
|
||||
"github.com/containerd/containerd/api/services/containers"
|
||||
"github.com/containerd/containerd/api/services/execution"
|
||||
"github.com/containerd/containerd/api/types/mount"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoImage = errors.New("container does not have an image")
|
||||
ErrNoRunningTask = errors.New("no running task")
|
||||
)
|
||||
|
||||
type Container interface {
|
||||
ID() string
|
||||
Proto() containers.Container
|
||||
Delete(context.Context) error
|
||||
NewTask(context.Context, IOCreation, ...NewTaskOpts) (Task, error)
|
||||
Spec() (*specs.Spec, error)
|
||||
Task(context.Context, IOAttach) (Task, error)
|
||||
Image(context.Context) (Image, error)
|
||||
}
|
||||
|
||||
func containerFromProto(client *Client, c containers.Container) *container {
|
||||
return &container{
|
||||
client: client,
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
var _ = (Container)(&container{})
|
||||
|
||||
type container struct {
|
||||
mu sync.Mutex
|
||||
|
||||
client *Client
|
||||
c containers.Container
|
||||
task *task
|
||||
}
|
||||
|
||||
// ID returns the container's unique id
|
||||
func (c *container) ID() string {
|
||||
return c.c.ID
|
||||
}
|
||||
|
||||
func (c *container) Proto() containers.Container {
|
||||
return c.c
|
||||
}
|
||||
|
||||
// Spec returns the current OCI specification for the container
|
||||
func (c *container) Spec() (*specs.Spec, error) {
|
||||
var s specs.Spec
|
||||
if err := json.Unmarshal(c.c.Spec.Value, &s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
// Delete deletes an existing container
|
||||
// an error is returned if the container has running tasks
|
||||
func (c *container) Delete(ctx context.Context) (err error) {
|
||||
// TODO: should the client be the one removing resources attached
|
||||
// to the container at the moment before we have GC?
|
||||
if c.c.RootFS != "" {
|
||||
err = c.client.SnapshotService().Remove(ctx, c.c.RootFS)
|
||||
}
|
||||
if _, cerr := c.client.ContainerService().Delete(ctx, &containers.DeleteContainerRequest{
|
||||
ID: c.c.ID,
|
||||
}); err == nil {
|
||||
err = cerr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *container) Task(ctx context.Context, attach IOAttach) (Task, error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if c.task == nil {
|
||||
t, err := c.loadTask(ctx, attach)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.task = t.(*task)
|
||||
}
|
||||
return c.task, nil
|
||||
}
|
||||
|
||||
// Image returns the image that the container is based on
|
||||
func (c *container) Image(ctx context.Context) (Image, error) {
|
||||
if c.c.Image == "" {
|
||||
return nil, ErrNoImage
|
||||
}
|
||||
i, err := c.client.ImageService().Get(ctx, c.c.Image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &image{
|
||||
client: c.client,
|
||||
i: i,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type NewTaskOpts func(context.Context, *Client, *execution.CreateRequest) error
|
||||
|
||||
func (c *container) NewTask(ctx context.Context, ioCreate IOCreation, opts ...NewTaskOpts) (Task, error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
i, err := ioCreate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request := &execution.CreateRequest{
|
||||
ContainerID: c.c.ID,
|
||||
Terminal: i.Terminal,
|
||||
Stdin: i.Stdin,
|
||||
Stdout: i.Stdout,
|
||||
Stderr: i.Stderr,
|
||||
}
|
||||
if c.c.RootFS != "" {
|
||||
// get the rootfs from the snapshotter and add it to the request
|
||||
mounts, err := c.client.SnapshotService().Mounts(ctx, c.c.RootFS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, m := range mounts {
|
||||
request.Rootfs = append(request.Rootfs, &mount.Mount{
|
||||
Type: m.Type,
|
||||
Source: m.Source,
|
||||
Options: m.Options,
|
||||
})
|
||||
}
|
||||
}
|
||||
for _, o := range opts {
|
||||
if err := o(ctx, c.client, request); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
t := &task{
|
||||
client: c.client,
|
||||
io: i,
|
||||
containerID: c.ID(),
|
||||
pidSync: make(chan struct{}),
|
||||
}
|
||||
|
||||
if request.Checkpoint != nil {
|
||||
// we need to defer the create call to start
|
||||
t.deferred = request
|
||||
} else {
|
||||
response, err := c.client.TaskService().Create(ctx, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.pid = response.Pid
|
||||
close(t.pidSync)
|
||||
}
|
||||
c.task = t
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (c *container) loadTask(ctx context.Context, ioAttach IOAttach) (Task, error) {
|
||||
response, err := c.client.TaskService().Info(ctx, &execution.InfoRequest{
|
||||
ContainerID: c.c.ID,
|
||||
})
|
||||
if err != nil {
|
||||
if grpc.Code(errors.Cause(err)) == codes.NotFound {
|
||||
return nil, ErrNoRunningTask
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
var i *IO
|
||||
if ioAttach != nil {
|
||||
// get the existing fifo paths from the task information stored by the daemon
|
||||
paths := &FifoSet{
|
||||
Dir: getFifoDir([]string{
|
||||
response.Task.Stdin,
|
||||
response.Task.Stdout,
|
||||
response.Task.Stderr,
|
||||
}),
|
||||
In: response.Task.Stdin,
|
||||
Out: response.Task.Stdout,
|
||||
Err: response.Task.Stderr,
|
||||
Terminal: response.Task.Terminal,
|
||||
}
|
||||
if i, err = ioAttach(paths); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// create and close a channel on load as we already have the pid
|
||||
// and don't want to block calls to Wait(), etc...
|
||||
ps := make(chan struct{})
|
||||
close(ps)
|
||||
t := &task{
|
||||
client: c.client,
|
||||
io: i,
|
||||
containerID: response.Task.ContainerID,
|
||||
pid: response.Task.Pid,
|
||||
pidSync: ps,
|
||||
}
|
||||
c.task = t
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// getFifoDir looks for any non-empty path for a stdio fifo
|
||||
// and returns the dir for where it is located
|
||||
func getFifoDir(paths []string) string {
|
||||
for _, p := range paths {
|
||||
if p != "" {
|
||||
return filepath.Dir(p)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
115
vendor/github.com/containerd/containerd/container_unix.go
generated
vendored
Normal file
115
vendor/github.com/containerd/containerd/container_unix.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
// +build !windows
|
||||
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/containerd/containerd/api/services/containers"
|
||||
"github.com/containerd/containerd/api/services/execution"
|
||||
"github.com/containerd/containerd/api/types/descriptor"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/snapshot"
|
||||
protobuf "github.com/gogo/protobuf/types"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"github.com/opencontainers/image-spec/identity"
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
func WithCheckpoint(desc v1.Descriptor, rootfsID string) NewContainerOpts {
|
||||
// set image and rw, and spec
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
id := desc.Digest
|
||||
store := client.ContentStore()
|
||||
index, err := decodeIndex(ctx, store, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var rw *v1.Descriptor
|
||||
for _, m := range index.Manifests {
|
||||
switch m.MediaType {
|
||||
case v1.MediaTypeImageLayer:
|
||||
fk := m
|
||||
rw = &fk
|
||||
case images.MediaTypeDockerSchema2Manifest:
|
||||
config, err := images.Config(ctx, store, m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
diffIDs, err := images.RootFS(ctx, store, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := client.SnapshotService().Prepare(ctx, rootfsID, identity.ChainID(diffIDs).String()); err != nil {
|
||||
if !snapshot.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
c.Image = index.Annotations["image.name"]
|
||||
case images.MediaTypeContainerd1CheckpointConfig:
|
||||
r, err := store.Reader(ctx, m.Digest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := ioutil.ReadAll(r)
|
||||
r.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Spec = &protobuf.Any{
|
||||
TypeUrl: specs.Version,
|
||||
Value: data,
|
||||
}
|
||||
}
|
||||
}
|
||||
if rw != nil {
|
||||
// apply the rw snapshot to the new rw layer
|
||||
mounts, err := client.SnapshotService().Mounts(ctx, rootfsID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := client.DiffService().Apply(ctx, *rw, mounts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
c.RootFS = rootfsID
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithTaskCheckpoint(desc v1.Descriptor) NewTaskOpts {
|
||||
return func(ctx context.Context, c *Client, r *execution.CreateRequest) error {
|
||||
id := desc.Digest
|
||||
index, err := decodeIndex(ctx, c.ContentStore(), id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, m := range index.Manifests {
|
||||
if m.MediaType == images.MediaTypeContainerd1Checkpoint {
|
||||
r.Checkpoint = &descriptor.Descriptor{
|
||||
MediaType: m.MediaType,
|
||||
Size_: m.Size,
|
||||
Digest: m.Digest,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("checkpoint not found in index %s", id)
|
||||
}
|
||||
}
|
||||
|
||||
func decodeIndex(ctx context.Context, store content.Store, id digest.Digest) (*v1.Index, error) {
|
||||
var index v1.Index
|
||||
r, err := store.Reader(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = json.NewDecoder(r).Decode(&index)
|
||||
r.Close()
|
||||
return &index, err
|
||||
}
|
||||
35
vendor/github.com/containerd/containerd/grpc.go
generated
vendored
Normal file
35
vendor/github.com/containerd/containerd/grpc.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type namespaceInterceptor struct {
|
||||
namespace string
|
||||
}
|
||||
|
||||
func (ni namespaceInterceptor) unary(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
|
||||
_, ok := namespaces.Namespace(ctx)
|
||||
if !ok {
|
||||
ctx = namespaces.WithNamespace(ctx, ni.namespace)
|
||||
}
|
||||
return invoker(ctx, method, req, reply, cc, opts...)
|
||||
}
|
||||
|
||||
func (ni namespaceInterceptor) stream(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
|
||||
_, ok := namespaces.Namespace(ctx)
|
||||
if !ok {
|
||||
ctx = namespaces.WithNamespace(ctx, ni.namespace)
|
||||
}
|
||||
|
||||
return streamer(ctx, desc, cc, method, opts...)
|
||||
}
|
||||
|
||||
func newNSInterceptors(ns string) (grpc.UnaryClientInterceptor, grpc.StreamClientInterceptor) {
|
||||
ni := namespaceInterceptor{
|
||||
namespace: ns,
|
||||
}
|
||||
return grpc.UnaryClientInterceptor(ni.unary), grpc.StreamClientInterceptor(ni.stream)
|
||||
}
|
||||
76
vendor/github.com/containerd/containerd/image.go
generated
vendored
Normal file
76
vendor/github.com/containerd/containerd/image.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/rootfs"
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Image interface {
|
||||
Name() string
|
||||
Target() ocispec.Descriptor
|
||||
|
||||
Unpack(context.Context) error
|
||||
}
|
||||
|
||||
var _ = (Image)(&image{})
|
||||
|
||||
type image struct {
|
||||
client *Client
|
||||
|
||||
i images.Image
|
||||
}
|
||||
|
||||
func (i *image) Name() string {
|
||||
return i.i.Name
|
||||
}
|
||||
|
||||
func (i *image) Target() ocispec.Descriptor {
|
||||
return i.i.Target
|
||||
}
|
||||
|
||||
func (i *image) Unpack(ctx context.Context) error {
|
||||
layers, err := i.getLayers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := rootfs.ApplyLayers(ctx, layers, i.client.SnapshotService(), i.client.DiffService()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *image) getLayers(ctx context.Context) ([]rootfs.Layer, error) {
|
||||
cs := i.client.ContentStore()
|
||||
p, err := content.ReadBlob(ctx, cs, i.i.Target.Digest)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to read manifest blob")
|
||||
}
|
||||
var manifest v1.Manifest
|
||||
if err := json.Unmarshal(p, &manifest); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal manifest")
|
||||
}
|
||||
diffIDs, err := i.i.RootFS(ctx, cs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to resolve rootfs")
|
||||
}
|
||||
if len(diffIDs) != len(manifest.Layers) {
|
||||
return nil, errors.Errorf("mismatched image rootfs and manifest layers")
|
||||
}
|
||||
layers := make([]rootfs.Layer, len(diffIDs))
|
||||
for i := range diffIDs {
|
||||
layers[i].Diff = v1.Descriptor{
|
||||
// TODO: derive media type from compressed type
|
||||
MediaType: v1.MediaTypeImageLayer,
|
||||
Digest: diffIDs[i],
|
||||
}
|
||||
layers[i].Blob = manifest.Layers[i]
|
||||
}
|
||||
return layers, nil
|
||||
}
|
||||
140
vendor/github.com/containerd/containerd/io.go
generated
vendored
Normal file
140
vendor/github.com/containerd/containerd/io.go
generated
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type IO struct {
|
||||
Terminal bool
|
||||
Stdin string
|
||||
Stdout string
|
||||
Stderr string
|
||||
|
||||
closer io.Closer
|
||||
}
|
||||
|
||||
func (i *IO) Close() error {
|
||||
if i.closer == nil {
|
||||
return nil
|
||||
}
|
||||
return i.closer.Close()
|
||||
}
|
||||
|
||||
type IOCreation func() (*IO, error)
|
||||
|
||||
type IOAttach func(*FifoSet) (*IO, error)
|
||||
|
||||
func NewIO(stdin io.Reader, stdout, stderr io.Writer) IOCreation {
|
||||
return NewIOWithTerminal(stdin, stdout, stderr, false)
|
||||
}
|
||||
|
||||
func NewIOWithTerminal(stdin io.Reader, stdout, stderr io.Writer, terminal bool) IOCreation {
|
||||
return func() (*IO, error) {
|
||||
paths, err := NewFifos()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i := &IO{
|
||||
Terminal: terminal,
|
||||
Stdout: paths.Out,
|
||||
Stderr: paths.Err,
|
||||
Stdin: paths.In,
|
||||
}
|
||||
set := &ioSet{
|
||||
in: stdin,
|
||||
out: stdout,
|
||||
err: stderr,
|
||||
}
|
||||
closer, err := copyIO(paths, set, i.Terminal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i.closer = closer
|
||||
return i, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func WithAttach(stdin io.Reader, stdout, stderr io.Writer) IOAttach {
|
||||
return func(paths *FifoSet) (*IO, error) {
|
||||
if paths == nil {
|
||||
return nil, fmt.Errorf("cannot attach to existing fifos")
|
||||
}
|
||||
i := &IO{
|
||||
Terminal: paths.Terminal,
|
||||
Stdout: paths.Out,
|
||||
Stderr: paths.Err,
|
||||
Stdin: paths.In,
|
||||
}
|
||||
set := &ioSet{
|
||||
in: stdin,
|
||||
out: stdout,
|
||||
err: stderr,
|
||||
}
|
||||
closer, err := copyIO(paths, set, i.Terminal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i.closer = closer
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Stdio returns an IO implementation to be used for a task
|
||||
// that outputs the container's IO as the current processes Stdio
|
||||
func Stdio() (*IO, error) {
|
||||
return NewIO(os.Stdin, os.Stdout, os.Stderr)()
|
||||
}
|
||||
|
||||
// StdioTerminal will setup the IO for the task to use a terminal
|
||||
func StdioTerminal() (*IO, error) {
|
||||
return NewIOWithTerminal(os.Stdin, os.Stdout, os.Stderr, true)()
|
||||
}
|
||||
|
||||
// NewFifos returns a new set of fifos for the task
|
||||
func NewFifos() (*FifoSet, error) {
|
||||
root := filepath.Join(os.TempDir(), "containerd")
|
||||
if err := os.MkdirAll(root, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dir, err := ioutil.TempDir(root, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &FifoSet{
|
||||
Dir: dir,
|
||||
In: filepath.Join(dir, "stdin"),
|
||||
Out: filepath.Join(dir, "stdout"),
|
||||
Err: filepath.Join(dir, "stderr"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type FifoSet struct {
|
||||
// Dir is the directory holding the task fifos
|
||||
Dir string
|
||||
In, Out, Err string
|
||||
Terminal bool
|
||||
}
|
||||
|
||||
type ioSet struct {
|
||||
in io.Reader
|
||||
out, err io.Writer
|
||||
}
|
||||
|
||||
type wgCloser struct {
|
||||
wg *sync.WaitGroup
|
||||
dir string
|
||||
}
|
||||
|
||||
func (g *wgCloser) Close() error {
|
||||
g.wg.Wait()
|
||||
if g.dir != "" {
|
||||
return os.RemoveAll(g.dir)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
71
vendor/github.com/containerd/containerd/io_unix.go
generated
vendored
Normal file
71
vendor/github.com/containerd/containerd/io_unix.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
// +build !windows
|
||||
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/containerd/fifo"
|
||||
)
|
||||
|
||||
func copyIO(fifos *FifoSet, ioset *ioSet, tty bool) (closer io.Closer, err error) {
|
||||
var (
|
||||
f io.ReadWriteCloser
|
||||
ctx = context.Background()
|
||||
wg = &sync.WaitGroup{}
|
||||
)
|
||||
|
||||
if f, err = fifo.OpenFifo(ctx, fifos.In, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func(c io.Closer) {
|
||||
if err != nil {
|
||||
c.Close()
|
||||
}
|
||||
}(f)
|
||||
go func(w io.WriteCloser) {
|
||||
io.Copy(w, ioset.in)
|
||||
w.Close()
|
||||
}(f)
|
||||
|
||||
if f, err = fifo.OpenFifo(ctx, fifos.Out, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func(c io.Closer) {
|
||||
if err != nil {
|
||||
c.Close()
|
||||
}
|
||||
}(f)
|
||||
wg.Add(1)
|
||||
go func(r io.ReadCloser) {
|
||||
io.Copy(ioset.out, r)
|
||||
r.Close()
|
||||
wg.Done()
|
||||
}(f)
|
||||
|
||||
if f, err = fifo.OpenFifo(ctx, fifos.Err, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func(c io.Closer) {
|
||||
if err != nil {
|
||||
c.Close()
|
||||
}
|
||||
}(f)
|
||||
|
||||
if !tty {
|
||||
wg.Add(1)
|
||||
go func(r io.ReadCloser) {
|
||||
io.Copy(ioset.err, r)
|
||||
r.Close()
|
||||
wg.Done()
|
||||
}(f)
|
||||
}
|
||||
|
||||
return &wgCloser{
|
||||
wg: wg,
|
||||
dir: fifos.Dir,
|
||||
}, nil
|
||||
}
|
||||
93
vendor/github.com/containerd/containerd/io_windows.go
generated
vendored
Normal file
93
vendor/github.com/containerd/containerd/io_windows.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
winio "github.com/Microsoft/go-winio"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func copyIO(fifos *FifoSet, ioset *ioSet, tty bool) (closer io.Closer, err error) {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
if fifos.In != "" {
|
||||
l, err := winio.ListenPipe(fifos.In, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to create stdin pipe %s", fifos.In)
|
||||
}
|
||||
defer func(l net.Listener) {
|
||||
if err != nil {
|
||||
l.Close()
|
||||
}
|
||||
}(l)
|
||||
|
||||
go func() {
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
log.L.WithError(err).Errorf("failed to accept stdin connection on %s", fifos.In)
|
||||
return
|
||||
}
|
||||
io.Copy(c, ioset.in)
|
||||
c.Close()
|
||||
l.Close()
|
||||
}()
|
||||
}
|
||||
|
||||
if fifos.Out != "" {
|
||||
l, err := winio.ListenPipe(fifos.Out, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to create stdin pipe %s", fifos.Out)
|
||||
}
|
||||
defer func(l net.Listener) {
|
||||
if err != nil {
|
||||
l.Close()
|
||||
}
|
||||
}(l)
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
log.L.WithError(err).Errorf("failed to accept stdout connection on %s", fifos.Out)
|
||||
return
|
||||
}
|
||||
io.Copy(ioset.out, c)
|
||||
c.Close()
|
||||
l.Close()
|
||||
}()
|
||||
}
|
||||
|
||||
if !tty && fifos.Err != "" {
|
||||
l, err := winio.ListenPipe(fifos.Err, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to create stderr pipe %s", fifos.Err)
|
||||
}
|
||||
defer func(l net.Listener) {
|
||||
if err != nil {
|
||||
l.Close()
|
||||
}
|
||||
}(l)
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
log.L.WithError(err).Errorf("failed to accept stderr connection on %s", fifos.Err)
|
||||
return
|
||||
}
|
||||
io.Copy(ioset.err, c)
|
||||
c.Close()
|
||||
l.Close()
|
||||
}()
|
||||
}
|
||||
|
||||
return &wgCloser{
|
||||
wg: &wg,
|
||||
dir: fifos.Dir,
|
||||
}, nil
|
||||
}
|
||||
124
vendor/github.com/containerd/containerd/process.go
generated
vendored
Normal file
124
vendor/github.com/containerd/containerd/process.go
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"syscall"
|
||||
|
||||
"github.com/containerd/containerd/api/services/execution"
|
||||
taskapi "github.com/containerd/containerd/api/types/task"
|
||||
protobuf "github.com/gogo/protobuf/types"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
type process struct {
|
||||
task *task
|
||||
|
||||
// this is a hack to make a blocking Wait work
|
||||
// exec does not have a create/start split so if a quick exiting process like `exit 1`
|
||||
// run, the wait does not have enough time to get the pid catch the event. So we need
|
||||
// to lock this on process struct create and only unlock it after the pid is set
|
||||
// this allow the wait to be called before calling process start and not race with the exit event
|
||||
pidSync chan struct{}
|
||||
|
||||
io *IO
|
||||
pid uint32
|
||||
spec *specs.Process
|
||||
}
|
||||
|
||||
// Pid returns the pid of the process
|
||||
// The pid is not set until start is called and returns
|
||||
func (p *process) Pid() uint32 {
|
||||
return p.pid
|
||||
}
|
||||
|
||||
// Start starts the exec process
|
||||
func (p *process) Start(ctx context.Context) error {
|
||||
data, err := json.Marshal(p.spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request := &execution.ExecRequest{
|
||||
ContainerID: p.task.containerID,
|
||||
Terminal: p.io.Terminal,
|
||||
Stdin: p.io.Stdin,
|
||||
Stdout: p.io.Stdout,
|
||||
Stderr: p.io.Stderr,
|
||||
Spec: &protobuf.Any{
|
||||
TypeUrl: specs.Version,
|
||||
Value: data,
|
||||
},
|
||||
}
|
||||
response, err := p.task.client.TaskService().Exec(ctx, request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.pid = response.Pid
|
||||
close(p.pidSync)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *process) Kill(ctx context.Context, s syscall.Signal) error {
|
||||
_, err := p.task.client.TaskService().Kill(ctx, &execution.KillRequest{
|
||||
Signal: uint32(s),
|
||||
ContainerID: p.task.containerID,
|
||||
PidOrAll: &execution.KillRequest_Pid{
|
||||
Pid: p.pid,
|
||||
},
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *process) Wait(ctx context.Context) (uint32, error) {
|
||||
events, err := p.task.client.TaskService().Events(ctx, &execution.EventsRequest{})
|
||||
if err != nil {
|
||||
return UnknownExitStatus, err
|
||||
}
|
||||
<-p.pidSync
|
||||
for {
|
||||
e, err := events.Recv()
|
||||
if err != nil {
|
||||
return UnknownExitStatus, err
|
||||
}
|
||||
if e.Type != taskapi.Event_EXIT {
|
||||
continue
|
||||
}
|
||||
if e.ID == p.task.containerID && e.Pid == p.pid {
|
||||
return e.ExitStatus, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *process) CloseStdin(ctx context.Context) error {
|
||||
_, err := p.task.client.TaskService().CloseStdin(ctx, &execution.CloseStdinRequest{
|
||||
ContainerID: p.task.containerID,
|
||||
Pid: p.pid,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *process) IO() *IO {
|
||||
return p.io
|
||||
}
|
||||
|
||||
func (p *process) Resize(ctx context.Context, w, h uint32) error {
|
||||
_, err := p.task.client.TaskService().Pty(ctx, &execution.PtyRequest{
|
||||
ContainerID: p.task.containerID,
|
||||
Width: w,
|
||||
Height: h,
|
||||
Pid: p.pid,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *process) Delete(ctx context.Context) (uint32, error) {
|
||||
cerr := p.io.Close()
|
||||
r, err := p.task.client.TaskService().DeleteProcess(ctx, &execution.DeleteProcessRequest{
|
||||
ContainerID: p.task.containerID,
|
||||
Pid: p.pid,
|
||||
})
|
||||
if err != nil {
|
||||
return UnknownExitStatus, err
|
||||
}
|
||||
return r.ExitStatus, cerr
|
||||
}
|
||||
27
vendor/github.com/containerd/containerd/spec.go
generated
vendored
Normal file
27
vendor/github.com/containerd/containerd/spec.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package containerd
|
||||
|
||||
import specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
|
||||
type SpecOpts func(s *specs.Spec) error
|
||||
|
||||
func WithProcessArgs(args ...string) SpecOpts {
|
||||
return func(s *specs.Spec) error {
|
||||
s.Process.Args = args
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateSpec will generate a default spec from the provided image
|
||||
// for use as a containerd container
|
||||
func GenerateSpec(opts ...SpecOpts) (*specs.Spec, error) {
|
||||
s, err := createDefaultSpec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, o := range opts {
|
||||
if err := o(s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
274
vendor/github.com/containerd/containerd/spec_unix.go
generated
vendored
Normal file
274
vendor/github.com/containerd/containerd/spec_unix.go
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
// +build !windows
|
||||
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/api/services/containers"
|
||||
"github.com/containerd/containerd/images"
|
||||
protobuf "github.com/gogo/protobuf/types"
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
const (
|
||||
rwm = "rwm"
|
||||
defaultRootfsPath = "rootfs"
|
||||
)
|
||||
|
||||
func defaltCaps() []string {
|
||||
return []string{
|
||||
"CAP_CHOWN",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_FSETID",
|
||||
"CAP_FOWNER",
|
||||
"CAP_MKNOD",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_KILL",
|
||||
"CAP_AUDIT_WRITE",
|
||||
}
|
||||
}
|
||||
|
||||
func defaultNamespaces() []specs.LinuxNamespace {
|
||||
return []specs.LinuxNamespace{
|
||||
{
|
||||
Type: specs.PIDNamespace,
|
||||
},
|
||||
{
|
||||
Type: specs.IPCNamespace,
|
||||
},
|
||||
{
|
||||
Type: specs.UTSNamespace,
|
||||
},
|
||||
{
|
||||
Type: specs.MountNamespace,
|
||||
},
|
||||
{
|
||||
Type: specs.NetworkNamespace,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createDefaultSpec() (*specs.Spec, error) {
|
||||
s := &specs.Spec{
|
||||
Version: specs.Version,
|
||||
Platform: specs.Platform{
|
||||
OS: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
},
|
||||
Root: specs.Root{
|
||||
Path: defaultRootfsPath,
|
||||
},
|
||||
Process: specs.Process{
|
||||
Cwd: "/",
|
||||
NoNewPrivileges: true,
|
||||
User: specs.User{
|
||||
UID: 0,
|
||||
GID: 0,
|
||||
},
|
||||
Capabilities: &specs.LinuxCapabilities{
|
||||
Bounding: defaltCaps(),
|
||||
Permitted: defaltCaps(),
|
||||
Inheritable: defaltCaps(),
|
||||
Effective: defaltCaps(),
|
||||
Ambient: defaltCaps(),
|
||||
},
|
||||
Rlimits: []specs.LinuxRlimit{
|
||||
{
|
||||
Type: "RLIMIT_NOFILE",
|
||||
Hard: uint64(1024),
|
||||
Soft: uint64(1024),
|
||||
},
|
||||
},
|
||||
},
|
||||
Mounts: []specs.Mount{
|
||||
{
|
||||
Destination: "/proc",
|
||||
Type: "proc",
|
||||
Source: "proc",
|
||||
},
|
||||
{
|
||||
Destination: "/dev",
|
||||
Type: "tmpfs",
|
||||
Source: "tmpfs",
|
||||
Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
|
||||
},
|
||||
{
|
||||
Destination: "/dev/pts",
|
||||
Type: "devpts",
|
||||
Source: "devpts",
|
||||
Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
|
||||
},
|
||||
{
|
||||
Destination: "/dev/shm",
|
||||
Type: "tmpfs",
|
||||
Source: "shm",
|
||||
Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"},
|
||||
},
|
||||
{
|
||||
Destination: "/dev/mqueue",
|
||||
Type: "mqueue",
|
||||
Source: "mqueue",
|
||||
Options: []string{"nosuid", "noexec", "nodev"},
|
||||
},
|
||||
{
|
||||
Destination: "/sys",
|
||||
Type: "sysfs",
|
||||
Source: "sysfs",
|
||||
Options: []string{"nosuid", "noexec", "nodev", "ro"},
|
||||
},
|
||||
{
|
||||
Destination: "/run",
|
||||
Type: "tmpfs",
|
||||
Source: "tmpfs",
|
||||
Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
|
||||
},
|
||||
{
|
||||
Destination: "/etc/resolv.conf",
|
||||
Type: "bind",
|
||||
Source: "/etc/resolv.conf",
|
||||
Options: []string{"rbind", "ro"},
|
||||
},
|
||||
{
|
||||
Destination: "/etc/hosts",
|
||||
Type: "bind",
|
||||
Source: "/etc/hosts",
|
||||
Options: []string{"rbind", "ro"},
|
||||
},
|
||||
{
|
||||
Destination: "/etc/localtime",
|
||||
Type: "bind",
|
||||
Source: "/etc/localtime",
|
||||
Options: []string{"rbind", "ro"},
|
||||
},
|
||||
},
|
||||
Linux: &specs.Linux{
|
||||
// TODO (@crosbymichael) make sure we don't have have two containers in the same cgroup
|
||||
Resources: &specs.LinuxResources{
|
||||
Devices: []specs.LinuxDeviceCgroup{
|
||||
{
|
||||
Allow: false,
|
||||
Access: rwm,
|
||||
},
|
||||
},
|
||||
},
|
||||
Namespaces: defaultNamespaces(),
|
||||
},
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func WithTTY(s *specs.Spec) error {
|
||||
s.Process.Terminal = true
|
||||
s.Process.Env = append(s.Process.Env, "TERM=xterm")
|
||||
return nil
|
||||
}
|
||||
|
||||
func WithHostNamespace(ns specs.LinuxNamespaceType) SpecOpts {
|
||||
return func(s *specs.Spec) error {
|
||||
for i, n := range s.Linux.Namespaces {
|
||||
if n.Type == ns {
|
||||
s.Linux.Namespaces = append(s.Linux.Namespaces[:i], s.Linux.Namespaces[i+1:]...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithImageConfig(ctx context.Context, i Image) SpecOpts {
|
||||
return func(s *specs.Spec) error {
|
||||
var (
|
||||
image = i.(*image)
|
||||
store = image.client.ContentStore()
|
||||
)
|
||||
ic, err := image.i.Config(ctx, store)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
ociimage v1.Image
|
||||
config v1.ImageConfig
|
||||
)
|
||||
switch ic.MediaType {
|
||||
case v1.MediaTypeImageConfig, images.MediaTypeDockerSchema2Config:
|
||||
r, err := store.Reader(ctx, ic.Digest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.NewDecoder(r).Decode(&ociimage); err != nil {
|
||||
r.Close()
|
||||
return err
|
||||
}
|
||||
r.Close()
|
||||
config = ociimage.Config
|
||||
default:
|
||||
return fmt.Errorf("unknown image config media type %s", ic.MediaType)
|
||||
}
|
||||
env := []string{
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
}
|
||||
s.Process.Env = append(env, config.Env...)
|
||||
var (
|
||||
uid, gid uint32
|
||||
)
|
||||
cmd := config.Cmd
|
||||
s.Process.Args = append(config.Entrypoint, cmd...)
|
||||
if config.User != "" {
|
||||
parts := strings.Split(config.User, ":")
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
v, err := strconv.ParseUint(parts[0], 0, 10)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
uid, gid = uint32(v), uint32(v)
|
||||
case 2:
|
||||
v, err := strconv.ParseUint(parts[0], 0, 10)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
uid = uint32(v)
|
||||
if v, err = strconv.ParseUint(parts[1], 0, 10); err != nil {
|
||||
return err
|
||||
}
|
||||
gid = uint32(v)
|
||||
default:
|
||||
return fmt.Errorf("invalid USER value %s", config.User)
|
||||
}
|
||||
}
|
||||
s.Process.User.UID, s.Process.User.GID = uid, gid
|
||||
cwd := config.WorkingDir
|
||||
if cwd == "" {
|
||||
cwd = "/"
|
||||
}
|
||||
s.Process.Cwd = cwd
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithSpec(spec *specs.Spec) NewContainerOpts {
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
data, err := json.Marshal(spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Spec = &protobuf.Any{
|
||||
TypeUrl: spec.Version,
|
||||
Value: data,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
94
vendor/github.com/containerd/containerd/spec_windows.go
generated
vendored
Normal file
94
vendor/github.com/containerd/containerd/spec_windows.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/containerd/containerd/api/services/containers"
|
||||
"github.com/containerd/containerd/images"
|
||||
protobuf "github.com/gogo/protobuf/types"
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
const pipeRoot = `\\.\pipe`
|
||||
|
||||
func createDefaultSpec() (*specs.Spec, error) {
|
||||
return &specs.Spec{
|
||||
Version: specs.Version,
|
||||
Platform: specs.Platform{
|
||||
OS: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
},
|
||||
Root: specs.Root{},
|
||||
Process: specs.Process{
|
||||
ConsoleSize: specs.Box{
|
||||
Width: 80,
|
||||
Height: 20,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func WithImageConfig(ctx context.Context, i Image) SpecOpts {
|
||||
return func(s *specs.Spec) error {
|
||||
var (
|
||||
image = i.(*image)
|
||||
store = image.client.ContentStore()
|
||||
)
|
||||
ic, err := image.i.Config(ctx, store)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
ociimage v1.Image
|
||||
config v1.ImageConfig
|
||||
)
|
||||
switch ic.MediaType {
|
||||
case v1.MediaTypeImageConfig, images.MediaTypeDockerSchema2Config:
|
||||
r, err := store.Reader(ctx, ic.Digest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.NewDecoder(r).Decode(&ociimage); err != nil {
|
||||
r.Close()
|
||||
return err
|
||||
}
|
||||
r.Close()
|
||||
config = ociimage.Config
|
||||
default:
|
||||
return fmt.Errorf("unknown image config media type %s", ic.MediaType)
|
||||
}
|
||||
s.Process.Env = config.Env
|
||||
s.Process.Args = append(config.Entrypoint, config.Cmd...)
|
||||
s.Process.User = specs.User{
|
||||
Username: config.User,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithTTY(width, height int) SpecOpts {
|
||||
return func(s *specs.Spec) error {
|
||||
s.Process.Terminal = true
|
||||
s.Process.ConsoleSize.Width = uint(width)
|
||||
s.Process.ConsoleSize.Height = uint(height)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithSpec(spec *specs.Spec) NewContainerOpts {
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
data, err := json.Marshal(spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Spec = &protobuf.Any{
|
||||
TypeUrl: spec.Version,
|
||||
Value: data,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
335
vendor/github.com/containerd/containerd/task.go
generated
vendored
Normal file
335
vendor/github.com/containerd/containerd/task.go
generated
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/containerd/containerd/api/services/containers"
|
||||
"github.com/containerd/containerd/api/services/execution"
|
||||
taskapi "github.com/containerd/containerd/api/types/task"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/rootfs"
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
const UnknownExitStatus = 255
|
||||
|
||||
type TaskStatus string
|
||||
|
||||
const (
|
||||
Running TaskStatus = "running"
|
||||
Created TaskStatus = "created"
|
||||
Stopped TaskStatus = "stopped"
|
||||
Paused TaskStatus = "paused"
|
||||
Pausing TaskStatus = "pausing"
|
||||
)
|
||||
|
||||
type CheckpointOpts func(*execution.CheckpointRequest) error
|
||||
|
||||
type Task interface {
|
||||
Pid() uint32
|
||||
Delete(context.Context) (uint32, error)
|
||||
Kill(context.Context, syscall.Signal) error
|
||||
Pause(context.Context) error
|
||||
Resume(context.Context) error
|
||||
Start(context.Context) error
|
||||
Status(context.Context) (TaskStatus, error)
|
||||
Wait(context.Context) (uint32, error)
|
||||
Exec(context.Context, *specs.Process, IOCreation) (Process, error)
|
||||
Processes(context.Context) ([]uint32, error)
|
||||
CloseStdin(context.Context) error
|
||||
Resize(ctx context.Context, w, h uint32) error
|
||||
IO() *IO
|
||||
Checkpoint(context.Context, ...CheckpointOpts) (v1.Descriptor, error)
|
||||
}
|
||||
|
||||
type Process interface {
|
||||
Pid() uint32
|
||||
Start(context.Context) error
|
||||
Delete(context.Context) (uint32, error)
|
||||
Kill(context.Context, syscall.Signal) error
|
||||
Wait(context.Context) (uint32, error)
|
||||
CloseStdin(context.Context) error
|
||||
Resize(ctx context.Context, w, h uint32) error
|
||||
IO() *IO
|
||||
}
|
||||
|
||||
var _ = (Task)(&task{})
|
||||
|
||||
type task struct {
|
||||
client *Client
|
||||
|
||||
io *IO
|
||||
containerID string
|
||||
pid uint32
|
||||
|
||||
deferred *execution.CreateRequest
|
||||
pidSync chan struct{}
|
||||
}
|
||||
|
||||
// Pid returns the pid or process id for the task
|
||||
func (t *task) Pid() uint32 {
|
||||
return t.pid
|
||||
}
|
||||
|
||||
func (t *task) Start(ctx context.Context) error {
|
||||
if t.deferred != nil {
|
||||
response, err := t.client.TaskService().Create(ctx, t.deferred)
|
||||
t.deferred = nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.pid = response.Pid
|
||||
close(t.pidSync)
|
||||
return nil
|
||||
}
|
||||
_, err := t.client.TaskService().Start(ctx, &execution.StartRequest{
|
||||
ContainerID: t.containerID,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *task) Kill(ctx context.Context, s syscall.Signal) error {
|
||||
_, err := t.client.TaskService().Kill(ctx, &execution.KillRequest{
|
||||
Signal: uint32(s),
|
||||
ContainerID: t.containerID,
|
||||
PidOrAll: &execution.KillRequest_All{
|
||||
All: true,
|
||||
},
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *task) Pause(ctx context.Context) error {
|
||||
_, err := t.client.TaskService().Pause(ctx, &execution.PauseRequest{
|
||||
ContainerID: t.containerID,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *task) Resume(ctx context.Context) error {
|
||||
_, err := t.client.TaskService().Resume(ctx, &execution.ResumeRequest{
|
||||
ContainerID: t.containerID,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *task) Status(ctx context.Context) (TaskStatus, error) {
|
||||
r, err := t.client.TaskService().Info(ctx, &execution.InfoRequest{
|
||||
ContainerID: t.containerID,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return TaskStatus(strings.ToLower(r.Task.Status.String())), nil
|
||||
}
|
||||
|
||||
// Wait is a blocking call that will wait for the task to exit and return the exit status
|
||||
func (t *task) Wait(ctx context.Context) (uint32, error) {
|
||||
events, err := t.client.TaskService().Events(ctx, &execution.EventsRequest{})
|
||||
if err != nil {
|
||||
return UnknownExitStatus, err
|
||||
}
|
||||
<-t.pidSync
|
||||
for {
|
||||
e, err := events.Recv()
|
||||
if err != nil {
|
||||
return UnknownExitStatus, err
|
||||
}
|
||||
if e.Type != taskapi.Event_EXIT {
|
||||
continue
|
||||
}
|
||||
if e.ID == t.containerID && e.Pid == t.pid {
|
||||
return e.ExitStatus, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete deletes the task and its runtime state
|
||||
// it returns the exit status of the task and any errors that were encountered
|
||||
// during cleanup
|
||||
func (t *task) Delete(ctx context.Context) (uint32, error) {
|
||||
var cerr error
|
||||
if t.io != nil {
|
||||
cerr = t.io.Close()
|
||||
}
|
||||
r, err := t.client.TaskService().Delete(ctx, &execution.DeleteRequest{
|
||||
ContainerID: t.containerID,
|
||||
})
|
||||
if err != nil {
|
||||
return UnknownExitStatus, err
|
||||
}
|
||||
return r.ExitStatus, cerr
|
||||
}
|
||||
|
||||
func (t *task) Exec(ctx context.Context, spec *specs.Process, ioCreate IOCreation) (Process, error) {
|
||||
i, err := ioCreate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &process{
|
||||
task: t,
|
||||
io: i,
|
||||
spec: spec,
|
||||
pidSync: make(chan struct{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *task) Processes(ctx context.Context) ([]uint32, error) {
|
||||
response, err := t.client.TaskService().Processes(ctx, &execution.ProcessesRequest{
|
||||
ContainerID: t.containerID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out []uint32
|
||||
for _, p := range response.Processes {
|
||||
out = append(out, p.Pid)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (t *task) CloseStdin(ctx context.Context) error {
|
||||
_, err := t.client.TaskService().CloseStdin(ctx, &execution.CloseStdinRequest{
|
||||
ContainerID: t.containerID,
|
||||
Pid: t.pid,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *task) IO() *IO {
|
||||
return t.io
|
||||
}
|
||||
|
||||
func (t *task) Resize(ctx context.Context, w, h uint32) error {
|
||||
_, err := t.client.TaskService().Pty(ctx, &execution.PtyRequest{
|
||||
ContainerID: t.containerID,
|
||||
Width: w,
|
||||
Height: h,
|
||||
Pid: t.pid,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func WithExit(r *execution.CheckpointRequest) error {
|
||||
r.Exit = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *task) Checkpoint(ctx context.Context, opts ...CheckpointOpts) (d v1.Descriptor, err error) {
|
||||
request := &execution.CheckpointRequest{
|
||||
ContainerID: t.containerID,
|
||||
}
|
||||
for _, o := range opts {
|
||||
if err := o(request); err != nil {
|
||||
return d, err
|
||||
}
|
||||
}
|
||||
// if we are not exiting the container after the checkpoint, make sure we pause it and resume after
|
||||
// all other filesystem operations are completed
|
||||
if !request.Exit {
|
||||
if err := t.Pause(ctx); err != nil {
|
||||
return d, err
|
||||
}
|
||||
defer t.Resume(ctx)
|
||||
}
|
||||
cr, err := t.client.ContainerService().Get(ctx, &containers.GetContainerRequest{
|
||||
ID: t.containerID,
|
||||
})
|
||||
if err != nil {
|
||||
return d, err
|
||||
}
|
||||
var index v1.Index
|
||||
if err := t.checkpointTask(ctx, &index, request); err != nil {
|
||||
return d, err
|
||||
}
|
||||
if err := t.checkpointImage(ctx, &index, cr.Container.Image); err != nil {
|
||||
return d, err
|
||||
}
|
||||
if err := t.checkpointRWSnapshot(ctx, &index, cr.Container.RootFS); err != nil {
|
||||
return d, err
|
||||
}
|
||||
index.Annotations = make(map[string]string)
|
||||
index.Annotations["image.name"] = cr.Container.Image
|
||||
return t.writeIndex(ctx, &index)
|
||||
}
|
||||
|
||||
func (t *task) checkpointTask(ctx context.Context, index *v1.Index, request *execution.CheckpointRequest) error {
|
||||
response, err := t.client.TaskService().Checkpoint(ctx, request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// add the checkpoint descriptors to the index
|
||||
for _, d := range response.Descriptors {
|
||||
index.Manifests = append(index.Manifests, v1.Descriptor{
|
||||
MediaType: d.MediaType,
|
||||
Size: d.Size_,
|
||||
Digest: d.Digest,
|
||||
Platform: &v1.Platform{
|
||||
OS: runtime.GOOS,
|
||||
Architecture: runtime.GOARCH,
|
||||
},
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *task) checkpointRWSnapshot(ctx context.Context, index *v1.Index, id string) error {
|
||||
rw, err := rootfs.Diff(ctx, id, fmt.Sprintf("checkpoint-rw-%s", id), t.client.SnapshotService(), t.client.DiffService())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rw.Platform = &v1.Platform{
|
||||
OS: runtime.GOOS,
|
||||
Architecture: runtime.GOARCH,
|
||||
}
|
||||
index.Manifests = append(index.Manifests, rw)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *task) checkpointImage(ctx context.Context, index *v1.Index, image string) error {
|
||||
if image == "" {
|
||||
return fmt.Errorf("cannot checkpoint image with empty name")
|
||||
}
|
||||
ir, err := t.client.ImageService().Get(ctx, image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
index.Manifests = append(index.Manifests, ir.Target)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *task) writeIndex(ctx context.Context, index *v1.Index) (v1.Descriptor, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
if err := json.NewEncoder(buf).Encode(index); err != nil {
|
||||
return v1.Descriptor{}, err
|
||||
}
|
||||
return writeContent(ctx, t.client.ContentStore(), v1.MediaTypeImageIndex, t.containerID, buf)
|
||||
}
|
||||
|
||||
func writeContent(ctx context.Context, store content.Store, mediaType, ref string, r io.Reader) (d v1.Descriptor, err error) {
|
||||
writer, err := store.Writer(ctx, ref, 0, "")
|
||||
if err != nil {
|
||||
return d, err
|
||||
}
|
||||
defer writer.Close()
|
||||
size, err := io.Copy(writer, r)
|
||||
if err != nil {
|
||||
return d, err
|
||||
}
|
||||
if err := writer.Commit(0, ""); err != nil {
|
||||
return d, err
|
||||
}
|
||||
return v1.Descriptor{
|
||||
MediaType: mediaType,
|
||||
Digest: writer.Digest(),
|
||||
Size: size,
|
||||
}, nil
|
||||
}
|
||||
40
vendor/github.com/containerd/containerd/vendor.conf
generated
vendored
Normal file
40
vendor/github.com/containerd/containerd/vendor.conf
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
github.com/coreos/go-systemd 48702e0da86bd25e76cfef347e2adeb434a0d0a6
|
||||
github.com/containerd/go-runc 60e87b3b047d4c93faa996699f6fdcfa34685e65
|
||||
github.com/containerd/console e0a2cdcf03d4d99c3bc061635a66cf92336c6c82
|
||||
github.com/containerd/cgroups 7b2d1a0f50963678d5799e29d17a4d611f5a5dee
|
||||
github.com/docker/go-metrics 8fd5772bf1584597834c6f7961a530f06cbfbb87
|
||||
github.com/godbus/dbus c7fdd8b5cd55e87b4e1f4e372cdb1db61dd6c66f
|
||||
github.com/prometheus/client_golang v0.8.0
|
||||
github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6
|
||||
github.com/prometheus/common 195bde7883f7c39ea62b0d92ab7359b5327065cb
|
||||
github.com/prometheus/procfs fcdb11ccb4389efb1b210b7ffb623ab71c5fdd60
|
||||
github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.0
|
||||
github.com/docker/go-units v0.3.1
|
||||
github.com/gogo/protobuf d2e1ade2d719b78fe5b061b4c18a9f7111b5bdc8
|
||||
github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4
|
||||
github.com/opencontainers/runtime-spec v1.0.0-rc5
|
||||
github.com/opencontainers/runc 639454475cb9c8b861cc599f8bcd5c8c790ae402
|
||||
github.com/Sirupsen/logrus v0.11.0
|
||||
github.com/containerd/btrfs e9c546f46bccffefe71a6bc137e4c21b5503cc18
|
||||
github.com/stretchr/testify v1.1.4
|
||||
github.com/davecgh/go-spew v1.1.0
|
||||
github.com/pmezard/go-difflib v1.0.0
|
||||
github.com/containerd/fifo 69b99525e472735860a5269b75af1970142b3062
|
||||
github.com/urfave/cli 8ba6f23b6e36d03666a14bd9421f5e3efcb59aca
|
||||
golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
|
||||
google.golang.org/grpc v1.3.0
|
||||
github.com/pkg/errors v0.8.0
|
||||
github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448
|
||||
golang.org/x/sys f3918c30c5c2cb527c0b071a27c35120a6c0719a
|
||||
github.com/opencontainers/image-spec v1.0.0-rc6
|
||||
github.com/containerd/continuity 86cec1535a968310e7532819f699ff2830ed7463
|
||||
golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
|
||||
github.com/BurntSushi/toml v0.2.0-21-g9906417
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
|
||||
github.com/Microsoft/go-winio v0.4.1
|
||||
github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd
|
||||
github.com/Microsoft/hcsshim v0.5.15
|
||||
github.com/Azure/go-ansiterm fa152c58bc15761d0200cb75fe958b89a9d4888e
|
||||
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
|
||||
golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
|
||||
Reference in New Issue
Block a user