mirror of
https://git.vectorsigma.ru/public/k3s.git
synced 2026-07-29 00:09:33 +00:00
Update vendor
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
apiVersion: k3s.cattle.io/v1
|
||||
kind: HelmChart
|
||||
metadata:
|
||||
name: nginx-ingress
|
||||
namespace: kube-system
|
||||
spec:
|
||||
chart: stable/nginx-ingress
|
||||
249
trash.lock
249
trash.lock
@@ -17,12 +17,12 @@ import:
|
||||
- package: github.com/containerd/console
|
||||
version: c12b1e7919c14469339a5d38f2f8ed9b64a9de23
|
||||
- package: github.com/containerd/containerd
|
||||
version: v1.2.2-k3s2
|
||||
version: v1.2.3-k3s1
|
||||
repo: https://github.com/ibuildthecloud/containerd
|
||||
- package: github.com/containerd/continuity
|
||||
version: bd77b46c8352f74eb12c85bdc01f4b90f69d66b4
|
||||
- package: github.com/containerd/cri
|
||||
version: 0d5cabd006cb5319dc965046067b8432d9fa5ef8
|
||||
version: c3cf754321fc38c6af5dfd2552fdde0ad192b31d
|
||||
- package: github.com/containerd/fifo
|
||||
version: 3d5202aec260678c48179c56f40e6f38a095738c
|
||||
- package: github.com/containerd/go-cni
|
||||
@@ -53,8 +53,6 @@ import:
|
||||
version: 9461782956ad83b30282bf90e31fa6a70c255ba9
|
||||
- package: github.com/docker/go-metrics
|
||||
version: 4ea375f7759c82740c893fc030bc37088d2ec098
|
||||
- package: github.com/docker/go-units
|
||||
version: v0.3.1
|
||||
- package: github.com/docker/spdystream
|
||||
version: 449fdfce4d962303d702fec724ef0ad181c92528
|
||||
- package: github.com/emicklei/go-restful
|
||||
@@ -85,6 +83,9 @@ import:
|
||||
version: 2cf9dc699c5640a7e2c81403a44127bf28033600
|
||||
- package: github.com/json-iterator/go
|
||||
version: 1.1.5
|
||||
- package: github.com/kubernetes-sigs/cri-tools
|
||||
version: c465773e3ad8c941d1756c0a467d550b04a8f65b
|
||||
repo: https://github.com/ibuildthecloud/cri-tools.git
|
||||
- package: github.com/mattn/go-sqlite3
|
||||
version: v1.9.0
|
||||
- package: github.com/matttproud/golang_protobuf_extensions
|
||||
@@ -100,7 +101,7 @@ import:
|
||||
- package: github.com/opencontainers/image-spec
|
||||
version: v1.0.1
|
||||
- package: github.com/opencontainers/runc
|
||||
version: 96ec2177ae841256168fcf76954f7177af9446eb
|
||||
version: 12f6a991201fdb8f82579582d5e00e28fba06d0a
|
||||
- package: github.com/opencontainers/runtime-spec
|
||||
version: 5684b8af48c1ac3b1451fa499724e30e3c20a294
|
||||
- package: github.com/opencontainers/runtime-tools
|
||||
@@ -110,7 +111,7 @@ import:
|
||||
- package: github.com/pkg/errors
|
||||
version: v0.8.0
|
||||
- package: github.com/rancher/norman
|
||||
version: d640c72bf09d9fbff596dead44338453bba718cc
|
||||
version: e4f12a1656cb04b4b2a25c571fc05283ec25f946
|
||||
repo: https://github.com/ibuildthecloud/norman.git
|
||||
- package: github.com/seccomp/libseccomp-golang
|
||||
version: 32f571b70023028bd57d9288c20efbcb237f3ce0
|
||||
@@ -154,143 +155,145 @@ import:
|
||||
- package: gopkg.in/yaml.v2
|
||||
version: v2.2.1
|
||||
- package: k8s.io/kubernetes
|
||||
version: v1.13.3-klp1
|
||||
repo: file:///home/darren/src/kuberlite/.git
|
||||
version: v1.13.3-k3s2
|
||||
repo: https://github.com/ibuildthecloud/k3s.git
|
||||
transitive: true
|
||||
staging: true
|
||||
- package: github.com/google/btree
|
||||
version: 7d79101e329e5a3adf994758c578dab82b90c017
|
||||
- package: github.com/evanphx/json-patch
|
||||
version: v4.0.0-3-g36442dbdb58521
|
||||
- package: k8s.io/heapster
|
||||
version: v1.2.0-beta.1
|
||||
- package: github.com/JeffAshton/win_pdh
|
||||
version: 76bb4ee9f0ab50f77826f2a2ee7fb9d3880d6ec2
|
||||
- package: github.com/daviddengcn/go-colortext
|
||||
version: 511bcaf42ccd42c38aba7427b6673277bf19e2a1
|
||||
- package: github.com/docker/go-connections
|
||||
version: v0.3.0
|
||||
- package: github.com/ibuildthecloud/kvsql
|
||||
version: 1ca8c57d636e999d0363f4e7d953e96e13c1a2f4
|
||||
- package: github.com/container-storage-interface/spec
|
||||
version: v1.0.0
|
||||
- package: k8s.io/utils
|
||||
version: 66066c83e385e385ccc3c964b44fd7dcd413d0ed
|
||||
- package: github.com/imdario/mergo
|
||||
version: v0.3.5
|
||||
- package: github.com/vishvananda/netlink
|
||||
version: b2de5d10e38ecce8607e6b438b6d174f389a004e
|
||||
- package: gopkg.in/square/go-jose.v2
|
||||
version: v2.1.6-4-g89060dee6a84df
|
||||
- package: github.com/docker/go-units
|
||||
version: v0.3.1-11-g9e638d38cf6977
|
||||
- package: github.com/mistifyio/go-zfs
|
||||
version: v2.1.1-5-g1b4ae6fb4e77b0
|
||||
- package: bitbucket.org/ww/goautoneg
|
||||
version: a547fc61f48d567d5b4ec6f8aee5573d8efce11d
|
||||
repo: https://github.com/rancher/goautoneg.git
|
||||
- package: github.com/vishvananda/netns
|
||||
version: be1fbeda19366dea804f00efff2dd73a1642fdcc
|
||||
- package: github.com/docker/libnetwork
|
||||
version: v0.8.0-dev.2-1265-ga9cd636e378982
|
||||
- package: github.com/prometheus/client_golang
|
||||
version: v0.8.0-83-ge7e903064f5e9e
|
||||
- package: github.com/jonboulle/clockwork
|
||||
version: 72f9bd7c4e0c2a40055ab3d0f09654f730cce982
|
||||
- package: github.com/mrunalp/fileutils
|
||||
version: 4ee1cc9a80582a0c75febdd5cfa779ee4361cbca
|
||||
- package: sigs.k8s.io/yaml
|
||||
version: v1.1.0
|
||||
- package: github.com/exponent-io/jsonpath
|
||||
version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5
|
||||
- package: gopkg.in/natefinch/lumberjack.v2
|
||||
version: v1.0-16-g20b71e5b60d756
|
||||
- package: github.com/jteeuwen/go-bindata
|
||||
version: v3.0.7-72-ga0ff2567cfb709
|
||||
- package: github.com/Azure/go-ansiterm
|
||||
version: d6e3b3328b783f23731bc4d058875b0371ff8109
|
||||
- package: github.com/mxk/go-flowrate
|
||||
version: cca7078d478f8520f85629ad7c68962d31ed7682
|
||||
- package: github.com/coreos/go-semver
|
||||
version: v0.2.0-9-ge214231b295a8e
|
||||
- package: github.com/russross/blackfriday
|
||||
version: v1.4-2-g300106c228d52c
|
||||
- package: github.com/cyphar/filepath-securejoin
|
||||
version: v0.2.1-1-gae69057f2299fb
|
||||
- package: github.com/prometheus/client_model
|
||||
version: model-0.0.2-12-gfa8ad6fec33561
|
||||
- package: k8s.io/heapster
|
||||
version: v1.2.0-beta.1
|
||||
- package: github.com/miekg/dns
|
||||
version: 5d001d020961ae1c184f9f8152fdc73810481677
|
||||
- package: github.com/spf13/cobra
|
||||
version: v0.0.1-34-gc439c4fa093711
|
||||
- package: github.com/gregjones/httpcache
|
||||
version: 787624de3eb7bd915c329cba748687a3b22666a6
|
||||
- package: vbom.ml/util
|
||||
version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394
|
||||
- package: github.com/Azure/go-ansiterm
|
||||
version: d6e3b3328b783f23731bc4d058875b0371ff8109
|
||||
- package: github.com/coreos/pkg
|
||||
version: v4
|
||||
- package: github.com/jonboulle/clockwork
|
||||
version: 72f9bd7c4e0c2a40055ab3d0f09654f730cce982
|
||||
- package: github.com/robfig/cron
|
||||
version: v1-53-gdf38d32658d878
|
||||
- package: github.com/golang/groupcache
|
||||
version: 02826c3e79038b59d737d3b1c0a1d937f71a4433
|
||||
- package: github.com/prometheus/client_golang
|
||||
version: v0.8.0-83-ge7e903064f5e9e
|
||||
- package: golang.org/x/tools
|
||||
version: 2382e3994d48b1d22acc2c86bcad0a2aff028e32
|
||||
- package: github.com/fsnotify/fsnotify
|
||||
version: v1.3.1-1-gf12c6236fe7b5c
|
||||
- package: github.com/spf13/pflag
|
||||
version: v1.0.1
|
||||
- package: gopkg.in/natefinch/lumberjack.v2
|
||||
version: v1.0-16-g20b71e5b60d756
|
||||
- package: github.com/google/certificate-transparency-go
|
||||
version: v1.0.21
|
||||
- package: github.com/ibuildthecloud/kvsql
|
||||
version: 1ca8c57d636e999d0363f4e7d953e96e13c1a2f4
|
||||
- package: github.com/prometheus/common
|
||||
version: 13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207
|
||||
- package: github.com/sigma/go-inotify
|
||||
version: c87b6cf5033d2c6486046f045eeebdc3d910fd38
|
||||
- package: github.com/inconshreveable/mousetrap
|
||||
version: v1.0
|
||||
- package: bitbucket.org/ww/goautoneg
|
||||
version: a547fc61f48d567d5b4ec6f8aee5573d8efce11d
|
||||
repo: https://github.com/rancher/goautoneg.git
|
||||
- package: github.com/docker/libnetwork
|
||||
version: v0.8.0-dev.2-1265-ga9cd636e378982
|
||||
- package: github.com/mindprince/gonvml
|
||||
version: fee913ce8fb235edf54739d259ca0ecc226c7b8a
|
||||
- package: github.com/mxk/go-flowrate
|
||||
version: cca7078d478f8520f85629ad7c68962d31ed7682
|
||||
- package: github.com/prometheus/procfs
|
||||
version: 65c1f6f8f0fc1e2185eb9863a3bc751496404259
|
||||
- package: github.com/MakeNowJust/heredoc
|
||||
version: bb23615498cded5e105af4ce27de75b089cbe851
|
||||
- package: github.com/renstrom/dedent
|
||||
version: v1.0.0-3-g020d11c3b9c0c7
|
||||
- package: github.com/fsnotify/fsnotify
|
||||
version: v1.3.1-1-gf12c6236fe7b5c
|
||||
- package: github.com/ugorji/go
|
||||
version: bdcc60b419d136a85cdf2e7cbcac34b3f1cd6e57
|
||||
- package: github.com/vishvananda/netlink
|
||||
version: b2de5d10e38ecce8607e6b438b6d174f389a004e
|
||||
- package: github.com/miekg/dns
|
||||
version: 5d001d020961ae1c184f9f8152fdc73810481677
|
||||
- package: vbom.ml/util
|
||||
version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394
|
||||
- package: github.com/peterbourgon/diskv
|
||||
version: v2.0.1
|
||||
- package: github.com/armon/circbuf
|
||||
version: bbbad097214e2918d8543d5201d12bfd7bca254d
|
||||
- package: github.com/cloudflare/cfssl
|
||||
version: 1.3.2-21-g56268a613adfed
|
||||
- package: gopkg.in/square/go-jose.v2
|
||||
version: v2.1.6-4-g89060dee6a84df
|
||||
- package: github.com/container-storage-interface/spec
|
||||
version: v1.0.0
|
||||
- package: github.com/spf13/cobra
|
||||
version: v0.0.1-34-gc439c4fa093711
|
||||
- package: k8s.io/gengo
|
||||
version: 51747d6e00da1fc578d5a333a93bb2abcbce7a95
|
||||
- package: github.com/gregjones/httpcache
|
||||
version: 787624de3eb7bd915c329cba748687a3b22666a6
|
||||
- package: golang.org/x/tools
|
||||
version: 2382e3994d48b1d22acc2c86bcad0a2aff028e32
|
||||
- package: k8s.io/klog
|
||||
version: 8139d8cb77af419532b33dfa7dd09fbc5f1d344f
|
||||
- package: github.com/hashicorp/golang-lru
|
||||
version: a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
|
||||
- package: k8s.io/utils
|
||||
version: 66066c83e385e385ccc3c964b44fd7dcd413d0ed
|
||||
- package: github.com/Nvveen/Gotty
|
||||
version: cd527374f1e5bff4938207604a14f2e38a9cf512
|
||||
- package: github.com/euank/go-kmsg-parser
|
||||
version: v2.0.0
|
||||
- package: github.com/golang/groupcache
|
||||
version: 02826c3e79038b59d737d3b1c0a1d937f71a4433
|
||||
- package: github.com/pborman/uuid
|
||||
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
|
||||
- package: github.com/robfig/cron
|
||||
version: v1-53-gdf38d32658d878
|
||||
- package: github.com/coreos/etcd
|
||||
version: v3.3.10
|
||||
- package: github.com/coreos/pkg
|
||||
version: v4
|
||||
- package: github.com/mitchellh/go-wordwrap
|
||||
version: ad45545899c7b13c020ea92b2072220eefad42b8
|
||||
- package: github.com/google/certificate-transparency-go
|
||||
version: v1.0.21
|
||||
- package: sigs.k8s.io/yaml
|
||||
version: v1.1.0
|
||||
- package: github.com/russross/blackfriday
|
||||
version: v1.4-2-g300106c228d52c
|
||||
- package: github.com/google/btree
|
||||
version: 7d79101e329e5a3adf994758c578dab82b90c017
|
||||
- package: github.com/karrick/godirwalk
|
||||
version: v1.7.5
|
||||
- package: github.com/prometheus/client_model
|
||||
version: model-0.0.2-12-gfa8ad6fec33561
|
||||
- package: github.com/docker/docker
|
||||
version: docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8dd8794
|
||||
- package: github.com/fatih/camelcase
|
||||
version: f6a740d52f961c60348ebb109adde9f4635d7540
|
||||
- package: github.com/imdario/mergo
|
||||
version: v0.3.5
|
||||
- package: github.com/MakeNowJust/heredoc
|
||||
version: bb23615498cded5e105af4ce27de75b089cbe851
|
||||
- package: github.com/inconshreveable/mousetrap
|
||||
version: v1.0
|
||||
- package: github.com/mrunalp/fileutils
|
||||
version: 4ee1cc9a80582a0c75febdd5cfa779ee4361cbca
|
||||
- package: github.com/pborman/uuid
|
||||
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
|
||||
- package: github.com/evanphx/json-patch
|
||||
version: v4.0.0-3-g36442dbdb58521
|
||||
- package: github.com/hashicorp/golang-lru
|
||||
version: a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
|
||||
- package: github.com/Nvveen/Gotty
|
||||
version: cd527374f1e5bff4938207604a14f2e38a9cf512
|
||||
- package: github.com/daviddengcn/go-colortext
|
||||
version: 511bcaf42ccd42c38aba7427b6673277bf19e2a1
|
||||
- package: github.com/mattn/go-shellwords
|
||||
version: v1.0.3-20-gf8471b0a71ded0
|
||||
- package: github.com/fatih/camelcase
|
||||
version: f6a740d52f961c60348ebb109adde9f4635d7540
|
||||
- package: github.com/googleapis/gnostic
|
||||
version: 0c5108395e2debce0d731cf0287ddf7242066aba
|
||||
- package: github.com/cloudflare/cfssl
|
||||
version: 1.3.2-21-g56268a613adfed
|
||||
- package: github.com/euank/go-kmsg-parser
|
||||
version: v2.0.0
|
||||
- package: k8s.io/klog
|
||||
version: 8139d8cb77af419532b33dfa7dd09fbc5f1d344f
|
||||
- package: github.com/JeffAshton/win_pdh
|
||||
version: 76bb4ee9f0ab50f77826f2a2ee7fb9d3880d6ec2
|
||||
- package: github.com/mitchellh/go-wordwrap
|
||||
version: ad45545899c7b13c020ea92b2072220eefad42b8
|
||||
- package: github.com/prometheus/procfs
|
||||
version: 65c1f6f8f0fc1e2185eb9863a3bc751496404259
|
||||
- package: github.com/vishvananda/netns
|
||||
version: be1fbeda19366dea804f00efff2dd73a1642fdcc
|
||||
- package: github.com/chai2010/gettext-go
|
||||
version: c6fed771bfd517099caf0f7a961671fa8ed08723
|
||||
- package: github.com/exponent-io/jsonpath
|
||||
version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5
|
||||
- package: k8s.io/gengo
|
||||
version: 51747d6e00da1fc578d5a333a93bb2abcbce7a95
|
||||
- package: github.com/cyphar/filepath-securejoin
|
||||
version: v0.2.1-1-gae69057f2299fb
|
||||
- package: github.com/ugorji/go
|
||||
version: bdcc60b419d136a85cdf2e7cbcac34b3f1cd6e57
|
||||
- package: github.com/google/cadvisor
|
||||
version: 91dab6eb91496ed68acbef68b02b34b3392ca754
|
||||
repo: https://github.com/ibuildthecloud/cadvisor.git
|
||||
- package: github.com/googleapis/gnostic
|
||||
version: 0c5108395e2debce0d731cf0287ddf7242066aba
|
||||
- package: github.com/shurcooL/sanitized_anchor_name
|
||||
version: 10ef21a441db47d8b13ebcc5fd2310f636973c77
|
||||
- package: github.com/spf13/pflag
|
||||
version: v1.0.1
|
||||
- package: github.com/chai2010/gettext-go
|
||||
version: c6fed771bfd517099caf0f7a961671fa8ed08723
|
||||
- package: github.com/peterbourgon/diskv
|
||||
version: v2.0.1
|
||||
- package: github.com/docker/go-connections
|
||||
version: v0.3.0
|
||||
- package: github.com/jteeuwen/go-bindata
|
||||
version: v3.0.7-72-ga0ff2567cfb709
|
||||
- package: github.com/armon/circbuf
|
||||
version: bbbad097214e2918d8543d5201d12bfd7bca254d
|
||||
- package: github.com/coreos/etcd
|
||||
version: v3.3.10
|
||||
- package: github.com/renstrom/dedent
|
||||
version: v1.0.0-3-g020d11c3b9c0c7
|
||||
|
||||
15
vendor.conf
15
vendor.conf
@@ -9,9 +9,9 @@ package=github.com/opencontainers/runc/libcontainer/nsenter
|
||||
package=github.com/opencontainers/runc/libcontainer/specconv
|
||||
package=github.com/opencontainers/runc/contrib/cmd/recvtty
|
||||
|
||||
k8s.io/kubernetes v1.13.3-klp1 file:///home/darren/src/kuberlite/.git transitive=true,staging=true
|
||||
k8s.io/kubernetes v1.13.3-k3s2 https://github.com/ibuildthecloud/k3s.git transitive=true,staging=true
|
||||
|
||||
github.com/rancher/norman d640c72bf09d9fbff596dead44338453bba718cc https://github.com/ibuildthecloud/norman.git
|
||||
github.com/rancher/norman e4f12a1656cb04b4b2a25c571fc05283ec25f946 https://github.com/ibuildthecloud/norman.git
|
||||
github.com/coreos/flannel 823afe66b2266bf71f5bec24e6e28b26d70cfc7c https://github.com/ibuildthecloud/flannel.git
|
||||
github.com/natefinch/lumberjack aee4629129445bbdfb69aa565537dcfa16544311
|
||||
github.com/gorilla/mux v1.6.2
|
||||
@@ -36,7 +36,7 @@ github.com/alexflint/go-filemutex 72bdc8eae2aef913234599b837f5dda445ca9bd9
|
||||
github.com/opencontainers/runtime-spec 5684b8af48c1ac3b1451fa499724e30e3c20a294
|
||||
|
||||
# containerd
|
||||
github.com/containerd/containerd v1.2.2-k3s2 https://github.com/ibuildthecloud/containerd
|
||||
github.com/containerd/containerd v1.2.3-k3s1 https://github.com/ibuildthecloud/containerd
|
||||
github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3
|
||||
github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
|
||||
github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2
|
||||
@@ -47,7 +47,7 @@ github.com/containerd/continuity bd77b46c8352f74eb12c85bdc01f4b90f69d66b4
|
||||
github.com/coreos/go-systemd 48702e0da86bd25e76cfef347e2adeb434a0d0a6
|
||||
github.com/docker/go-metrics 4ea375f7759c82740c893fc030bc37088d2ec098
|
||||
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
|
||||
github.com/docker/go-units v0.3.1
|
||||
#github.com/docker/go-units v0.3.3
|
||||
github.com/godbus/dbus c7fdd8b5cd55e87b4e1f4e372cdb1db61dd6c66f
|
||||
#github.com/prometheus/client_golang f4fb1b73fb099f396a7f0036bf86aa8def4ed823
|
||||
#github.com/prometheus/client_model 99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c
|
||||
@@ -59,7 +59,7 @@ github.com/gogo/protobuf v1.0.0
|
||||
github.com/gogo/googleapis 08a7655d27152912db7aaf4f983275eaf8d128ef
|
||||
github.com/golang/protobuf v1.1.0
|
||||
#github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353 # v1.0.1-45-geba862d
|
||||
github.com/opencontainers/runc 96ec2177ae841256168fcf76954f7177af9446eb
|
||||
github.com/opencontainers/runc 12f6a991201fdb8f82579582d5e00e28fba06d0a
|
||||
github.com/sirupsen/logrus v1.0.3
|
||||
github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
|
||||
golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac
|
||||
@@ -81,8 +81,11 @@ gotest.tools v2.1.0
|
||||
github.com/google/go-cmp v0.1.0
|
||||
go.etcd.io/bbolt v1.3.1-etcd.8
|
||||
|
||||
# crictl
|
||||
github.com/kubernetes-sigs/cri-tools c465773e3ad8c941d1756c0a467d550b04a8f65b https://github.com/ibuildthecloud/cri-tools.git
|
||||
|
||||
# cri dependencies
|
||||
github.com/containerd/cri 0d5cabd006cb5319dc965046067b8432d9fa5ef8 # release/1.2 branch
|
||||
github.com/containerd/cri c3cf754321fc38c6af5dfd2552fdde0ad192b31d # release/1.2 branch
|
||||
github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90
|
||||
github.com/blang/semver v3.1.0
|
||||
github.com/containernetworking/cni v0.6.0
|
||||
|
||||
1
vendor/github.com/containerd/containerd/.gometalinter.json
generated
vendored
1
vendor/github.com/containerd/containerd/.gometalinter.json
generated
vendored
@@ -10,7 +10,6 @@
|
||||
|
||||
"Enable": [
|
||||
"structcheck",
|
||||
"unused",
|
||||
"varcheck",
|
||||
"staticcheck",
|
||||
"unconvert",
|
||||
|
||||
2
vendor/github.com/containerd/containerd/.mailmap
generated
vendored
2
vendor/github.com/containerd/containerd/.mailmap
generated
vendored
@@ -24,3 +24,5 @@ Jian Liao <jliao@alauda.io> liaojian <liaojian@Dabllo.local>
|
||||
Rui Cao <ruicao@alauda.io> ruicao <ruicao@alauda.io>
|
||||
Xuean Yan <yan.xuean@zte.com.cn> yanxuean <yan.xuean@zte.com.cn>
|
||||
Mike Brown <brownwm@us.ibm.com> Mike Brown <mikebrow@users.noreply.github.com>
|
||||
Ace-Tang <aceapril@126.com>
|
||||
Wei Fu <fuweid89@gmail.com>
|
||||
|
||||
4
vendor/github.com/containerd/containerd/archive/tar.go
generated
vendored
4
vendor/github.com/containerd/containerd/archive/tar.go
generated
vendored
@@ -100,7 +100,7 @@ const (
|
||||
// readdir calls to this directory do not follow to lower layers.
|
||||
whiteoutOpaqueDir = whiteoutMetaPrefix + ".opq"
|
||||
|
||||
paxSchilyXattr = "SCHILY.xattrs."
|
||||
paxSchilyXattr = "SCHILY.xattr."
|
||||
)
|
||||
|
||||
// Apply applies a tar stream of an OCI style diff tar.
|
||||
@@ -295,7 +295,7 @@ func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyO
|
||||
linkBasename := filepath.Base(hdr.Linkname)
|
||||
srcHdr = aufsHardlinks[linkBasename]
|
||||
if srcHdr == nil {
|
||||
return 0, fmt.Errorf("Invalid aufs hardlink")
|
||||
return 0, fmt.Errorf("invalid aufs hardlink")
|
||||
}
|
||||
p, err := fs.RootPath(aufsTempdir, linkBasename)
|
||||
if err != nil {
|
||||
|
||||
8
vendor/github.com/containerd/containerd/archive/tar_windows.go
generated
vendored
8
vendor/github.com/containerd/containerd/archive/tar_windows.go
generated
vendored
@@ -74,7 +74,7 @@ func tarName(p string) (string, error) {
|
||||
// in file names, it is mostly safe to replace however we must
|
||||
// check just in case
|
||||
if strings.Contains(p, "/") {
|
||||
return "", fmt.Errorf("Windows path contains forward slash: %s", p)
|
||||
return "", fmt.Errorf("windows path contains forward slash: %s", p)
|
||||
}
|
||||
|
||||
return strings.Replace(p, string(os.PathSeparator), "/", -1), nil
|
||||
@@ -130,11 +130,7 @@ func skipFile(hdr *tar.Header) bool {
|
||||
// specific or Linux-specific, this warning should be changed to an error
|
||||
// to cater for the situation where someone does manage to upload a Linux
|
||||
// image but have it tagged as Windows inadvertently.
|
||||
if strings.Contains(hdr.Name, ":") {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
return strings.Contains(hdr.Name, ":")
|
||||
}
|
||||
|
||||
// handleTarTypeBlockCharFifo is an OS-specific helper function used by
|
||||
|
||||
65
vendor/github.com/containerd/containerd/client.go
generated
vendored
65
vendor/github.com/containerd/containerd/client.go
generated
vendored
@@ -338,7 +338,8 @@ func (c *Client) Fetch(ctx context.Context, ref string, opts ...RemoteOpt) (imag
|
||||
}
|
||||
defer done(ctx)
|
||||
|
||||
return c.fetch(ctx, fetchCtx, ref, 0)
|
||||
img, _, err := c.fetch(ctx, fetchCtx, ref, 0)
|
||||
return img, err
|
||||
}
|
||||
|
||||
// Pull downloads the provided content into containerd's content store
|
||||
@@ -372,12 +373,12 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
|
||||
}
|
||||
defer done(ctx)
|
||||
|
||||
img, err := c.fetch(ctx, pullCtx, ref, 1)
|
||||
img, imagePlatforms, err := c.fetch(ctx, pullCtx, ref, 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
i := NewImageWithPlatform(c, img, pullCtx.PlatformMatcher)
|
||||
i := NewImageWithPlatform(c, img, imagePlatforms)
|
||||
|
||||
if pullCtx.Unpack {
|
||||
if err := i.Unpack(ctx, pullCtx.Snapshotter); err != nil {
|
||||
@@ -388,25 +389,36 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, limit int) (images.Image, error) {
|
||||
func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, limit int) (images.Image, platforms.MatchComparer, error) {
|
||||
platformCapture := images.NewPlatformCapture(rCtx.PlatformMatcher)
|
||||
store := c.ContentStore()
|
||||
name, desc, err := rCtx.Resolver.Resolve(ctx, ref)
|
||||
if err != nil {
|
||||
return images.Image{}, errors.Wrapf(err, "failed to resolve reference %q", ref)
|
||||
return images.Image{}, nil, errors.Wrapf(err, "failed to resolve reference %q", ref)
|
||||
}
|
||||
|
||||
fetcher, err := rCtx.Resolver.Fetcher(ctx, name)
|
||||
if err != nil {
|
||||
return images.Image{}, errors.Wrapf(err, "failed to get fetcher for %q", name)
|
||||
return images.Image{}, nil, errors.Wrapf(err, "failed to get fetcher for %q", name)
|
||||
}
|
||||
|
||||
var (
|
||||
schema1Converter *schema1.Converter
|
||||
handler images.Handler
|
||||
handler images.Handler
|
||||
|
||||
isConvertible bool
|
||||
converterFunc func(context.Context, ocispec.Descriptor) (ocispec.Descriptor, error)
|
||||
)
|
||||
|
||||
if desc.MediaType == images.MediaTypeDockerSchema1Manifest && rCtx.ConvertSchema1 {
|
||||
schema1Converter = schema1.NewConverter(store, fetcher)
|
||||
schema1Converter := schema1.NewConverter(store, fetcher)
|
||||
|
||||
handler = images.Handlers(append(rCtx.BaseHandlers, schema1Converter)...)
|
||||
|
||||
isConvertible = true
|
||||
|
||||
converterFunc = func(ctx context.Context, _ ocispec.Descriptor) (ocispec.Descriptor, error) {
|
||||
return schema1Converter.Convert(ctx)
|
||||
}
|
||||
} else {
|
||||
// Get all the children for a descriptor
|
||||
childrenHandler := images.ChildrenHandler(store)
|
||||
@@ -419,19 +431,38 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, lim
|
||||
childrenHandler = images.LimitManifests(childrenHandler, rCtx.PlatformMatcher, limit)
|
||||
}
|
||||
|
||||
// Save the platforms that match the PlatformMatcher
|
||||
childrenHandler = platformCapture.Handler(childrenHandler)
|
||||
|
||||
// set isConvertible to true if there is application/octet-stream media type
|
||||
convertibleHandler := images.HandlerFunc(
|
||||
func(_ context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
if desc.MediaType == docker.LegacyConfigMediaType {
|
||||
isConvertible = true
|
||||
}
|
||||
|
||||
return []ocispec.Descriptor{}, nil
|
||||
},
|
||||
)
|
||||
|
||||
handler = images.Handlers(append(rCtx.BaseHandlers,
|
||||
remotes.FetchHandler(store, fetcher),
|
||||
convertibleHandler,
|
||||
childrenHandler,
|
||||
)...)
|
||||
|
||||
converterFunc = func(ctx context.Context, desc ocispec.Descriptor) (ocispec.Descriptor, error) {
|
||||
return docker.ConvertManifest(ctx, store, desc)
|
||||
}
|
||||
}
|
||||
|
||||
if err := images.Dispatch(ctx, handler, desc); err != nil {
|
||||
return images.Image{}, err
|
||||
return images.Image{}, nil, err
|
||||
}
|
||||
if schema1Converter != nil {
|
||||
desc, err = schema1Converter.Convert(ctx)
|
||||
if err != nil {
|
||||
return images.Image{}, err
|
||||
|
||||
if isConvertible {
|
||||
if desc, err = converterFunc(ctx, desc); err != nil {
|
||||
return images.Image{}, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,7 +476,7 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, lim
|
||||
for {
|
||||
if created, err := is.Create(ctx, img); err != nil {
|
||||
if !errdefs.IsAlreadyExists(err) {
|
||||
return images.Image{}, err
|
||||
return images.Image{}, nil, err
|
||||
}
|
||||
|
||||
updated, err := is.Update(ctx, img)
|
||||
@@ -454,7 +485,7 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, lim
|
||||
if errdefs.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
return images.Image{}, err
|
||||
return images.Image{}, nil, err
|
||||
}
|
||||
|
||||
img = updated
|
||||
@@ -462,7 +493,7 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, lim
|
||||
img = created
|
||||
}
|
||||
|
||||
return img, nil
|
||||
return img, platformCapture.MatchComparer(), nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
116
vendor/github.com/containerd/containerd/cmd/ctr/app/main.go
generated
vendored
Normal file
116
vendor/github.com/containerd/containerd/cmd/ctr/app/main.go
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/containers"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/content"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/events"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/images"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/install"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/leases"
|
||||
namespacesCmd "github.com/containerd/containerd/cmd/ctr/commands/namespaces"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/plugins"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/pprof"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/run"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/snapshots"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/tasks"
|
||||
versionCmd "github.com/containerd/containerd/cmd/ctr/commands/version"
|
||||
"github.com/containerd/containerd/defaults"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/version"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
|
||||
var extraCmds = []cli.Command{}
|
||||
|
||||
func init() {
|
||||
// Discard grpc logs so that they don't mess with our stdio
|
||||
grpclog.SetLoggerV2(grpclog.NewLoggerV2(ioutil.Discard, ioutil.Discard, ioutil.Discard))
|
||||
|
||||
cli.VersionPrinter = func(c *cli.Context) {
|
||||
fmt.Println(c.App.Name, version.Package, c.App.Version)
|
||||
}
|
||||
}
|
||||
|
||||
// New returns a *cli.App instance.
|
||||
func New() *cli.App {
|
||||
app := cli.NewApp()
|
||||
app.Name = "ctr"
|
||||
app.Version = version.Version
|
||||
app.Usage = `
|
||||
__
|
||||
_____/ /______
|
||||
/ ___/ __/ ___/
|
||||
/ /__/ /_/ /
|
||||
\___/\__/_/
|
||||
|
||||
containerd CLI
|
||||
`
|
||||
app.Flags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "debug",
|
||||
Usage: "enable debug output in logs",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "address, a",
|
||||
Usage: "address for containerd's GRPC server",
|
||||
Value: defaults.DefaultAddress,
|
||||
},
|
||||
cli.DurationFlag{
|
||||
Name: "timeout",
|
||||
Usage: "total timeout for ctr commands",
|
||||
},
|
||||
cli.DurationFlag{
|
||||
Name: "connect-timeout",
|
||||
Usage: "timeout for connecting to containerd",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "namespace, n",
|
||||
Usage: "namespace to use with commands",
|
||||
Value: namespaces.Default,
|
||||
EnvVar: namespaces.NamespaceEnvVar,
|
||||
},
|
||||
}
|
||||
app.Commands = append([]cli.Command{
|
||||
plugins.Command,
|
||||
versionCmd.Command,
|
||||
containers.Command,
|
||||
content.Command,
|
||||
events.Command,
|
||||
images.Command,
|
||||
leases.Command,
|
||||
namespacesCmd.Command,
|
||||
pprof.Command,
|
||||
run.Command,
|
||||
snapshots.Command,
|
||||
tasks.Command,
|
||||
install.Command,
|
||||
}, extraCmds...)
|
||||
app.Before = func(context *cli.Context) error {
|
||||
if context.GlobalBool("debug") {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return app
|
||||
}
|
||||
25
vendor/github.com/containerd/containerd/cmd/ctr/app/main_unix.go
generated
vendored
Normal file
25
vendor/github.com/containerd/containerd/cmd/ctr/app/main_unix.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package app
|
||||
|
||||
import "github.com/containerd/containerd/cmd/ctr/commands/shim"
|
||||
|
||||
func init() {
|
||||
extraCmds = append(extraCmds, shim.Command)
|
||||
}
|
||||
56
vendor/github.com/containerd/containerd/cmd/ctr/commands/client.go
generated
vendored
Normal file
56
vendor/github.com/containerd/containerd/cmd/ctr/commands/client.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// AppContext returns the context for a command. Should only be called once per
|
||||
// command, near the start.
|
||||
//
|
||||
// This will ensure the namespace is picked up and set the timeout, if one is
|
||||
// defined.
|
||||
func AppContext(context *cli.Context) (gocontext.Context, gocontext.CancelFunc) {
|
||||
var (
|
||||
ctx = gocontext.Background()
|
||||
timeout = context.GlobalDuration("timeout")
|
||||
namespace = context.GlobalString("namespace")
|
||||
cancel gocontext.CancelFunc
|
||||
)
|
||||
ctx = namespaces.WithNamespace(ctx, namespace)
|
||||
if timeout > 0 {
|
||||
ctx, cancel = gocontext.WithTimeout(ctx, timeout)
|
||||
} else {
|
||||
ctx, cancel = gocontext.WithCancel(ctx)
|
||||
}
|
||||
return ctx, cancel
|
||||
}
|
||||
|
||||
// NewClient returns a new containerd client
|
||||
func NewClient(context *cli.Context, opts ...containerd.ClientOpt) (*containerd.Client, gocontext.Context, gocontext.CancelFunc, error) {
|
||||
client, err := containerd.New(context.GlobalString("address"), opts...)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
ctx, cancel := AppContext(context)
|
||||
return client, ctx, cancel, nil
|
||||
}
|
||||
187
vendor/github.com/containerd/containerd/cmd/ctr/commands/commands.go
generated
vendored
Normal file
187
vendor/github.com/containerd/containerd/cmd/ctr/commands/commands.go
generated
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
// SnapshotterFlags are cli flags specifying snapshotter names
|
||||
SnapshotterFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "snapshotter",
|
||||
Usage: "snapshotter name. Empty value stands for the default value.",
|
||||
Value: containerd.DefaultSnapshotter,
|
||||
EnvVar: "CONTAINERD_SNAPSHOTTER",
|
||||
},
|
||||
}
|
||||
|
||||
// LabelFlag is a cli flag specifying labels
|
||||
LabelFlag = cli.StringSliceFlag{
|
||||
Name: "label",
|
||||
Usage: "labels to attach to the image",
|
||||
}
|
||||
|
||||
// RegistryFlags are cli flags specifying registry options
|
||||
RegistryFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "skip-verify,k",
|
||||
Usage: "skip SSL certificate validation",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "plain-http",
|
||||
Usage: "allow connections using plain HTTP",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "user,u",
|
||||
Usage: "user[:password] Registry user and password",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "refresh",
|
||||
Usage: "refresh token for authorization server",
|
||||
},
|
||||
}
|
||||
|
||||
// ContainerFlags are cli flags specifying container options
|
||||
ContainerFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "config,c",
|
||||
Usage: "path to the runtime-specific spec config file",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "checkpoint",
|
||||
Usage: "provide the checkpoint digest to restore the container",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "cwd",
|
||||
Usage: "specify the working directory of the process",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "env",
|
||||
Usage: "specify additional container environment variables (i.e. FOO=bar)",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "label",
|
||||
Usage: "specify additional labels (i.e. foo=bar)",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "mount",
|
||||
Usage: "specify additional container mount (ex: type=bind,src=/tmp,dst=/host,options=rbind:ro)",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "net-host",
|
||||
Usage: "enable host networking for the container",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "privileged",
|
||||
Usage: "run privileged container",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "read-only",
|
||||
Usage: "set the containers filesystem as readonly",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "runtime",
|
||||
Usage: "runtime name",
|
||||
Value: fmt.Sprintf("io.containerd.runtime.v1.%s", runtime.GOOS),
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "tty,t",
|
||||
Usage: "allocate a TTY for the container",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "with-ns",
|
||||
Usage: "specify existing Linux namespaces to join at container runtime (format '<nstype>:<path>')",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "pid-file",
|
||||
Usage: "file path to write the task's pid",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "gpus",
|
||||
Usage: "add gpus to the container",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "allow-new-privs",
|
||||
Usage: "turn off OCI spec's NoNewPrivileges feature flag",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// ObjectWithLabelArgs returns the first arg and a LabelArgs object
|
||||
func ObjectWithLabelArgs(clicontext *cli.Context) (string, map[string]string) {
|
||||
var (
|
||||
first = clicontext.Args().First()
|
||||
labelStrings = clicontext.Args().Tail()
|
||||
)
|
||||
|
||||
return first, LabelArgs(labelStrings)
|
||||
}
|
||||
|
||||
// LabelArgs returns a map of label key,value pairs
|
||||
func LabelArgs(labelStrings []string) map[string]string {
|
||||
labels := make(map[string]string, len(labelStrings))
|
||||
for _, label := range labelStrings {
|
||||
parts := strings.SplitN(label, "=", 2)
|
||||
key := parts[0]
|
||||
value := "true"
|
||||
if len(parts) > 1 {
|
||||
value = parts[1]
|
||||
}
|
||||
|
||||
labels[key] = value
|
||||
}
|
||||
|
||||
return labels
|
||||
}
|
||||
|
||||
// PrintAsJSON prints input in JSON format
|
||||
func PrintAsJSON(x interface{}) {
|
||||
b, err := json.MarshalIndent(x, "", " ")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "can't marshal %+v as a JSON string: %v\n", x, err)
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
|
||||
// WritePidFile writes the pid atomically to a file
|
||||
func WritePidFile(path string, pid int) error {
|
||||
path, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tempPath := filepath.Join(filepath.Dir(path), fmt.Sprintf(".%s", filepath.Base(path)))
|
||||
f, err := os.OpenFile(tempPath, os.O_RDWR|os.O_CREATE|os.O_EXCL|os.O_SYNC, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = fmt.Fprintf(f, "%d", pid)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Rename(tempPath, path)
|
||||
}
|
||||
33
vendor/github.com/containerd/containerd/cmd/ctr/commands/commands_unix.go
generated
vendored
Normal file
33
vendor/github.com/containerd/containerd/cmd/ctr/commands/commands_unix.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func init() {
|
||||
ContainerFlags = append(ContainerFlags, cli.BoolFlag{
|
||||
Name: "rootfs",
|
||||
Usage: "use custom rootfs that is not managed by containerd snapshotter",
|
||||
}, cli.BoolFlag{
|
||||
Name: "no-pivot",
|
||||
Usage: "disable use of pivot-root (linux only)",
|
||||
})
|
||||
}
|
||||
284
vendor/github.com/containerd/containerd/cmd/ctr/commands/containers/containers.go
generated
vendored
Normal file
284
vendor/github.com/containerd/containerd/cmd/ctr/commands/containers/containers.go
generated
vendored
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package containers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/run"
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/typeurl"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// Command is the cli command for managing containers
|
||||
var Command = cli.Command{
|
||||
Name: "containers",
|
||||
Usage: "manage containers",
|
||||
Aliases: []string{"c", "container"},
|
||||
Subcommands: []cli.Command{
|
||||
createCommand,
|
||||
deleteCommand,
|
||||
infoCommand,
|
||||
listCommand,
|
||||
setLabelsCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var createCommand = cli.Command{
|
||||
Name: "create",
|
||||
Usage: "create container",
|
||||
ArgsUsage: "[flags] Image|RootFS CONTAINER",
|
||||
Flags: append(commands.SnapshotterFlags, commands.ContainerFlags...),
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
id string
|
||||
ref string
|
||||
config = context.IsSet("config")
|
||||
)
|
||||
|
||||
if config {
|
||||
id = context.Args().First()
|
||||
if context.NArg() > 1 {
|
||||
return errors.New("with spec config file, only container id should be provided")
|
||||
}
|
||||
} else {
|
||||
id = context.Args().Get(1)
|
||||
ref = context.Args().First()
|
||||
if ref == "" {
|
||||
return errors.New("image ref must be provided")
|
||||
}
|
||||
}
|
||||
if id == "" {
|
||||
return errors.New("container id must be provided")
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
_, err = run.NewContainer(ctx, client, context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var listCommand = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "list containers",
|
||||
ArgsUsage: "[flags] [<filter>, ...]",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
||||
Usage: "print only the container id",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
filters = context.Args()
|
||||
quiet = context.Bool("quiet")
|
||||
)
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
containers, err := client.Containers(ctx, filters...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if quiet {
|
||||
for _, c := range containers {
|
||||
fmt.Printf("%s\n", c.ID())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
w := tabwriter.NewWriter(os.Stdout, 4, 8, 4, ' ', 0)
|
||||
fmt.Fprintln(w, "CONTAINER\tIMAGE\tRUNTIME\t")
|
||||
for _, c := range containers {
|
||||
info, err := c.Info(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imageName := info.Image
|
||||
if imageName == "" {
|
||||
imageName = "-"
|
||||
}
|
||||
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t\n",
|
||||
c.ID(),
|
||||
imageName,
|
||||
info.Runtime.Name,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return w.Flush()
|
||||
},
|
||||
}
|
||||
|
||||
var deleteCommand = cli.Command{
|
||||
Name: "delete",
|
||||
Usage: "delete one or more existing containers",
|
||||
ArgsUsage: "[flags] CONTAINER [CONTAINER, ...]",
|
||||
Aliases: []string{"del", "rm"},
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "keep-snapshot",
|
||||
Usage: "do not clean up snapshot with container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var exitErr error
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
deleteOpts := []containerd.DeleteOpts{}
|
||||
if !context.Bool("keep-snapshot") {
|
||||
deleteOpts = append(deleteOpts, containerd.WithSnapshotCleanup)
|
||||
}
|
||||
|
||||
if context.NArg() == 0 {
|
||||
return errors.New("must specify at least one container to delete")
|
||||
}
|
||||
for _, arg := range context.Args() {
|
||||
if err := deleteContainer(ctx, client, arg, deleteOpts...); err != nil {
|
||||
if exitErr == nil {
|
||||
exitErr = err
|
||||
}
|
||||
log.G(ctx).WithError(err).Errorf("failed to delete container %q", arg)
|
||||
}
|
||||
}
|
||||
return exitErr
|
||||
},
|
||||
}
|
||||
|
||||
func deleteContainer(ctx context.Context, client *containerd.Client, id string, opts ...containerd.DeleteOpts) error {
|
||||
container, err := client.LoadContainer(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
task, err := container.Task(ctx, cio.Load)
|
||||
if err != nil {
|
||||
return container.Delete(ctx, opts...)
|
||||
}
|
||||
status, err := task.Status(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if status.Status == containerd.Stopped || status.Status == containerd.Created {
|
||||
if _, err := task.Delete(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return container.Delete(ctx, opts...)
|
||||
}
|
||||
return fmt.Errorf("cannot delete a non stopped container: %v", status)
|
||||
|
||||
}
|
||||
|
||||
var setLabelsCommand = cli.Command{
|
||||
Name: "label",
|
||||
Usage: "set and clear labels for a container",
|
||||
ArgsUsage: "[flags] CONTAINER [<key>=<value>, ...]",
|
||||
Description: "set and clear labels for a container",
|
||||
Flags: []cli.Flag{},
|
||||
Action: func(context *cli.Context) error {
|
||||
containerID, labels := commands.ObjectWithLabelArgs(context)
|
||||
if containerID == "" {
|
||||
return errors.New("container id must be provided")
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
container, err := client.LoadContainer(ctx, containerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
setlabels, err := container.SetLabels(ctx, labels)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var labelStrings []string
|
||||
for k, v := range setlabels {
|
||||
labelStrings = append(labelStrings, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
|
||||
fmt.Println(strings.Join(labelStrings, ","))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var infoCommand = cli.Command{
|
||||
Name: "info",
|
||||
Usage: "get info about a container",
|
||||
ArgsUsage: "CONTAINER",
|
||||
Action: func(context *cli.Context) error {
|
||||
id := context.Args().First()
|
||||
if id == "" {
|
||||
return errors.New("container id must be provided")
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
container, err := client.LoadContainer(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := container.Info(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if info.Spec != nil && info.Spec.Value != nil {
|
||||
v, err := typeurl.UnmarshalAny(info.Spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commands.PrintAsJSON(struct {
|
||||
containers.Container
|
||||
Spec interface{} `json:"Spec,omitempty"`
|
||||
}{
|
||||
Container: info,
|
||||
Spec: v,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
commands.PrintAsJSON(info)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
560
vendor/github.com/containerd/containerd/cmd/ctr/commands/content/content.go
generated
vendored
Normal file
560
vendor/github.com/containerd/containerd/cmd/ctr/commands/content/content.go
generated
vendored
Normal file
@@ -0,0 +1,560 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package content
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/log"
|
||||
units "github.com/docker/go-units"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
// Command is the cli command for managing content
|
||||
Command = cli.Command{
|
||||
Name: "content",
|
||||
Usage: "manage content",
|
||||
Subcommands: cli.Commands{
|
||||
activeIngestCommand,
|
||||
deleteCommand,
|
||||
editCommand,
|
||||
fetchCommand,
|
||||
fetchObjectCommand,
|
||||
getCommand,
|
||||
ingestCommand,
|
||||
listCommand,
|
||||
pushObjectCommand,
|
||||
setLabelsCommand,
|
||||
},
|
||||
}
|
||||
|
||||
getCommand = cli.Command{
|
||||
Name: "get",
|
||||
Usage: "get the data for an object",
|
||||
ArgsUsage: "[<digest>, ...]",
|
||||
Description: "display the image object",
|
||||
Action: func(context *cli.Context) error {
|
||||
dgst, err := digest.Parse(context.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
cs := client.ContentStore()
|
||||
ra, err := cs.ReaderAt(ctx, ocispec.Descriptor{Digest: dgst})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ra.Close()
|
||||
|
||||
_, err = io.Copy(os.Stdout, content.NewReader(ra))
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
ingestCommand = cli.Command{
|
||||
Name: "ingest",
|
||||
Usage: "accept content into the store",
|
||||
ArgsUsage: "[flags] <key>",
|
||||
Description: "ingest objects into the local content store",
|
||||
Flags: []cli.Flag{
|
||||
cli.Int64Flag{
|
||||
Name: "expected-size",
|
||||
Usage: "validate against provided size",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "expected-digest",
|
||||
Usage: "verify content against expected digest",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
ref = context.Args().First()
|
||||
expectedSize = context.Int64("expected-size")
|
||||
expectedDigest = digest.Digest(context.String("expected-digest"))
|
||||
)
|
||||
if err := expectedDigest.Validate(); expectedDigest != "" && err != nil {
|
||||
return err
|
||||
}
|
||||
if ref == "" {
|
||||
return errors.New("must specify a transaction reference")
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
cs := client.ContentStore()
|
||||
|
||||
// TODO(stevvooe): Allow ingest to be reentrant. Currently, we expect
|
||||
// all data to be written in a single invocation. Allow multiple writes
|
||||
// to the same transaction key followed by a commit.
|
||||
return content.WriteBlob(ctx, cs, ref, os.Stdin, ocispec.Descriptor{Size: expectedSize, Digest: expectedDigest})
|
||||
},
|
||||
}
|
||||
|
||||
activeIngestCommand = cli.Command{
|
||||
Name: "active",
|
||||
Usage: "display active transfers",
|
||||
ArgsUsage: "[flags] [<regexp>]",
|
||||
Description: "display the ongoing transfers",
|
||||
Flags: []cli.Flag{
|
||||
cli.DurationFlag{
|
||||
Name: "timeout, t",
|
||||
Usage: "total timeout for fetch",
|
||||
EnvVar: "CONTAINERD_FETCH_TIMEOUT",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "root",
|
||||
Usage: "path to content store root",
|
||||
Value: "/tmp/content", // TODO(stevvooe): for now, just use the PWD/.content
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
match := context.Args().First()
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
cs := client.ContentStore()
|
||||
active, err := cs.ListStatuses(ctx, match)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, '\t', 0)
|
||||
fmt.Fprintln(tw, "REF\tSIZE\tAGE\t")
|
||||
for _, active := range active {
|
||||
fmt.Fprintf(tw, "%s\t%s\t%s\t\n",
|
||||
active.Ref,
|
||||
units.HumanSize(float64(active.Offset)),
|
||||
units.HumanDuration(time.Since(active.StartedAt)))
|
||||
}
|
||||
|
||||
return tw.Flush()
|
||||
},
|
||||
}
|
||||
|
||||
listCommand = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "list all blobs in the store",
|
||||
ArgsUsage: "[flags]",
|
||||
Description: "list blobs in the content store",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
||||
Usage: "print only the blob digest",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
quiet = context.Bool("quiet")
|
||||
args = []string(context.Args())
|
||||
)
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
cs := client.ContentStore()
|
||||
|
||||
var walkFn content.WalkFunc
|
||||
if quiet {
|
||||
walkFn = func(info content.Info) error {
|
||||
fmt.Println(info.Digest)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, '\t', 0)
|
||||
defer tw.Flush()
|
||||
|
||||
fmt.Fprintln(tw, "DIGEST\tSIZE\tAGE\tLABELS")
|
||||
walkFn = func(info content.Info) error {
|
||||
var labelStrings []string
|
||||
for k, v := range info.Labels {
|
||||
labelStrings = append(labelStrings, strings.Join([]string{k, v}, "="))
|
||||
}
|
||||
labels := strings.Join(labelStrings, ",")
|
||||
if labels == "" {
|
||||
labels = "-"
|
||||
}
|
||||
|
||||
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n",
|
||||
info.Digest,
|
||||
units.HumanSize(float64(info.Size)),
|
||||
units.HumanDuration(time.Since(info.CreatedAt)),
|
||||
labels)
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return cs.Walk(ctx, walkFn, args...)
|
||||
},
|
||||
}
|
||||
|
||||
setLabelsCommand = cli.Command{
|
||||
Name: "label",
|
||||
Usage: "add labels to content",
|
||||
ArgsUsage: "<digest> [<label>=<value> ...]",
|
||||
Description: "labels blobs in the content store",
|
||||
Action: func(context *cli.Context) error {
|
||||
object, labels := commands.ObjectWithLabelArgs(context)
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
cs := client.ContentStore()
|
||||
|
||||
dgst, err := digest.Parse(object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info := content.Info{
|
||||
Digest: dgst,
|
||||
Labels: map[string]string{},
|
||||
}
|
||||
|
||||
var paths []string
|
||||
for k, v := range labels {
|
||||
paths = append(paths, fmt.Sprintf("labels.%s", k))
|
||||
if v != "" {
|
||||
info.Labels[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing updated, do no clear
|
||||
if len(paths) == 0 {
|
||||
info, err = cs.Info(ctx, info.Digest)
|
||||
} else {
|
||||
info, err = cs.Update(ctx, info, paths...)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var labelStrings []string
|
||||
for k, v := range info.Labels {
|
||||
labelStrings = append(labelStrings, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
|
||||
fmt.Println(strings.Join(labelStrings, ","))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
editCommand = cli.Command{
|
||||
Name: "edit",
|
||||
Usage: "edit a blob and return a new digest",
|
||||
ArgsUsage: "[flags] <digest>",
|
||||
Description: "edit a blob and return a new digest",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "validate",
|
||||
Usage: "validate the result against a format (json, mediatype, etc.)",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
validate = context.String("validate")
|
||||
object = context.Args().First()
|
||||
)
|
||||
|
||||
if validate != "" {
|
||||
return errors.New("validating the edit result not supported")
|
||||
}
|
||||
|
||||
// TODO(stevvooe): Support looking up objects by a reference through
|
||||
// the image metadata storage.
|
||||
|
||||
dgst, err := digest.Parse(object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
cs := client.ContentStore()
|
||||
ra, err := cs.ReaderAt(ctx, ocispec.Descriptor{Digest: dgst})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ra.Close()
|
||||
|
||||
nrc, err := edit(content.NewReader(ra))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer nrc.Close()
|
||||
|
||||
wr, err := cs.Writer(ctx, content.WithRef("edit-"+object)) // TODO(stevvooe): Choose a better key?
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := io.Copy(wr, nrc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := wr.Commit(ctx, 0, wr.Digest()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(wr.Digest())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
deleteCommand = cli.Command{
|
||||
Name: "delete",
|
||||
Aliases: []string{"del", "remove", "rm"},
|
||||
Usage: "permanently delete one or more blobs",
|
||||
ArgsUsage: "[<digest>, ...]",
|
||||
Description: `Delete one or more blobs permanently. Successfully deleted
|
||||
blobs are printed to stdout.`,
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
args = []string(context.Args())
|
||||
exitError error
|
||||
)
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
cs := client.ContentStore()
|
||||
|
||||
for _, arg := range args {
|
||||
dgst, err := digest.Parse(arg)
|
||||
if err != nil {
|
||||
if exitError == nil {
|
||||
exitError = err
|
||||
}
|
||||
log.G(ctx).WithError(err).Errorf("could not delete %v", dgst)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := cs.Delete(ctx, dgst); err != nil {
|
||||
if !errdefs.IsNotFound(err) {
|
||||
if exitError == nil {
|
||||
exitError = err
|
||||
}
|
||||
log.G(ctx).WithError(err).Errorf("could not delete %v", dgst)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Println(dgst)
|
||||
}
|
||||
|
||||
return exitError
|
||||
},
|
||||
}
|
||||
|
||||
// TODO(stevvooe): Create "multi-fetch" mode that just takes a remote
|
||||
// then receives object/hint lines on stdin, returning content as
|
||||
// needed.
|
||||
fetchObjectCommand = cli.Command{
|
||||
Name: "fetch-object",
|
||||
Usage: "retrieve objects from a remote",
|
||||
ArgsUsage: "[flags] <remote> <object> [<hint>, ...]",
|
||||
Description: `Fetch objects by identifier from a remote.`,
|
||||
Flags: commands.RegistryFlags,
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
ref = context.Args().First()
|
||||
)
|
||||
ctx, cancel := commands.AppContext(context)
|
||||
defer cancel()
|
||||
|
||||
resolver, err := commands.GetResolver(ctx, context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx = log.WithLogger(ctx, log.G(ctx).WithField("ref", ref))
|
||||
|
||||
log.G(ctx).Debugf("resolving")
|
||||
name, desc, err := resolver.Resolve(ctx, ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fetcher, err := resolver.Fetcher(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.G(ctx).Debugf("fetching")
|
||||
rc, err := fetcher.Fetch(ctx, desc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rc.Close()
|
||||
|
||||
_, err = io.Copy(os.Stdout, rc)
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
pushObjectCommand = cli.Command{
|
||||
Name: "push-object",
|
||||
Usage: "push an object to a remote",
|
||||
ArgsUsage: "[flags] <remote> <object> <type>",
|
||||
Description: `Push objects by identifier to a remote.`,
|
||||
Flags: commands.RegistryFlags,
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
ref = context.Args().Get(0)
|
||||
object = context.Args().Get(1)
|
||||
media = context.Args().Get(2)
|
||||
)
|
||||
dgst, err := digest.Parse(object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
resolver, err := commands.GetResolver(ctx, context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx = log.WithLogger(ctx, log.G(ctx).WithField("ref", ref))
|
||||
|
||||
log.G(ctx).Debugf("resolving")
|
||||
pusher, err := resolver.Pusher(ctx, ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cs := client.ContentStore()
|
||||
|
||||
info, err := cs.Info(ctx, dgst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
desc := ocispec.Descriptor{
|
||||
MediaType: media,
|
||||
Digest: dgst,
|
||||
Size: info.Size,
|
||||
}
|
||||
|
||||
ra, err := cs.ReaderAt(ctx, desc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ra.Close()
|
||||
|
||||
cw, err := pusher.Push(ctx, desc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Progress reader
|
||||
if err := content.Copy(ctx, cw, content.NewReader(ra), desc.Size, desc.Digest); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Pushed %s %s\n", desc.Digest, desc.MediaType)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func edit(rd io.Reader) (io.ReadCloser, error) {
|
||||
tmp, err := ioutil.TempFile(os.Getenv("XDG_RUNTIME_DIR"), "edit-")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := io.Copy(tmp, rd); err != nil {
|
||||
tmp.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmd := exec.Command("sh", "-c", "$EDITOR "+tmp.Name())
|
||||
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Env = os.Environ()
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
tmp.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := tmp.Seek(0, io.SeekStart); err != nil {
|
||||
tmp.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return onCloser{ReadCloser: tmp, onClose: func() error {
|
||||
return os.RemoveAll(tmp.Name())
|
||||
}}, nil
|
||||
}
|
||||
|
||||
type onCloser struct {
|
||||
io.ReadCloser
|
||||
onClose func() error
|
||||
}
|
||||
|
||||
func (oc onCloser) Close() error {
|
||||
var err error
|
||||
if err1 := oc.ReadCloser.Close(); err1 != nil {
|
||||
err = err1
|
||||
}
|
||||
|
||||
if oc.onClose != nil {
|
||||
err1 := oc.onClose()
|
||||
if err == nil {
|
||||
err = err1
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
379
vendor/github.com/containerd/containerd/cmd/ctr/commands/content/fetch.go
generated
vendored
Normal file
379
vendor/github.com/containerd/containerd/cmd/ctr/commands/content/fetch.go
generated
vendored
Normal file
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package content
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/pkg/progress"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var fetchCommand = cli.Command{
|
||||
Name: "fetch",
|
||||
Usage: "fetch all content for an image into containerd",
|
||||
ArgsUsage: "[flags] <remote> <object>",
|
||||
Description: `Fetch an image into containerd.
|
||||
|
||||
This command ensures that containerd has all the necessary resources to build
|
||||
an image's rootfs and convert the configuration to a runtime format supported
|
||||
by containerd.
|
||||
|
||||
This command uses the same syntax, of remote and object, as 'ctr fetch-object'.
|
||||
We may want to make this nicer, but agnostism is preferred for the moment.
|
||||
|
||||
Right now, the responsibility of the daemon and the cli aren't quite clear. Do
|
||||
not use this implementation as a guide. The end goal should be having metadata,
|
||||
content and snapshots ready for a direct use via the 'ctr run'.
|
||||
|
||||
Most of this is experimental and there are few leaps to make this work.`,
|
||||
Flags: append(commands.RegistryFlags, commands.LabelFlag,
|
||||
cli.StringSliceFlag{
|
||||
Name: "platform",
|
||||
Usage: "Pull content from a specific platform",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "all-platforms",
|
||||
Usage: "pull content from all platforms",
|
||||
},
|
||||
),
|
||||
Action: func(clicontext *cli.Context) error {
|
||||
var (
|
||||
ref = clicontext.Args().First()
|
||||
)
|
||||
client, ctx, cancel, err := commands.NewClient(clicontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
config, err := NewFetchConfig(ctx, clicontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = Fetch(ctx, client, ref, config)
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
// FetchConfig for content fetch
|
||||
type FetchConfig struct {
|
||||
// Resolver
|
||||
Resolver remotes.Resolver
|
||||
// ProgressOutput to display progress
|
||||
ProgressOutput io.Writer
|
||||
// Labels to set on the content
|
||||
Labels []string
|
||||
// Platforms to fetch
|
||||
Platforms []string
|
||||
}
|
||||
|
||||
// NewFetchConfig returns the default FetchConfig from cli flags
|
||||
func NewFetchConfig(ctx context.Context, clicontext *cli.Context) (*FetchConfig, error) {
|
||||
resolver, err := commands.GetResolver(ctx, clicontext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config := &FetchConfig{
|
||||
Resolver: resolver,
|
||||
Labels: clicontext.StringSlice("label"),
|
||||
}
|
||||
if !clicontext.GlobalBool("debug") {
|
||||
config.ProgressOutput = os.Stdout
|
||||
}
|
||||
if !clicontext.Bool("all-platforms") {
|
||||
p := clicontext.StringSlice("platform")
|
||||
if len(p) == 0 {
|
||||
p = append(p, platforms.DefaultString())
|
||||
}
|
||||
config.Platforms = p
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// Fetch loads all resources into the content store and returns the image
|
||||
func Fetch(ctx context.Context, client *containerd.Client, ref string, config *FetchConfig) (images.Image, error) {
|
||||
ongoing := newJobs(ref)
|
||||
|
||||
pctx, stopProgress := context.WithCancel(ctx)
|
||||
progress := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
if config.ProgressOutput != nil {
|
||||
// no progress bar, because it hides some debug logs
|
||||
showProgress(pctx, ongoing, client.ContentStore(), config.ProgressOutput)
|
||||
}
|
||||
close(progress)
|
||||
}()
|
||||
|
||||
h := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
if desc.MediaType != images.MediaTypeDockerSchema1Manifest {
|
||||
ongoing.add(desc)
|
||||
}
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
log.G(pctx).WithField("image", ref).Debug("fetching")
|
||||
labels := commands.LabelArgs(config.Labels)
|
||||
opts := []containerd.RemoteOpt{
|
||||
containerd.WithPullLabels(labels),
|
||||
containerd.WithResolver(config.Resolver),
|
||||
containerd.WithImageHandler(h),
|
||||
containerd.WithSchema1Conversion,
|
||||
}
|
||||
for _, platform := range config.Platforms {
|
||||
opts = append(opts, containerd.WithPlatform(platform))
|
||||
}
|
||||
img, err := client.Fetch(pctx, ref, opts...)
|
||||
stopProgress()
|
||||
if err != nil {
|
||||
return images.Image{}, err
|
||||
}
|
||||
|
||||
<-progress
|
||||
return img, nil
|
||||
}
|
||||
|
||||
func showProgress(ctx context.Context, ongoing *jobs, cs content.Store, out io.Writer) {
|
||||
var (
|
||||
ticker = time.NewTicker(100 * time.Millisecond)
|
||||
fw = progress.NewWriter(out)
|
||||
start = time.Now()
|
||||
statuses = map[string]StatusInfo{}
|
||||
done bool
|
||||
)
|
||||
defer ticker.Stop()
|
||||
|
||||
outer:
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
fw.Flush()
|
||||
|
||||
tw := tabwriter.NewWriter(fw, 1, 8, 1, ' ', 0)
|
||||
|
||||
resolved := "resolved"
|
||||
if !ongoing.isResolved() {
|
||||
resolved = "resolving"
|
||||
}
|
||||
statuses[ongoing.name] = StatusInfo{
|
||||
Ref: ongoing.name,
|
||||
Status: resolved,
|
||||
}
|
||||
keys := []string{ongoing.name}
|
||||
|
||||
activeSeen := map[string]struct{}{}
|
||||
if !done {
|
||||
active, err := cs.ListStatuses(ctx, "")
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Error("active check failed")
|
||||
continue
|
||||
}
|
||||
// update status of active entries!
|
||||
for _, active := range active {
|
||||
statuses[active.Ref] = StatusInfo{
|
||||
Ref: active.Ref,
|
||||
Status: "downloading",
|
||||
Offset: active.Offset,
|
||||
Total: active.Total,
|
||||
StartedAt: active.StartedAt,
|
||||
UpdatedAt: active.UpdatedAt,
|
||||
}
|
||||
activeSeen[active.Ref] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// now, update the items in jobs that are not in active
|
||||
for _, j := range ongoing.jobs() {
|
||||
key := remotes.MakeRefKey(ctx, j)
|
||||
keys = append(keys, key)
|
||||
if _, ok := activeSeen[key]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
status, ok := statuses[key]
|
||||
if !done && (!ok || status.Status == "downloading") {
|
||||
info, err := cs.Info(ctx, j.Digest)
|
||||
if err != nil {
|
||||
if !errdefs.IsNotFound(err) {
|
||||
log.G(ctx).WithError(err).Errorf("failed to get content info")
|
||||
continue outer
|
||||
} else {
|
||||
statuses[key] = StatusInfo{
|
||||
Ref: key,
|
||||
Status: "waiting",
|
||||
}
|
||||
}
|
||||
} else if info.CreatedAt.After(start) {
|
||||
statuses[key] = StatusInfo{
|
||||
Ref: key,
|
||||
Status: "done",
|
||||
Offset: info.Size,
|
||||
Total: info.Size,
|
||||
UpdatedAt: info.CreatedAt,
|
||||
}
|
||||
} else {
|
||||
statuses[key] = StatusInfo{
|
||||
Ref: key,
|
||||
Status: "exists",
|
||||
}
|
||||
}
|
||||
} else if done {
|
||||
if ok {
|
||||
if status.Status != "done" && status.Status != "exists" {
|
||||
status.Status = "done"
|
||||
statuses[key] = status
|
||||
}
|
||||
} else {
|
||||
statuses[key] = StatusInfo{
|
||||
Ref: key,
|
||||
Status: "done",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var ordered []StatusInfo
|
||||
for _, key := range keys {
|
||||
ordered = append(ordered, statuses[key])
|
||||
}
|
||||
|
||||
Display(tw, ordered, start)
|
||||
tw.Flush()
|
||||
|
||||
if done {
|
||||
fw.Flush()
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
done = true // allow ui to update once more
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// jobs provides a way of identifying the download keys for a particular task
|
||||
// encountering during the pull walk.
|
||||
//
|
||||
// This is very minimal and will probably be replaced with something more
|
||||
// featured.
|
||||
type jobs struct {
|
||||
name string
|
||||
added map[digest.Digest]struct{}
|
||||
descs []ocispec.Descriptor
|
||||
mu sync.Mutex
|
||||
resolved bool
|
||||
}
|
||||
|
||||
func newJobs(name string) *jobs {
|
||||
return &jobs{
|
||||
name: name,
|
||||
added: map[digest.Digest]struct{}{},
|
||||
}
|
||||
}
|
||||
|
||||
func (j *jobs) add(desc ocispec.Descriptor) {
|
||||
j.mu.Lock()
|
||||
defer j.mu.Unlock()
|
||||
j.resolved = true
|
||||
|
||||
if _, ok := j.added[desc.Digest]; ok {
|
||||
return
|
||||
}
|
||||
j.descs = append(j.descs, desc)
|
||||
j.added[desc.Digest] = struct{}{}
|
||||
}
|
||||
|
||||
func (j *jobs) jobs() []ocispec.Descriptor {
|
||||
j.mu.Lock()
|
||||
defer j.mu.Unlock()
|
||||
|
||||
var descs []ocispec.Descriptor
|
||||
return append(descs, j.descs...)
|
||||
}
|
||||
|
||||
func (j *jobs) isResolved() bool {
|
||||
j.mu.Lock()
|
||||
defer j.mu.Unlock()
|
||||
return j.resolved
|
||||
}
|
||||
|
||||
// StatusInfo holds the status info for an upload or download
|
||||
type StatusInfo struct {
|
||||
Ref string
|
||||
Status string
|
||||
Offset int64
|
||||
Total int64
|
||||
StartedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// Display pretty prints out the download or upload progress
|
||||
func Display(w io.Writer, statuses []StatusInfo, start time.Time) {
|
||||
var total int64
|
||||
for _, status := range statuses {
|
||||
total += status.Offset
|
||||
switch status.Status {
|
||||
case "downloading", "uploading":
|
||||
var bar progress.Bar
|
||||
if status.Total > 0.0 {
|
||||
bar = progress.Bar(float64(status.Offset) / float64(status.Total))
|
||||
}
|
||||
fmt.Fprintf(w, "%s:\t%s\t%40r\t%8.8s/%s\t\n",
|
||||
status.Ref,
|
||||
status.Status,
|
||||
bar,
|
||||
progress.Bytes(status.Offset), progress.Bytes(status.Total))
|
||||
case "resolving", "waiting":
|
||||
bar := progress.Bar(0.0)
|
||||
fmt.Fprintf(w, "%s:\t%s\t%40r\t\n",
|
||||
status.Ref,
|
||||
status.Status,
|
||||
bar)
|
||||
default:
|
||||
bar := progress.Bar(1.0)
|
||||
fmt.Fprintf(w, "%s:\t%s\t%40r\t\n",
|
||||
status.Ref,
|
||||
status.Status,
|
||||
bar)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "elapsed: %-4.1fs\ttotal: %7.6v\t(%v)\t\n",
|
||||
time.Since(start).Seconds(),
|
||||
// TODO(stevvooe): These calculations are actually way off.
|
||||
// Need to account for previously downloaded data. These
|
||||
// will basically be right for a download the first time
|
||||
// but will be skewed if restarting, as it includes the
|
||||
// data into the start time before.
|
||||
progress.Bytes(total),
|
||||
progress.NewBytesPerSecond(total, time.Since(start)))
|
||||
}
|
||||
77
vendor/github.com/containerd/containerd/cmd/ctr/commands/events/events.go
generated
vendored
Normal file
77
vendor/github.com/containerd/containerd/cmd/ctr/commands/events/events.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package events
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/events"
|
||||
"github.com/containerd/typeurl"
|
||||
"github.com/urfave/cli"
|
||||
|
||||
// Register grpc event types
|
||||
_ "github.com/containerd/containerd/api/events"
|
||||
)
|
||||
|
||||
// Command is the cli command for displaying containerd events
|
||||
var Command = cli.Command{
|
||||
Name: "events",
|
||||
Aliases: []string{"event"},
|
||||
Usage: "display containerd events",
|
||||
Action: func(context *cli.Context) error {
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
eventsClient := client.EventService()
|
||||
eventsCh, errCh := eventsClient.Subscribe(ctx, context.Args()...)
|
||||
open := true
|
||||
for open {
|
||||
var e *events.Envelope
|
||||
select {
|
||||
case e = <-eventsCh:
|
||||
case err, open = <-errCh:
|
||||
return err
|
||||
}
|
||||
if e != nil {
|
||||
var out []byte
|
||||
if e.Event != nil {
|
||||
v, err := typeurl.UnmarshalAny(e.Event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out, err = json.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err := fmt.Println(
|
||||
e.Timestamp,
|
||||
e.Namespace,
|
||||
e.Topic,
|
||||
string(out),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
125
vendor/github.com/containerd/containerd/cmd/ctr/commands/images/export.go
generated
vendored
Normal file
125
vendor/github.com/containerd/containerd/cmd/ctr/commands/images/export.go
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package images
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
oci "github.com/containerd/containerd/images/oci"
|
||||
"github.com/containerd/containerd/reference"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var exportCommand = cli.Command{
|
||||
Name: "export",
|
||||
Usage: "export an image",
|
||||
ArgsUsage: "[flags] <out> <image>",
|
||||
Description: `Export an image to a tar stream.
|
||||
Currently, only OCI format is supported.
|
||||
`,
|
||||
Flags: []cli.Flag{
|
||||
// TODO(AkihiroSuda): make this map[string]string as in moby/moby#33355?
|
||||
cli.StringFlag{
|
||||
Name: "oci-ref-name",
|
||||
Value: "",
|
||||
Usage: "override org.opencontainers.image.ref.name annotation",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "manifest",
|
||||
Usage: "digest of manifest",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "manifest-type",
|
||||
Usage: "media type of manifest digest",
|
||||
Value: ocispec.MediaTypeImageManifest,
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
out = context.Args().First()
|
||||
local = context.Args().Get(1)
|
||||
desc ocispec.Descriptor
|
||||
)
|
||||
if out == "" || local == "" {
|
||||
return errors.New("please provide both an output filename and an image reference to export")
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
if manifest := context.String("manifest"); manifest != "" {
|
||||
desc.Digest, err = digest.Parse(manifest)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid manifest digest")
|
||||
}
|
||||
desc.MediaType = context.String("manifest-type")
|
||||
} else {
|
||||
img, err := client.ImageService().Get(ctx, local)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to resolve image to manifest")
|
||||
}
|
||||
desc = img.Target
|
||||
}
|
||||
|
||||
if desc.Annotations == nil {
|
||||
desc.Annotations = make(map[string]string)
|
||||
}
|
||||
if s, ok := desc.Annotations[ocispec.AnnotationRefName]; !ok || s == "" {
|
||||
if ociRefName := determineOCIRefName(local); ociRefName != "" {
|
||||
desc.Annotations[ocispec.AnnotationRefName] = ociRefName
|
||||
}
|
||||
if ociRefName := context.String("oci-ref-name"); ociRefName != "" {
|
||||
desc.Annotations[ocispec.AnnotationRefName] = ociRefName
|
||||
}
|
||||
}
|
||||
var w io.WriteCloser
|
||||
if out == "-" {
|
||||
w = os.Stdout
|
||||
} else {
|
||||
w, err = os.Create(out)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
r, err := client.Export(ctx, &oci.V1Exporter{}, desc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(w, r); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.Close()
|
||||
},
|
||||
}
|
||||
|
||||
func determineOCIRefName(local string) string {
|
||||
refspec, err := reference.Parse(local)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
tag, _ := reference.SplitObject(refspec.Object)
|
||||
return tag
|
||||
}
|
||||
330
vendor/github.com/containerd/containerd/cmd/ctr/commands/images/images.go
generated
vendored
Normal file
330
vendor/github.com/containerd/containerd/cmd/ctr/commands/images/images.go
generated
vendored
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package images
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/pkg/progress"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// Command is the cli command for managing images
|
||||
var Command = cli.Command{
|
||||
Name: "images",
|
||||
Aliases: []string{"image", "i"},
|
||||
Usage: "manage images",
|
||||
Subcommands: cli.Commands{
|
||||
checkCommand,
|
||||
exportCommand,
|
||||
importCommand,
|
||||
listCommand,
|
||||
pullCommand,
|
||||
pushCommand,
|
||||
removeCommand,
|
||||
setLabelsCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var listCommand = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "list images known to containerd",
|
||||
ArgsUsage: "[flags] <ref>",
|
||||
Description: "list images registered with containerd",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
||||
Usage: "print only the image refs",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
filters = context.Args()
|
||||
quiet = context.Bool("quiet")
|
||||
)
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
var (
|
||||
imageStore = client.ImageService()
|
||||
cs = client.ContentStore()
|
||||
)
|
||||
imageList, err := imageStore.List(ctx, filters...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to list images")
|
||||
}
|
||||
if quiet {
|
||||
for _, image := range imageList {
|
||||
fmt.Println(image.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0)
|
||||
fmt.Fprintln(tw, "REF\tTYPE\tDIGEST\tSIZE\tPLATFORMS\tLABELS\t")
|
||||
for _, image := range imageList {
|
||||
size, err := image.Size(ctx, cs, platforms.Default())
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Errorf("failed calculating size for image %s", image.Name)
|
||||
}
|
||||
|
||||
platformColumn := "-"
|
||||
specs, err := images.Platforms(ctx, cs, image.Target)
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Errorf("failed resolving platform for image %s", image.Name)
|
||||
} else if len(specs) > 0 {
|
||||
psm := map[string]struct{}{}
|
||||
for _, p := range specs {
|
||||
psm[platforms.Format(p)] = struct{}{}
|
||||
}
|
||||
var ps []string
|
||||
for p := range psm {
|
||||
ps = append(ps, p)
|
||||
}
|
||||
sort.Stable(sort.StringSlice(ps))
|
||||
platformColumn = strings.Join(ps, ",")
|
||||
}
|
||||
|
||||
labels := "-"
|
||||
if len(image.Labels) > 0 {
|
||||
var pairs []string
|
||||
for k, v := range image.Labels {
|
||||
pairs = append(pairs, fmt.Sprintf("%v=%v", k, v))
|
||||
}
|
||||
sort.Strings(pairs)
|
||||
labels = strings.Join(pairs, ",")
|
||||
}
|
||||
|
||||
fmt.Fprintf(tw, "%v\t%v\t%v\t%v\t%v\t%s\t\n",
|
||||
image.Name,
|
||||
image.Target.MediaType,
|
||||
image.Target.Digest,
|
||||
progress.Bytes(size),
|
||||
platformColumn,
|
||||
labels)
|
||||
}
|
||||
|
||||
return tw.Flush()
|
||||
},
|
||||
}
|
||||
|
||||
var setLabelsCommand = cli.Command{
|
||||
Name: "label",
|
||||
Usage: "set and clear labels for an image",
|
||||
ArgsUsage: "[flags] <name> [<key>=<value>, ...]",
|
||||
Description: "set and clear labels for an image",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "replace-all, r",
|
||||
Usage: "replace all labels",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
replaceAll = context.Bool("replace-all")
|
||||
name, labels = commands.ObjectWithLabelArgs(context)
|
||||
)
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
if name == "" {
|
||||
return errors.New("please specify an image")
|
||||
}
|
||||
|
||||
var (
|
||||
is = client.ImageService()
|
||||
fieldpaths []string
|
||||
)
|
||||
|
||||
for k := range labels {
|
||||
if replaceAll {
|
||||
fieldpaths = append(fieldpaths, "labels")
|
||||
} else {
|
||||
fieldpaths = append(fieldpaths, strings.Join([]string{"labels", k}, "."))
|
||||
}
|
||||
}
|
||||
|
||||
image := images.Image{
|
||||
Name: name,
|
||||
Labels: labels,
|
||||
}
|
||||
|
||||
updated, err := is.Update(ctx, image, fieldpaths...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var labelStrings []string
|
||||
for k, v := range updated.Labels {
|
||||
labelStrings = append(labelStrings, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
|
||||
fmt.Println(strings.Join(labelStrings, ","))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var checkCommand = cli.Command{
|
||||
Name: "check",
|
||||
Usage: "check that an image has all content available locally",
|
||||
ArgsUsage: "[flags] <ref> [<ref>, ...]",
|
||||
Description: "check that an image has all content available locally",
|
||||
Flags: commands.SnapshotterFlags,
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
exitErr error
|
||||
)
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
var (
|
||||
contentStore = client.ContentStore()
|
||||
tw = tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0)
|
||||
)
|
||||
fmt.Fprintln(tw, "REF\tTYPE\tDIGEST\tSTATUS\tSIZE\tUNPACKED\t")
|
||||
|
||||
args := []string(context.Args())
|
||||
imageList, err := client.ListImages(ctx, args...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed listing images")
|
||||
}
|
||||
|
||||
for _, image := range imageList {
|
||||
var (
|
||||
status string = "complete"
|
||||
size string
|
||||
requiredSize int64
|
||||
presentSize int64
|
||||
)
|
||||
|
||||
available, required, present, missing, err := images.Check(ctx, contentStore, image.Target(), platforms.Default())
|
||||
if err != nil {
|
||||
if exitErr == nil {
|
||||
exitErr = errors.Wrapf(err, "unable to check %v", image.Name())
|
||||
}
|
||||
log.G(ctx).WithError(err).Errorf("unable to check %v", image.Name())
|
||||
status = "error"
|
||||
}
|
||||
|
||||
if status != "error" {
|
||||
for _, d := range required {
|
||||
requiredSize += d.Size
|
||||
}
|
||||
|
||||
for _, d := range present {
|
||||
presentSize += d.Size
|
||||
}
|
||||
|
||||
if len(missing) > 0 {
|
||||
status = "incomplete"
|
||||
}
|
||||
|
||||
if available {
|
||||
status += fmt.Sprintf(" (%v/%v)", len(present), len(required))
|
||||
size = fmt.Sprintf("%v/%v", progress.Bytes(presentSize), progress.Bytes(requiredSize))
|
||||
} else {
|
||||
status = fmt.Sprintf("unavailable (%v/?)", len(present))
|
||||
size = fmt.Sprintf("%v/?", progress.Bytes(presentSize))
|
||||
}
|
||||
} else {
|
||||
size = "-"
|
||||
}
|
||||
|
||||
unpacked, err := image.IsUnpacked(ctx, context.String("snapshotter"))
|
||||
if err != nil {
|
||||
if exitErr == nil {
|
||||
exitErr = errors.Wrapf(err, "unable to check unpack for %v", image.Name())
|
||||
}
|
||||
log.G(ctx).WithError(err).Errorf("unable to check unpack for %v", image.Name())
|
||||
}
|
||||
|
||||
fmt.Fprintf(tw, "%v\t%v\t%v\t%v\t%v\t%t\n",
|
||||
image.Name(),
|
||||
image.Target().MediaType,
|
||||
image.Target().Digest,
|
||||
status,
|
||||
size,
|
||||
unpacked)
|
||||
}
|
||||
tw.Flush()
|
||||
|
||||
return exitErr
|
||||
},
|
||||
}
|
||||
|
||||
var removeCommand = cli.Command{
|
||||
Name: "remove",
|
||||
Aliases: []string{"rm"},
|
||||
Usage: "remove one or more images by reference",
|
||||
ArgsUsage: "[flags] <ref> [<ref>, ...]",
|
||||
Description: "remove one or more images by reference",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "sync",
|
||||
Usage: "Synchronously remove image and all associated resources",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
var (
|
||||
exitErr error
|
||||
imageStore = client.ImageService()
|
||||
)
|
||||
for i, target := range context.Args() {
|
||||
var opts []images.DeleteOpt
|
||||
if context.Bool("sync") && i == context.NArg()-1 {
|
||||
opts = append(opts, images.SynchronousDelete())
|
||||
}
|
||||
if err := imageStore.Delete(ctx, target, opts...); err != nil {
|
||||
if !errdefs.IsNotFound(err) {
|
||||
if exitErr == nil {
|
||||
exitErr = errors.Wrapf(err, "unable to delete %v", target)
|
||||
}
|
||||
log.G(ctx).WithError(err).Errorf("unable to delete %v", target)
|
||||
continue
|
||||
}
|
||||
// image ref not found in metadata store; log not found condition
|
||||
log.G(ctx).Warnf("%v: image not found", target)
|
||||
} else {
|
||||
fmt.Println(target)
|
||||
}
|
||||
}
|
||||
|
||||
return exitErr
|
||||
},
|
||||
}
|
||||
132
vendor/github.com/containerd/containerd/cmd/ctr/commands/images/import.go
generated
vendored
Normal file
132
vendor/github.com/containerd/containerd/cmd/ctr/commands/images/import.go
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package images
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/images/archive"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var importCommand = cli.Command{
|
||||
Name: "import",
|
||||
Usage: "import images",
|
||||
ArgsUsage: "[flags] <in>",
|
||||
Description: `Import images from a tar stream.
|
||||
Implemented formats:
|
||||
- oci.v1
|
||||
- docker.v1.1
|
||||
- docker.v1.2
|
||||
|
||||
|
||||
For OCI v1, you may need to specify --base-name because an OCI archive may
|
||||
contain only partial image references (tags without the base image name).
|
||||
If no base image name is provided, a name will be generated as "import-%{yyyy-MM-dd}".
|
||||
|
||||
e.g.
|
||||
$ ctr images import --base-name foo/bar foobar.tar
|
||||
|
||||
If foobar.tar contains an OCI ref named "latest" and anonymous ref "sha256:deadbeef", the command will create
|
||||
"foo/bar:latest" and "foo/bar@sha256:deadbeef" images in the containerd store.
|
||||
`,
|
||||
Flags: append([]cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "base-name",
|
||||
Value: "",
|
||||
Usage: "base image name for added images, when provided only images with this name prefix are imported",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "digests",
|
||||
Usage: "whether to create digest images (default: false)",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "index-name",
|
||||
Usage: "image name to keep index as, by default index is discarded",
|
||||
},
|
||||
}, commands.SnapshotterFlags...),
|
||||
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
in = context.Args().First()
|
||||
opts []containerd.ImportOpt
|
||||
)
|
||||
|
||||
prefix := context.String("base-name")
|
||||
if prefix == "" {
|
||||
prefix = fmt.Sprintf("import-%s", time.Now().Format("2006-01-02"))
|
||||
opts = append(opts, containerd.WithImageRefTranslator(archive.AddRefPrefix(prefix)))
|
||||
} else {
|
||||
// When provided, filter out references which do not match
|
||||
opts = append(opts, containerd.WithImageRefTranslator(archive.FilterRefPrefix(prefix)))
|
||||
}
|
||||
|
||||
if context.Bool("digests") {
|
||||
opts = append(opts, containerd.WithDigestRef(archive.DigestTranslator(prefix)))
|
||||
}
|
||||
|
||||
if idxName := context.String("index-name"); idxName != "" {
|
||||
opts = append(opts, containerd.WithIndexName(idxName))
|
||||
}
|
||||
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
var r io.ReadCloser
|
||||
if in == "-" {
|
||||
r = os.Stdin
|
||||
} else {
|
||||
r, err = os.Open(in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
imgs, err := client.Import(ctx, r, opts...)
|
||||
closeErr := r.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if closeErr != nil {
|
||||
return closeErr
|
||||
}
|
||||
|
||||
log.G(ctx).Debugf("unpacking %d images", len(imgs))
|
||||
|
||||
for _, img := range imgs {
|
||||
// TODO: Allow configuration of the platform
|
||||
image := containerd.NewImage(client, img)
|
||||
|
||||
// TODO: Show unpack status
|
||||
fmt.Printf("unpacking %s (%s)...", img.Name, img.Target.Digest)
|
||||
err = image.Unpack(ctx, context.String("snapshotter"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("done")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
121
vendor/github.com/containerd/containerd/cmd/ctr/commands/images/pull.go
generated
vendored
Normal file
121
vendor/github.com/containerd/containerd/cmd/ctr/commands/images/pull.go
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package images
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var pullCommand = cli.Command{
|
||||
Name: "pull",
|
||||
Usage: "pull an image from a remote",
|
||||
ArgsUsage: "[flags] <ref>",
|
||||
Description: `Fetch and prepare an image for use in containerd.
|
||||
|
||||
After pulling an image, it should be ready to use the same reference in a run
|
||||
command. As part of this process, we do the following:
|
||||
|
||||
1. Fetch all resources into containerd.
|
||||
2. Prepare the snapshot filesystem with the pulled resources.
|
||||
3. Register metadata for the image.
|
||||
`,
|
||||
Flags: append(append(commands.RegistryFlags, append(commands.SnapshotterFlags, commands.LabelFlag)...),
|
||||
cli.StringSliceFlag{
|
||||
Name: "platform",
|
||||
Usage: "Pull content from a specific platform",
|
||||
Value: &cli.StringSlice{},
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "all-platforms",
|
||||
Usage: "pull content from all platforms",
|
||||
},
|
||||
),
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
ref = context.Args().First()
|
||||
)
|
||||
if ref == "" {
|
||||
return fmt.Errorf("please provide an image reference to pull")
|
||||
}
|
||||
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
ctx, done, err := client.WithLease(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer done(ctx)
|
||||
|
||||
config, err := content.NewFetchConfig(ctx, context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
img, err := content.Fetch(ctx, client, ref, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.G(ctx).WithField("image", ref).Debug("unpacking")
|
||||
|
||||
// TODO: Show unpack status
|
||||
|
||||
var p []ocispec.Platform
|
||||
if context.Bool("all-platforms") {
|
||||
p, err = images.Platforms(ctx, client.ContentStore(), img.Target)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to resolve image platforms")
|
||||
}
|
||||
} else {
|
||||
for _, s := range context.StringSlice("platform") {
|
||||
ps, err := platforms.Parse(s)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to parse platform %s", s)
|
||||
}
|
||||
p = append(p, ps)
|
||||
}
|
||||
}
|
||||
if len(p) == 0 {
|
||||
p = append(p, platforms.DefaultSpec())
|
||||
}
|
||||
|
||||
for _, platform := range p {
|
||||
fmt.Printf("unpacking %s %s...\n", platforms.Format(platform), img.Target.Digest)
|
||||
i := containerd.NewImageWithPlatform(client, img, platforms.Any(platform))
|
||||
err = i.Unpack(ctx, context.String("snapshotter"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("done")
|
||||
return nil
|
||||
},
|
||||
}
|
||||
212
vendor/github.com/containerd/containerd/cmd/ctr/commands/images/push.go
generated
vendored
Normal file
212
vendor/github.com/containerd/containerd/cmd/ctr/commands/images/push.go
generated
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package images
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"os"
|
||||
"sync"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/pkg/progress"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
var pushCommand = cli.Command{
|
||||
Name: "push",
|
||||
Usage: "push an image to a remote",
|
||||
ArgsUsage: "[flags] <remote> [<local>]",
|
||||
Description: `Pushes an image reference from containerd.
|
||||
|
||||
All resources associated with the manifest reference will be pushed.
|
||||
The ref is used to resolve to a locally existing image manifest.
|
||||
The image manifest must exist before push. Creating a new image
|
||||
manifest can be done through calculating the diff for layers,
|
||||
creating the associated configuration, and creating the manifest
|
||||
which references those resources.
|
||||
`,
|
||||
Flags: append(commands.RegistryFlags, cli.StringFlag{
|
||||
Name: "manifest",
|
||||
Usage: "digest of manifest",
|
||||
}, cli.StringFlag{
|
||||
Name: "manifest-type",
|
||||
Usage: "media type of manifest digest",
|
||||
Value: ocispec.MediaTypeImageManifest,
|
||||
}),
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
ref = context.Args().First()
|
||||
local = context.Args().Get(1)
|
||||
desc ocispec.Descriptor
|
||||
)
|
||||
if ref == "" {
|
||||
return errors.New("please provide a remote image reference to push")
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
if manifest := context.String("manifest"); manifest != "" {
|
||||
desc.Digest, err = digest.Parse(manifest)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid manifest digest")
|
||||
}
|
||||
desc.MediaType = context.String("manifest-type")
|
||||
} else {
|
||||
if local == "" {
|
||||
local = ref
|
||||
}
|
||||
img, err := client.ImageService().Get(ctx, local)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to resolve image to manifest")
|
||||
}
|
||||
desc = img.Target
|
||||
}
|
||||
|
||||
resolver, err := commands.GetResolver(ctx, context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ongoing := newPushJobs(commands.PushTracker)
|
||||
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
eg.Go(func() error {
|
||||
log.G(ctx).WithField("image", ref).WithField("digest", desc.Digest).Debug("pushing")
|
||||
|
||||
jobHandler := images.HandlerFunc(func(ctx gocontext.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
ongoing.add(remotes.MakeRefKey(ctx, desc))
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
return client.Push(ctx, ref, desc,
|
||||
containerd.WithResolver(resolver),
|
||||
containerd.WithImageHandler(jobHandler),
|
||||
)
|
||||
})
|
||||
|
||||
errs := make(chan error)
|
||||
go func() {
|
||||
defer close(errs)
|
||||
errs <- eg.Wait()
|
||||
}()
|
||||
|
||||
var (
|
||||
ticker = time.NewTicker(100 * time.Millisecond)
|
||||
fw = progress.NewWriter(os.Stdout)
|
||||
start = time.Now()
|
||||
done bool
|
||||
)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
fw.Flush()
|
||||
|
||||
tw := tabwriter.NewWriter(fw, 1, 8, 1, ' ', 0)
|
||||
|
||||
content.Display(tw, ongoing.status(), start)
|
||||
tw.Flush()
|
||||
|
||||
if done {
|
||||
fw.Flush()
|
||||
return nil
|
||||
}
|
||||
case err := <-errs:
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
done = true
|
||||
case <-ctx.Done():
|
||||
done = true // allow ui to update once more
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
type pushjobs struct {
|
||||
jobs map[string]struct{}
|
||||
ordered []string
|
||||
tracker docker.StatusTracker
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func newPushJobs(tracker docker.StatusTracker) *pushjobs {
|
||||
return &pushjobs{
|
||||
jobs: make(map[string]struct{}),
|
||||
tracker: tracker,
|
||||
}
|
||||
}
|
||||
|
||||
func (j *pushjobs) add(ref string) {
|
||||
j.mu.Lock()
|
||||
defer j.mu.Unlock()
|
||||
|
||||
if _, ok := j.jobs[ref]; ok {
|
||||
return
|
||||
}
|
||||
j.ordered = append(j.ordered, ref)
|
||||
j.jobs[ref] = struct{}{}
|
||||
}
|
||||
|
||||
func (j *pushjobs) status() []content.StatusInfo {
|
||||
j.mu.Lock()
|
||||
defer j.mu.Unlock()
|
||||
|
||||
statuses := make([]content.StatusInfo, 0, len(j.jobs))
|
||||
for _, name := range j.ordered {
|
||||
si := content.StatusInfo{
|
||||
Ref: name,
|
||||
}
|
||||
|
||||
status, err := j.tracker.GetStatus(name)
|
||||
if err != nil {
|
||||
si.Status = "waiting"
|
||||
} else {
|
||||
si.Offset = status.Offset
|
||||
si.Total = status.Total
|
||||
si.StartedAt = status.StartedAt
|
||||
si.UpdatedAt = status.UpdatedAt
|
||||
if status.Offset >= status.Total {
|
||||
if status.UploadUUID == "" {
|
||||
si.Status = "done"
|
||||
} else {
|
||||
si.Status = "committing"
|
||||
}
|
||||
} else {
|
||||
si.Status = "uploading"
|
||||
}
|
||||
}
|
||||
statuses = append(statuses, si)
|
||||
}
|
||||
|
||||
return statuses
|
||||
}
|
||||
68
vendor/github.com/containerd/containerd/cmd/ctr/commands/install/install.go
generated
vendored
Normal file
68
vendor/github.com/containerd/containerd/cmd/ctr/commands/install/install.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package install
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// Command to install binary packages
|
||||
var Command = cli.Command{
|
||||
Name: "install",
|
||||
Usage: "install a new package",
|
||||
ArgsUsage: "<ref>",
|
||||
Description: "install a new package",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "libs,l",
|
||||
Usage: "install libs from the image",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "replace,r",
|
||||
Usage: "replace any binaries or libs in the opt directory",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "path",
|
||||
Usage: "set an optional install path other than the managed opt directory",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
ref := context.Args().First()
|
||||
image, err := client.GetImage(ctx, ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var opts []containerd.InstallOpts
|
||||
if context.Bool("libs") {
|
||||
opts = append(opts, containerd.WithInstallLibs)
|
||||
}
|
||||
if context.Bool("replace") {
|
||||
opts = append(opts, containerd.WithInstallReplace)
|
||||
}
|
||||
if path := context.String("path"); path != "" {
|
||||
opts = append(opts, containerd.WithInstallPath(path))
|
||||
}
|
||||
return client.Install(ctx, image, opts...)
|
||||
},
|
||||
}
|
||||
202
vendor/github.com/containerd/containerd/cmd/ctr/commands/leases/leases.go
generated
vendored
Normal file
202
vendor/github.com/containerd/containerd/cmd/ctr/commands/leases/leases.go
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package leases
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/leases"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// Command is the cli command for managing content
|
||||
var Command = cli.Command{
|
||||
Name: "leases",
|
||||
Usage: "manage leases",
|
||||
Subcommands: cli.Commands{
|
||||
listCommand,
|
||||
createCommand,
|
||||
deleteCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var listCommand = cli.Command{
|
||||
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "list all active leases",
|
||||
ArgsUsage: "[flags] <filter>",
|
||||
Description: "list active leases by containerd",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
||||
Usage: "print only the blob digest",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
filters = context.Args()
|
||||
quiet = context.Bool("quiet")
|
||||
)
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
ls := client.LeasesService()
|
||||
|
||||
leaseList, err := ls.List(ctx, filters...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to list leases")
|
||||
}
|
||||
if quiet {
|
||||
for _, l := range leaseList {
|
||||
fmt.Println(l.ID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0)
|
||||
fmt.Fprintln(tw, "ID\tCREATED AT\tLABELS\t")
|
||||
for _, l := range leaseList {
|
||||
labels := "-"
|
||||
if len(l.Labels) > 0 {
|
||||
var pairs []string
|
||||
for k, v := range l.Labels {
|
||||
pairs = append(pairs, fmt.Sprintf("%v=%v", k, v))
|
||||
}
|
||||
sort.Strings(pairs)
|
||||
labels = strings.Join(pairs, ",")
|
||||
}
|
||||
|
||||
fmt.Fprintf(tw, "%v\t%v\t%s\t\n",
|
||||
l.ID,
|
||||
l.CreatedAt.Local().Format(time.RFC3339),
|
||||
labels)
|
||||
}
|
||||
|
||||
return tw.Flush()
|
||||
},
|
||||
}
|
||||
|
||||
var createCommand = cli.Command{
|
||||
Name: "create",
|
||||
Usage: "create lease",
|
||||
ArgsUsage: "[flags] <label>=<value> ...",
|
||||
Description: "create a new lease",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Usage: "set the id for the lease, will be generated by default",
|
||||
},
|
||||
cli.DurationFlag{
|
||||
Name: "expires, x",
|
||||
Usage: "expiration of lease (0 value will not expire)",
|
||||
Value: 24 * time.Hour,
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var labelstr = context.Args()
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
ls := client.LeasesService()
|
||||
opts := []leases.Opt{}
|
||||
if len(labelstr) > 0 {
|
||||
labels := map[string]string{}
|
||||
for _, lstr := range labelstr {
|
||||
l := strings.SplitN(lstr, "=", 2)
|
||||
if len(l) == 1 {
|
||||
labels[l[0]] = ""
|
||||
} else {
|
||||
labels[l[0]] = l[1]
|
||||
}
|
||||
}
|
||||
opts = append(opts, leases.WithLabels(labels))
|
||||
}
|
||||
|
||||
if id := context.String("id"); id != "" {
|
||||
opts = append(opts, leases.WithID(id))
|
||||
}
|
||||
if exp := context.Duration("expires"); exp > 0 {
|
||||
opts = append(opts, leases.WithExpiration(exp))
|
||||
}
|
||||
|
||||
l, err := ls.Create(ctx, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(l.ID)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var deleteCommand = cli.Command{
|
||||
Name: "delete",
|
||||
Aliases: []string{"rm"},
|
||||
Usage: "delete a lease",
|
||||
ArgsUsage: "[flags] <lease id> ...",
|
||||
Description: "delete a lease",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "sync",
|
||||
Usage: "Synchronously remove leases and all unreferenced resources",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var lids = context.Args()
|
||||
if len(lids) == 0 {
|
||||
return cli.ShowSubcommandHelp(context)
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
ls := client.LeasesService()
|
||||
sync := context.Bool("sync")
|
||||
for i, lid := range lids {
|
||||
var opts []leases.DeleteOpt
|
||||
if sync && i == len(lids)-1 {
|
||||
opts = append(opts, leases.SynchronousDelete)
|
||||
}
|
||||
|
||||
lease := leases.Lease{
|
||||
ID: lid,
|
||||
}
|
||||
if err := ls.Delete(ctx, lease, opts...); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(lid)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
173
vendor/github.com/containerd/containerd/cmd/ctr/commands/namespaces/namespaces.go
generated
vendored
Normal file
173
vendor/github.com/containerd/containerd/cmd/ctr/commands/namespaces/namespaces.go
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package namespaces
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// Command is the cli command for managing namespaces
|
||||
var Command = cli.Command{
|
||||
Name: "namespaces",
|
||||
Aliases: []string{"namespace"},
|
||||
Usage: "manage namespaces",
|
||||
Subcommands: cli.Commands{
|
||||
createCommand,
|
||||
listCommand,
|
||||
removeCommand,
|
||||
setLabelsCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var createCommand = cli.Command{
|
||||
Name: "create",
|
||||
Usage: "create a new namespace",
|
||||
ArgsUsage: "<name> [<key>=<value]",
|
||||
Description: "create a new namespace. it must be unique",
|
||||
Action: func(context *cli.Context) error {
|
||||
namespace, labels := commands.ObjectWithLabelArgs(context)
|
||||
if namespace == "" {
|
||||
return errors.New("please specify a namespace")
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
namespaces := client.NamespaceService()
|
||||
return namespaces.Create(ctx, namespace, labels)
|
||||
},
|
||||
}
|
||||
|
||||
var setLabelsCommand = cli.Command{
|
||||
Name: "label",
|
||||
Usage: "set and clear labels for a namespace",
|
||||
ArgsUsage: "<name> [<key>=<value>, ...]",
|
||||
Description: "set and clear labels for a namespace",
|
||||
Action: func(context *cli.Context) error {
|
||||
namespace, labels := commands.ObjectWithLabelArgs(context)
|
||||
if namespace == "" {
|
||||
return errors.New("please specify a namespace")
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
namespaces := client.NamespaceService()
|
||||
for k, v := range labels {
|
||||
if err := namespaces.SetLabel(ctx, namespace, k, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var listCommand = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "list namespaces",
|
||||
ArgsUsage: "[flags]",
|
||||
Description: "list namespaces",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
||||
Usage: "print only the namespace name",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
quiet := context.Bool("quiet")
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
namespaces := client.NamespaceService()
|
||||
nss, err := namespaces.List(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if quiet {
|
||||
for _, ns := range nss {
|
||||
fmt.Println(ns)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0)
|
||||
fmt.Fprintln(tw, "NAME\tLABELS\t")
|
||||
for _, ns := range nss {
|
||||
labels, err := namespaces.Labels(ctx, ns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var labelStrings []string
|
||||
for k, v := range labels {
|
||||
labelStrings = append(labelStrings, strings.Join([]string{k, v}, "="))
|
||||
}
|
||||
sort.Strings(labelStrings)
|
||||
|
||||
fmt.Fprintf(tw, "%v\t%v\t\n", ns, strings.Join(labelStrings, ","))
|
||||
}
|
||||
return tw.Flush()
|
||||
},
|
||||
}
|
||||
|
||||
var removeCommand = cli.Command{
|
||||
Name: "remove",
|
||||
Aliases: []string{"rm"},
|
||||
Usage: "remove one or more namespaces",
|
||||
ArgsUsage: "<name> [<name>, ...]",
|
||||
Description: "remove one or more namespaces. for now, the namespace must be empty",
|
||||
Action: func(context *cli.Context) error {
|
||||
var exitErr error
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
namespaces := client.NamespaceService()
|
||||
for _, target := range context.Args() {
|
||||
if err := namespaces.Delete(ctx, target); err != nil {
|
||||
if !errdefs.IsNotFound(err) {
|
||||
if exitErr == nil {
|
||||
exitErr = errors.Wrapf(err, "unable to delete %v", target)
|
||||
}
|
||||
log.G(ctx).WithError(err).Errorf("unable to delete %v", target)
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fmt.Println(target)
|
||||
}
|
||||
return exitErr
|
||||
},
|
||||
}
|
||||
162
vendor/github.com/containerd/containerd/cmd/ctr/commands/plugins/plugins.go
generated
vendored
Normal file
162
vendor/github.com/containerd/containerd/cmd/ctr/commands/plugins/plugins.go
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
introspection "github.com/containerd/containerd/api/services/introspection/v1"
|
||||
"github.com/containerd/containerd/api/types"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/urfave/cli"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
// Command is a cli command that outputs plugin information
|
||||
var Command = cli.Command{
|
||||
Name: "plugins",
|
||||
Aliases: []string{"plugin"},
|
||||
Usage: "provides information about containerd plugins",
|
||||
Subcommands: []cli.Command{
|
||||
listCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var listCommand = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "lists containerd plugins",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "quiet,q",
|
||||
Usage: "print only the plugin ids",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "detailed,d",
|
||||
Usage: "print detailed information about each plugin",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
quiet = context.Bool("quiet")
|
||||
detailed = context.Bool("detailed")
|
||||
)
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
ps := client.IntrospectionService()
|
||||
response, err := ps.Plugins(ctx, &introspection.PluginsRequest{
|
||||
Filters: context.Args(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if quiet {
|
||||
for _, plugin := range response.Plugins {
|
||||
fmt.Println(plugin.ID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
w := tabwriter.NewWriter(os.Stdout, 4, 8, 4, ' ', 0)
|
||||
if detailed {
|
||||
first := true
|
||||
for _, plugin := range response.Plugins {
|
||||
if !first {
|
||||
fmt.Fprintln(w, "\t\t\t")
|
||||
}
|
||||
first = false
|
||||
fmt.Fprintln(w, "Type:\t", plugin.Type)
|
||||
fmt.Fprintln(w, "ID:\t", plugin.ID)
|
||||
if len(plugin.Requires) > 0 {
|
||||
fmt.Fprintln(w, "Requires:\t")
|
||||
for _, r := range plugin.Requires {
|
||||
fmt.Fprintln(w, "\t", r)
|
||||
}
|
||||
}
|
||||
if len(plugin.Platforms) > 0 {
|
||||
fmt.Fprintln(w, "Platforms:\t", prettyPlatforms(plugin.Platforms))
|
||||
}
|
||||
|
||||
if len(plugin.Exports) > 0 {
|
||||
fmt.Fprintln(w, "Exports:\t")
|
||||
for k, v := range plugin.Exports {
|
||||
fmt.Fprintln(w, "\t", k, "\t", v)
|
||||
}
|
||||
}
|
||||
|
||||
if len(plugin.Capabilities) > 0 {
|
||||
fmt.Fprintln(w, "Capabilities:\t", strings.Join(plugin.Capabilities, ","))
|
||||
}
|
||||
|
||||
if plugin.InitErr != nil {
|
||||
fmt.Fprintln(w, "Error:\t")
|
||||
fmt.Fprintln(w, "\t Code:\t", codes.Code(plugin.InitErr.Code))
|
||||
fmt.Fprintln(w, "\t Message:\t", plugin.InitErr.Message)
|
||||
}
|
||||
}
|
||||
return w.Flush()
|
||||
}
|
||||
|
||||
fmt.Fprintln(w, "TYPE\tID\tPLATFORMS\tSTATUS\t")
|
||||
for _, plugin := range response.Plugins {
|
||||
status := "ok"
|
||||
|
||||
if plugin.InitErr != nil {
|
||||
status = "error"
|
||||
}
|
||||
|
||||
var platformColumn = "-"
|
||||
if len(plugin.Platforms) > 0 {
|
||||
platformColumn = prettyPlatforms(plugin.Platforms)
|
||||
}
|
||||
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t\n",
|
||||
plugin.Type,
|
||||
plugin.ID,
|
||||
platformColumn,
|
||||
status,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return w.Flush()
|
||||
},
|
||||
}
|
||||
|
||||
func prettyPlatforms(pspb []types.Platform) string {
|
||||
psm := map[string]struct{}{}
|
||||
for _, p := range pspb {
|
||||
psm[platforms.Format(v1.Platform{
|
||||
OS: p.OS,
|
||||
Architecture: p.Architecture,
|
||||
Variant: p.Variant,
|
||||
})] = struct{}{}
|
||||
}
|
||||
var ps []string
|
||||
for p := range psm {
|
||||
ps = append(ps, p)
|
||||
}
|
||||
sort.Stable(sort.StringSlice(ps))
|
||||
return strings.Join(ps, ",")
|
||||
}
|
||||
189
vendor/github.com/containerd/containerd/cmd/ctr/commands/pprof/pprof.go
generated
vendored
Normal file
189
vendor/github.com/containerd/containerd/cmd/ctr/commands/pprof/pprof.go
generated
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package pprof
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/defaults"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
type pprofDialer struct {
|
||||
proto string
|
||||
addr string
|
||||
}
|
||||
|
||||
// Command is the cli command for providing golang pprof outputs for containerd
|
||||
var Command = cli.Command{
|
||||
Name: "pprof",
|
||||
Usage: "provide golang pprof outputs for containerd",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "debug-socket, d",
|
||||
Usage: "socket path for containerd's debug server",
|
||||
Value: defaults.DefaultDebugAddress,
|
||||
},
|
||||
},
|
||||
Subcommands: []cli.Command{
|
||||
pprofBlockCommand,
|
||||
pprofGoroutinesCommand,
|
||||
pprofHeapCommand,
|
||||
pprofProfileCommand,
|
||||
pprofThreadcreateCommand,
|
||||
pprofTraceCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var pprofGoroutinesCommand = cli.Command{
|
||||
Name: "goroutines",
|
||||
Usage: "dump goroutine stack dump",
|
||||
Action: func(context *cli.Context) error {
|
||||
client := getPProfClient(context)
|
||||
|
||||
output, err := httpGetRequest(client, "/debug/pprof/goroutine?debug=2")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output.Close()
|
||||
_, err = io.Copy(os.Stdout, output)
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
var pprofHeapCommand = cli.Command{
|
||||
Name: "heap",
|
||||
Usage: "dump heap profile",
|
||||
Action: func(context *cli.Context) error {
|
||||
client := getPProfClient(context)
|
||||
|
||||
output, err := httpGetRequest(client, "/debug/pprof/heap")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output.Close()
|
||||
_, err = io.Copy(os.Stdout, output)
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
var pprofProfileCommand = cli.Command{
|
||||
Name: "profile",
|
||||
Usage: "CPU profile",
|
||||
Flags: []cli.Flag{
|
||||
cli.DurationFlag{
|
||||
Name: "seconds,s",
|
||||
Usage: "duration for collection (seconds)",
|
||||
Value: 30 * time.Second,
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
client := getPProfClient(context)
|
||||
|
||||
seconds := context.Duration("seconds").Seconds()
|
||||
output, err := httpGetRequest(client, fmt.Sprintf("/debug/pprof/profile?seconds=%v", seconds))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output.Close()
|
||||
_, err = io.Copy(os.Stdout, output)
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
var pprofTraceCommand = cli.Command{
|
||||
Name: "trace",
|
||||
Usage: "collect execution trace",
|
||||
Flags: []cli.Flag{
|
||||
cli.DurationFlag{
|
||||
Name: "seconds,s",
|
||||
Usage: "trace time (seconds)",
|
||||
Value: 5 * time.Second,
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
client := getPProfClient(context)
|
||||
|
||||
seconds := context.Duration("seconds").Seconds()
|
||||
uri := fmt.Sprintf("/debug/pprof/trace?seconds=%v", seconds)
|
||||
output, err := httpGetRequest(client, uri)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output.Close()
|
||||
_, err = io.Copy(os.Stdout, output)
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
var pprofBlockCommand = cli.Command{
|
||||
Name: "block",
|
||||
Usage: "goroutine blocking profile",
|
||||
Action: func(context *cli.Context) error {
|
||||
client := getPProfClient(context)
|
||||
|
||||
output, err := httpGetRequest(client, "/debug/pprof/block")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output.Close()
|
||||
_, err = io.Copy(os.Stdout, output)
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
var pprofThreadcreateCommand = cli.Command{
|
||||
Name: "threadcreate",
|
||||
Usage: "goroutine thread creating profile",
|
||||
Action: func(context *cli.Context) error {
|
||||
client := getPProfClient(context)
|
||||
|
||||
output, err := httpGetRequest(client, "/debug/pprof/threadcreate")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output.Close()
|
||||
_, err = io.Copy(os.Stdout, output)
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
func getPProfClient(context *cli.Context) *http.Client {
|
||||
dialer := getPProfDialer(context.GlobalString("debug-socket"))
|
||||
|
||||
tr := &http.Transport{
|
||||
Dial: dialer.pprofDial,
|
||||
}
|
||||
client := &http.Client{Transport: tr}
|
||||
return client
|
||||
}
|
||||
|
||||
func httpGetRequest(client *http.Client, request string) (io.ReadCloser, error) {
|
||||
resp, err := client.Get("http://." + request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, errors.Errorf("http get failed with status: %s", resp.Status)
|
||||
}
|
||||
return resp.Body, nil
|
||||
}
|
||||
29
vendor/github.com/containerd/containerd/cmd/ctr/commands/pprof/pprof_unix.go
generated
vendored
Normal file
29
vendor/github.com/containerd/containerd/cmd/ctr/commands/pprof/pprof_unix.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package pprof
|
||||
|
||||
import "net"
|
||||
|
||||
func (d *pprofDialer) pprofDial(proto, addr string) (conn net.Conn, err error) {
|
||||
return net.Dial(d.proto, d.addr)
|
||||
}
|
||||
|
||||
func getPProfDialer(addr string) *pprofDialer {
|
||||
return &pprofDialer{"unix", addr}
|
||||
}
|
||||
31
vendor/github.com/containerd/containerd/cmd/ctr/commands/pprof/pprof_windows.go
generated
vendored
Normal file
31
vendor/github.com/containerd/containerd/cmd/ctr/commands/pprof/pprof_windows.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package pprof
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
winio "github.com/Microsoft/go-winio"
|
||||
)
|
||||
|
||||
func (d *pprofDialer) pprofDial(proto, addr string) (conn net.Conn, err error) {
|
||||
return winio.DialPipe(d.addr, nil)
|
||||
}
|
||||
|
||||
func getPProfDialer(addr string) *pprofDialer {
|
||||
return &pprofDialer{"winpipe", addr}
|
||||
}
|
||||
109
vendor/github.com/containerd/containerd/cmd/ctr/commands/resolver.go
generated
vendored
Normal file
109
vendor/github.com/containerd/containerd/cmd/ctr/commands/resolver.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
gocontext "context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// PushTracker returns a new InMemoryTracker which tracks the ref status
|
||||
var PushTracker = docker.NewInMemoryTracker()
|
||||
|
||||
func passwordPrompt() (string, error) {
|
||||
c := console.Current()
|
||||
defer c.Reset()
|
||||
|
||||
if err := c.DisableEcho(); err != nil {
|
||||
return "", errors.Wrap(err, "failed to disable echo")
|
||||
}
|
||||
|
||||
line, _, err := bufio.NewReader(c).ReadLine()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to read line")
|
||||
}
|
||||
return string(line), nil
|
||||
}
|
||||
|
||||
// GetResolver prepares the resolver from the environment and options
|
||||
func GetResolver(ctx gocontext.Context, clicontext *cli.Context) (remotes.Resolver, error) {
|
||||
username := clicontext.String("user")
|
||||
var secret string
|
||||
if i := strings.IndexByte(username, ':'); i > 0 {
|
||||
secret = username[i+1:]
|
||||
username = username[0:i]
|
||||
}
|
||||
options := docker.ResolverOptions{
|
||||
PlainHTTP: clicontext.Bool("plain-http"),
|
||||
Tracker: PushTracker,
|
||||
}
|
||||
if username != "" {
|
||||
if secret == "" {
|
||||
fmt.Printf("Password: ")
|
||||
|
||||
var err error
|
||||
secret, err = passwordPrompt()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fmt.Print("\n")
|
||||
}
|
||||
} else if rt := clicontext.String("refresh"); rt != "" {
|
||||
secret = rt
|
||||
}
|
||||
|
||||
tr := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
DualStack: true,
|
||||
}).DialContext,
|
||||
MaxIdleConns: 10,
|
||||
IdleConnTimeout: 30 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: clicontext.Bool("insecure"),
|
||||
},
|
||||
ExpectContinueTimeout: 5 * time.Second,
|
||||
}
|
||||
|
||||
options.Client = &http.Client{
|
||||
Transport: tr,
|
||||
}
|
||||
|
||||
credentials := func(host string) (string, string, error) {
|
||||
// Only one host
|
||||
return username, secret, nil
|
||||
}
|
||||
options.Authorizer = docker.NewAuthorizer(options.Client, credentials)
|
||||
|
||||
return docker.NewResolver(options), nil
|
||||
}
|
||||
206
vendor/github.com/containerd/containerd/cmd/ctr/commands/run/run.go
generated
vendored
Normal file
206
vendor/github.com/containerd/containerd/cmd/ctr/commands/run/run.go
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package run
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands/tasks"
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/oci"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func withMounts(context *cli.Context) oci.SpecOpts {
|
||||
return func(ctx gocontext.Context, client oci.Client, container *containers.Container, s *specs.Spec) error {
|
||||
mounts := make([]specs.Mount, 0)
|
||||
for _, mount := range context.StringSlice("mount") {
|
||||
m, err := parseMountFlag(mount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mounts = append(mounts, m)
|
||||
}
|
||||
return oci.WithMounts(mounts)(ctx, client, container, s)
|
||||
}
|
||||
}
|
||||
|
||||
// parseMountFlag parses a mount string in the form "type=foo,source=/path,destination=/target,options=rbind:rw"
|
||||
func parseMountFlag(m string) (specs.Mount, error) {
|
||||
mount := specs.Mount{}
|
||||
r := csv.NewReader(strings.NewReader(m))
|
||||
|
||||
fields, err := r.Read()
|
||||
if err != nil {
|
||||
return mount, err
|
||||
}
|
||||
|
||||
for _, field := range fields {
|
||||
v := strings.Split(field, "=")
|
||||
if len(v) != 2 {
|
||||
return mount, fmt.Errorf("invalid mount specification: expected key=val")
|
||||
}
|
||||
|
||||
key := v[0]
|
||||
val := v[1]
|
||||
switch key {
|
||||
case "type":
|
||||
mount.Type = val
|
||||
case "source", "src":
|
||||
mount.Source = val
|
||||
case "destination", "dst":
|
||||
mount.Destination = val
|
||||
case "options":
|
||||
mount.Options = strings.Split(val, ":")
|
||||
default:
|
||||
return mount, fmt.Errorf("mount option %q not supported", key)
|
||||
}
|
||||
}
|
||||
|
||||
return mount, nil
|
||||
}
|
||||
|
||||
// Command runs a container
|
||||
var Command = cli.Command{
|
||||
Name: "run",
|
||||
Usage: "run a container",
|
||||
ArgsUsage: "[flags] Image|RootFS ID [COMMAND] [ARG...]",
|
||||
Flags: append([]cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "rm",
|
||||
Usage: "remove the container after running",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "null-io",
|
||||
Usage: "send all IO to /dev/null",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "detach,d",
|
||||
Usage: "detach from the task after it has started execution",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "fifo-dir",
|
||||
Usage: "directory used for storing IO FIFOs",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "isolated",
|
||||
Usage: "run the container with vm isolation",
|
||||
},
|
||||
}, append(commands.SnapshotterFlags, commands.ContainerFlags...)...),
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
err error
|
||||
id string
|
||||
ref string
|
||||
|
||||
tty = context.Bool("tty")
|
||||
detach = context.Bool("detach")
|
||||
config = context.IsSet("config")
|
||||
)
|
||||
|
||||
if config {
|
||||
id = context.Args().First()
|
||||
if context.NArg() > 1 {
|
||||
return errors.New("with spec config file, only container id should be provided")
|
||||
}
|
||||
} else {
|
||||
id = context.Args().Get(1)
|
||||
ref = context.Args().First()
|
||||
|
||||
if ref == "" {
|
||||
return errors.New("image ref must be provided")
|
||||
}
|
||||
}
|
||||
if id == "" {
|
||||
return errors.New("container id must be provided")
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
container, err := NewContainer(ctx, client, context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if context.Bool("rm") && !detach {
|
||||
defer container.Delete(ctx, containerd.WithSnapshotCleanup)
|
||||
}
|
||||
var con console.Console
|
||||
if tty {
|
||||
con = console.Current()
|
||||
defer con.Reset()
|
||||
if err := con.SetRaw(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
opts := getNewTaskOpts(context)
|
||||
ioOpts := []cio.Opt{cio.WithFIFODir(context.String("fifo-dir"))}
|
||||
task, err := tasks.NewTask(ctx, client, container, context.String("checkpoint"), con, context.Bool("null-io"), ioOpts, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var statusC <-chan containerd.ExitStatus
|
||||
if !detach {
|
||||
defer task.Delete(ctx)
|
||||
if statusC, err = task.Wait(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if context.IsSet("pid-file") {
|
||||
if err := commands.WritePidFile(context.String("pid-file"), int(task.Pid())); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := task.Start(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if detach {
|
||||
return nil
|
||||
}
|
||||
if tty {
|
||||
if err := tasks.HandleConsoleResize(ctx, task, con); err != nil {
|
||||
logrus.WithError(err).Error("console resize")
|
||||
}
|
||||
} else {
|
||||
sigc := commands.ForwardAllSignals(ctx, task)
|
||||
defer commands.StopCatch(sigc)
|
||||
}
|
||||
status := <-statusC
|
||||
code, _, err := status.Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := task.Delete(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if code != 0 {
|
||||
return cli.NewExitError("", int(code))
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
179
vendor/github.com/containerd/containerd/cmd/ctr/commands/run/run_unix.go
generated
vendored
Normal file
179
vendor/github.com/containerd/containerd/cmd/ctr/commands/run/run_unix.go
generated
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package run
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/contrib/nvidia"
|
||||
"github.com/containerd/containerd/oci"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// NewContainer creates a new container
|
||||
func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli.Context) (containerd.Container, error) {
|
||||
var (
|
||||
id string
|
||||
config = context.IsSet("config")
|
||||
)
|
||||
if config {
|
||||
id = context.Args().First()
|
||||
} else {
|
||||
id = context.Args().Get(1)
|
||||
}
|
||||
|
||||
if raw := context.String("checkpoint"); raw != "" {
|
||||
im, err := client.GetImage(ctx, raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client.NewContainer(ctx, id, containerd.WithCheckpoint(im, id), containerd.WithRuntime(context.String("runtime"), nil))
|
||||
}
|
||||
|
||||
var (
|
||||
opts []oci.SpecOpts
|
||||
cOpts []containerd.NewContainerOpts
|
||||
spec containerd.NewContainerOpts
|
||||
)
|
||||
|
||||
cOpts = append(cOpts, containerd.WithContainerLabels(commands.LabelArgs(context.StringSlice("label"))))
|
||||
if config {
|
||||
opts = append(opts, oci.WithSpecFromFile(context.String("config")))
|
||||
} else {
|
||||
var (
|
||||
ref = context.Args().First()
|
||||
//for container's id is Args[1]
|
||||
args = context.Args()[2:]
|
||||
)
|
||||
opts = append(opts, oci.WithDefaultSpec(), oci.WithDefaultUnixDevices)
|
||||
opts = append(opts, oci.WithEnv(context.StringSlice("env")))
|
||||
opts = append(opts, withMounts(context))
|
||||
|
||||
if context.Bool("rootfs") {
|
||||
rootfs, err := filepath.Abs(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts = append(opts, oci.WithRootFSPath(rootfs))
|
||||
} else {
|
||||
snapshotter := context.String("snapshotter")
|
||||
image, err := client.GetImage(ctx, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
unpacked, err := image.IsUnpacked(ctx, snapshotter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !unpacked {
|
||||
if err := image.Unpack(ctx, snapshotter); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
opts = append(opts, oci.WithImageConfig(image))
|
||||
cOpts = append(cOpts,
|
||||
containerd.WithImage(image),
|
||||
containerd.WithSnapshotter(snapshotter),
|
||||
// Even when "readonly" is set, we don't use KindView snapshot here. (#1495)
|
||||
// We pass writable snapshot to the OCI runtime, and the runtime remounts it as read-only,
|
||||
// after creating some mount points on demand.
|
||||
containerd.WithNewSnapshot(id, image),
|
||||
containerd.WithImageStopSignal(image, "SIGTERM"))
|
||||
}
|
||||
if context.Bool("readonly") {
|
||||
opts = append(opts, oci.WithRootFSReadonly())
|
||||
}
|
||||
if len(args) > 0 {
|
||||
opts = append(opts, oci.WithProcessArgs(args...))
|
||||
}
|
||||
if cwd := context.String("cwd"); cwd != "" {
|
||||
opts = append(opts, oci.WithProcessCwd(cwd))
|
||||
}
|
||||
if context.Bool("tty") {
|
||||
opts = append(opts, oci.WithTTY)
|
||||
}
|
||||
if context.Bool("privileged") {
|
||||
opts = append(opts, oci.WithPrivileged)
|
||||
}
|
||||
if context.Bool("net-host") {
|
||||
opts = append(opts, oci.WithHostNamespace(specs.NetworkNamespace), oci.WithHostHostsFile, oci.WithHostResolvconf)
|
||||
}
|
||||
|
||||
joinNs := context.StringSlice("with-ns")
|
||||
for _, ns := range joinNs {
|
||||
parts := strings.Split(ns, ":")
|
||||
if len(parts) != 2 {
|
||||
return nil, errors.New("joining a Linux namespace using --with-ns requires the format 'nstype:path'")
|
||||
}
|
||||
if !validNamespace(parts[0]) {
|
||||
return nil, errors.New("the Linux namespace type specified in --with-ns is not valid: " + parts[0])
|
||||
}
|
||||
opts = append(opts, oci.WithLinuxNamespace(specs.LinuxNamespace{
|
||||
Type: specs.LinuxNamespaceType(parts[0]),
|
||||
Path: parts[1],
|
||||
}))
|
||||
}
|
||||
if context.IsSet("gpus") {
|
||||
opts = append(opts, nvidia.WithGPUs(nvidia.WithDevices(context.Int("gpus")), nvidia.WithAllCapabilities))
|
||||
}
|
||||
if context.IsSet("allow-new-privs") {
|
||||
opts = append(opts, oci.WithNewPrivileges)
|
||||
}
|
||||
}
|
||||
|
||||
cOpts = append(cOpts, containerd.WithRuntime(context.String("runtime"), nil))
|
||||
|
||||
var s specs.Spec
|
||||
spec = containerd.WithSpec(&s, opts...)
|
||||
|
||||
cOpts = append(cOpts, spec)
|
||||
|
||||
// oci.WithImageConfig (WithUsername, WithUserID) depends on access to rootfs for resolving via
|
||||
// the /etc/{passwd,group} files. So cOpts needs to have precedence over opts.
|
||||
return client.NewContainer(ctx, id, cOpts...)
|
||||
}
|
||||
|
||||
func getNewTaskOpts(context *cli.Context) []containerd.NewTaskOpts {
|
||||
if context.Bool("no-pivot") {
|
||||
return []containerd.NewTaskOpts{containerd.WithNoPivotRoot}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validNamespace(ns string) bool {
|
||||
linuxNs := specs.LinuxNamespaceType(ns)
|
||||
switch linuxNs {
|
||||
case specs.PIDNamespace,
|
||||
specs.NetworkNamespace,
|
||||
specs.UTSNamespace,
|
||||
specs.MountNamespace,
|
||||
specs.UserNamespace,
|
||||
specs.IPCNamespace,
|
||||
specs.CgroupNamespace:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
115
vendor/github.com/containerd/containerd/cmd/ctr/commands/run/run_windows.go
generated
vendored
Normal file
115
vendor/github.com/containerd/containerd/cmd/ctr/commands/run/run_windows.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package run
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/oci"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// NewContainer creates a new container
|
||||
func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli.Context) (containerd.Container, error) {
|
||||
var (
|
||||
id string
|
||||
opts []oci.SpecOpts
|
||||
cOpts []containerd.NewContainerOpts
|
||||
spec containerd.NewContainerOpts
|
||||
|
||||
config = context.IsSet("config")
|
||||
)
|
||||
|
||||
if config {
|
||||
id = context.Args().First()
|
||||
opts = append(opts, oci.WithSpecFromFile(context.String("config")))
|
||||
} else {
|
||||
var (
|
||||
ref = context.Args().First()
|
||||
args = context.Args()[2:]
|
||||
)
|
||||
|
||||
id = context.Args().Get(1)
|
||||
snapshotter := context.String("snapshotter")
|
||||
if snapshotter == "windows-lcow" {
|
||||
opts = append(opts, oci.WithDefaultSpecForPlatform("linux/amd64"))
|
||||
// Clear the rootfs section.
|
||||
opts = append(opts, oci.WithRootFSPath(""))
|
||||
} else {
|
||||
opts = append(opts, oci.WithDefaultSpec())
|
||||
}
|
||||
opts = append(opts, oci.WithEnv(context.StringSlice("env")))
|
||||
opts = append(opts, withMounts(context))
|
||||
|
||||
image, err := client.GetImage(ctx, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
unpacked, err := image.IsUnpacked(ctx, snapshotter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !unpacked {
|
||||
if err := image.Unpack(ctx, snapshotter); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
opts = append(opts, oci.WithImageConfig(image))
|
||||
cOpts = append(cOpts, containerd.WithImage(image))
|
||||
cOpts = append(cOpts, containerd.WithSnapshotter(snapshotter))
|
||||
cOpts = append(cOpts, containerd.WithNewSnapshot(id, image))
|
||||
|
||||
if len(args) > 0 {
|
||||
opts = append(opts, oci.WithProcessArgs(args...))
|
||||
}
|
||||
if cwd := context.String("cwd"); cwd != "" {
|
||||
opts = append(opts, oci.WithProcessCwd(cwd))
|
||||
}
|
||||
if context.Bool("tty") {
|
||||
opts = append(opts, oci.WithTTY)
|
||||
|
||||
con := console.Current()
|
||||
size, err := con.Size()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("console size")
|
||||
}
|
||||
opts = append(opts, oci.WithTTYSize(int(size.Width), int(size.Height)))
|
||||
}
|
||||
if context.Bool("isolated") {
|
||||
opts = append(opts, oci.WithWindowsHyperV)
|
||||
}
|
||||
}
|
||||
|
||||
cOpts = append(cOpts, containerd.WithContainerLabels(commands.LabelArgs(context.StringSlice("label"))))
|
||||
cOpts = append(cOpts, containerd.WithRuntime(context.String("runtime"), nil))
|
||||
|
||||
var s specs.Spec
|
||||
spec = containerd.WithSpec(&s, opts...)
|
||||
|
||||
cOpts = append(cOpts, spec)
|
||||
|
||||
return client.NewContainer(ctx, id, cOpts...)
|
||||
}
|
||||
|
||||
func getNewTaskOpts(_ *cli.Context) []containerd.NewTaskOpts {
|
||||
return nil
|
||||
}
|
||||
93
vendor/github.com/containerd/containerd/cmd/ctr/commands/shim/io_unix.go
generated
vendored
Normal file
93
vendor/github.com/containerd/containerd/cmd/ctr/commands/shim/io_unix.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package shim
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/fifo"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var bufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
buffer := make([]byte, 32<<10)
|
||||
return &buffer
|
||||
},
|
||||
}
|
||||
|
||||
func prepareStdio(stdin, stdout, stderr string, console bool) (wg *sync.WaitGroup, err error) {
|
||||
wg = &sync.WaitGroup{}
|
||||
ctx := gocontext.Background()
|
||||
|
||||
f, err := fifo.OpenFifo(ctx, stdin, unix.O_WRONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func(c io.Closer) {
|
||||
if err != nil {
|
||||
c.Close()
|
||||
}
|
||||
}(f)
|
||||
go func(w io.WriteCloser) {
|
||||
p := bufPool.Get().(*[]byte)
|
||||
defer bufPool.Put(p)
|
||||
io.CopyBuffer(w, os.Stdin, *p)
|
||||
w.Close()
|
||||
}(f)
|
||||
|
||||
f, err = fifo.OpenFifo(ctx, stdout, unix.O_RDONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700)
|
||||
if 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(os.Stdout, r)
|
||||
r.Close()
|
||||
wg.Done()
|
||||
}(f)
|
||||
|
||||
f, err = fifo.OpenFifo(ctx, stderr, unix.O_RDONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func(c io.Closer) {
|
||||
if err != nil {
|
||||
c.Close()
|
||||
}
|
||||
}(f)
|
||||
if !console {
|
||||
wg.Add(1)
|
||||
go func(r io.ReadCloser) {
|
||||
io.Copy(os.Stderr, r)
|
||||
r.Close()
|
||||
wg.Done()
|
||||
}(f)
|
||||
}
|
||||
|
||||
return wg, nil
|
||||
}
|
||||
245
vendor/github.com/containerd/containerd/cmd/ctr/commands/shim/shim.go
generated
vendored
Normal file
245
vendor/github.com/containerd/containerd/cmd/ctr/commands/shim/shim.go
generated
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package shim
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/runtime/v2/task"
|
||||
"github.com/containerd/ttrpc"
|
||||
"github.com/containerd/typeurl"
|
||||
ptypes "github.com/gogo/protobuf/types"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var fifoFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "stdin",
|
||||
Usage: "specify the path to the stdin fifo",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "stdout",
|
||||
Usage: "specify the path to the stdout fifo",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "stderr",
|
||||
Usage: "specify the path to the stderr fifo",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "tty,t",
|
||||
Usage: "enable tty support",
|
||||
},
|
||||
}
|
||||
|
||||
// Command is the cli command for interacting with a task
|
||||
var Command = cli.Command{
|
||||
Name: "shim",
|
||||
Usage: "interact with a shim directly",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "socket",
|
||||
Usage: "socket on which to connect to the shim",
|
||||
},
|
||||
},
|
||||
Subcommands: []cli.Command{
|
||||
deleteCommand,
|
||||
execCommand,
|
||||
startCommand,
|
||||
stateCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var startCommand = cli.Command{
|
||||
Name: "start",
|
||||
Usage: "start a container with a task",
|
||||
Action: func(context *cli.Context) error {
|
||||
service, err := getTaskService(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = service.Start(gocontext.Background(), &task.StartRequest{
|
||||
ID: context.Args().First(),
|
||||
})
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
var deleteCommand = cli.Command{
|
||||
Name: "delete",
|
||||
Usage: "delete a container with a task",
|
||||
Action: func(context *cli.Context) error {
|
||||
service, err := getTaskService(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r, err := service.Delete(gocontext.Background(), &task.DeleteRequest{
|
||||
ID: context.Args().First(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("container deleted and returned exit status %d\n", r.ExitStatus)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var stateCommand = cli.Command{
|
||||
Name: "state",
|
||||
Usage: "get the state of all the processes of the task",
|
||||
Action: func(context *cli.Context) error {
|
||||
service, err := getTaskService(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r, err := service.State(gocontext.Background(), &task.StateRequest{
|
||||
ID: context.Args().First(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commands.PrintAsJSON(r)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var execCommand = cli.Command{
|
||||
Name: "exec",
|
||||
Usage: "exec a new process in the task's container",
|
||||
Flags: append(fifoFlags,
|
||||
cli.BoolFlag{
|
||||
Name: "attach,a",
|
||||
Usage: "stay attached to the container and open the fifos",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "env,e",
|
||||
Usage: "add environment vars",
|
||||
Value: &cli.StringSlice{},
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "cwd",
|
||||
Usage: "current working directory",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "spec",
|
||||
Usage: "runtime spec",
|
||||
},
|
||||
),
|
||||
Action: func(context *cli.Context) error {
|
||||
service, err := getTaskService(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
id = context.Args().First()
|
||||
ctx = gocontext.Background()
|
||||
)
|
||||
|
||||
if id == "" {
|
||||
return errors.New("exec id must be provided")
|
||||
}
|
||||
|
||||
tty := context.Bool("tty")
|
||||
wg, err := prepareStdio(context.String("stdin"), context.String("stdout"), context.String("stderr"), tty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// read spec file and extract Any object
|
||||
spec, err := ioutil.ReadFile(context.String("spec"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
url, err := typeurl.TypeURL(specs.Process{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rq := &task.ExecProcessRequest{
|
||||
ID: id,
|
||||
Spec: &ptypes.Any{
|
||||
TypeUrl: url,
|
||||
Value: spec,
|
||||
},
|
||||
Stdin: context.String("stdin"),
|
||||
Stdout: context.String("stdout"),
|
||||
Stderr: context.String("stderr"),
|
||||
Terminal: tty,
|
||||
}
|
||||
if _, err := service.Exec(ctx, rq); err != nil {
|
||||
return err
|
||||
}
|
||||
r, err := service.Start(ctx, &task.StartRequest{
|
||||
ID: id,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("exec running with pid %d\n", r.Pid)
|
||||
if context.Bool("attach") {
|
||||
logrus.Info("attaching")
|
||||
if tty {
|
||||
current := console.Current()
|
||||
defer current.Reset()
|
||||
if err := current.SetRaw(); err != nil {
|
||||
return err
|
||||
}
|
||||
size, err := current.Size()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := service.ResizePty(ctx, &task.ResizePtyRequest{
|
||||
ID: id,
|
||||
Width: uint32(size.Width),
|
||||
Height: uint32(size.Height),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func getTaskService(context *cli.Context) (task.TaskService, error) {
|
||||
bindSocket := context.GlobalString("socket")
|
||||
if bindSocket == "" {
|
||||
return nil, errors.New("socket path must be specified")
|
||||
}
|
||||
|
||||
conn, err := net.Dial("unix", "\x00"+bindSocket)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := ttrpc.NewClient(conn)
|
||||
|
||||
// TODO(stevvooe): This actually leaks the connection. We were leaking it
|
||||
// before, so may not be a huge deal.
|
||||
|
||||
return task.NewTaskClient(client), nil
|
||||
}
|
||||
52
vendor/github.com/containerd/containerd/cmd/ctr/commands/signals.go
generated
vendored
Normal file
52
vendor/github.com/containerd/containerd/cmd/ctr/commands/signals.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type killer interface {
|
||||
Kill(gocontext.Context, syscall.Signal, ...containerd.KillOpts) error
|
||||
}
|
||||
|
||||
// ForwardAllSignals forwards signals
|
||||
func ForwardAllSignals(ctx gocontext.Context, task killer) chan os.Signal {
|
||||
sigc := make(chan os.Signal, 128)
|
||||
signal.Notify(sigc)
|
||||
go func() {
|
||||
for s := range sigc {
|
||||
logrus.Debug("forwarding signal ", s)
|
||||
if err := task.Kill(ctx, s.(syscall.Signal)); err != nil {
|
||||
logrus.WithError(err).Errorf("forward signal %s", s)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return sigc
|
||||
}
|
||||
|
||||
// StopCatch stops and closes a channel
|
||||
func StopCatch(sigc chan os.Signal) {
|
||||
signal.Stop(sigc)
|
||||
close(sigc)
|
||||
}
|
||||
636
vendor/github.com/containerd/containerd/cmd/ctr/commands/snapshots/snapshots.go
generated
vendored
Normal file
636
vendor/github.com/containerd/containerd/cmd/ctr/commands/snapshots/snapshots.go
generated
vendored
Normal file
@@ -0,0 +1,636 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package snapshots
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/diff"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/containerd/containerd/pkg/progress"
|
||||
"github.com/containerd/containerd/rootfs"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// Command is the cli command for managing snapshots
|
||||
var Command = cli.Command{
|
||||
Name: "snapshots",
|
||||
Aliases: []string{"snapshot"},
|
||||
Usage: "manage snapshots",
|
||||
Flags: commands.SnapshotterFlags,
|
||||
Subcommands: cli.Commands{
|
||||
commitCommand,
|
||||
diffCommand,
|
||||
infoCommand,
|
||||
listCommand,
|
||||
mountCommand,
|
||||
prepareCommand,
|
||||
removeCommand,
|
||||
setLabelCommand,
|
||||
treeCommand,
|
||||
unpackCommand,
|
||||
usageCommand,
|
||||
viewCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var listCommand = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "list snapshots",
|
||||
Action: func(context *cli.Context) error {
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
var (
|
||||
snapshotter = client.SnapshotService(context.GlobalString("snapshotter"))
|
||||
tw = tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0)
|
||||
)
|
||||
fmt.Fprintln(tw, "KEY\tPARENT\tKIND\t")
|
||||
if err := snapshotter.Walk(ctx, func(ctx gocontext.Context, info snapshots.Info) error {
|
||||
fmt.Fprintf(tw, "%v\t%v\t%v\t\n",
|
||||
info.Name,
|
||||
info.Parent,
|
||||
info.Kind)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tw.Flush()
|
||||
},
|
||||
}
|
||||
|
||||
var diffCommand = cli.Command{
|
||||
Name: "diff",
|
||||
Usage: "get the diff of two snapshots. the default second snapshot is the first snapshot's parent.",
|
||||
ArgsUsage: "[flags] <idA> [<idB>]",
|
||||
Flags: append([]cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "media-type",
|
||||
Usage: "media type to use for creating diff",
|
||||
Value: ocispec.MediaTypeImageLayerGzip,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "ref",
|
||||
Usage: "content upload reference to use",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "keep",
|
||||
Usage: "keep diff content. up to creator to delete it.",
|
||||
},
|
||||
}, commands.LabelFlag),
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
idA = context.Args().First()
|
||||
idB = context.Args().Get(1)
|
||||
)
|
||||
if idA == "" {
|
||||
return errors.New("snapshot id must be provided")
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
ctx, done, err := client.WithLease(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer done(ctx)
|
||||
|
||||
var desc ocispec.Descriptor
|
||||
labels := commands.LabelArgs(context.StringSlice("label"))
|
||||
snapshotter := client.SnapshotService(context.GlobalString("snapshotter"))
|
||||
|
||||
fmt.Println(context.String("media-type"))
|
||||
|
||||
if context.Bool("keep") {
|
||||
labels["containerd.io/gc.root"] = time.Now().UTC().Format(time.RFC3339)
|
||||
}
|
||||
opts := []diff.Opt{
|
||||
diff.WithMediaType(context.String("media-type")),
|
||||
diff.WithReference(context.String("ref")),
|
||||
diff.WithLabels(labels),
|
||||
}
|
||||
|
||||
if idB == "" {
|
||||
desc, err = rootfs.CreateDiff(ctx, idA, snapshotter, client.DiffService(), opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
var a, b []mount.Mount
|
||||
ds := client.DiffService()
|
||||
|
||||
a, err = getMounts(ctx, idA, snapshotter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b, err = getMounts(ctx, idB, snapshotter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
desc, err = ds.Compare(ctx, a, b, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ra, err := client.ContentStore().ReaderAt(ctx, desc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(os.Stdout, content.NewReader(ra))
|
||||
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
func getMounts(ctx gocontext.Context, id string, sn snapshots.Snapshotter) ([]mount.Mount, error) {
|
||||
var mounts []mount.Mount
|
||||
info, err := sn.Stat(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if info.Kind == snapshots.KindActive {
|
||||
mounts, err = sn.Mounts(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
key := fmt.Sprintf("%s-view-key", id)
|
||||
mounts, err = sn.View(ctx, key, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer sn.Remove(ctx, key)
|
||||
}
|
||||
return mounts, nil
|
||||
}
|
||||
|
||||
var usageCommand = cli.Command{
|
||||
Name: "usage",
|
||||
Usage: "usage snapshots",
|
||||
ArgsUsage: "[flags] [<key>, ...]",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "b",
|
||||
Usage: "display size in bytes",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var displaySize func(int64) string
|
||||
if context.Bool("b") {
|
||||
displaySize = func(s int64) string {
|
||||
return fmt.Sprintf("%d", s)
|
||||
}
|
||||
} else {
|
||||
displaySize = func(s int64) string {
|
||||
return progress.Bytes(s).String()
|
||||
}
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
var (
|
||||
snapshotter = client.SnapshotService(context.GlobalString("snapshotter"))
|
||||
tw = tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0)
|
||||
)
|
||||
fmt.Fprintln(tw, "KEY\tSIZE\tINODES\t")
|
||||
if context.NArg() == 0 {
|
||||
if err := snapshotter.Walk(ctx, func(ctx gocontext.Context, info snapshots.Info) error {
|
||||
usage, err := snapshotter.Usage(ctx, info.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(tw, "%v\t%s\t%d\t\n", info.Name, displaySize(usage.Size), usage.Inodes)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
for _, id := range context.Args() {
|
||||
usage, err := snapshotter.Usage(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(tw, "%v\t%s\t%d\t\n", id, displaySize(usage.Size), usage.Inodes)
|
||||
}
|
||||
}
|
||||
|
||||
return tw.Flush()
|
||||
},
|
||||
}
|
||||
|
||||
var removeCommand = cli.Command{
|
||||
Name: "remove",
|
||||
Aliases: []string{"rm"},
|
||||
ArgsUsage: "<key> [<key>, ...]",
|
||||
Usage: "remove snapshots",
|
||||
Action: func(context *cli.Context) error {
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
snapshotter := client.SnapshotService(context.GlobalString("snapshotter"))
|
||||
for _, key := range context.Args() {
|
||||
err = snapshotter.Remove(ctx, key)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to remove %q", key)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var prepareCommand = cli.Command{
|
||||
Name: "prepare",
|
||||
Usage: "prepare a snapshot from a committed snapshot",
|
||||
ArgsUsage: "[flags] <key> [<parent>]",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "target, t",
|
||||
Usage: "mount target path, will print mount, if provided",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
if narg := context.NArg(); narg < 1 || narg > 2 {
|
||||
return cli.ShowSubcommandHelp(context)
|
||||
}
|
||||
var (
|
||||
target = context.String("target")
|
||||
key = context.Args().Get(0)
|
||||
parent = context.Args().Get(1)
|
||||
)
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
snapshotter := client.SnapshotService(context.GlobalString("snapshotter"))
|
||||
labels := map[string]string{
|
||||
"containerd.io/gc.root": time.Now().UTC().Format(time.RFC3339),
|
||||
}
|
||||
|
||||
mounts, err := snapshotter.Prepare(ctx, key, parent, snapshots.WithLabels(labels))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if target != "" {
|
||||
printMounts(target, mounts)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var viewCommand = cli.Command{
|
||||
Name: "view",
|
||||
Usage: "create a read-only snapshot from a committed snapshot",
|
||||
ArgsUsage: "[flags] <key> [<parent>]",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "target, t",
|
||||
Usage: "mount target path, will print mount, if provided",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
if narg := context.NArg(); narg < 1 || narg > 2 {
|
||||
return cli.ShowSubcommandHelp(context)
|
||||
}
|
||||
var (
|
||||
target = context.String("target")
|
||||
key = context.Args().Get(0)
|
||||
parent = context.Args().Get(1)
|
||||
)
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
snapshotter := client.SnapshotService(context.GlobalString("snapshotter"))
|
||||
mounts, err := snapshotter.View(ctx, key, parent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if target != "" {
|
||||
printMounts(target, mounts)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var mountCommand = cli.Command{
|
||||
Name: "mounts",
|
||||
Aliases: []string{"m", "mount"},
|
||||
Usage: "mount gets mount commands for the snapshots",
|
||||
ArgsUsage: "<target> <key>",
|
||||
Action: func(context *cli.Context) error {
|
||||
if context.NArg() != 2 {
|
||||
return cli.ShowSubcommandHelp(context)
|
||||
}
|
||||
var (
|
||||
target = context.Args().Get(0)
|
||||
key = context.Args().Get(1)
|
||||
)
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
snapshotter := client.SnapshotService(context.GlobalString("snapshotter"))
|
||||
mounts, err := snapshotter.Mounts(ctx, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printMounts(target, mounts)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var commitCommand = cli.Command{
|
||||
Name: "commit",
|
||||
Usage: "commit an active snapshot into the provided name",
|
||||
ArgsUsage: "<key> <active>",
|
||||
Action: func(context *cli.Context) error {
|
||||
if context.NArg() != 2 {
|
||||
return cli.ShowSubcommandHelp(context)
|
||||
}
|
||||
var (
|
||||
key = context.Args().Get(0)
|
||||
active = context.Args().Get(1)
|
||||
)
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
snapshotter := client.SnapshotService(context.GlobalString("snapshotter"))
|
||||
labels := map[string]string{
|
||||
"containerd.io/gc.root": time.Now().UTC().Format(time.RFC3339),
|
||||
}
|
||||
return snapshotter.Commit(ctx, key, active, snapshots.WithLabels(labels))
|
||||
},
|
||||
}
|
||||
|
||||
var treeCommand = cli.Command{
|
||||
Name: "tree",
|
||||
Usage: "display tree view of snapshot branches",
|
||||
Action: func(context *cli.Context) error {
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
var (
|
||||
snapshotter = client.SnapshotService(context.GlobalString("snapshotter"))
|
||||
tree = newSnapshotTree()
|
||||
)
|
||||
|
||||
if err := snapshotter.Walk(ctx, func(ctx gocontext.Context, info snapshots.Info) error {
|
||||
// Get or create node and add node details
|
||||
tree.add(info)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printTree(tree)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var infoCommand = cli.Command{
|
||||
Name: "info",
|
||||
Usage: "get info about a snapshot",
|
||||
ArgsUsage: "<key>",
|
||||
Action: func(context *cli.Context) error {
|
||||
if context.NArg() != 1 {
|
||||
return cli.ShowSubcommandHelp(context)
|
||||
}
|
||||
|
||||
key := context.Args().Get(0)
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
snapshotter := client.SnapshotService(context.GlobalString("snapshotter"))
|
||||
info, err := snapshotter.Stat(ctx, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
commands.PrintAsJSON(info)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var setLabelCommand = cli.Command{
|
||||
Name: "label",
|
||||
Usage: "add labels to content",
|
||||
ArgsUsage: "<name> [<label>=<value> ...]",
|
||||
Description: "labels snapshots in the snapshotter",
|
||||
Action: func(context *cli.Context) error {
|
||||
key, labels := commands.ObjectWithLabelArgs(context)
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
snapshotter := client.SnapshotService(context.GlobalString("snapshotter"))
|
||||
|
||||
info := snapshots.Info{
|
||||
Name: key,
|
||||
Labels: map[string]string{},
|
||||
}
|
||||
|
||||
var paths []string
|
||||
for k, v := range labels {
|
||||
paths = append(paths, fmt.Sprintf("labels.%s", k))
|
||||
if v != "" {
|
||||
info.Labels[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing updated, do no clear
|
||||
if len(paths) == 0 {
|
||||
info, err = snapshotter.Stat(ctx, info.Name)
|
||||
} else {
|
||||
info, err = snapshotter.Update(ctx, info, paths...)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var labelStrings []string
|
||||
for k, v := range info.Labels {
|
||||
labelStrings = append(labelStrings, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
|
||||
fmt.Println(strings.Join(labelStrings, ","))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var unpackCommand = cli.Command{
|
||||
Name: "unpack",
|
||||
Usage: "unpack applies layers from a manifest to a snapshot",
|
||||
ArgsUsage: "[flags] <digest>",
|
||||
Flags: commands.SnapshotterFlags,
|
||||
Action: func(context *cli.Context) error {
|
||||
dgst, err := digest.Parse(context.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
log.G(ctx).Debugf("unpacking layers from manifest %s", dgst.String())
|
||||
// TODO: Support unpack by name
|
||||
images, err := client.ListImages(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var unpacked bool
|
||||
for _, image := range images {
|
||||
if image.Target().Digest == dgst {
|
||||
fmt.Printf("unpacking %s (%s)...", dgst, image.Target().MediaType)
|
||||
if err := image.Unpack(ctx, context.String("snapshotter")); err != nil {
|
||||
fmt.Println()
|
||||
return err
|
||||
}
|
||||
fmt.Println("done")
|
||||
unpacked = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !unpacked {
|
||||
return errors.New("manifest not found")
|
||||
}
|
||||
// TODO: Get rootfs from Image
|
||||
//log.G(ctx).Infof("chain ID: %s", chainID.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
type snapshotTree struct {
|
||||
nodes []*snapshotTreeNode
|
||||
index map[string]*snapshotTreeNode
|
||||
}
|
||||
|
||||
func newSnapshotTree() *snapshotTree {
|
||||
return &snapshotTree{
|
||||
index: make(map[string]*snapshotTreeNode),
|
||||
}
|
||||
}
|
||||
|
||||
type snapshotTreeNode struct {
|
||||
info snapshots.Info
|
||||
children []string
|
||||
}
|
||||
|
||||
func (st *snapshotTree) add(info snapshots.Info) *snapshotTreeNode {
|
||||
entry, ok := st.index[info.Name]
|
||||
if !ok {
|
||||
entry = &snapshotTreeNode{info: info}
|
||||
st.nodes = append(st.nodes, entry)
|
||||
st.index[info.Name] = entry
|
||||
} else {
|
||||
entry.info = info // update info if we created placeholder
|
||||
}
|
||||
|
||||
if info.Parent != "" {
|
||||
pn := st.get(info.Parent)
|
||||
if pn == nil {
|
||||
// create a placeholder
|
||||
pn = st.add(snapshots.Info{Name: info.Parent})
|
||||
}
|
||||
|
||||
pn.children = append(pn.children, info.Name)
|
||||
}
|
||||
return entry
|
||||
}
|
||||
|
||||
func (st *snapshotTree) get(name string) *snapshotTreeNode {
|
||||
return st.index[name]
|
||||
}
|
||||
|
||||
func printTree(st *snapshotTree) {
|
||||
for _, node := range st.nodes {
|
||||
// Print for root(parent-less) nodes only
|
||||
if node.info.Parent == "" {
|
||||
printNode(node.info.Name, st, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printNode(name string, tree *snapshotTree, level int) {
|
||||
node := tree.index[name]
|
||||
prefix := strings.Repeat(" ", level)
|
||||
|
||||
if level > 0 {
|
||||
prefix += "\\_"
|
||||
}
|
||||
|
||||
fmt.Printf(prefix+" %s\n", node.info.Name)
|
||||
level++
|
||||
for _, child := range node.children {
|
||||
printNode(child, tree, level)
|
||||
}
|
||||
}
|
||||
|
||||
func printMounts(target string, mounts []mount.Mount) {
|
||||
// FIXME: This is specific to Unix
|
||||
for _, m := range mounts {
|
||||
fmt.Printf("mount -t %s %s %s -o %s\n", m.Type, m.Source, target, strings.Join(m.Options, ","))
|
||||
}
|
||||
}
|
||||
86
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/attach.go
generated
vendored
Normal file
86
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/attach.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var attachCommand = cli.Command{
|
||||
Name: "attach",
|
||||
Usage: "attach to the IO of a running container",
|
||||
ArgsUsage: "CONTAINER",
|
||||
Action: func(context *cli.Context) error {
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
container, err := client.LoadContainer(ctx, context.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
spec, err := container.Spec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
con console.Console
|
||||
tty = spec.Process.Terminal
|
||||
)
|
||||
if tty {
|
||||
con = console.Current()
|
||||
defer con.Reset()
|
||||
if err := con.SetRaw(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
task, err := container.Task(ctx, cio.NewAttach(cio.WithStdio))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer task.Delete(ctx)
|
||||
|
||||
statusC, err := task.Wait(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tty {
|
||||
if err := HandleConsoleResize(ctx, task, con); err != nil {
|
||||
logrus.WithError(err).Error("console resize")
|
||||
}
|
||||
} else {
|
||||
sigc := commands.ForwardAllSignals(ctx, task)
|
||||
defer commands.StopCatch(sigc)
|
||||
}
|
||||
|
||||
ec := <-statusC
|
||||
code, _, err := ec.Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if code != 0 {
|
||||
return cli.NewExitError("", int(code))
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
101
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/checkpoint.go
generated
vendored
Normal file
101
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/checkpoint.go
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/runtime/linux/runctypes"
|
||||
"github.com/containerd/containerd/runtime/v2/runc/options"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var checkpointCommand = cli.Command{
|
||||
Name: "checkpoint",
|
||||
Usage: "checkpoint a container",
|
||||
ArgsUsage: "[flags] CONTAINER",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "exit",
|
||||
Usage: "stop the container after the checkpoint",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "runtime",
|
||||
Usage: "runtime name",
|
||||
Value: fmt.Sprintf("io.containerd.runtime.v1.%s", runtime.GOOS),
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
id := context.Args().First()
|
||||
if id == "" {
|
||||
return errors.New("container id must be provided")
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context, containerd.WithDefaultRuntime(context.String("runtime")))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
container, err := client.LoadContainer(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
task, err := container.Task(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var opts []containerd.CheckpointTaskOpts
|
||||
if context.Bool("exit") {
|
||||
opts = append(opts, withExit(context.String("runtime")))
|
||||
}
|
||||
checkpoint, err := task.Checkpoint(ctx, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(checkpoint.Name())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func withExit(rt string) containerd.CheckpointTaskOpts {
|
||||
return func(r *containerd.CheckpointTaskInfo) error {
|
||||
switch rt {
|
||||
case "io.containerd.runc.v1":
|
||||
if r.Options == nil {
|
||||
r.Options = &options.CheckpointOptions{
|
||||
Exit: true,
|
||||
}
|
||||
} else {
|
||||
opts, _ := r.Options.(*options.CheckpointOptions)
|
||||
opts.Exit = true
|
||||
}
|
||||
default:
|
||||
if r.Options == nil {
|
||||
r.Options = &runctypes.CheckpointOptions{
|
||||
Exit: true,
|
||||
}
|
||||
} else {
|
||||
opts, _ := r.Options.(*runctypes.CheckpointOptions)
|
||||
opts.Exit = true
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
63
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/delete.go
generated
vendored
Normal file
63
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/delete.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var deleteCommand = cli.Command{
|
||||
Name: "delete",
|
||||
Usage: "[flags] delete a task",
|
||||
ArgsUsage: "CONTAINER",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "force, f",
|
||||
Usage: "force delete task process",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
container, err := client.LoadContainer(ctx, context.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
task, err := container.Task(ctx, cio.Load)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var opts []containerd.ProcessDeleteOpts
|
||||
if context.Bool("force") {
|
||||
opts = append(opts, containerd.WithProcessKill)
|
||||
}
|
||||
status, err := task.Delete(ctx, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ec := status.ExitCode(); ec != 0 {
|
||||
return cli.NewExitError("", int(ec))
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
129
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/exec.go
generated
vendored
Normal file
129
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/exec.go
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
//TODO:(jessvalarezo) exec-id is optional here, update to required arg
|
||||
var execCommand = cli.Command{
|
||||
Name: "exec",
|
||||
Usage: "execute additional processes in an existing container",
|
||||
ArgsUsage: "[flags] CONTAINER CMD [ARG...]",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "cwd",
|
||||
Usage: "working directory of the new process",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "tty,t",
|
||||
Usage: "allocate a TTY for the container",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "exec-id",
|
||||
Usage: "exec specific id for the process",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "fifo-dir",
|
||||
Usage: "directory used for storing IO FIFOs",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
id = context.Args().First()
|
||||
args = context.Args().Tail()
|
||||
tty = context.Bool("tty")
|
||||
)
|
||||
if id == "" {
|
||||
return errors.New("container id must be provided")
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
container, err := client.LoadContainer(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
spec, err := container.Spec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
task, err := container.Task(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pspec := spec.Process
|
||||
pspec.Terminal = tty
|
||||
pspec.Args = args
|
||||
|
||||
cioOpts := []cio.Opt{cio.WithStdio, cio.WithFIFODir(context.String("fifo-dir"))}
|
||||
if tty {
|
||||
cioOpts = append(cioOpts, cio.WithTerminal)
|
||||
}
|
||||
ioCreator := cio.NewCreator(cioOpts...)
|
||||
process, err := task.Exec(ctx, context.String("exec-id"), pspec, ioCreator)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer process.Delete(ctx)
|
||||
|
||||
statusC, err := process.Wait(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var con console.Console
|
||||
if tty {
|
||||
con = console.Current()
|
||||
defer con.Reset()
|
||||
if err := con.SetRaw(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if tty {
|
||||
if err := HandleConsoleResize(ctx, process, con); err != nil {
|
||||
logrus.WithError(err).Error("console resize")
|
||||
}
|
||||
} else {
|
||||
sigc := commands.ForwardAllSignals(ctx, process)
|
||||
defer commands.StopCatch(sigc)
|
||||
}
|
||||
|
||||
if err := process.Start(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
status := <-statusC
|
||||
code, _, err := status.Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if code != 0 {
|
||||
return cli.NewExitError("", int(code))
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
96
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/kill.go
generated
vendored
Normal file
96
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/kill.go
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
const defaultSignal = "SIGTERM"
|
||||
|
||||
var killCommand = cli.Command{
|
||||
Name: "kill",
|
||||
Usage: "signal a container (default: SIGTERM)",
|
||||
ArgsUsage: "[flags] CONTAINER",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "signal, s",
|
||||
Value: "",
|
||||
Usage: "signal to send to the container",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "exec-id",
|
||||
Usage: "process ID to kill",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "all, a",
|
||||
Usage: "send signal to all processes inside the container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
id := context.Args().First()
|
||||
if id == "" {
|
||||
return errors.New("container id must be provided")
|
||||
}
|
||||
signal, err := containerd.ParseSignal(defaultSignal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
all = context.Bool("all")
|
||||
execID = context.String("exec-id")
|
||||
opts []containerd.KillOpts
|
||||
)
|
||||
if all && execID != "" {
|
||||
return errors.New("specify an exec-id or all; not both")
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
if all {
|
||||
opts = append(opts, containerd.WithKillAll)
|
||||
}
|
||||
if execID != "" {
|
||||
opts = append(opts, containerd.WithKillExecID(execID))
|
||||
}
|
||||
container, err := client.LoadContainer(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if context.String("signal") != "" {
|
||||
signal, err = containerd.ParseSignal(context.String("signal"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
signal, err = containerd.GetStopSignal(ctx, container, signal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
task, err := container.Task(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return task.Kill(ctx, signal, opts...)
|
||||
},
|
||||
}
|
||||
71
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/list.go
generated
vendored
Normal file
71
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/list.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
tasks "github.com/containerd/containerd/api/services/tasks/v1"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var listCommand = cli.Command{
|
||||
Name: "list",
|
||||
Usage: "list tasks",
|
||||
Aliases: []string{"ls"},
|
||||
ArgsUsage: "[flags]",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
||||
Usage: "print only the task id",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
quiet := context.Bool("quiet")
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
s := client.TaskService()
|
||||
response, err := s.List(ctx, &tasks.ListTasksRequest{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if quiet {
|
||||
for _, task := range response.Tasks {
|
||||
fmt.Println(task.ID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
w := tabwriter.NewWriter(os.Stdout, 4, 8, 4, ' ', 0)
|
||||
fmt.Fprintln(w, "TASK\tPID\tSTATUS\t")
|
||||
for _, task := range response.Tasks {
|
||||
if _, err := fmt.Fprintf(w, "%s\t%d\t%s\n",
|
||||
task.ID,
|
||||
task.Pid,
|
||||
task.Status.String(),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return w.Flush()
|
||||
},
|
||||
}
|
||||
117
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/metrics.go
generated
vendored
Normal file
117
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/metrics.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/containerd/cgroups"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/typeurl"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// metricsCommand is only added on Linux as github.com/containerd/cgroups
|
||||
// does not compile on darwin or windows
|
||||
Command.Subcommands = append(Command.Subcommands, metricsCommand)
|
||||
}
|
||||
|
||||
const (
|
||||
formatFlag = "format"
|
||||
formatTable = "table"
|
||||
formatJSON = "json"
|
||||
)
|
||||
|
||||
var metricsCommand = cli.Command{
|
||||
Name: "metrics",
|
||||
Usage: "get a single data point of metrics for a task with the built-in Linux runtime",
|
||||
ArgsUsage: "CONTAINER",
|
||||
Aliases: []string{"metric"},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: formatFlag,
|
||||
Usage: `"table" or "json"`,
|
||||
Value: formatTable,
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
container, err := client.LoadContainer(ctx, context.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
task, err := container.Task(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
metric, err := task.Metrics(ctx)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
anydata, err := typeurl.UnmarshalAny(metric.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, ok := anydata.(*cgroups.Metrics)
|
||||
if !ok {
|
||||
return errors.New("cannot convert metric data to cgroups.Metrics")
|
||||
}
|
||||
|
||||
switch context.String(formatFlag) {
|
||||
case formatTable:
|
||||
w := tabwriter.NewWriter(os.Stdout, 1, 8, 4, ' ', 0)
|
||||
fmt.Fprintf(w, "ID\tTIMESTAMP\t\n")
|
||||
fmt.Fprintf(w, "%s\t%s\t\n\n", metric.ID, metric.Timestamp)
|
||||
|
||||
fmt.Fprintf(w, "METRIC\tVALUE\t\n")
|
||||
if data.Memory != nil {
|
||||
fmt.Fprintf(w, "memory.usage_in_bytes\t%d\t\n", data.Memory.Usage.Usage)
|
||||
fmt.Fprintf(w, "memory.limit_in_bytes\t%d\t\n", data.Memory.Usage.Limit)
|
||||
fmt.Fprintf(w, "memory.stat.cache\t%d\t\n", data.Memory.TotalCache)
|
||||
}
|
||||
if data.CPU != nil {
|
||||
fmt.Fprintf(w, "cpuacct.usage\t%d\t\n", data.CPU.Usage.Total)
|
||||
fmt.Fprintf(w, "cpuacct.usage_percpu\t%v\t\n", data.CPU.Usage.PerCPU)
|
||||
}
|
||||
if data.Pids != nil {
|
||||
fmt.Fprintf(w, "pids.current\t%v\t\n", data.Pids.Current)
|
||||
fmt.Fprintf(w, "pids.limit\t%v\t\n", data.Pids.Limit)
|
||||
}
|
||||
return w.Flush()
|
||||
case formatJSON:
|
||||
marshaledJSON, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(marshaledJSON))
|
||||
return nil
|
||||
default:
|
||||
return errors.New("format must be table or json")
|
||||
}
|
||||
},
|
||||
}
|
||||
44
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/pause.go
generated
vendored
Normal file
44
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/pause.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var pauseCommand = cli.Command{
|
||||
Name: "pause",
|
||||
Usage: "pause an existing container",
|
||||
ArgsUsage: "CONTAINER",
|
||||
Action: func(context *cli.Context) error {
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
container, err := client.LoadContainer(ctx, context.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
task, err := container.Task(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return task.Pause(ctx)
|
||||
},
|
||||
}
|
||||
72
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/ps.go
generated
vendored
Normal file
72
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/ps.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/typeurl"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var psCommand = cli.Command{
|
||||
Name: "ps",
|
||||
Usage: "list processes for container",
|
||||
ArgsUsage: "CONTAINER",
|
||||
Action: func(context *cli.Context) error {
|
||||
id := context.Args().First()
|
||||
if id == "" {
|
||||
return errors.New("container id must be provided")
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
container, err := client.LoadContainer(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
task, err := container.Task(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
processes, err := task.Pids(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w := tabwriter.NewWriter(os.Stdout, 1, 8, 4, ' ', 0)
|
||||
fmt.Fprintln(w, "PID\tINFO")
|
||||
for _, ps := range processes {
|
||||
var info interface{} = "-"
|
||||
if ps.Info != nil {
|
||||
info, err = typeurl.UnmarshalAny(ps.Info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err := fmt.Fprintf(w, "%d\t%+v\n", ps.Pid, info); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return w.Flush()
|
||||
},
|
||||
}
|
||||
44
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/resume.go
generated
vendored
Normal file
44
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/resume.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var resumeCommand = cli.Command{
|
||||
Name: "resume",
|
||||
Usage: "resume a paused container",
|
||||
ArgsUsage: "CONTAINER",
|
||||
Action: func(context *cli.Context) error {
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
container, err := client.LoadContainer(ctx, context.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
task, err := container.Task(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return task.Resume(ctx)
|
||||
},
|
||||
}
|
||||
133
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/start.go
generated
vendored
Normal file
133
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/start.go
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var startCommand = cli.Command{
|
||||
Name: "start",
|
||||
Usage: "start a container that have been created",
|
||||
ArgsUsage: "CONTAINER",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "null-io",
|
||||
Usage: "send all IO to /dev/null",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "fifo-dir",
|
||||
Usage: "directory used for storing IO FIFOs",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "pid-file",
|
||||
Usage: "file path to write the task's pid",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "detach,d",
|
||||
Usage: "detach from the task after it has started execution",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
err error
|
||||
id = context.Args().Get(0)
|
||||
detach = context.Bool("detach")
|
||||
)
|
||||
if id == "" {
|
||||
return errors.New("container id must be provided")
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
container, err := client.LoadContainer(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
spec, err := container.Spec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
tty = spec.Process.Terminal
|
||||
opts = getNewTaskOpts(context)
|
||||
ioOpts = []cio.Opt{cio.WithFIFODir(context.String("fifo-dir"))}
|
||||
)
|
||||
var con console.Console
|
||||
if tty {
|
||||
con = console.Current()
|
||||
defer con.Reset()
|
||||
if err := con.SetRaw(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
task, err := NewTask(ctx, client, container, "", con, context.Bool("null-io"), ioOpts, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var statusC <-chan containerd.ExitStatus
|
||||
if !detach {
|
||||
defer task.Delete(ctx)
|
||||
if statusC, err = task.Wait(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if context.IsSet("pid-file") {
|
||||
if err := commands.WritePidFile(context.String("pid-file"), int(task.Pid())); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := task.Start(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if detach {
|
||||
return nil
|
||||
}
|
||||
if tty {
|
||||
if err := HandleConsoleResize(ctx, task, con); err != nil {
|
||||
logrus.WithError(err).Error("console resize")
|
||||
}
|
||||
} else {
|
||||
sigc := commands.ForwardAllSignals(ctx, task)
|
||||
defer commands.StopCatch(sigc)
|
||||
}
|
||||
|
||||
status := <-statusC
|
||||
code, _, err := status.Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := task.Delete(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if code != 0 {
|
||||
return cli.NewExitError("", int(code))
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
46
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/tasks.go
generated
vendored
Normal file
46
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/tasks.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
type resizer interface {
|
||||
Resize(ctx gocontext.Context, w, h uint32) error
|
||||
}
|
||||
|
||||
// Command is the cli command for managing tasks
|
||||
var Command = cli.Command{
|
||||
Name: "tasks",
|
||||
Usage: "manage tasks",
|
||||
Aliases: []string{"t", "task"},
|
||||
Subcommands: []cli.Command{
|
||||
attachCommand,
|
||||
checkpointCommand,
|
||||
deleteCommand,
|
||||
execCommand,
|
||||
listCommand,
|
||||
killCommand,
|
||||
pauseCommand,
|
||||
psCommand,
|
||||
resumeCommand,
|
||||
startCommand,
|
||||
},
|
||||
}
|
||||
97
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/tasks_unix.go
generated
vendored
Normal file
97
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/tasks_unix.go
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func init() {
|
||||
startCommand.Flags = append(startCommand.Flags, cli.BoolFlag{
|
||||
Name: "no-pivot",
|
||||
Usage: "disable use of pivot-root (linux only)",
|
||||
})
|
||||
}
|
||||
|
||||
// HandleConsoleResize resizes the console
|
||||
func HandleConsoleResize(ctx gocontext.Context, task resizer, con console.Console) error {
|
||||
// do an initial resize of the console
|
||||
size, err := con.Size()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := task.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil {
|
||||
log.G(ctx).WithError(err).Error("resize pty")
|
||||
}
|
||||
s := make(chan os.Signal, 16)
|
||||
signal.Notify(s, unix.SIGWINCH)
|
||||
go func() {
|
||||
for range s {
|
||||
size, err := con.Size()
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Error("get pty size")
|
||||
continue
|
||||
}
|
||||
if err := task.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil {
|
||||
log.G(ctx).WithError(err).Error("resize pty")
|
||||
}
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewTask creates a new task
|
||||
func NewTask(ctx gocontext.Context, client *containerd.Client, container containerd.Container, checkpoint string, con console.Console, nullIO bool, ioOpts []cio.Opt, opts ...containerd.NewTaskOpts) (containerd.Task, error) {
|
||||
stdio := cio.NewCreator(append([]cio.Opt{cio.WithStdio}, ioOpts...)...)
|
||||
if checkpoint != "" {
|
||||
im, err := client.GetImage(ctx, checkpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts = append(opts, containerd.WithTaskCheckpoint(im))
|
||||
}
|
||||
ioCreator := stdio
|
||||
if con != nil {
|
||||
ioCreator = cio.NewCreator(append([]cio.Opt{cio.WithStreams(con, con, nil), cio.WithTerminal}, ioOpts...)...)
|
||||
}
|
||||
if nullIO {
|
||||
if con != nil {
|
||||
return nil, errors.New("tty and null-io cannot be used together")
|
||||
}
|
||||
ioCreator = cio.NullIO
|
||||
}
|
||||
return container.NewTask(ctx, ioCreator, opts...)
|
||||
}
|
||||
|
||||
func getNewTaskOpts(context *cli.Context) []containerd.NewTaskOpts {
|
||||
if context.Bool("no-pivot") {
|
||||
return []containerd.NewTaskOpts{containerd.WithNoPivotRoot}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
78
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/tasks_windows.go
generated
vendored
Normal file
78
vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/tasks_windows.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tasks
|
||||
|
||||
import (
|
||||
gocontext "context"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// HandleConsoleResize resizes the console
|
||||
func HandleConsoleResize(ctx gocontext.Context, task resizer, con console.Console) error {
|
||||
// do an initial resize of the console
|
||||
size, err := con.Size()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
prevSize := size
|
||||
for {
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
|
||||
size, err := con.Size()
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Error("get pty size")
|
||||
continue
|
||||
}
|
||||
|
||||
if size.Width != prevSize.Width || size.Height != prevSize.Height {
|
||||
if err := task.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil {
|
||||
log.G(ctx).WithError(err).Error("resize pty")
|
||||
}
|
||||
prevSize = size
|
||||
}
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewTask creates a new task
|
||||
func NewTask(ctx gocontext.Context, client *containerd.Client, container containerd.Container, _ string, con console.Console, nullIO bool, ioOpts []cio.Opt, opts ...containerd.NewTaskOpts) (containerd.Task, error) {
|
||||
var ioCreator cio.Creator
|
||||
if con != nil {
|
||||
if nullIO {
|
||||
return nil, errors.New("tty and null-io cannot be used together")
|
||||
}
|
||||
ioCreator = cio.NewCreator(append([]cio.Opt{cio.WithStreams(con, con, con), cio.WithTerminal}, ioOpts...)...)
|
||||
} else if nullIO {
|
||||
ioCreator = cio.NullIO
|
||||
} else {
|
||||
ioCreator = cio.NewCreator(append([]cio.Opt{cio.WithStdio}, ioOpts...)...)
|
||||
}
|
||||
return container.NewTask(ctx, ioCreator)
|
||||
}
|
||||
|
||||
func getNewTaskOpts(_ *cli.Context) []containerd.NewTaskOpts {
|
||||
return nil
|
||||
}
|
||||
57
vendor/github.com/containerd/containerd/cmd/ctr/commands/version/version.go
generated
vendored
Normal file
57
vendor/github.com/containerd/containerd/cmd/ctr/commands/version/version.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||
"github.com/containerd/containerd/version"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// Command is a cli command to output the client and containerd server version
|
||||
var Command = cli.Command{
|
||||
Name: "version",
|
||||
Usage: "print the client and server versions",
|
||||
Action: func(context *cli.Context) error {
|
||||
fmt.Println("Client:")
|
||||
fmt.Println(" Version: ", version.Version)
|
||||
fmt.Println(" Revision:", version.Revision)
|
||||
fmt.Println("")
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
v, err := client.Version(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Server:")
|
||||
fmt.Println(" Version: ", v.Version)
|
||||
fmt.Println(" Revision:", v.Revision)
|
||||
if v.Version != version.Version {
|
||||
fmt.Fprintln(os.Stderr, "WARNING: version mismatch")
|
||||
}
|
||||
if v.Revision != version.Revision {
|
||||
fmt.Fprintln(os.Stderr, "WARNING: revision mismatch")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
4
vendor/github.com/containerd/containerd/content/local/locks.go
generated
vendored
4
vendor/github.com/containerd/containerd/content/local/locks.go
generated
vendored
@@ -47,7 +47,5 @@ func unlock(ref string) {
|
||||
locksMu.Lock()
|
||||
defer locksMu.Unlock()
|
||||
|
||||
if _, ok := locks[ref]; ok {
|
||||
delete(locks, ref)
|
||||
}
|
||||
delete(locks, ref)
|
||||
}
|
||||
|
||||
205
vendor/github.com/containerd/containerd/contrib/nvidia/nvidia.go
generated
vendored
Normal file
205
vendor/github.com/containerd/containerd/contrib/nvidia/nvidia.go
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package nvidia
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/oci"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
const nvidiaCLI = "nvidia-container-cli"
|
||||
|
||||
// Capability specifies capabilities for the gpu inside the container
|
||||
// Detailed explanation of options can be found:
|
||||
// https://github.com/nvidia/nvidia-container-runtime#supported-driver-capabilities
|
||||
type Capability string
|
||||
|
||||
const (
|
||||
// Compute capability
|
||||
Compute Capability = "compute"
|
||||
// Compat32 capability
|
||||
Compat32 Capability = "compat32"
|
||||
// Graphics capability
|
||||
Graphics Capability = "graphics"
|
||||
// Utility capability
|
||||
Utility Capability = "utility"
|
||||
// Video capability
|
||||
Video Capability = "video"
|
||||
// Display capability
|
||||
Display Capability = "display"
|
||||
)
|
||||
|
||||
var allCaps = []Capability{
|
||||
Compute,
|
||||
Compat32,
|
||||
Graphics,
|
||||
Utility,
|
||||
Video,
|
||||
Display,
|
||||
}
|
||||
|
||||
// WithGPUs adds NVIDIA gpu support to a container
|
||||
func WithGPUs(opts ...Opts) oci.SpecOpts {
|
||||
return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error {
|
||||
c := &config{}
|
||||
for _, o := range opts {
|
||||
if err := o(c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if c.OCIHookPath == "" {
|
||||
path, err := exec.LookPath("containerd")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.OCIHookPath = path
|
||||
}
|
||||
nvidiaPath, err := exec.LookPath(nvidiaCLI)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.Hooks == nil {
|
||||
s.Hooks = &specs.Hooks{}
|
||||
}
|
||||
s.Hooks.Prestart = append(s.Hooks.Prestart, specs.Hook{
|
||||
Path: c.OCIHookPath,
|
||||
Args: append([]string{
|
||||
"containerd",
|
||||
"oci-hook",
|
||||
"--",
|
||||
nvidiaPath,
|
||||
}, c.args()...),
|
||||
Env: os.Environ(),
|
||||
})
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type config struct {
|
||||
Devices []string
|
||||
Capabilities []Capability
|
||||
LoadKmods bool
|
||||
LDCache string
|
||||
LDConfig string
|
||||
Requirements []string
|
||||
OCIHookPath string
|
||||
}
|
||||
|
||||
func (c *config) args() []string {
|
||||
var args []string
|
||||
|
||||
if c.LoadKmods {
|
||||
args = append(args, "--load-kmods")
|
||||
}
|
||||
if c.LDCache != "" {
|
||||
args = append(args, fmt.Sprintf("--ldcache=%s", c.LDCache))
|
||||
}
|
||||
args = append(args,
|
||||
"configure",
|
||||
)
|
||||
if len(c.Devices) > 0 {
|
||||
args = append(args, fmt.Sprintf("--device=%s", strings.Join(c.Devices, ",")))
|
||||
}
|
||||
for _, c := range c.Capabilities {
|
||||
args = append(args, fmt.Sprintf("--%s", c))
|
||||
}
|
||||
if c.LDConfig != "" {
|
||||
args = append(args, fmt.Sprintf("--ldconfig=%s", c.LDConfig))
|
||||
}
|
||||
for _, r := range c.Requirements {
|
||||
args = append(args, fmt.Sprintf("--require=%s", r))
|
||||
}
|
||||
args = append(args, "--pid={{pid}}", "{{rootfs}}")
|
||||
return args
|
||||
}
|
||||
|
||||
// Opts are options for configuring gpu support
|
||||
type Opts func(*config) error
|
||||
|
||||
// WithDevices adds the provided device indexes to the container
|
||||
func WithDevices(ids ...int) Opts {
|
||||
return func(c *config) error {
|
||||
for _, i := range ids {
|
||||
c.Devices = append(c.Devices, strconv.Itoa(i))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithDeviceUUIDs adds the specific device UUID to the container
|
||||
func WithDeviceUUIDs(uuids ...string) Opts {
|
||||
return func(c *config) error {
|
||||
c.Devices = append(c.Devices, uuids...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithAllDevices adds all gpus to the container
|
||||
func WithAllDevices(c *config) error {
|
||||
c.Devices = []string{"all"}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithAllCapabilities adds all capabilities to the container for the gpus
|
||||
func WithAllCapabilities(c *config) error {
|
||||
c.Capabilities = allCaps
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithCapabilities adds the specified capabilities to the container for the gpus
|
||||
func WithCapabilities(caps ...Capability) Opts {
|
||||
return func(c *config) error {
|
||||
c.Capabilities = append(c.Capabilities, caps...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithRequiredCUDAVersion sets the required cuda version
|
||||
func WithRequiredCUDAVersion(major, minor int) Opts {
|
||||
return func(c *config) error {
|
||||
c.Requirements = append(c.Requirements, fmt.Sprintf("cuda>=%d.%d", major, minor))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithOCIHookPath sets the hook path for the binary
|
||||
func WithOCIHookPath(path string) Opts {
|
||||
return func(c *config) error {
|
||||
c.OCIHookPath = path
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithLookupOCIHookPath sets the hook path for the binary via a binary name
|
||||
func WithLookupOCIHookPath(name string) Opts {
|
||||
return func(c *config) error {
|
||||
path, err := exec.LookPath(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.OCIHookPath = path
|
||||
return nil
|
||||
}
|
||||
}
|
||||
4
vendor/github.com/containerd/containerd/contrib/seccomp/seccomp.go
generated
vendored
4
vendor/github.com/containerd/containerd/contrib/seccomp/seccomp.go
generated
vendored
@@ -37,10 +37,10 @@ func WithProfile(profile string) oci.SpecOpts {
|
||||
s.Linux.Seccomp = &specs.LinuxSeccomp{}
|
||||
f, err := ioutil.ReadFile(profile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot load seccomp profile %q: %v", profile, err)
|
||||
return fmt.Errorf("cannot load seccomp profile %q: %v", profile, err)
|
||||
}
|
||||
if err := json.Unmarshal(f, s.Linux.Seccomp); err != nil {
|
||||
return fmt.Errorf("Decoding seccomp profile failed %q: %v", profile, err)
|
||||
return fmt.Errorf("decoding seccomp profile failed %q: %v", profile, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
2
vendor/github.com/containerd/containerd/diff/apply/apply.go
generated
vendored
2
vendor/github.com/containerd/containerd/diff/apply/apply.go
generated
vendored
@@ -58,7 +58,7 @@ func (s *fsApplier) Apply(ctx context.Context, desc ocispec.Descriptor, mounts [
|
||||
defer func() {
|
||||
if err == nil {
|
||||
log.G(ctx).WithFields(logrus.Fields{
|
||||
"d": time.Now().Sub(t1),
|
||||
"d": time.Since(t1),
|
||||
"dgst": desc.Digest,
|
||||
"size": desc.Size,
|
||||
"media": desc.MediaType,
|
||||
|
||||
1
vendor/github.com/containerd/containerd/filters/scanner.go
generated
vendored
1
vendor/github.com/containerd/containerd/filters/scanner.go
generated
vendored
@@ -185,7 +185,6 @@ func (s *scanner) scanQuoted(quote rune) {
|
||||
ch = s.next()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *scanner) scanEscape(quote rune) rune {
|
||||
|
||||
70
vendor/github.com/containerd/containerd/images/handlers.go
generated
vendored
70
vendor/github.com/containerd/containerd/images/handlers.go
generated
vendored
@@ -222,22 +222,66 @@ func LimitManifests(f HandlerFunc, m platforms.MatchComparer, n int) HandlerFunc
|
||||
|
||||
switch desc.MediaType {
|
||||
case ocispec.MediaTypeImageIndex, MediaTypeDockerSchema2ManifestList:
|
||||
sort.SliceStable(children, func(i, j int) bool {
|
||||
if children[i].Platform == nil {
|
||||
return false
|
||||
}
|
||||
if children[j].Platform == nil {
|
||||
return true
|
||||
}
|
||||
return m.Less(*children[i].Platform, *children[j].Platform)
|
||||
})
|
||||
|
||||
if n > 0 && len(children) > n {
|
||||
children = children[:n]
|
||||
}
|
||||
children = limitChildren(children, m, n)
|
||||
default:
|
||||
// only limit manifests from an index
|
||||
}
|
||||
return children, nil
|
||||
}
|
||||
}
|
||||
|
||||
func limitChildren(children []ocispec.Descriptor, m platforms.MatchComparer, n int) []ocispec.Descriptor {
|
||||
sort.SliceStable(children, func(i, j int) bool {
|
||||
if children[i].Platform == nil {
|
||||
return false
|
||||
}
|
||||
if children[j].Platform == nil {
|
||||
return true
|
||||
}
|
||||
return m.Less(*children[i].Platform, *children[j].Platform)
|
||||
})
|
||||
|
||||
if n > 0 && len(children) > n {
|
||||
children = children[:n]
|
||||
}
|
||||
|
||||
return children
|
||||
}
|
||||
|
||||
type PlatformCapture struct {
|
||||
requested platforms.MatchComparer
|
||||
platforms []ocispec.Platform
|
||||
}
|
||||
|
||||
func NewPlatformCapture(comparer platforms.MatchComparer) *PlatformCapture {
|
||||
return &PlatformCapture{
|
||||
requested: comparer,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PlatformCapture) MatchComparer() platforms.MatchComparer {
|
||||
if len(p.platforms) == 0 {
|
||||
return p.requested
|
||||
}
|
||||
return platforms.Any(p.platforms...)
|
||||
}
|
||||
|
||||
func (p *PlatformCapture) Handler(f HandlerFunc) HandlerFunc {
|
||||
return func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) {
|
||||
children, err := f(ctx, desc)
|
||||
if err != nil {
|
||||
return children, err
|
||||
}
|
||||
|
||||
switch desc.MediaType {
|
||||
case ocispec.MediaTypeImageIndex, MediaTypeDockerSchema2ManifestList:
|
||||
for _, child := range children {
|
||||
if child.Platform != nil {
|
||||
p.platforms = append(p.platforms, *child.Platform)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return children, nil
|
||||
}
|
||||
}
|
||||
|
||||
5
vendor/github.com/containerd/containerd/images/image.go
generated
vendored
5
vendor/github.com/containerd/containerd/images/image.go
generated
vendored
@@ -119,7 +119,7 @@ func (image *Image) Size(ctx context.Context, provider content.Provider, platfor
|
||||
}
|
||||
size += desc.Size
|
||||
return nil, nil
|
||||
}), FilterPlatforms(ChildrenHandler(provider), platform)), image.Target)
|
||||
}), LimitManifests(FilterPlatforms(ChildrenHandler(provider), platform), platform, 1)), image.Target)
|
||||
}
|
||||
|
||||
type platformManifest struct {
|
||||
@@ -210,6 +210,9 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
|
||||
}
|
||||
}
|
||||
|
||||
// mimic behavior of client.Pull which limits to 1 manifest list child
|
||||
descs = limitChildren(descs, platform, 1)
|
||||
|
||||
wasIndex = true
|
||||
|
||||
return descs, nil
|
||||
|
||||
203
vendor/github.com/containerd/containerd/images/oci/exporter.go
generated
vendored
Normal file
203
vendor/github.com/containerd/containerd/images/oci/exporter.go
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"sort"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
ocispecs "github.com/opencontainers/image-spec/specs-go"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// V1Exporter implements OCI Image Spec v1.
|
||||
// It is up to caller to put "org.opencontainers.image.ref.name" annotation to desc.
|
||||
//
|
||||
// TODO(AkihiroSuda): add V1Exporter{TranslateMediaTypes: true} that transforms media types,
|
||||
// e.g. application/vnd.docker.image.rootfs.diff.tar.gzip
|
||||
// -> application/vnd.oci.image.layer.v1.tar+gzip
|
||||
type V1Exporter struct {
|
||||
}
|
||||
|
||||
// Export implements Exporter.
|
||||
func (oe *V1Exporter) Export(ctx context.Context, store content.Provider, desc ocispec.Descriptor, writer io.Writer) error {
|
||||
tw := tar.NewWriter(writer)
|
||||
defer tw.Close()
|
||||
|
||||
records := []tarRecord{
|
||||
ociLayoutFile(""),
|
||||
ociIndexRecord(desc),
|
||||
}
|
||||
|
||||
algorithms := map[string]struct{}{}
|
||||
exportHandler := func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
records = append(records, blobRecord(store, desc))
|
||||
algorithms[desc.Digest.Algorithm().String()] = struct{}{}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
handlers := images.Handlers(
|
||||
images.ChildrenHandler(store),
|
||||
images.HandlerFunc(exportHandler),
|
||||
)
|
||||
|
||||
// Walk sequentially since the number of fetchs is likely one and doing in
|
||||
// parallel requires locking the export handler
|
||||
if err := images.Walk(ctx, handlers, desc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(algorithms) > 0 {
|
||||
records = append(records, directoryRecord("blobs/", 0755))
|
||||
for alg := range algorithms {
|
||||
records = append(records, directoryRecord("blobs/"+alg+"/", 0755))
|
||||
}
|
||||
}
|
||||
|
||||
return writeTar(ctx, tw, records)
|
||||
}
|
||||
|
||||
type tarRecord struct {
|
||||
Header *tar.Header
|
||||
CopyTo func(context.Context, io.Writer) (int64, error)
|
||||
}
|
||||
|
||||
func blobRecord(cs content.Provider, desc ocispec.Descriptor) tarRecord {
|
||||
path := "blobs/" + desc.Digest.Algorithm().String() + "/" + desc.Digest.Hex()
|
||||
return tarRecord{
|
||||
Header: &tar.Header{
|
||||
Name: path,
|
||||
Mode: 0444,
|
||||
Size: desc.Size,
|
||||
Typeflag: tar.TypeReg,
|
||||
},
|
||||
CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
|
||||
r, err := cs.ReaderAt(ctx, desc)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "failed to get reader")
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
// Verify digest
|
||||
dgstr := desc.Digest.Algorithm().Digester()
|
||||
|
||||
n, err := io.Copy(io.MultiWriter(w, dgstr.Hash()), content.NewReader(r))
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "failed to copy to tar")
|
||||
}
|
||||
if dgstr.Digest() != desc.Digest {
|
||||
return 0, errors.Errorf("unexpected digest %s copied", dgstr.Digest())
|
||||
}
|
||||
return n, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func directoryRecord(name string, mode int64) tarRecord {
|
||||
return tarRecord{
|
||||
Header: &tar.Header{
|
||||
Name: name,
|
||||
Mode: mode,
|
||||
Typeflag: tar.TypeDir,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ociLayoutFile(version string) tarRecord {
|
||||
if version == "" {
|
||||
version = ocispec.ImageLayoutVersion
|
||||
}
|
||||
layout := ocispec.ImageLayout{
|
||||
Version: version,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(layout)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return tarRecord{
|
||||
Header: &tar.Header{
|
||||
Name: ocispec.ImageLayoutFile,
|
||||
Mode: 0444,
|
||||
Size: int64(len(b)),
|
||||
Typeflag: tar.TypeReg,
|
||||
},
|
||||
CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
|
||||
n, err := w.Write(b)
|
||||
return int64(n), err
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func ociIndexRecord(manifests ...ocispec.Descriptor) tarRecord {
|
||||
index := ocispec.Index{
|
||||
Versioned: ocispecs.Versioned{
|
||||
SchemaVersion: 2,
|
||||
},
|
||||
Manifests: manifests,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(index)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return tarRecord{
|
||||
Header: &tar.Header{
|
||||
Name: "index.json",
|
||||
Mode: 0644,
|
||||
Size: int64(len(b)),
|
||||
Typeflag: tar.TypeReg,
|
||||
},
|
||||
CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
|
||||
n, err := w.Write(b)
|
||||
return int64(n), err
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func writeTar(ctx context.Context, tw *tar.Writer, records []tarRecord) error {
|
||||
sort.Slice(records, func(i, j int) bool {
|
||||
return records[i].Header.Name < records[j].Header.Name
|
||||
})
|
||||
|
||||
for _, record := range records {
|
||||
if err := tw.WriteHeader(record.Header); err != nil {
|
||||
return err
|
||||
}
|
||||
if record.CopyTo != nil {
|
||||
n, err := record.CopyTo(ctx, tw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != record.Header.Size {
|
||||
return errors.Errorf("unexpected copy size for %s", record.Header.Name)
|
||||
}
|
||||
} else if record.Header.Size > 0 {
|
||||
return errors.Errorf("no content to write to record with non-zero size for %s", record.Header.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
3
vendor/github.com/containerd/containerd/import.go
generated
vendored
3
vendor/github.com/containerd/containerd/import.go
generated
vendored
@@ -99,8 +99,7 @@ func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt
|
||||
})
|
||||
}
|
||||
|
||||
var handler images.HandlerFunc
|
||||
handler = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
var handler images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
// Only save images at top level
|
||||
if desc.Digest != index.Digest {
|
||||
return images.Children(ctx, cs, desc)
|
||||
|
||||
2
vendor/github.com/containerd/containerd/metadata/content.go
generated
vendored
2
vendor/github.com/containerd/containerd/metadata/content.go
generated
vendored
@@ -766,7 +766,7 @@ func (cs *contentStore) garbageCollect(ctx context.Context) (d time.Duration, er
|
||||
t1 := time.Now()
|
||||
defer func() {
|
||||
if err == nil {
|
||||
d = time.Now().Sub(t1)
|
||||
d = time.Since(t1)
|
||||
}
|
||||
cs.l.Unlock()
|
||||
}()
|
||||
|
||||
8
vendor/github.com/containerd/containerd/metadata/db.go
generated
vendored
8
vendor/github.com/containerd/containerd/metadata/db.go
generated
vendored
@@ -154,7 +154,7 @@ func (m *DB) Init(ctx context.Context) error {
|
||||
if err := m.migrate(tx); err != nil {
|
||||
return errors.Wrapf(err, "failed to migrate to %s.%d", m.schema, m.version)
|
||||
}
|
||||
log.G(ctx).WithField("d", time.Now().Sub(t0)).Debugf("finished database migration to %s.%d", m.schema, m.version)
|
||||
log.G(ctx).WithField("d", time.Since(t0)).Debugf("finished database migration to %s.%d", m.schema, m.version)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
|
||||
m.cleanupSnapshotter(snapshotterName)
|
||||
|
||||
sl.Lock()
|
||||
stats.SnapshotD[snapshotterName] = time.Now().Sub(st1)
|
||||
stats.SnapshotD[snapshotterName] = time.Since(st1)
|
||||
sl.Unlock()
|
||||
|
||||
wg.Done()
|
||||
@@ -321,7 +321,7 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
|
||||
go func() {
|
||||
ct1 := time.Now()
|
||||
m.cleanupContent()
|
||||
stats.ContentD = time.Now().Sub(ct1)
|
||||
stats.ContentD = time.Since(ct1)
|
||||
wg.Done()
|
||||
}()
|
||||
m.dirtyCS = false
|
||||
@@ -329,7 +329,7 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
|
||||
|
||||
m.dirtyL.Unlock()
|
||||
|
||||
stats.MetaD = time.Now().Sub(t1)
|
||||
stats.MetaD = time.Since(t1)
|
||||
m.wlock.Unlock()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
4
vendor/github.com/containerd/containerd/metadata/gc.go
generated
vendored
4
vendor/github.com/containerd/containerd/metadata/gc.go
generated
vendored
@@ -296,10 +296,6 @@ func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)
|
||||
|
||||
bkt := getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectSnapshots, []byte(ss), []byte(name))
|
||||
if bkt == nil {
|
||||
getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectSnapshots).ForEach(func(k, v []byte) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
// Node may be created from dead edge
|
||||
return nil
|
||||
}
|
||||
|
||||
2
vendor/github.com/containerd/containerd/metadata/snapshot.go
generated
vendored
2
vendor/github.com/containerd/containerd/metadata/snapshot.go
generated
vendored
@@ -628,7 +628,7 @@ func (s *snapshotter) garbageCollect(ctx context.Context) (d time.Duration, err
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
d = time.Now().Sub(t1)
|
||||
d = time.Since(t1)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
8
vendor/github.com/containerd/containerd/mount/mountinfo_linux.go
generated
vendored
8
vendor/github.com/containerd/containerd/mount/mountinfo_linux.go
generated
vendored
@@ -68,7 +68,7 @@ func parseInfoFile(r io.Reader) ([]Info, error) {
|
||||
numFields := len(fields)
|
||||
if numFields < 10 {
|
||||
// should be at least 10 fields
|
||||
return nil, fmt.Errorf("Parsing '%s' failed: not enough fields (%d)", text, numFields)
|
||||
return nil, fmt.Errorf("parsing '%s' failed: not enough fields (%d)", text, numFields)
|
||||
}
|
||||
p := Info{}
|
||||
// ignore any numbers parsing errors, as there should not be any
|
||||
@@ -76,7 +76,7 @@ func parseInfoFile(r io.Reader) ([]Info, error) {
|
||||
p.Parent, _ = strconv.Atoi(fields[1])
|
||||
mm := strings.Split(fields[2], ":")
|
||||
if len(mm) != 2 {
|
||||
return nil, fmt.Errorf("Parsing '%s' failed: unexpected minor:major pair %s", text, mm)
|
||||
return nil, fmt.Errorf("parsing '%s' failed: unexpected minor:major pair %s", text, mm)
|
||||
}
|
||||
p.Major, _ = strconv.Atoi(mm[0])
|
||||
p.Minor, _ = strconv.Atoi(mm[1])
|
||||
@@ -101,11 +101,11 @@ func parseInfoFile(r io.Reader) ([]Info, error) {
|
||||
}
|
||||
}
|
||||
if i == numFields {
|
||||
return nil, fmt.Errorf("Parsing '%s' failed: missing separator ('-')", text)
|
||||
return nil, fmt.Errorf("parsing '%s' failed: missing separator ('-')", text)
|
||||
}
|
||||
// There should be 3 fields after the separator...
|
||||
if i+4 > numFields {
|
||||
return nil, fmt.Errorf("Parsing '%s' failed: not enough fields after a separator", text)
|
||||
return nil, fmt.Errorf("parsing '%s' failed: not enough fields after a separator", text)
|
||||
}
|
||||
// ... but in Linux <= 3.9 mounting a cifs with spaces in a share name
|
||||
// (like "//serv/My Documents") _may_ end up having a space in the last field
|
||||
|
||||
82
vendor/github.com/containerd/containerd/pkg/progress/bar.go
generated
vendored
Normal file
82
vendor/github.com/containerd/containerd/pkg/progress/bar.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package progress
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// TODO(stevvooe): We may want to support more interesting parameterization of
|
||||
// the bar. For now, it is very simple.
|
||||
|
||||
// Bar provides a very simple progress bar implementation.
|
||||
//
|
||||
// Use with fmt.Printf and "r" to format the progress bar. A "-" flag makes it
|
||||
// progress from right to left.
|
||||
type Bar float64
|
||||
|
||||
var _ fmt.Formatter = Bar(1.0)
|
||||
|
||||
// Format the progress bar as output
|
||||
func (h Bar) Format(state fmt.State, r rune) {
|
||||
switch r {
|
||||
case 'r':
|
||||
default:
|
||||
panic(fmt.Sprintf("%v: unexpected format character", float64(h)))
|
||||
}
|
||||
|
||||
if h > 1.0 {
|
||||
h = 1.0
|
||||
}
|
||||
|
||||
if h < 0.0 {
|
||||
h = 0.0
|
||||
}
|
||||
|
||||
if state.Flag('-') {
|
||||
h = 1.0 - h
|
||||
}
|
||||
|
||||
width, ok := state.Width()
|
||||
if !ok {
|
||||
// default width of 40
|
||||
width = 40
|
||||
}
|
||||
|
||||
var pad int
|
||||
|
||||
extra := len([]byte(green)) + len([]byte(reset))
|
||||
|
||||
p := make([]byte, width+extra)
|
||||
p[0], p[len(p)-1] = '|', '|'
|
||||
pad += 2
|
||||
|
||||
positive := int(Bar(width-pad) * h)
|
||||
negative := width - pad - positive
|
||||
|
||||
n := 1
|
||||
n += copy(p[n:], []byte(green))
|
||||
n += copy(p[n:], bytes.Repeat([]byte("+"), positive))
|
||||
n += copy(p[n:], []byte(reset))
|
||||
|
||||
if negative > 0 {
|
||||
copy(p[n:len(p)-1], bytes.Repeat([]byte("-"), negative))
|
||||
}
|
||||
|
||||
state.Write(p)
|
||||
}
|
||||
18
vendor/github.com/containerd/containerd/pkg/progress/doc.go
generated
vendored
Normal file
18
vendor/github.com/containerd/containerd/pkg/progress/doc.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package progress assists in displaying human readable progress information.
|
||||
package progress
|
||||
24
vendor/github.com/containerd/containerd/pkg/progress/escape.go
generated
vendored
Normal file
24
vendor/github.com/containerd/containerd/pkg/progress/escape.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package progress
|
||||
|
||||
const (
|
||||
escape = "\x1b"
|
||||
reset = escape + "[0m"
|
||||
red = escape + "[31m" // nolint: staticcheck, varcheck
|
||||
green = escape + "[32m"
|
||||
)
|
||||
45
vendor/github.com/containerd/containerd/pkg/progress/humaans.go
generated
vendored
Normal file
45
vendor/github.com/containerd/containerd/pkg/progress/humaans.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package progress
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
units "github.com/docker/go-units"
|
||||
)
|
||||
|
||||
// Bytes converts a regular int64 to human readable type.
|
||||
type Bytes int64
|
||||
|
||||
// String returns the string representation of bytes
|
||||
func (b Bytes) String() string {
|
||||
return units.CustomSize("%02.1f %s", float64(b), 1024.0, []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"})
|
||||
}
|
||||
|
||||
// BytesPerSecond is the rate in seconds for byte operations
|
||||
type BytesPerSecond int64
|
||||
|
||||
// NewBytesPerSecond returns the rate that n bytes were written in the provided duration
|
||||
func NewBytesPerSecond(n int64, duration time.Duration) BytesPerSecond {
|
||||
return BytesPerSecond(float64(n) / duration.Seconds())
|
||||
}
|
||||
|
||||
// String returns the string representation of the rate
|
||||
func (bps BytesPerSecond) String() string {
|
||||
return fmt.Sprintf("%v/s", Bytes(bps))
|
||||
}
|
||||
115
vendor/github.com/containerd/containerd/pkg/progress/writer.go
generated
vendored
Normal file
115
vendor/github.com/containerd/containerd/pkg/progress/writer.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package progress
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/console"
|
||||
)
|
||||
|
||||
var (
|
||||
regexCleanLine = regexp.MustCompile("\x1b\\[[0-9]+m[\x1b]?")
|
||||
)
|
||||
|
||||
// Writer buffers writes until flush, at which time the last screen is cleared
|
||||
// and the current buffer contents are written. This is useful for
|
||||
// implementing progress displays, such as those implemented in docker and
|
||||
// git.
|
||||
type Writer struct {
|
||||
buf bytes.Buffer
|
||||
w io.Writer
|
||||
lines int
|
||||
}
|
||||
|
||||
// NewWriter returns a writer
|
||||
func NewWriter(w io.Writer) *Writer {
|
||||
return &Writer{
|
||||
w: w,
|
||||
}
|
||||
}
|
||||
|
||||
// Write the provided bytes
|
||||
func (w *Writer) Write(p []byte) (n int, err error) {
|
||||
return w.buf.Write(p)
|
||||
}
|
||||
|
||||
// Flush should be called when refreshing the current display.
|
||||
func (w *Writer) Flush() error {
|
||||
if w.buf.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := w.clearLines(); err != nil {
|
||||
return err
|
||||
}
|
||||
w.lines = countLines(w.buf.String())
|
||||
|
||||
if _, err := w.w.Write(w.buf.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.buf.Reset()
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO(stevvooe): The following are system specific. Break these out if we
|
||||
// decide to build this package further.
|
||||
|
||||
func (w *Writer) clearLines() error {
|
||||
for i := 0; i < w.lines; i++ {
|
||||
if _, err := fmt.Fprintf(w.w, "\x1b[1A\x1b[2K\r"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// countLines in the output. If a line is longer than the console width then
|
||||
// an extra line is added to the count for each wrapped line. If the console
|
||||
// width is undefined then 0 is returned so that no lines are cleared on the next
|
||||
// flush.
|
||||
func countLines(output string) int {
|
||||
con, err := console.ConsoleFromFile(os.Stdin)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
ws, err := con.Size()
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
width := int(ws.Width)
|
||||
if width <= 0 {
|
||||
return 0
|
||||
}
|
||||
strlines := strings.Split(output, "\n")
|
||||
lines := -1
|
||||
for _, line := range strlines {
|
||||
lines += (len(stripLine(line))-1)/width + 1
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
func stripLine(line string) string {
|
||||
return string(regexCleanLine.ReplaceAll([]byte(line), []byte{}))
|
||||
}
|
||||
5
vendor/github.com/containerd/containerd/plugin/plugin.go
generated
vendored
5
vendor/github.com/containerd/containerd/plugin/plugin.go
generated
vendored
@@ -42,10 +42,7 @@ var (
|
||||
|
||||
// IsSkipPlugin returns true if the error is skipping the plugin
|
||||
func IsSkipPlugin(err error) bool {
|
||||
if errors.Cause(err) == ErrSkipPlugin {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return errors.Cause(err) == ErrSkipPlugin
|
||||
}
|
||||
|
||||
// Type is the type of the plugin
|
||||
|
||||
8
vendor/github.com/containerd/containerd/process.go
generated
vendored
8
vendor/github.com/containerd/containerd/process.go
generated
vendored
@@ -111,9 +111,11 @@ func (p *process) Start(ctx context.Context) error {
|
||||
ExecID: p.id,
|
||||
})
|
||||
if err != nil {
|
||||
p.io.Cancel()
|
||||
p.io.Wait()
|
||||
p.io.Close()
|
||||
if p.io != nil {
|
||||
p.io.Cancel()
|
||||
p.io.Wait()
|
||||
p.io.Close()
|
||||
}
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
p.pid = r.Pid
|
||||
|
||||
4
vendor/github.com/containerd/containerd/remotes/docker/auth.go
generated
vendored
4
vendor/github.com/containerd/containerd/remotes/docker/auth.go
generated
vendored
@@ -79,8 +79,8 @@ func init() {
|
||||
var t octetType
|
||||
isCtl := c <= 31 || c == 127
|
||||
isChar := 0 <= c && c <= 127
|
||||
isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0
|
||||
if strings.IndexRune(" \t\r\n", rune(c)) >= 0 {
|
||||
isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c))
|
||||
if strings.ContainsRune(" \t\r\n", rune(c)) {
|
||||
t |= isSpace
|
||||
}
|
||||
if isChar && !isCtl && !isSeparator {
|
||||
|
||||
88
vendor/github.com/containerd/containerd/remotes/docker/converter.go
generated
vendored
Normal file
88
vendor/github.com/containerd/containerd/remotes/docker/converter.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package docker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// LegacyConfigMediaType should be replaced by OCI image spec.
|
||||
//
|
||||
// More detail: docker/distribution#1622
|
||||
const LegacyConfigMediaType = "application/octet-stream"
|
||||
|
||||
// ConvertManifest changes application/octet-stream to schema2 config media type if need.
|
||||
//
|
||||
// NOTE:
|
||||
// 1. original manifest will be deleted by next gc round.
|
||||
// 2. don't cover manifest list.
|
||||
func ConvertManifest(ctx context.Context, store content.Store, desc ocispec.Descriptor) (ocispec.Descriptor, error) {
|
||||
if !(desc.MediaType == images.MediaTypeDockerSchema2Manifest ||
|
||||
desc.MediaType == ocispec.MediaTypeImageManifest) {
|
||||
|
||||
log.G(ctx).Warnf("do nothing for media type: %s", desc.MediaType)
|
||||
return desc, nil
|
||||
}
|
||||
|
||||
// read manifest data
|
||||
mb, err := content.ReadBlob(ctx, store, desc)
|
||||
if err != nil {
|
||||
return ocispec.Descriptor{}, errors.Wrap(err, "failed to read index data")
|
||||
}
|
||||
|
||||
var manifest ocispec.Manifest
|
||||
if err := json.Unmarshal(mb, &manifest); err != nil {
|
||||
return ocispec.Descriptor{}, errors.Wrap(err, "failed to unmarshal data into manifest")
|
||||
}
|
||||
|
||||
// check config media type
|
||||
if manifest.Config.MediaType != LegacyConfigMediaType {
|
||||
return desc, nil
|
||||
}
|
||||
|
||||
manifest.Config.MediaType = images.MediaTypeDockerSchema2Config
|
||||
data, err := json.MarshalIndent(manifest, "", " ")
|
||||
if err != nil {
|
||||
return ocispec.Descriptor{}, errors.Wrap(err, "failed to marshal manifest")
|
||||
}
|
||||
|
||||
// update manifest with gc labels
|
||||
desc.Digest = digest.Canonical.FromBytes(data)
|
||||
desc.Size = int64(len(data))
|
||||
|
||||
labels := map[string]string{}
|
||||
for i, c := range append([]ocispec.Descriptor{manifest.Config}, manifest.Layers...) {
|
||||
labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = c.Digest.String()
|
||||
}
|
||||
|
||||
ref := remotes.MakeRefKey(ctx, desc)
|
||||
if err := content.WriteBlob(ctx, store, ref, bytes.NewReader(data), desc, content.WithLabels(labels)); err != nil {
|
||||
return ocispec.Descriptor{}, errors.Wrap(err, "failed to update content")
|
||||
}
|
||||
return desc, nil
|
||||
}
|
||||
4
vendor/github.com/containerd/containerd/runtime/runtime.go
generated
vendored
4
vendor/github.com/containerd/containerd/runtime/runtime.go
generated
vendored
@@ -69,4 +69,8 @@ type PlatformRuntime interface {
|
||||
// Tasks returns all the current tasks for the runtime.
|
||||
// Any container runs at most one task at a time.
|
||||
Tasks(context.Context, bool) ([]Task, error)
|
||||
// Add adds a task into runtime.
|
||||
Add(context.Context, Task) error
|
||||
// Delete remove a task.
|
||||
Delete(context.Context, string)
|
||||
}
|
||||
|
||||
4
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/deleted_state.go
generated
vendored
4
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/deleted_state.go
generated
vendored
@@ -69,7 +69,3 @@ func (s *deletedState) SetExited(status int) {
|
||||
func (s *deletedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
|
||||
return nil, errors.Errorf("cannot exec in a deleted state")
|
||||
}
|
||||
|
||||
func (s *deletedState) Pid() int {
|
||||
return -1
|
||||
}
|
||||
|
||||
29
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/exec.go
generated
vendored
29
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/exec.go
generated
vendored
@@ -49,7 +49,7 @@ type execProcess struct {
|
||||
io runc.IO
|
||||
status int
|
||||
exited time.Time
|
||||
pid int
|
||||
pid *safePid
|
||||
closers []io.Closer
|
||||
stdin io.Closer
|
||||
stdio proc.Stdio
|
||||
@@ -69,11 +69,7 @@ func (e *execProcess) ID() string {
|
||||
}
|
||||
|
||||
func (e *execProcess) Pid() int {
|
||||
return e.execState.Pid()
|
||||
}
|
||||
|
||||
func (e *execProcess) pidv() int {
|
||||
return e.pid
|
||||
return e.pid.get()
|
||||
}
|
||||
|
||||
func (e *execProcess) ExitStatus() int {
|
||||
@@ -145,7 +141,7 @@ func (e *execProcess) Kill(ctx context.Context, sig uint32, _ bool) error {
|
||||
}
|
||||
|
||||
func (e *execProcess) kill(ctx context.Context, sig uint32, _ bool) error {
|
||||
pid := e.pid
|
||||
pid := e.pid.get()
|
||||
if pid != 0 {
|
||||
if err := unix.Kill(pid, syscall.Signal(sig)); err != nil {
|
||||
return errors.Wrapf(checkKillError(err), "exec kill error")
|
||||
@@ -170,6 +166,12 @@ func (e *execProcess) Start(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (e *execProcess) start(ctx context.Context) (err error) {
|
||||
// The reaper may receive exit signal right after
|
||||
// the container is started, before the e.pid is updated.
|
||||
// In that case, we want to block the signal handler to
|
||||
// access e.pid until it is updated.
|
||||
e.pid.Lock()
|
||||
defer e.pid.Unlock()
|
||||
var (
|
||||
socket *runc.Socket
|
||||
pidfile = filepath.Join(e.path, fmt.Sprintf("%s.pid", e.id))
|
||||
@@ -201,7 +203,7 @@ func (e *execProcess) start(ctx context.Context) (err error) {
|
||||
return e.parent.runtimeError(err, "OCI runtime exec failed")
|
||||
}
|
||||
if e.stdio.Stdin != "" {
|
||||
sc, err := fifo.OpenFifo(ctx, e.stdio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
|
||||
sc, err := fifo.OpenFifo(context.Background(), e.stdio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to open stdin fifo %s", e.stdio.Stdin)
|
||||
}
|
||||
@@ -210,29 +212,26 @@ func (e *execProcess) start(ctx context.Context) (err error) {
|
||||
}
|
||||
var copyWaitGroup sync.WaitGroup
|
||||
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
||||
defer cancel()
|
||||
if socket != nil {
|
||||
console, err := socket.ReceiveMaster()
|
||||
if err != nil {
|
||||
cancel()
|
||||
return errors.Wrap(err, "failed to retrieve console master")
|
||||
}
|
||||
if e.console, err = e.parent.Platform.CopyConsole(ctx, console, e.stdio.Stdin, e.stdio.Stdout, e.stdio.Stderr, &e.wg, ©WaitGroup); err != nil {
|
||||
cancel()
|
||||
return errors.Wrap(err, "failed to start console copy")
|
||||
}
|
||||
} else if !e.stdio.IsNull() {
|
||||
if err := copyPipes(ctx, e.io, e.stdio.Stdin, e.stdio.Stdout, e.stdio.Stderr, &e.wg, ©WaitGroup); err != nil {
|
||||
cancel()
|
||||
return errors.Wrap(err, "failed to start io pipe copy")
|
||||
}
|
||||
}
|
||||
copyWaitGroup.Wait()
|
||||
pid, err := runc.ReadPidFile(opts.PidFile)
|
||||
if err != nil {
|
||||
cancel()
|
||||
return errors.Wrap(err, "failed to retrieve OCI runtime exec pid")
|
||||
}
|
||||
e.pid = pid
|
||||
e.pid.pid = pid
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -250,11 +249,11 @@ func (e *execProcess) Status(ctx context.Context) (string, error) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
// if we don't have a pid then the exec process has just been created
|
||||
if e.pid == 0 {
|
||||
if e.pid.get() == 0 {
|
||||
return "created", nil
|
||||
}
|
||||
// if we have a pid and it can be signaled, the process is running
|
||||
if err := unix.Kill(e.pid, 0); err == nil {
|
||||
if err := unix.Kill(e.pid.get(), 0); err == nil {
|
||||
return "running", nil
|
||||
}
|
||||
// else if we have a pid but it can nolonger be signaled, it has stopped
|
||||
|
||||
17
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/exec_state.go
generated
vendored
17
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/exec_state.go
generated
vendored
@@ -31,7 +31,6 @@ type execState interface {
|
||||
Delete(context.Context) error
|
||||
Kill(context.Context, uint32, bool) error
|
||||
SetExited(int)
|
||||
Pid() int
|
||||
}
|
||||
|
||||
type execCreatedState struct {
|
||||
@@ -83,12 +82,6 @@ func (s *execCreatedState) SetExited(status int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *execCreatedState) Pid() int {
|
||||
s.p.mu.Lock()
|
||||
defer s.p.mu.Unlock()
|
||||
return s.p.pidv()
|
||||
}
|
||||
|
||||
type execRunningState struct {
|
||||
p *execProcess
|
||||
}
|
||||
@@ -127,12 +120,6 @@ func (s *execRunningState) SetExited(status int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *execRunningState) Pid() int {
|
||||
s.p.mu.Lock()
|
||||
defer s.p.mu.Unlock()
|
||||
return s.p.pidv()
|
||||
}
|
||||
|
||||
type execStoppedState struct {
|
||||
p *execProcess
|
||||
}
|
||||
@@ -170,7 +157,3 @@ func (s *execStoppedState) Kill(ctx context.Context, sig uint32, all bool) error
|
||||
func (s *execStoppedState) SetExited(status int) {
|
||||
// no op
|
||||
}
|
||||
|
||||
func (s *execStoppedState) Pid() int {
|
||||
return s.p.pidv()
|
||||
}
|
||||
|
||||
8
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/init.go
generated
vendored
8
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/init.go
generated
vendored
@@ -160,7 +160,7 @@ func (p *Init) Create(ctx context.Context, r *CreateConfig) error {
|
||||
return p.runtimeError(err, "OCI runtime create failed")
|
||||
}
|
||||
if r.Stdin != "" {
|
||||
sc, err := fifo.OpenFifo(ctx, r.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
|
||||
sc, err := fifo.OpenFifo(context.Background(), r.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to open stdin fifo %s", r.Stdin)
|
||||
}
|
||||
@@ -169,21 +169,19 @@ func (p *Init) Create(ctx context.Context, r *CreateConfig) error {
|
||||
}
|
||||
var copyWaitGroup sync.WaitGroup
|
||||
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
||||
defer cancel()
|
||||
if socket != nil {
|
||||
console, err := socket.ReceiveMaster()
|
||||
if err != nil {
|
||||
cancel()
|
||||
return errors.Wrap(err, "failed to retrieve console master")
|
||||
}
|
||||
console, err = p.Platform.CopyConsole(ctx, console, r.Stdin, r.Stdout, r.Stderr, &p.wg, ©WaitGroup)
|
||||
if err != nil {
|
||||
cancel()
|
||||
return errors.Wrap(err, "failed to start console copy")
|
||||
}
|
||||
p.console = console
|
||||
} else if !hasNoIO(r) {
|
||||
if err := copyPipes(ctx, p.io, r.Stdin, r.Stdout, r.Stderr, &p.wg, ©WaitGroup); err != nil {
|
||||
cancel()
|
||||
return errors.Wrap(err, "failed to start io pipe copy")
|
||||
}
|
||||
}
|
||||
@@ -191,7 +189,6 @@ func (p *Init) Create(ctx context.Context, r *CreateConfig) error {
|
||||
copyWaitGroup.Wait()
|
||||
pid, err := runc.ReadPidFile(pidFile)
|
||||
if err != nil {
|
||||
cancel()
|
||||
return errors.Wrap(err, "failed to retrieve OCI runtime container pid")
|
||||
}
|
||||
p.pid = pid
|
||||
@@ -409,6 +406,7 @@ func (p *Init) exec(ctx context.Context, path string, r *ExecConfig) (proc.Proce
|
||||
Terminal: r.Terminal,
|
||||
},
|
||||
waitBlock: make(chan struct{}),
|
||||
pid: &safePid{},
|
||||
}
|
||||
e.execState = &execCreatedState{p: e}
|
||||
return e, nil
|
||||
|
||||
2
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/init_state.go
generated
vendored
2
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/init_state.go
generated
vendored
@@ -172,7 +172,7 @@ func (s *createdCheckpointState) Start(ctx context.Context) error {
|
||||
return p.runtimeError(err, "OCI runtime restore failed")
|
||||
}
|
||||
if sio.Stdin != "" {
|
||||
sc, err := fifo.OpenFifo(ctx, sio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
|
||||
sc, err := fifo.OpenFifo(context.Background(), sio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to open stdin fifo %s", sio.Stdin)
|
||||
}
|
||||
|
||||
2
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/io.go
generated
vendored
2
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/io.go
generated
vendored
@@ -111,7 +111,7 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
|
||||
if stdin == "" {
|
||||
return nil
|
||||
}
|
||||
f, err := fifo.OpenFifo(ctx, stdin, syscall.O_RDONLY|syscall.O_NONBLOCK, 0)
|
||||
f, err := fifo.OpenFifo(context.Background(), stdin, syscall.O_RDONLY|syscall.O_NONBLOCK, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("containerd-shim: opening %s failed: %s", stdin, err)
|
||||
}
|
||||
|
||||
13
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/utils.go
generated
vendored
13
vendor/github.com/containerd/containerd/runtime/v1/linux/proc/utils.go
generated
vendored
@@ -23,6 +23,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
@@ -31,6 +32,18 @@ import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// safePid is a thread safe wrapper for pid.
|
||||
type safePid struct {
|
||||
sync.Mutex
|
||||
pid int
|
||||
}
|
||||
|
||||
func (s *safePid) get() int {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
return s.pid
|
||||
}
|
||||
|
||||
// TODO(mlaventure): move to runc package?
|
||||
func getLastRuntimeError(r *runc.Runc) (string, error) {
|
||||
if r.Log == "" {
|
||||
|
||||
10
vendor/github.com/containerd/containerd/runtime/v1/linux/runtime.go
generated
vendored
10
vendor/github.com/containerd/containerd/runtime/v1/linux/runtime.go
generated
vendored
@@ -303,6 +303,16 @@ func (r *Runtime) Get(ctx context.Context, id string) (runtime.Task, error) {
|
||||
return r.tasks.Get(ctx, id)
|
||||
}
|
||||
|
||||
// Add a runtime task
|
||||
func (r *Runtime) Add(ctx context.Context, task runtime.Task) error {
|
||||
return r.tasks.Add(ctx, task)
|
||||
}
|
||||
|
||||
// Delete a runtime task
|
||||
func (r *Runtime) Delete(ctx context.Context, id string) {
|
||||
r.tasks.Delete(ctx, id)
|
||||
}
|
||||
|
||||
func (r *Runtime) loadTasks(ctx context.Context, ns string) ([]*Task, error) {
|
||||
dir, err := ioutil.ReadDir(filepath.Join(r.state, ns))
|
||||
if err != nil {
|
||||
|
||||
10
vendor/github.com/containerd/containerd/runtime/v2/manager.go
generated
vendored
10
vendor/github.com/containerd/containerd/runtime/v2/manager.go
generated
vendored
@@ -130,6 +130,16 @@ func (m *TaskManager) Get(ctx context.Context, id string) (runtime.Task, error)
|
||||
return m.tasks.Get(ctx, id)
|
||||
}
|
||||
|
||||
// Add a runtime task
|
||||
func (m *TaskManager) Add(ctx context.Context, task runtime.Task) error {
|
||||
return m.tasks.Add(ctx, task)
|
||||
}
|
||||
|
||||
// Delete a runtime task
|
||||
func (m *TaskManager) Delete(ctx context.Context, id string) {
|
||||
m.tasks.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// Tasks lists all tasks
|
||||
func (m *TaskManager) Tasks(ctx context.Context, all bool) ([]runtime.Task, error) {
|
||||
return m.tasks.GetAll(ctx, all)
|
||||
|
||||
4
vendor/github.com/containerd/containerd/runtime/v2/shim/shim_unix.go
generated
vendored
4
vendor/github.com/containerd/containerd/runtime/v2/shim/shim_unix.go
generated
vendored
@@ -72,9 +72,9 @@ func serveListener(path string) (net.Listener, error) {
|
||||
|
||||
func handleSignals(logger *logrus.Entry, signals chan os.Signal) error {
|
||||
logger.Info("starting signal loop")
|
||||
|
||||
for {
|
||||
select {
|
||||
case s := <-signals:
|
||||
for s := range signals {
|
||||
switch s {
|
||||
case unix.SIGCHLD:
|
||||
if err := Reap(); err != nil {
|
||||
|
||||
5
vendor/github.com/containerd/containerd/runtime/v2/shim/shim_windows.go
generated
vendored
5
vendor/github.com/containerd/containerd/runtime/v2/shim/shim_windows.go
generated
vendored
@@ -113,12 +113,11 @@ func serveListener(path string) (net.Listener, error) {
|
||||
|
||||
func handleSignals(logger *logrus.Entry, signals chan os.Signal) error {
|
||||
logger.Info("starting signal loop")
|
||||
|
||||
for {
|
||||
select {
|
||||
case s := <-signals:
|
||||
for s := range signals {
|
||||
switch s {
|
||||
case os.Interrupt:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
4
vendor/github.com/containerd/containerd/runtime/v2/shim/util_windows.go
generated
vendored
4
vendor/github.com/containerd/containerd/runtime/v2/shim/util_windows.go
generated
vendored
@@ -54,7 +54,7 @@ func AnonDialer(address string, timeout time.Duration) (net.Conn, error) {
|
||||
timedOutError := errors.Errorf("timed out waiting for npipe %s", address)
|
||||
start := time.Now()
|
||||
for {
|
||||
remaining := timeout - time.Now().Sub(start)
|
||||
remaining := timeout - time.Since(start)
|
||||
if remaining <= 0 {
|
||||
lastError = timedOutError
|
||||
break
|
||||
@@ -71,7 +71,7 @@ func AnonDialer(address string, timeout time.Duration) (net.Conn, error) {
|
||||
// serve it within 5 seconds. We use the passed in timeout for the
|
||||
// `DialPipe` timeout if the pipe exists however to give the pipe time
|
||||
// to `Accept` the connection.
|
||||
if time.Now().Sub(start) >= 5*time.Second {
|
||||
if time.Since(start) >= 5*time.Second {
|
||||
lastError = timedOutError
|
||||
break
|
||||
}
|
||||
|
||||
2
vendor/github.com/containerd/containerd/runtime/v2/shim_unix.go
generated
vendored
2
vendor/github.com/containerd/containerd/runtime/v2/shim_unix.go
generated
vendored
@@ -28,5 +28,5 @@ import (
|
||||
)
|
||||
|
||||
func openShimLog(ctx context.Context, bundle *Bundle) (io.ReadCloser, error) {
|
||||
return fifo.OpenFifo(ctx, filepath.Join(bundle.Path, "log"), unix.O_RDONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700)
|
||||
return fifo.OpenFifo(ctx, filepath.Join(bundle.Path, "log"), unix.O_RDWR|unix.O_CREAT, 0700)
|
||||
}
|
||||
|
||||
4
vendor/github.com/containerd/containerd/services/containers/local.go
generated
vendored
4
vendor/github.com/containerd/containerd/services/containers/local.go
generated
vendored
@@ -147,9 +147,7 @@ func (l *local) Update(ctx context.Context, req *api.UpdateContainerRequest, _ .
|
||||
if err := l.withStoreUpdate(ctx, func(ctx context.Context, store containers.Store) error {
|
||||
var fieldpaths []string
|
||||
if req.UpdateMask != nil && len(req.UpdateMask.Paths) > 0 {
|
||||
for _, path := range req.UpdateMask.Paths {
|
||||
fieldpaths = append(fieldpaths, path)
|
||||
}
|
||||
fieldpaths = append(fieldpaths, req.UpdateMask.Paths...)
|
||||
}
|
||||
|
||||
updated, err := store.Update(ctx, container, fieldpaths...)
|
||||
|
||||
4
vendor/github.com/containerd/containerd/services/images/local.go
generated
vendored
4
vendor/github.com/containerd/containerd/services/images/local.go
generated
vendored
@@ -137,9 +137,7 @@ func (l *local) Update(ctx context.Context, req *imagesapi.UpdateImageRequest, _
|
||||
)
|
||||
|
||||
if req.UpdateMask != nil && len(req.UpdateMask.Paths) > 0 {
|
||||
for _, path := range req.UpdateMask.Paths {
|
||||
fieldpaths = append(fieldpaths, path)
|
||||
}
|
||||
fieldpaths = append(fieldpaths, req.UpdateMask.Paths...)
|
||||
}
|
||||
|
||||
updated, err := l.store.Update(ctx, image, fieldpaths...)
|
||||
|
||||
6
vendor/github.com/containerd/containerd/task.go
generated
vendored
6
vendor/github.com/containerd/containerd/task.go
generated
vendored
@@ -185,8 +185,10 @@ func (t *task) Start(ctx context.Context) error {
|
||||
ContainerID: t.id,
|
||||
})
|
||||
if err != nil {
|
||||
t.io.Cancel()
|
||||
t.io.Close()
|
||||
if t.io != nil {
|
||||
t.io.Cancel()
|
||||
t.io.Close()
|
||||
}
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
t.pid = r.Pid
|
||||
|
||||
4
vendor/github.com/containerd/containerd/vendor.conf
generated
vendored
4
vendor/github.com/containerd/containerd/vendor.conf
generated
vendored
@@ -20,7 +20,7 @@ github.com/gogo/protobuf v1.0.0
|
||||
github.com/gogo/googleapis 08a7655d27152912db7aaf4f983275eaf8d128ef
|
||||
github.com/golang/protobuf v1.1.0
|
||||
github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353 # v1.0.1-45-geba862d
|
||||
github.com/opencontainers/runc 96ec2177ae841256168fcf76954f7177af9446eb
|
||||
github.com/opencontainers/runc 12f6a991201fdb8f82579582d5e00e28fba06d0a
|
||||
github.com/sirupsen/logrus v1.0.0
|
||||
github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
|
||||
golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac
|
||||
@@ -43,7 +43,7 @@ github.com/google/go-cmp v0.1.0
|
||||
go.etcd.io/bbolt v1.3.1-etcd.8
|
||||
|
||||
# cri dependencies
|
||||
github.com/containerd/cri 0d5cabd006cb5319dc965046067b8432d9fa5ef8 # release/1.2 branch
|
||||
github.com/containerd/cri c3cf754321fc38c6af5dfd2552fdde0ad192b31d # release/1.2 branch
|
||||
github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90
|
||||
github.com/blang/semver v3.1.0
|
||||
github.com/containernetworking/cni v0.6.0
|
||||
|
||||
2
vendor/github.com/containerd/containerd/version/version.go
generated
vendored
2
vendor/github.com/containerd/containerd/version/version.go
generated
vendored
@@ -21,7 +21,7 @@ var (
|
||||
Package = "github.com/containerd/containerd"
|
||||
|
||||
// Version holds the complete version number. Filled in at linking time.
|
||||
Version = "1.2.2+unknown"
|
||||
Version = "1.2.3+unknown"
|
||||
|
||||
// Revision is filled with the VCS (e.g. git) revision being used to build
|
||||
// the program at linking time.
|
||||
|
||||
7
vendor/github.com/containerd/cri/pkg/server/container_remove.go
generated
vendored
7
vendor/github.com/containerd/cri/pkg/server/container_remove.go
generated
vendored
@@ -98,9 +98,12 @@ func (c *criService) RemoveContainer(ctx context.Context, r *runtime.RemoveConta
|
||||
// container will not be started or removed again.
|
||||
func setContainerRemoving(container containerstore.Container) error {
|
||||
return container.Status.Update(func(status containerstore.Status) (containerstore.Status, error) {
|
||||
// Do not remove container if it's still running.
|
||||
// Do not remove container if it's still running or unknown.
|
||||
if status.State() == runtime.ContainerState_CONTAINER_RUNNING {
|
||||
return status, errors.New("container is still running")
|
||||
return status, errors.New("container is still running, to stop first")
|
||||
}
|
||||
if status.State() == runtime.ContainerState_CONTAINER_UNKNOWN {
|
||||
return status, errors.New("container state is unknown, to stop first")
|
||||
}
|
||||
if status.Removing {
|
||||
return status, errors.New("container is already in removing state")
|
||||
|
||||
9
vendor/github.com/containerd/cri/pkg/server/container_status.go
generated
vendored
9
vendor/github.com/containerd/cri/pkg/server/container_status.go
generated
vendored
@@ -60,6 +60,15 @@ func (c *criService) ContainerStatus(ctx context.Context, r *runtime.ContainerSt
|
||||
}
|
||||
}
|
||||
status := toCRIContainerStatus(container, spec, imageRef)
|
||||
if status.GetCreatedAt() == 0 {
|
||||
// CRI doesn't allow CreatedAt == 0.
|
||||
info, err := container.Container.Info(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get CreatedAt in %q state", status.State)
|
||||
}
|
||||
status.CreatedAt = info.CreatedAt.UnixNano()
|
||||
}
|
||||
|
||||
info, err := toCRIContainerInfo(ctx, container, r.GetVerbose())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get verbose container info")
|
||||
|
||||
59
vendor/github.com/containerd/cri/pkg/server/container_stop.go
generated
vendored
59
vendor/github.com/containerd/cri/pkg/server/container_stop.go
generated
vendored
@@ -19,6 +19,8 @@ package server
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
eventtypes "github.com/containerd/containerd/api/events"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/pkg/errors"
|
||||
@@ -60,8 +62,9 @@ func (c *criService) stopContainer(ctx context.Context, container containerstore
|
||||
// Return without error if container is not running. This makes sure that
|
||||
// stop only takes real action after the container is started.
|
||||
state := container.Status.Get().State()
|
||||
if state != runtime.ContainerState_CONTAINER_RUNNING {
|
||||
logrus.Infof("Container to stop %q is not running, current state %q",
|
||||
if state != runtime.ContainerState_CONTAINER_RUNNING &&
|
||||
state != runtime.ContainerState_CONTAINER_UNKNOWN {
|
||||
logrus.Infof("Container to stop %q must be in running or unknown state, current state %q",
|
||||
id, criContainerStateToString(state))
|
||||
return nil
|
||||
}
|
||||
@@ -69,9 +72,39 @@ func (c *criService) stopContainer(ctx context.Context, container containerstore
|
||||
task, err := container.Container.Task(ctx, nil)
|
||||
if err != nil {
|
||||
if !errdefs.IsNotFound(err) {
|
||||
return errors.Wrapf(err, "failed to stop container, task not found for container %q", id)
|
||||
return errors.Wrapf(err, "failed to get task for container %q", id)
|
||||
}
|
||||
// Don't return for unknown state, some cleanup needs to be done.
|
||||
if state != runtime.ContainerState_CONTAINER_UNKNOWN {
|
||||
return nil
|
||||
}
|
||||
// Task is an interface, explicitly set it to nil just in case.
|
||||
task = nil
|
||||
}
|
||||
|
||||
// Handle unknown state.
|
||||
if state == runtime.ContainerState_CONTAINER_UNKNOWN {
|
||||
status, err := getTaskStatus(ctx, task)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to get task status for %q", id)
|
||||
}
|
||||
switch status.Status {
|
||||
case containerd.Running, containerd.Created:
|
||||
// The task is still running, continue stopping the task.
|
||||
case containerd.Stopped:
|
||||
// The task has exited. If the task exited after containerd
|
||||
// started, the event monitor will receive its exit event; if it
|
||||
// exited before containerd started, the event monitor will never
|
||||
// receive its exit event.
|
||||
// However, we can't tell that because the task state was not
|
||||
// successfully loaded during containerd start (container is
|
||||
// in UNKNOWN state).
|
||||
// So always do cleanup here, just in case that we've missed the
|
||||
// exit event.
|
||||
return cleanupUnknownContainer(ctx, id, status, container)
|
||||
default:
|
||||
return errors.Wrapf(err, "unsupported task status %q", status.Status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// We only need to kill the task. The event handler will Delete the
|
||||
@@ -141,3 +174,21 @@ func (c *criService) waitContainerStop(ctx context.Context, container containers
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// cleanupUnknownContainer cleanup stopped container in unknown state.
|
||||
func cleanupUnknownContainer(ctx context.Context, id string, status containerd.Status,
|
||||
cntr containerstore.Container) error {
|
||||
// Reuse handleContainerExit to do the cleanup.
|
||||
// NOTE(random-liu): If the task did exit after containerd started, both
|
||||
// the event monitor and the cleanup function would update the container
|
||||
// state. The final container state will be whatever being updated first.
|
||||
// There is no way to completely avoid this race condition, and for best
|
||||
// effort unknown state container cleanup, this seems acceptable.
|
||||
return handleContainerExit(ctx, &eventtypes.TaskExit{
|
||||
ContainerID: id,
|
||||
ID: id,
|
||||
Pid: 0,
|
||||
ExitStatus: status.ExitStatus,
|
||||
ExitedAt: status.ExitTime,
|
||||
}, cntr)
|
||||
}
|
||||
|
||||
40
vendor/github.com/containerd/cri/pkg/server/events.go
generated
vendored
40
vendor/github.com/containerd/cri/pkg/server/events.go
generated
vendored
@@ -112,17 +112,17 @@ func convertEvent(e *gogotypes.Any) (string, interface{}, error) {
|
||||
return "", nil, errors.Wrap(err, "failed to unmarshalany")
|
||||
}
|
||||
|
||||
switch evt.(type) {
|
||||
switch e := evt.(type) {
|
||||
case *eventtypes.TaskExit:
|
||||
id = evt.(*eventtypes.TaskExit).ContainerID
|
||||
id = e.ContainerID
|
||||
case *eventtypes.TaskOOM:
|
||||
id = evt.(*eventtypes.TaskOOM).ContainerID
|
||||
id = e.ContainerID
|
||||
case *eventtypes.ImageCreate:
|
||||
id = evt.(*eventtypes.ImageCreate).Name
|
||||
id = e.Name
|
||||
case *eventtypes.ImageUpdate:
|
||||
id = evt.(*eventtypes.ImageUpdate).Name
|
||||
id = e.Name
|
||||
case *eventtypes.ImageDelete:
|
||||
id = evt.(*eventtypes.ImageDelete).Name
|
||||
id = e.Name
|
||||
default:
|
||||
return "", nil, errors.New("unsupported event")
|
||||
}
|
||||
@@ -200,13 +200,12 @@ func (em *eventMonitor) handleEvent(any interface{}) error {
|
||||
ctx, cancel := context.WithTimeout(ctx, handleEventTimeout)
|
||||
defer cancel()
|
||||
|
||||
switch any.(type) {
|
||||
switch e := any.(type) {
|
||||
// If containerd-shim exits unexpectedly, there will be no corresponding event.
|
||||
// However, containerd could not retrieve container state in that case, so it's
|
||||
// fine to leave out that case for now.
|
||||
// TODO(random-liu): [P2] Handle containerd-shim exit.
|
||||
case *eventtypes.TaskExit:
|
||||
e := any.(*eventtypes.TaskExit)
|
||||
logrus.Infof("TaskExit event %+v", e)
|
||||
// Use ID instead of ContainerID to rule out TaskExit event for exec.
|
||||
cntr, err := em.c.containerStore.Get(e.ID)
|
||||
@@ -218,7 +217,7 @@ func (em *eventMonitor) handleEvent(any interface{}) error {
|
||||
} else if err != store.ErrNotExist {
|
||||
return errors.Wrap(err, "can't find container for TaskExit event")
|
||||
}
|
||||
// Use GetAll to include sandbox in unknown state.
|
||||
// Use GetAll to include sandbox in init state.
|
||||
sb, err := em.c.sandboxStore.GetAll(e.ID)
|
||||
if err == nil {
|
||||
if err := handleSandboxExit(ctx, e, sb); err != nil {
|
||||
@@ -230,7 +229,6 @@ func (em *eventMonitor) handleEvent(any interface{}) error {
|
||||
}
|
||||
return nil
|
||||
case *eventtypes.TaskOOM:
|
||||
e := any.(*eventtypes.TaskOOM)
|
||||
logrus.Infof("TaskOOM event %+v", e)
|
||||
// For TaskOOM, we only care which container it belongs to.
|
||||
cntr, err := em.c.containerStore.Get(e.ContainerID)
|
||||
@@ -248,15 +246,12 @@ func (em *eventMonitor) handleEvent(any interface{}) error {
|
||||
return errors.Wrap(err, "failed to update container status for TaskOOM event")
|
||||
}
|
||||
case *eventtypes.ImageCreate:
|
||||
e := any.(*eventtypes.ImageCreate)
|
||||
logrus.Infof("ImageCreate event %+v", e)
|
||||
return em.c.updateImage(ctx, e.Name)
|
||||
case *eventtypes.ImageUpdate:
|
||||
e := any.(*eventtypes.ImageUpdate)
|
||||
logrus.Infof("ImageUpdate event %+v", e)
|
||||
return em.c.updateImage(ctx, e.Name)
|
||||
case *eventtypes.ImageDelete:
|
||||
e := any.(*eventtypes.ImageDelete)
|
||||
logrus.Infof("ImageDelete event %+v", e)
|
||||
return em.c.updateImage(ctx, e.Name)
|
||||
}
|
||||
@@ -269,7 +264,16 @@ func handleContainerExit(ctx context.Context, e *eventtypes.TaskExit, cntr conta
|
||||
// Attach container IO so that `Delete` could cleanup the stream properly.
|
||||
task, err := cntr.Container.Task(ctx,
|
||||
func(*containerdio.FIFOSet) (containerdio.IO, error) {
|
||||
return cntr.IO, nil
|
||||
// We can't directly return cntr.IO here, because
|
||||
// even if cntr.IO is nil, the cio.IO interface
|
||||
// is not.
|
||||
// See https://tour.golang.org/methods/12:
|
||||
// Note that an interface value that holds a nil
|
||||
// concrete value is itself non-nil.
|
||||
if cntr.IO != nil {
|
||||
return cntr.IO, nil
|
||||
}
|
||||
return nil, nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
@@ -322,13 +326,13 @@ func handleSandboxExit(ctx context.Context, e *eventtypes.TaskExit, sb sandboxst
|
||||
}
|
||||
}
|
||||
err = sb.Status.Update(func(status sandboxstore.Status) (sandboxstore.Status, error) {
|
||||
// NOTE(random-liu): We SHOULD NOT change UNKNOWN state here.
|
||||
// If sandbox state is UNKNOWN when event monitor receives an TaskExit event,
|
||||
// NOTE(random-liu): We SHOULD NOT change INIT state here.
|
||||
// If sandbox state is INIT when event monitor receives an TaskExit event,
|
||||
// it means that sandbox start has failed. In that case, `RunPodSandbox` will
|
||||
// cleanup everything immediately.
|
||||
// Once sandbox state goes out of UNKNOWN, it becomes visable to the user, which
|
||||
// Once sandbox state goes out of INIT, it becomes visable to the user, which
|
||||
// is not what we want.
|
||||
if status.State != sandboxstore.StateUnknown {
|
||||
if status.State != sandboxstore.StateInit {
|
||||
status.State = sandboxstore.StateNotReady
|
||||
}
|
||||
status.Pid = 0
|
||||
|
||||
55
vendor/github.com/containerd/cri/pkg/server/helpers.go
generated
vendored
55
vendor/github.com/containerd/cri/pkg/server/helpers.go
generated
vendored
@@ -24,9 +24,12 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/runtime/linux/runctypes"
|
||||
runcoptions "github.com/containerd/containerd/runtime/v2/runc/options"
|
||||
"github.com/containerd/typeurl"
|
||||
@@ -42,7 +45,9 @@ import (
|
||||
|
||||
criconfig "github.com/containerd/cri/pkg/config"
|
||||
"github.com/containerd/cri/pkg/store"
|
||||
containerstore "github.com/containerd/cri/pkg/store/container"
|
||||
imagestore "github.com/containerd/cri/pkg/store/image"
|
||||
sandboxstore "github.com/containerd/cri/pkg/store/sandbox"
|
||||
"github.com/containerd/cri/pkg/util"
|
||||
)
|
||||
|
||||
@@ -496,3 +501,53 @@ func getRuntimeOptions(c containers.Container) (interface{}, error) {
|
||||
}
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
const (
|
||||
// unknownExitCode is the exit code when exit reason is unknown.
|
||||
unknownExitCode = 255
|
||||
// unknownExitReason is the exit reason when exit reason is unknown.
|
||||
unknownExitReason = "Unknown"
|
||||
)
|
||||
|
||||
// unknownContainerStatus returns the default container status when its status is unknown.
|
||||
func unknownContainerStatus() containerstore.Status {
|
||||
return containerstore.Status{
|
||||
CreatedAt: 0,
|
||||
StartedAt: 0,
|
||||
FinishedAt: 0,
|
||||
ExitCode: unknownExitCode,
|
||||
Reason: unknownExitReason,
|
||||
}
|
||||
}
|
||||
|
||||
// unknownSandboxStatus returns the default sandbox status when its status is unknown.
|
||||
func unknownSandboxStatus() sandboxstore.Status {
|
||||
return sandboxstore.Status{
|
||||
State: sandboxstore.StateUnknown,
|
||||
}
|
||||
}
|
||||
|
||||
// unknownExitStatus generates containerd.Status for container exited with unknown exit code.
|
||||
func unknownExitStatus() containerd.Status {
|
||||
return containerd.Status{
|
||||
Status: containerd.Stopped,
|
||||
ExitStatus: unknownExitCode,
|
||||
ExitTime: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// getTaskStatus returns status for a given task. It returns unknown exit status if
|
||||
// the task is nil or not found.
|
||||
func getTaskStatus(ctx context.Context, task containerd.Task) (containerd.Status, error) {
|
||||
if task == nil {
|
||||
return unknownExitStatus(), nil
|
||||
}
|
||||
status, err := task.Status(ctx)
|
||||
if err != nil {
|
||||
if !errdefs.IsNotFound(err) {
|
||||
return containerd.Status{}, err
|
||||
}
|
||||
return unknownExitStatus(), nil
|
||||
}
|
||||
return status, nil
|
||||
}
|
||||
|
||||
78
vendor/github.com/containerd/cri/pkg/server/io/logger.go
generated
vendored
78
vendor/github.com/containerd/cri/pkg/server/io/logger.go
generated
vendored
@@ -19,6 +19,7 @@ package io
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
@@ -61,6 +62,56 @@ func NewCRILogger(path string, w io.Writer, stream StreamType, maxLen int) (io.W
|
||||
return pwc, stop
|
||||
}
|
||||
|
||||
// bufio.ReadLine in golang eats both read errors and tailing newlines
|
||||
// (See https://golang.org/pkg/bufio/#Reader.ReadLine). When reading
|
||||
// to io.EOF, it is impossible for the caller to figure out whether
|
||||
// there is a newline at the end, for example:
|
||||
// 1) When reading "CONTENT\n", it returns "CONTENT" without error;
|
||||
// 2) When reading "CONTENT", it also returns "CONTENT" without error.
|
||||
//
|
||||
// To differentiate these 2 cases, we need to write a readLine function
|
||||
// ourselves to not ignore the error.
|
||||
//
|
||||
// The code is similar with https://golang.org/src/bufio/bufio.go?s=9537:9604#L359.
|
||||
// The only difference is that it returns all errors from `ReadSlice`.
|
||||
//
|
||||
// readLine returns err != nil if and only if line does not end with a new line.
|
||||
func readLine(b *bufio.Reader) (line []byte, isPrefix bool, err error) {
|
||||
line, err = b.ReadSlice('\n')
|
||||
if err == bufio.ErrBufferFull {
|
||||
// Handle the case where "\r\n" straddles the buffer.
|
||||
if len(line) > 0 && line[len(line)-1] == '\r' {
|
||||
// Unread the last '\r'
|
||||
if err := b.UnreadByte(); err != nil {
|
||||
panic(fmt.Sprintf("invalid unread %v", err))
|
||||
}
|
||||
line = line[:len(line)-1]
|
||||
}
|
||||
return line, true, nil
|
||||
}
|
||||
|
||||
if len(line) == 0 {
|
||||
if err != nil {
|
||||
line = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if line[len(line)-1] == '\n' {
|
||||
// "ReadSlice returns err != nil if and only if line does not end in delim"
|
||||
// (See https://golang.org/pkg/bufio/#Reader.ReadSlice).
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("full read with unexpected error %v", err))
|
||||
}
|
||||
drop := 1
|
||||
if len(line) > 1 && line[len(line)-2] == '\r' {
|
||||
drop = 2
|
||||
}
|
||||
line = line[:len(line)-drop]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func redirectLogs(path string, rc io.ReadCloser, w io.Writer, s StreamType, maxLen int) {
|
||||
defer rc.Close()
|
||||
var (
|
||||
@@ -88,7 +139,16 @@ func redirectLogs(path string, rc io.ReadCloser, w io.Writer, s StreamType, maxL
|
||||
}
|
||||
for {
|
||||
var stop bool
|
||||
newLine, isPrefix, err := r.ReadLine()
|
||||
newLine, isPrefix, err := readLine(r)
|
||||
// NOTE(random-liu): readLine can return actual content even if there is an error.
|
||||
if len(newLine) > 0 {
|
||||
// Buffer returned by ReadLine will change after
|
||||
// next read, copy it.
|
||||
l := make([]byte, len(newLine))
|
||||
copy(l, newLine)
|
||||
buf = append(buf, l)
|
||||
length += len(l)
|
||||
}
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
logrus.Debugf("Getting EOF from stream %q while redirecting to log file %q", s, path)
|
||||
@@ -101,13 +161,6 @@ func redirectLogs(path string, rc io.ReadCloser, w io.Writer, s StreamType, maxL
|
||||
}
|
||||
// Stop after writing the content left in buffer.
|
||||
stop = true
|
||||
} else {
|
||||
// Buffer returned by ReadLine will change after
|
||||
// next read, copy it.
|
||||
l := make([]byte, len(newLine))
|
||||
copy(l, newLine)
|
||||
buf = append(buf, l)
|
||||
length += len(l)
|
||||
}
|
||||
if maxLen > 0 && length > maxLen {
|
||||
exceedLen := length - maxLen
|
||||
@@ -125,7 +178,14 @@ func redirectLogs(path string, rc io.ReadCloser, w io.Writer, s StreamType, maxL
|
||||
if isPrefix {
|
||||
continue
|
||||
}
|
||||
writeLine(full, bytes.Join(buf, nil))
|
||||
if stop {
|
||||
// readLine only returns error when the message doesn't
|
||||
// end with a newline, in that case it should be treated
|
||||
// as a partial line.
|
||||
writeLine(partial, bytes.Join(buf, nil))
|
||||
} else {
|
||||
writeLine(full, bytes.Join(buf, nil))
|
||||
}
|
||||
buf = nil
|
||||
length = 0
|
||||
if stop {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user