Merge pull request #314 from ibuildthecloud/k8s-14

k8s 1.14
This commit is contained in:
Darren Shepherd 2019-04-08 22:59:02 -07:00 committed by GitHub
commit 184f69732f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2230 changed files with 134354 additions and 146372 deletions

View file

@ -20,6 +20,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"k8s.io/apimachinery/pkg/util/net"
"k8s.io/kubernetes/pkg/volume"
_ "github.com/mattn/go-sqlite3" // ensure we have sqlite
)
@ -70,6 +71,9 @@ func run(app *cli.Context, cfg *cmds.Server) error {
return fmt.Errorf("must run as root unless --disable-agent is specified")
}
// If running agent in server, set this so that CSI initializes properly
volume.WaitForValidHost = !cfg.DisableAgent
serverConfig := server.Config{}
serverConfig.ControlConfig.ClusterSecret = cfg.ClusterSecret
serverConfig.ControlConfig.DataDir = cfg.DataDir

View file

@ -12,7 +12,7 @@ import (
"github.com/rancher/k3s/pkg/daemons/config"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/util/net"
"k8s.io/apiserver/pkg/util/logs"
"k8s.io/component-base/logs"
app2 "k8s.io/kubernetes/cmd/kube-proxy/app"
"k8s.io/kubernetes/cmd/kubelet/app"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
@ -82,6 +82,7 @@ func kubelet(cfg *config.Agent) {
if cfg.RuntimeSocket != "" {
args = append(args, "--container-runtime", "remote")
args = append(args, "--container-runtime-endpoint", cfg.RuntimeSocket)
args = append(args, "--serialize-image-pulls=false")
}
if cfg.ListenAddress != "" {
args = append(args, "--address", cfg.ListenAddress)

View file

@ -24,9 +24,9 @@ import (
"time"
"github.com/rancher/k3s/pkg/daemons/config"
certutil "github.com/rancher/norman/pkg/cert"
"github.com/sirupsen/logrus"
"k8s.io/apiserver/pkg/authentication/authenticator"
certutil "k8s.io/client-go/util/cert"
"k8s.io/kubernetes/cmd/kube-apiserver/app"
cmapp "k8s.io/kubernetes/cmd/kube-controller-manager/app"
sapp "k8s.io/kubernetes/cmd/kube-scheduler/app"

View file

@ -9,8 +9,8 @@ import (
"github.com/rancher/k3s/pkg/server"
"github.com/spf13/pflag"
utilflag "k8s.io/apiserver/pkg/util/flag"
"k8s.io/apiserver/pkg/util/logs"
utilflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/logs"
"k8s.io/kubernetes/pkg/kubectl/cmd"
)

File diff suppressed because one or more lines are too long

View file

@ -1,47 +1,28 @@
package: package=github.com/rancher/k3s
import:
- package: bitbucket.org/ww/goautoneg
version: a547fc61f48d567d5b4ec6f8aee5573d8efce11d
repo: https://github.com/rancher/goautoneg.git
- package: github.com/Azure/go-ansiterm
version: d6e3b3328b783f23731bc4d058875b0371ff8109
- package: github.com/BurntSushi/toml
version: a368813c5e648fee92e5f6c30e3944ff9d5e8895
- package: github.com/JeffAshton/win_pdh
version: 76bb4ee9f0ab50f77826f2a2ee7fb9d3880d6ec2
- package: github.com/MakeNowJust/heredoc
version: bb23615498cded5e105af4ce27de75b089cbe851
- package: github.com/Microsoft/go-winio
version: v0.4.11
- package: github.com/Microsoft/hcsshim
version: v0.8.3
- package: github.com/Nvveen/Gotty
version: cd527374f1e5bff4938207604a14f2e38a9cf512
- package: github.com/alexflint/go-filemutex
version: 72bdc8eae2aef913234599b837f5dda445ca9bd9
- package: github.com/armon/circbuf
version: bbbad097214e2918d8543d5201d12bfd7bca254d
- package: github.com/beorn7/perks
version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
- package: github.com/blang/semver
version: v3.1.0
- package: github.com/chai2010/gettext-go
version: c6fed771bfd517099caf0f7a961671fa8ed08723
- package: github.com/cloudflare/cfssl
version: 1.3.2-21-g56268a613adfed
- package: github.com/container-storage-interface/spec
version: v1.0.0
- package: github.com/containerd/cgroups
version: 5e610833b72089b37d0e615de9a92dfc043757c2
version: 4994991857f9b0ae8dc439551e8bebdbb4bf66c1
- package: github.com/containerd/console
version: c12b1e7919c14469339a5d38f2f8ed9b64a9de23
- package: github.com/containerd/containerd
version: v1.2.4-k3s1
version: v1.2.6-k3s1
repo: https://github.com/ibuildthecloud/containerd
- package: github.com/containerd/continuity
version: bd77b46c8352f74eb12c85bdc01f4b90f69d66b4
- package: github.com/containerd/cri
version: c3cf754321fc38c6af5dfd2552fdde0ad192b31d
version: eb926cd79d3bac188dcc4ed7694fc9298f8831be
- package: github.com/containerd/fifo
version: 3d5202aec260678c48179c56f40e6f38a095738c
- package: github.com/containerd/go-cni
@ -57,53 +38,25 @@ import:
- package: github.com/containernetworking/plugins
version: 9810b7d5137b171c4e07ce59bb18be9feccec557
repo: https://github.com/ibuildthecloud/plugins.git
- package: github.com/coreos/etcd
version: v3.3.10
- package: github.com/coreos/flannel
version: 823afe66b2266bf71f5bec24e6e28b26d70cfc7c
repo: https://github.com/ibuildthecloud/flannel.git
- package: github.com/coreos/go-iptables
version: 47f22b0dd3355c0ba570ba12b0b8a36bf214c04b
- package: github.com/coreos/go-semver
version: v0.2.0-9-ge214231b295a8e
- package: github.com/coreos/go-systemd
version: 48702e0da86bd25e76cfef347e2adeb434a0d0a6
- package: github.com/coreos/pkg
version: v4
- package: github.com/cyphar/filepath-securejoin
version: v0.2.1-1-gae69057f2299fb
- package: github.com/davecgh/go-spew
version: v1.1.0
- package: github.com/daviddengcn/go-colortext
version: 511bcaf42ccd42c38aba7427b6673277bf19e2a1
- package: github.com/docker/distribution
version: 0d3efadf0154c2b8a4e7b6621fff9809655cc580
- package: github.com/docker/docker
version: docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8dd8794
- package: github.com/docker/go-connections
version: v0.3.0
- package: github.com/docker/go-events
version: 9461782956ad83b30282bf90e31fa6a70c255ba9
- package: github.com/docker/go-metrics
version: 4ea375f7759c82740c893fc030bc37088d2ec098
- package: github.com/docker/go-units
version: v0.3.1-11-g9e638d38cf6977
- package: github.com/docker/libnetwork
version: v0.8.0-dev.2-1265-ga9cd636e378982
- package: github.com/docker/spdystream
version: 449fdfce4d962303d702fec724ef0ad181c92528
- package: github.com/emicklei/go-restful
version: v2.2.1
- package: github.com/euank/go-kmsg-parser
version: v2.0.0
- package: github.com/evanphx/json-patch
version: v4.1.0-19-g5858425f75500d
- package: github.com/exponent-io/jsonpath
version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5
- package: github.com/fatih/camelcase
version: f6a740d52f961c60348ebb109adde9f4635d7540
- package: github.com/fsnotify/fsnotify
version: v1.3.1-1-gf12c6236fe7b5c
- package: github.com/ghodss/yaml
version: v1.0.0
- package: github.com/godbus/dbus
@ -112,76 +65,35 @@ import:
version: 08a7655d27152912db7aaf4f983275eaf8d128ef
- package: github.com/gogo/protobuf
version: v1.0.0
- package: github.com/golang/groupcache
version: 02826c3e79038b59d737d3b1c0a1d937f71a4433
- package: github.com/golang/protobuf
version: v1.1.0
- package: github.com/google/btree
version: 7d79101e329e5a3adf994758c578dab82b90c017
- package: github.com/google/cadvisor
version: 87e237ff35b9d752ba58860a06e0ebe57816cbb7
repo: https://github.com/ibuildthecloud/cadvisor.git
- package: github.com/google/certificate-transparency-go
version: v1.0.21
- package: github.com/google/gofuzz
version: 44d81051d367757e1c7c6a5a86423ece9afcf63c
- package: github.com/googleapis/gnostic
version: 0c5108395e2debce0d731cf0287ddf7242066aba
- package: github.com/gorilla/mux
version: v1.6.2
- package: github.com/gorilla/websocket
version: v1.2.0
- package: github.com/gregjones/httpcache
version: 787624de3eb7bd915c329cba748687a3b22666a6
- package: github.com/grpc-ecosystem/go-grpc-prometheus
version: 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
- package: github.com/hashicorp/errwrap
version: 7554cd9344cec97297fa6649b055a8c98c2a1e55
- package: github.com/hashicorp/go-multierror
version: ed905158d87462226a13fe39ddf685ea65f1c11f
- package: github.com/hashicorp/golang-lru
version: a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
- package: github.com/ibuildthecloud/kvsql
version: c649f12fe5250718e4e024b8b40e7de796ab095e
- package: github.com/imdario/mergo
version: v0.3.5
- package: github.com/inconshreveable/mousetrap
version: v1.0
- package: github.com/j-keck/arping
version: 2cf9dc699c5640a7e2c81403a44127bf28033600
- package: github.com/jonboulle/clockwork
version: 72f9bd7c4e0c2a40055ab3d0f09654f730cce982
- package: github.com/json-iterator/go
version: 1.1.5
- package: github.com/jteeuwen/go-bindata
version: v3.0.7-72-ga0ff2567cfb709
- package: github.com/karrick/godirwalk
version: v1.7.5
- package: github.com/kubernetes-sigs/cri-tools
version: c465773e3ad8c941d1756c0a467d550b04a8f65b
repo: https://github.com/ibuildthecloud/cri-tools.git
- package: github.com/mattn/go-shellwords
version: v1.0.3-20-gf8471b0a71ded0
- package: github.com/mattn/go-sqlite3
version: v1.9.0
- package: github.com/matttproud/golang_protobuf_extensions
version: v1.0.0
- package: github.com/miekg/dns
version: 5d001d020961ae1c184f9f8152fdc73810481677
- package: github.com/mindprince/gonvml
version: fee913ce8fb235edf54739d259ca0ecc226c7b8a
- package: github.com/mistifyio/go-zfs
version: v2.1.1-5-g1b4ae6fb4e77b0
- package: github.com/mitchellh/go-wordwrap
version: ad45545899c7b13c020ea92b2072220eefad42b8
- package: github.com/modern-go/concurrent
version: 1.0.3
- package: github.com/modern-go/reflect2
version: 1.0.1
- package: github.com/mrunalp/fileutils
version: 4ee1cc9a80582a0c75febdd5cfa779ee4361cbca
- package: github.com/mxk/go-flowrate
version: cca7078d478f8520f85629ad7c68962d31ed7682
- package: github.com/natefinch/lumberjack
version: aee4629129445bbdfb69aa565537dcfa16544311
- package: github.com/opencontainers/go-digest
@ -189,60 +101,28 @@ import:
- package: github.com/opencontainers/image-spec
version: v1.0.1
- package: github.com/opencontainers/runc
version: 6635b4f0c6af3810594d2770f662f34ddc15b40d
version: 69ae5da6afdcaaf38285a10b36f362e41cb298d6
- package: github.com/opencontainers/runtime-spec
version: 5684b8af48c1ac3b1451fa499724e30e3c20a294
- package: github.com/opencontainers/runtime-tools
version: v0.6.0
- package: github.com/opencontainers/selinux
version: b6fa367ed7f534f9ba25391cc2d467085dbb445a
- package: github.com/pborman/uuid
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
- package: github.com/peterbourgon/diskv
version: v2.0.1
version: v1.2.1
- package: github.com/pkg/errors
version: v0.8.0
- package: github.com/prometheus/client_golang
version: v0.8.0-83-ge7e903064f5e9e
- package: github.com/prometheus/client_model
version: model-0.0.2-12-gfa8ad6fec33561
- package: github.com/prometheus/common
version: 13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207
- package: github.com/prometheus/procfs
version: 65c1f6f8f0fc1e2185eb9863a3bc751496404259
- package: github.com/rancher/norman
version: f75e3607e96e1a5d3cbaf4ee7cea1459cc727f61
version: 50017efee23caa79542ef685b65a7b783e0a73ca
repo: https://github.com/ibuildthecloud/norman.git
- package: github.com/renstrom/dedent
version: v1.0.0-3-g020d11c3b9c0c7
- package: github.com/robfig/cron
version: v1-53-gdf38d32658d878
- package: github.com/russross/blackfriday
version: v1.4-2-g300106c228d52c
- package: github.com/seccomp/libseccomp-golang
version: 32f571b70023028bd57d9288c20efbcb237f3ce0
- package: github.com/shurcooL/sanitized_anchor_name
version: 10ef21a441db47d8b13ebcc5fd2310f636973c77
- package: github.com/sigma/go-inotify
version: c87b6cf5033d2c6486046f045eeebdc3d910fd38
- package: github.com/sirupsen/logrus
version: v1.0.3
- package: github.com/spf13/cobra
version: v0.0.1-34-gc439c4fa093711
- package: github.com/spf13/pflag
version: v1.0.1
- package: github.com/syndtr/gocapability
version: db04d3cc01c8b54962a58ec7e491717d06cfcc16
- package: github.com/tchap/go-patricia
version: v2.2.6
- package: github.com/ugorji/go
version: bdcc60b419d136a85cdf2e7cbcac34b3f1cd6e57
- package: github.com/urfave/cli
version: 8e01ec4cd3e2d84ab2fe90d8210528ffbb06d8ff
- package: github.com/vishvananda/netlink
version: b2de5d10e38ecce8607e6b438b6d174f389a004e
- package: github.com/vishvananda/netns
version: be1fbeda19366dea804f00efff2dd73a1642fdcc
- package: github.com/xeipuuv/gojsonpointer
version: 4e3ac2762d5f479393488629ee9370b50873b3a6
- package: github.com/xeipuuv/gojsonreference
@ -266,34 +146,157 @@ import:
version: 19e51611da83d6be54ddafce4a4af510cb3e9ea4
- package: golang.org/x/time
version: f51c12702a4d776e4c1fa9b0fabab841babae631
- package: golang.org/x/tools
version: 2382e3994d48b1d22acc2c86bcad0a2aff028e32
- package: google.golang.org/genproto
version: d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
- package: google.golang.org/grpc
version: v1.12.0
- package: gopkg.in/inf.v0
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
- package: gopkg.in/natefinch/lumberjack.v2
version: v1.0-16-g20b71e5b60d756
- package: gopkg.in/square/go-jose.v2
version: v2.1.6-4-g89060dee6a84df
- package: gopkg.in/yaml.v2
version: v2.2.1
- package: k8s.io/kubernetes
version: v1.14.1-k3s.1
repo: https://github.com/rancher/k3s.git
transitive: true
staging: true
- package: vbom.ml/util
version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394
- package: github.com/mxk/go-flowrate
version: cca7078d478f8520f85629ad7c68962d31ed7682
- package: github.com/ugorji/go
version: bdcc60b419d136a85cdf2e7cbcac34b3f1cd6e57
- package: github.com/sigma/go-inotify
version: c87b6cf5033d2c6486046f045eeebdc3d910fd38
- package: github.com/spf13/cobra
version: v0.0.1-34-gc439c4fa093711
- package: github.com/liggitt/tabwriter
version: 89fcab3d43de07060e4fd4c1547430ed57e87f24
- package: github.com/mindprince/gonvml
version: fee913ce8fb235edf54739d259ca0ecc226c7b8a
- package: github.com/mistifyio/go-zfs
version: v2.1.1-5-g1b4ae6fb4e77b0
- package: github.com/peterbourgon/diskv
version: v2.0.1
- package: github.com/russross/blackfriday
version: v1.4-2-g300106c228d52c
- package: github.com/inconshreveable/mousetrap
version: v1.0
- package: github.com/imdario/mergo
version: v0.3.5
- package: github.com/vishvananda/netns
version: be1fbeda19366dea804f00efff2dd73a1642fdcc
- package: github.com/prometheus/client_golang
version: v0.9.2
- package: github.com/mattn/go-shellwords
version: v1.0.3-20-gf8471b0a71ded0
- package: github.com/prometheus/procfs
version: 65c1f6f8f0fc1e2185eb9863a3bc751496404259
- package: github.com/vishvananda/netlink
version: b2de5d10e38ecce8607e6b438b6d174f389a004e
- package: github.com/chai2010/gettext-go
version: c6fed771bfd517099caf0f7a961671fa8ed08723
- package: github.com/container-storage-interface/spec
version: v1.1.0
- package: github.com/hashicorp/golang-lru
version: v0.5.0
- package: github.com/spf13/pflag
version: v1.0.1
- package: github.com/shurcooL/sanitized_anchor_name
version: 10ef21a441db47d8b13ebcc5fd2310f636973c77
- package: github.com/MakeNowJust/heredoc
version: bb23615498cded5e105af4ce27de75b089cbe851
- package: github.com/prometheus/common
version: v0.2.0
- package: github.com/coreos/go-semver
version: v0.2.0-9-ge214231b295a8e
- package: github.com/google/cadvisor
version: v0.33.1-k3s.1
repo: https://github.com/ibuildthecloud/cadvisor.git
- package: github.com/cyphar/filepath-securejoin
version: v0.2.1-1-gae69057f2299fb
- package: github.com/ibuildthecloud/kvsql
version: 0e798b1475327aadf3b8da5d2d1f99bb93dfd667
- package: github.com/JeffAshton/win_pdh
version: 76bb4ee9f0ab50f77826f2a2ee7fb9d3880d6ec2
- package: github.com/prometheus/client_model
version: model-0.0.2-12-gfa8ad6fec33561
- package: github.com/miekg/dns
version: 5d001d020961ae1c184f9f8152fdc73810481677
- package: github.com/daviddengcn/go-colortext
version: 511bcaf42ccd42c38aba7427b6673277bf19e2a1
- package: github.com/gregjones/httpcache
version: 787624de3eb7bd915c329cba748687a3b22666a6
- package: github.com/karrick/godirwalk
version: v1.7.5
- package: k8s.io/gengo
version: 51747d6e00da1fc578d5a333a93bb2abcbce7a95
- package: k8s.io/heapster
version: v1.2.0-beta.1
- package: github.com/checkpoint-restore/go-criu
version: v3.11
- package: github.com/google/btree
version: 7d79101e329e5a3adf994758c578dab82b90c017
- package: github.com/google/certificate-transparency-go
version: v1.0.21
- package: github.com/robfig/cron
version: v1-53-gdf38d32658d878
- package: github.com/mrunalp/fileutils
version: 4ee1cc9a80582a0c75febdd5cfa779ee4361cbca
- package: github.com/Nvveen/Gotty
version: cd527374f1e5bff4938207604a14f2e38a9cf512
- package: github.com/exponent-io/jsonpath
version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5
- package: github.com/fsnotify/fsnotify
version: v1.3.1-1-gf12c6236fe7b5c
- package: github.com/jteeuwen/go-bindata
version: v3.0.7-72-ga0ff2567cfb709
- package: gopkg.in/square/go-jose.v2
version: v2.1.6-4-g89060dee6a84df
- package: k8s.io/klog
version: 8139d8cb77af419532b33dfa7dd09fbc5f1d344f
- package: k8s.io/kubernetes
version: v1.13.5-k3s.1
repo: https://github.com/rancher/k3s.git
transitive: true
staging: true
version: v0.2.0-14-g8e90cee79f8237
- package: github.com/munnerz/goautoneg
version: a547fc61f48d567d5b4ec6f8aee5573d8efce11d
- package: github.com/docker/go-units
version: v0.3.1-11-g9e638d38cf6977
- package: github.com/fatih/camelcase
version: f6a740d52f961c60348ebb109adde9f4635d7540
- package: k8s.io/utils
version: 66066c83e385e385ccc3c964b44fd7dcd413d0ed
version: c2654d5206da6b7b6ace12841e8f359bb89b443c
- package: github.com/coreos/etcd
version: v3.3.10
- package: github.com/docker/go-connections
version: v0.3.0
- package: github.com/golang/groupcache
version: 02826c3e79038b59d737d3b1c0a1d937f71a4433
- package: gopkg.in/natefinch/lumberjack.v2
version: v1.0-16-g20b71e5b60d756
- package: github.com/mitchellh/go-wordwrap
version: ad45545899c7b13c020ea92b2072220eefad42b8
- package: github.com/docker/libnetwork
version: v0.8.0-dev.2-1265-ga9cd636e378982
- package: sigs.k8s.io/yaml
version: v1.1.0
- package: vbom.ml/util
version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394
- package: github.com/euank/go-kmsg-parser
version: v2.0.0
- package: github.com/evanphx/json-patch
version: v4.1.0-19-g5858425f75500d
- package: github.com/lithammer/dedent
version: v1.1.0
- package: github.com/jonboulle/clockwork
version: 72f9bd7c4e0c2a40055ab3d0f09654f730cce982
- package: github.com/cloudflare/cfssl
version: 1.3.2-21-g56268a613adfed
- package: github.com/docker/docker
version: docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8dd8794
- package: github.com/coreos/pkg
version: v4
- package: github.com/Azure/go-ansiterm
version: d6e3b3328b783f23731bc4d058875b0371ff8109
- package: github.com/armon/circbuf
version: bbbad097214e2918d8543d5201d12bfd7bca254d
- package: golang.org/x/tools
version: 7f7074d5bcfd282eb16bc382b0bb3da762461985
- package: github.com/pborman/uuid
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
- package: github.com/googleapis/gnostic
version: 0c5108395e2debce0d731cf0287ddf7242066aba

View file

@ -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.5-k3s.1 https://github.com/rancher/k3s.git transitive=true,staging=true
k8s.io/kubernetes v1.14.1-k3s.1 https://github.com/rancher/k3s.git transitive=true,staging=true
github.com/rancher/norman efb72b594a2a34f2573b9565c6cd9926a1f6ae08 https://github.com/ibuildthecloud/norman.git
github.com/rancher/norman 50017efee23caa79542ef685b65a7b783e0a73ca 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,10 +36,10 @@ github.com/alexflint/go-filemutex 72bdc8eae2aef913234599b837f5dda445ca9bd9
github.com/opencontainers/runtime-spec 5684b8af48c1ac3b1451fa499724e30e3c20a294
# containerd
github.com/containerd/containerd v1.2.4-k3s1 https://github.com/ibuildthecloud/containerd
github.com/containerd/containerd v1.2.6-k3s1 https://github.com/ibuildthecloud/containerd
github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3
github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2
github.com/containerd/cgroups 4994991857f9b0ae8dc439551e8bebdbb4bf66c1
github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
github.com/containerd/btrfs 2e1aa0ddf94f91fa282b6ed87c23bf0d64911244
@ -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 6635b4f0c6af3810594d2770f662f34ddc15b40d
github.com/opencontainers/runc 69ae5da6afdcaaf38285a10b36f362e41cb298d6
github.com/sirupsen/logrus v1.0.3
github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac
@ -85,11 +85,11 @@ go.etcd.io/bbolt v1.3.1-etcd.8
github.com/kubernetes-sigs/cri-tools c465773e3ad8c941d1756c0a467d550b04a8f65b https://github.com/ibuildthecloud/cri-tools.git
# cri dependencies
github.com/containerd/cri c3cf754321fc38c6af5dfd2552fdde0ad192b31d # release/1.2 branch
github.com/containerd/cri eb926cd79d3bac188dcc4ed7694fc9298f8831be # release/1.2 branch
github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90
github.com/blang/semver v3.1.0
github.com/containernetworking/cni v0.6.0
#github.com/containernetworking/plugins v0.7.0
#github.com/containernetworking/plugins v0.7.5
github.com/davecgh/go-spew v1.1.0
github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580
#github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00
@ -104,7 +104,7 @@ github.com/json-iterator/go 1.1.5
github.com/modern-go/reflect2 1.0.1
github.com/modern-go/concurrent 1.0.3
github.com/opencontainers/runtime-tools v0.6.0
github.com/opencontainers/selinux b6fa367ed7f534f9ba25391cc2d467085dbb445a
github.com/opencontainers/selinux v1.2.1
github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
github.com/tchap/go-patricia v2.2.6
github.com/xeipuuv/gojsonpointer 4e3ac2762d5f479393488629ee9370b50873b3a6

View file

@ -0,0 +1,5 @@
test/test
test/piggie
test/phaul
image
rpc/rpc.proto

View file

@ -0,0 +1,25 @@
language: go
sudo: required
os:
- linux
go:
- "1.8"
- "1.9"
- "1.10"
env:
# Run the tests with CRIU master and criu-dev
- CRIU_BRANCH="master"
- CRIU_BRANCH="criu-dev"
install:
- sudo apt-get update
- sudo apt-get install -y libprotobuf-dev libprotobuf-c0-dev protobuf-c-compiler protobuf-compiler python-protobuf libnl-3-dev libnet-dev libcap-dev
- go get github.com/checkpoint-restore/go-criu
- git clone --single-branch -b ${CRIU_BRANCH} https://github.com/checkpoint-restore/criu.git
- cd criu; make
- sudo install -D -m 755 criu/criu /usr/sbin/
- cd ..
script:
# This builds the code without running the tests.
- make build phaul test/test test/phaul test/piggie
# Run actual test as root as it uses CRIU.
- sudo make test phaul-test

60
vendor/github.com/checkpoint-restore/go-criu/Makefile generated vendored Normal file
View file

@ -0,0 +1,60 @@
GO ?= go
CC ?= gcc
ifeq ($(GOPATH),)
export GOPATH := $(shell $(GO) env GOPATH)
endif
FIRST_GOPATH := $(firstword $(subst :, ,$(GOPATH)))
GOBIN := $(shell $(GO) env GOBIN)
ifeq ($(GOBIN),)
GOBIN := $(FIRST_GOPATH)/bin
endif
all: build test phaul phaul-test
lint:
@golint . test phaul
build:
@$(GO) build -v
test/piggie: test/piggie.c
@$(CC) $^ -o $@
test/test: test/main.go
@$(GO) build -v -o test/test test/main.go
test: test/test test/piggie
mkdir -p image
test/piggie
test/test dump `pidof piggie` image
test/test restore image
pkill -9 piggie || :
phaul:
@cd phaul; go build -v
test/phaul: test/phaul-main.go
@$(GO) build -v -o test/phaul test/phaul-main.go
phaul-test: test/phaul test/piggie
rm -rf image
test/piggie
test/phaul `pidof piggie`
pkill -9 piggie || :
clean:
@rm -f test/test test/piggie test/phaul
@rm -rf image
@rm -f rpc/rpc.proto
install.tools:
if [ ! -x "$(GOBIN)/golint" ]; then \
$(GO) get -u golang.org/x/lint/golint; \
fi
rpc/rpc.proto:
curl -s https://raw.githubusercontent.com/checkpoint-restore/criu/master/images/rpc.proto -o $@
rpc/rpc.pb.go: rpc/rpc.proto
protoc --go_out=. $^
.PHONY: build test clean lint phaul

58
vendor/github.com/checkpoint-restore/go-criu/README.md generated vendored Normal file
View file

@ -0,0 +1,58 @@
[![master](https://travis-ci.org/checkpoint-restore/go-criu.svg?branch=master)](https://travis-ci.org/checkpoint-restore/go-criu)
## go-criu -- Go bindings for [CRIU](https://criu.org/)
This repository provides Go bindings for CRIU. The code is based on the Go based PHaul
implementation from the CRIU repository. For easier inclusion into other Go projects the
CRIU Go bindings have been moved to this repository.
The Go bindings provide an easy way to use the CRIU RPC calls from Go without the need
to set up all the infrastructure to make the actual RPC connection to CRIU.
The following example would print the version of CRIU:
```
c := criu.MakeCriu()
version, err := c.GetCriuVersion()
fmt.Println(version)
```
or to just check if at least a certain CRIU version is installed:
```
c := criu.MakeCriu()
result, err := c.IsCriuAtLeast(31100)
```
## How to contribute
While bug fixes can first be identified via an "issue", that is not required.
It's ok to just open up a PR with the fix, but make sure you include the same
information you would have included in an issue - like how to reproduce it.
PRs for new features should include some background on what use cases the
new code is trying to address. When possible and when it makes sense, try to
break-up larger PRs into smaller ones - it's easier to review smaller
code changes. But only if those smaller ones make sense as stand-alone PRs.
Regardless of the type of PR, all PRs should include:
* well documented code changes
* additional testcases. Ideally, they should fail w/o your code change applied
* documentation changes
Squash your commits into logical pieces of work that might want to be reviewed
separate from the rest of the PRs. Ideally, each commit should implement a
single idea, and the PR branch should pass the tests at every commit. GitHub
makes it easy to review the cumulative effect of many commits; so, when in
doubt, use smaller commits.
PRs that fix issues should include a reference like `Closes #XXXX` in the
commit message so that github will automatically close the referenced issue
when the PR is merged.
Contributors must assert that they are in compliance with the [Developer
Certificate of Origin 1.1](http://developercertificate.org/). This is achieved
by adding a "Signed-off-by" line containing the contributor's name and e-mail
to every commit message. Your signature certifies that you wrote the patch or
otherwise have the right to pass it on as an open-source patch.
### License
The license of go-criu is the Apache 2.0 license.

View file

@ -1,11 +1,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: criurpc.proto
// source: rpc/rpc.proto
/*
Package criurpc is a generated protocol buffer package.
Package rpc is a generated protocol buffer package.
It is generated from these files:
criurpc.proto
rpc/rpc.proto
It has these top-level messages:
CriuPageServerInfo
@ -24,7 +24,7 @@ It has these top-level messages:
CriuResp
CriuVersion
*/
package criurpc
package rpc
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
@ -93,17 +93,19 @@ func (CriuCgMode) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []i
type CriuReqType int32
const (
CriuReqType_EMPTY CriuReqType = 0
CriuReqType_DUMP CriuReqType = 1
CriuReqType_RESTORE CriuReqType = 2
CriuReqType_CHECK CriuReqType = 3
CriuReqType_PRE_DUMP CriuReqType = 4
CriuReqType_PAGE_SERVER CriuReqType = 5
CriuReqType_NOTIFY CriuReqType = 6
CriuReqType_CPUINFO_DUMP CriuReqType = 7
CriuReqType_CPUINFO_CHECK CriuReqType = 8
CriuReqType_FEATURE_CHECK CriuReqType = 9
CriuReqType_VERSION CriuReqType = 10
CriuReqType_EMPTY CriuReqType = 0
CriuReqType_DUMP CriuReqType = 1
CriuReqType_RESTORE CriuReqType = 2
CriuReqType_CHECK CriuReqType = 3
CriuReqType_PRE_DUMP CriuReqType = 4
CriuReqType_PAGE_SERVER CriuReqType = 5
CriuReqType_NOTIFY CriuReqType = 6
CriuReqType_CPUINFO_DUMP CriuReqType = 7
CriuReqType_CPUINFO_CHECK CriuReqType = 8
CriuReqType_FEATURE_CHECK CriuReqType = 9
CriuReqType_VERSION CriuReqType = 10
CriuReqType_WAIT_PID CriuReqType = 11
CriuReqType_PAGE_SERVER_CHLD CriuReqType = 12
)
var CriuReqType_name = map[int32]string{
@ -118,19 +120,23 @@ var CriuReqType_name = map[int32]string{
8: "CPUINFO_CHECK",
9: "FEATURE_CHECK",
10: "VERSION",
11: "WAIT_PID",
12: "PAGE_SERVER_CHLD",
}
var CriuReqType_value = map[string]int32{
"EMPTY": 0,
"DUMP": 1,
"RESTORE": 2,
"CHECK": 3,
"PRE_DUMP": 4,
"PAGE_SERVER": 5,
"NOTIFY": 6,
"CPUINFO_DUMP": 7,
"CPUINFO_CHECK": 8,
"FEATURE_CHECK": 9,
"VERSION": 10,
"EMPTY": 0,
"DUMP": 1,
"RESTORE": 2,
"CHECK": 3,
"PRE_DUMP": 4,
"PAGE_SERVER": 5,
"NOTIFY": 6,
"CPUINFO_DUMP": 7,
"CPUINFO_CHECK": 8,
"FEATURE_CHECK": 9,
"VERSION": 10,
"WAIT_PID": 11,
"PAGE_SERVER_CHLD": 12,
}
func (x CriuReqType) Enum() *CriuReqType {
@ -855,8 +861,10 @@ type CriuReq struct {
// 'features' can be used to query which features
// are supported by the installed criu/kernel
// via RPC.
Features *CriuFeatures `protobuf:"bytes,5,opt,name=features" json:"features,omitempty"`
XXX_unrecognized []byte `json:"-"`
Features *CriuFeatures `protobuf:"bytes,5,opt,name=features" json:"features,omitempty"`
// 'pid' is used for WAIT_PID
Pid *uint32 `protobuf:"varint,6,opt,name=pid" json:"pid,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *CriuReq) Reset() { *m = CriuReq{} }
@ -899,6 +907,13 @@ func (m *CriuReq) GetFeatures() *CriuFeatures {
return nil
}
func (m *CriuReq) GetPid() uint32 {
if m != nil && m.Pid != nil {
return *m.Pid
}
return 0
}
type CriuResp struct {
Type *CriuReqType `protobuf:"varint,1,req,name=type,enum=CriuReqType" json:"type,omitempty"`
Success *bool `protobuf:"varint,2,req,name=success" json:"success,omitempty"`
@ -910,6 +925,7 @@ type CriuResp struct {
Features *CriuFeatures `protobuf:"bytes,8,opt,name=features" json:"features,omitempty"`
CrErrmsg *string `protobuf:"bytes,9,opt,name=cr_errmsg,json=crErrmsg" json:"cr_errmsg,omitempty"`
Version *CriuVersion `protobuf:"bytes,10,opt,name=version" json:"version,omitempty"`
Status *int32 `protobuf:"varint,11,opt,name=status" json:"status,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
@ -988,6 +1004,13 @@ func (m *CriuResp) GetVersion() *CriuVersion {
return nil
}
func (m *CriuResp) GetStatus() int32 {
if m != nil && m.Status != nil {
return *m.Status
}
return 0
}
// Answer for criu_req_type.VERSION requests
type CriuVersion struct {
Major *int32 `protobuf:"varint,1,req,name=major" json:"major,omitempty"`
@ -1066,121 +1089,123 @@ func init() {
proto.RegisterEnum("CriuReqType", CriuReqType_name, CriuReqType_value)
}
func init() { proto.RegisterFile("criurpc.proto", fileDescriptor0) }
func init() { proto.RegisterFile("rpc/rpc.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 1795 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x56, 0xdd, 0x72, 0x5b, 0xb7,
0x11, 0x0e, 0x29, 0xf1, 0x0f, 0xfc, 0x31, 0x0d, 0xff, 0x04, 0x4e, 0x6a, 0x9b, 0xa1, 0xe3, 0x44,
0x55, 0x5c, 0x36, 0x61, 0xec, 0xb8, 0xce, 0xb4, 0x17, 0x1e, 0x89, 0x74, 0xd9, 0x48, 0x22, 0x07,
0x94, 0x3c, 0x93, 0x2b, 0xcc, 0xd1, 0x39, 0x20, 0x05, 0xf3, 0x1c, 0x9c, 0x53, 0x00, 0x54, 0x24,
0x3f, 0x48, 0x9f, 0xa2, 0xcf, 0xd0, 0x57, 0xea, 0x65, 0x6f, 0x3b, 0xbb, 0x00, 0x65, 0x29, 0xc9,
0xb4, 0xb9, 0xc3, 0x7e, 0xbb, 0x00, 0xf6, 0x7f, 0x97, 0xb4, 0x63, 0xa3, 0xd6, 0xa6, 0x88, 0x07,
0x85, 0xc9, 0x5d, 0xde, 0x5f, 0x92, 0x7b, 0x00, 0x88, 0x22, 0x5a, 0x4a, 0x61, 0xa5, 0x39, 0x97,
0x46, 0x28, 0xbd, 0xc8, 0x29, 0x23, 0xb5, 0x28, 0x49, 0x8c, 0xb4, 0x96, 0x95, 0x7a, 0xa5, 0x9d,
0x06, 0xdf, 0x90, 0x94, 0x92, 0xed, 0x22, 0x37, 0x8e, 0x95, 0x7b, 0xa5, 0x9d, 0x0a, 0xc7, 0x33,
0xed, 0x92, 0xad, 0x42, 0x25, 0x6c, 0x0b, 0x21, 0x38, 0xd2, 0x0e, 0x29, 0x2f, 0x12, 0xb6, 0x8d,
0x40, 0x79, 0x91, 0xf4, 0xff, 0x4c, 0x3a, 0xf8, 0xd1, 0xb9, 0x74, 0x67, 0xa2, 0x88, 0x94, 0xa1,
0x77, 0x48, 0x45, 0x2d, 0x84, 0xd2, 0xac, 0xd4, 0x2b, 0xef, 0x34, 0xf8, 0xb6, 0x5a, 0x4c, 0x34,
0xbd, 0x47, 0xaa, 0x6a, 0x21, 0xf2, 0x35, 0x3c, 0x0f, 0x68, 0x45, 0x2d, 0xa6, 0x6b, 0xd7, 0xff,
0x96, 0xb4, 0xe5, 0x85, 0x13, 0x59, 0xbe, 0xd6, 0x4e, 0x64, 0x51, 0x01, 0x1f, 0xae, 0xe4, 0x65,
0xb8, 0x0a, 0x47, 0x40, 0xce, 0xa3, 0x34, 0x5c, 0x83, 0x63, 0xff, 0x2d, 0xe9, 0xbc, 0xcb, 0x95,
0x16, 0x3a, 0xca, 0xa4, 0x2d, 0xa2, 0x58, 0x82, 0x52, 0xda, 0x86, 0x4b, 0x65, 0x6d, 0xe9, 0xc7,
0xa4, 0xa6, 0xad, 0x58, 0xa8, 0x54, 0x86, 0x7b, 0x55, 0x6d, 0xc7, 0x2a, 0x95, 0xf4, 0x53, 0xd2,
0x90, 0x17, 0xce, 0x44, 0x22, 0x2f, 0x1c, 0x5a, 0xd5, 0xe0, 0x75, 0x04, 0xa6, 0x85, 0xeb, 0x0f,
0x08, 0x51, 0xfa, 0x4c, 0x1a, 0xe5, 0xc4, 0x22, 0xf9, 0x15, 0x4d, 0xbc, 0xe9, 0xf0, 0xa0, 0x37,
0xfd, 0x05, 0x69, 0xc6, 0x4b, 0x93, 0xaf, 0x0b, 0x61, 0xf2, 0xdc, 0x81, 0xff, 0x62, 0x67, 0xd2,
0xe0, 0x56, 0x3c, 0xa3, 0x4f, 0x23, 0x77, 0x16, 0xb4, 0xc0, 0x73, 0xff, 0x31, 0xa9, 0xad, 0xb5,
0xba, 0x10, 0x76, 0x45, 0xef, 0x92, 0x8a, 0xd2, 0x79, 0x22, 0xf1, 0x97, 0x36, 0xf7, 0x44, 0xff,
0xdf, 0x6d, 0xd2, 0x40, 0x9f, 0xe6, 0x85, 0xb3, 0xb4, 0x4f, 0xda, 0x2a, 0x8b, 0x96, 0xd2, 0x8a,
0x44, 0x19, 0xb1, 0x48, 0x50, 0xb6, 0xc2, 0x9b, 0x1e, 0xdc, 0x57, 0x66, 0x9c, 0x6c, 0xc2, 0x54,
0xfe, 0x10, 0xa6, 0x27, 0xa4, 0x9d, 0xca, 0xe8, 0x5c, 0x0a, 0xb3, 0xd6, 0x5a, 0xe9, 0x25, 0x1a,
0x5b, 0xe7, 0x2d, 0x04, 0xb9, 0xc7, 0xe8, 0x23, 0xd2, 0x04, 0xef, 0x07, 0x6d, 0x30, 0xa8, 0x75,
0x0e, 0x0e, 0x3a, 0xd1, 0xea, 0x62, 0xbe, 0xa2, 0x5f, 0x92, 0x5b, 0x2e, 0x2e, 0x84, 0xb4, 0x2e,
0x3a, 0x4d, 0x95, 0x3d, 0x93, 0x09, 0xab, 0xa0, 0x4c, 0xc7, 0xc5, 0xc5, 0xe8, 0x03, 0x0a, 0x82,
0xf2, 0x3c, 0xb2, 0xea, 0x5c, 0x8a, 0x44, 0x9e, 0xab, 0x58, 0x5a, 0x56, 0xf5, 0x82, 0x01, 0xde,
0xf7, 0x28, 0xf8, 0xdf, 0x9e, 0xc9, 0x34, 0x15, 0xef, 0xf2, 0x53, 0x56, 0x43, 0x91, 0x3a, 0x02,
0x7f, 0xcb, 0x4f, 0xe9, 0x43, 0x42, 0x20, 0x64, 0x22, 0xcd, 0xe3, 0x95, 0x65, 0x75, 0xaf, 0x0d,
0x20, 0x07, 0x00, 0xd0, 0x47, 0xa4, 0x91, 0xe6, 0x4b, 0x91, 0xca, 0x73, 0x99, 0xb2, 0x06, 0x98,
0xfa, 0x7d, 0x69, 0xc8, 0xeb, 0x69, 0xbe, 0x3c, 0x00, 0x88, 0x3e, 0x20, 0x70, 0xf6, 0x51, 0x27,
0x3e, 0xb5, 0xd3, 0x7c, 0x89, 0x61, 0xff, 0x82, 0x94, 0x0b, 0xcb, 0x9a, 0xbd, 0xd2, 0x4e, 0x73,
0x78, 0x7f, 0xf0, 0xab, 0x85, 0xc1, 0xcb, 0x85, 0xa5, 0x4f, 0x49, 0x47, 0xe7, 0x4e, 0x2d, 0x2e,
0x85, 0x8d, 0x8d, 0x2a, 0x9c, 0x65, 0x2d, 0xd4, 0xa2, 0xed, 0xd1, 0xb9, 0x07, 0x21, 0xaa, 0x10,
0x71, 0xd6, 0xf6, 0x91, 0xc6, 0xe8, 0x3f, 0x24, 0xa4, 0x88, 0x8c, 0xd4, 0x4e, 0xa8, 0x6c, 0xc9,
0x3a, 0xc8, 0x69, 0x78, 0x64, 0x92, 0x2d, 0xc1, 0x70, 0x67, 0xa2, 0x78, 0x25, 0x32, 0x99, 0xb1,
0x5b, 0xde, 0x70, 0x04, 0x0e, 0x65, 0x06, 0x77, 0xa3, 0xb5, 0xcb, 0x45, 0x22, 0x93, 0x75, 0xc1,
0xba, 0xde, 0x70, 0x40, 0xf6, 0x01, 0x80, 0x30, 0xfd, 0x94, 0x9b, 0xd5, 0x26, 0xfe, 0xb7, 0x31,
0xca, 0x0d, 0x80, 0x7c, 0xf4, 0x1f, 0x12, 0x92, 0x2a, 0xbd, 0x12, 0x46, 0x66, 0x51, 0xc1, 0xa8,
0xbf, 0x0e, 0x08, 0x07, 0x80, 0x3e, 0x25, 0x15, 0x28, 0x4e, 0xcb, 0xee, 0xf4, 0xb6, 0x76, 0x9a,
0xc3, 0x5b, 0x83, 0x9b, 0xf5, 0xca, 0x3d, 0x97, 0x3e, 0x21, 0xb5, 0xb8, 0x58, 0x8b, 0x38, 0x2a,
0xd8, 0xdd, 0x5e, 0x69, 0xa7, 0xfd, 0x3d, 0x79, 0x3e, 0x7c, 0xf5, 0xfc, 0xd5, 0x77, 0x2f, 0x87,
0xaf, 0x5e, 0xf0, 0x6a, 0x5c, 0xac, 0xf7, 0xa2, 0x82, 0x3e, 0x26, 0xcd, 0x45, 0x6e, 0x62, 0x29,
0x94, 0x81, 0xbf, 0xee, 0xe1, 0x5f, 0x04, 0xa1, 0x09, 0x20, 0x10, 0x04, 0x79, 0x21, 0x63, 0x11,
0x67, 0x09, 0xbb, 0xdf, 0xdb, 0x82, 0x20, 0x00, 0xbd, 0x97, 0x41, 0x92, 0xd4, 0xb0, 0xd6, 0xb5,
0x63, 0x1f, 0xa3, 0x26, 0x9d, 0xc1, 0x8d, 0xda, 0xe7, 0x55, 0x79, 0xe1, 0x0e, 0xb5, 0x83, 0x28,
0x64, 0x91, 0x86, 0xf8, 0xf8, 0xf2, 0xb2, 0x8c, 0xf9, 0x28, 0x78, 0x74, 0xcf, 0x83, 0xf4, 0x29,
0xa9, 0xc5, 0x4b, 0x2c, 0x3d, 0xf6, 0x00, 0xdf, 0x6b, 0x0d, 0xae, 0x95, 0x23, 0xaf, 0xc6, 0x4b,
0x0e, 0x81, 0x79, 0x4c, 0x9a, 0xc6, 0x3a, 0x61, 0xd5, 0x69, 0x0a, 0x75, 0xf0, 0x89, 0x57, 0xd9,
0x58, 0x37, 0xf7, 0x08, 0xdd, 0xbd, 0x5e, 0xf6, 0xec, 0x53, 0x7c, 0xaa, 0x39, 0xf8, 0x00, 0xf1,
0x46, 0x38, 0x8f, 0x13, 0xda, 0x23, 0x2d, 0x8c, 0xd4, 0xc6, 0x90, 0xdf, 0xf9, 0xd7, 0x00, 0x1b,
0x79, 0xe5, 0x1f, 0xfb, 0x9a, 0xb2, 0x67, 0x91, 0x81, 0xef, 0x1e, 0x7a, 0x01, 0x79, 0xe1, 0xe6,
0x1e, 0xd9, 0x08, 0x64, 0x91, 0x75, 0xd2, 0x58, 0xf6, 0xe8, 0x4a, 0xe0, 0xd0, 0x23, 0xe0, 0x42,
0xbb, 0x52, 0x05, 0xbe, 0xff, 0xd8, 0xbb, 0x10, 0x68, 0x78, 0x1c, 0xda, 0x97, 0x8e, 0x4e, 0x53,
0x29, 0x16, 0x96, 0xf5, 0x90, 0x57, 0xf7, 0xc0, 0xd8, 0xd2, 0x1d, 0xd2, 0x0c, 0x95, 0x2c, 0x94,
0xce, 0xd9, 0x67, 0x68, 0x48, 0x7d, 0x10, 0x30, 0xde, 0x58, 0x63, 0x51, 0x4f, 0x74, 0x4e, 0xff,
0x42, 0xee, 0xdc, 0x74, 0xb0, 0xc8, 0xa0, 0x09, 0xf5, 0x7b, 0xa5, 0x9d, 0xce, 0xb0, 0xed, 0xf3,
0x23, 0x5e, 0x22, 0xc8, 0x6f, 0xdf, 0x70, 0xfa, 0x61, 0x9e, 0x48, 0xf8, 0x68, 0x79, 0x96, 0x5b,
0x27, 0x52, 0x95, 0x29, 0xc7, 0x9e, 0x60, 0xb6, 0xd4, 0xbe, 0xf9, 0xfa, 0xf9, 0x9f, 0x5e, 0xbc,
0xfc, 0x8e, 0x13, 0xe4, 0x1d, 0x00, 0x8b, 0xee, 0x90, 0x2e, 0x26, 0x8a, 0xb0, 0x71, 0xa4, 0x05,
0x74, 0x3f, 0xcb, 0x3e, 0x47, 0xb5, 0x3b, 0x88, 0xcf, 0xe3, 0x48, 0xcf, 0x00, 0xa5, 0x9f, 0x40,
0xde, 0x38, 0x69, 0x74, 0x94, 0xb2, 0xa7, 0xc1, 0xb0, 0x40, 0x63, 0x4e, 0x65, 0x85, 0xbb, 0x14,
0xda, 0xb2, 0x2f, 0xe0, 0x33, 0x5e, 0x43, 0xfa, 0x08, 0x6c, 0xae, 0xf9, 0x51, 0x60, 0xd9, 0x97,
0x21, 0xbb, 0x6f, 0x8e, 0x06, 0x5e, 0x05, 0xfa, 0xc8, 0xd2, 0xcf, 0x48, 0x2b, 0x64, 0x47, 0x61,
0xf2, 0xc2, 0xb2, 0xdf, 0x63, 0x85, 0x86, 0x06, 0x3e, 0x03, 0x88, 0xee, 0x92, 0xdb, 0xd7, 0x45,
0x7c, 0x27, 0xd9, 0x45, 0xb9, 0x5b, 0xd7, 0xe4, 0xb0, 0xa3, 0x3c, 0x27, 0xf7, 0x83, 0x6c, 0xb2,
0xce, 0x0a, 0x11, 0xe7, 0xda, 0x99, 0x3c, 0x4d, 0xa5, 0x61, 0x5f, 0xa1, 0xf6, 0x77, 0x3d, 0x77,
0x7f, 0x9d, 0x15, 0x7b, 0x57, 0x3c, 0xe8, 0xca, 0x0b, 0x23, 0xe5, 0xfb, 0x8d, 0xe3, 0xd9, 0x33,
0x7c, 0xbd, 0xe5, 0x41, 0xef, 0x63, 0x98, 0xd0, 0x4e, 0x65, 0x12, 0x66, 0xe5, 0x1f, 0xbc, 0xb5,
0x81, 0xa4, 0x5f, 0x11, 0x0a, 0xfd, 0x18, 0xb3, 0x43, 0x69, 0xb1, 0x48, 0xd5, 0xf2, 0xcc, 0xb1,
0x01, 0x66, 0x10, 0x74, 0xea, 0xf9, 0x4a, 0x15, 0x13, 0x3d, 0x46, 0x18, 0x0c, 0xfe, 0x49, 0x46,
0x2b, 0x61, 0x2f, 0x6d, 0xec, 0x52, 0xcb, 0xfe, 0x88, 0x62, 0x4d, 0xc0, 0xe6, 0x1e, 0xc2, 0xc6,
0x11, 0xbd, 0xbf, 0xc4, 0x5e, 0x68, 0xd9, 0xd7, 0xa1, 0x71, 0x44, 0xef, 0x2f, 0x67, 0x00, 0x60,
0xb3, 0x76, 0x91, 0x5b, 0x5b, 0xa8, 0x8b, 0x6f, 0xb0, 0xeb, 0xd4, 0x3d, 0x30, 0x4e, 0xc0, 0x59,
0xb9, 0x29, 0xce, 0x20, 0xac, 0xce, 0x86, 0x6c, 0x66, 0x43, 0xaf, 0x8a, 0x67, 0xcc, 0x9c, 0xf5,
0x29, 0x0d, 0x29, 0x1f, 0xe7, 0x7a, 0xa1, 0x42, 0x73, 0xfe, 0x16, 0x8d, 0x26, 0x1e, 0x02, 0x6f,
0xf6, 0x9f, 0x85, 0x25, 0x02, 0x7d, 0x69, 0xa4, 0x2d, 0x20, 0x1f, 0x8c, 0xb4, 0x2e, 0x37, 0x32,
0xc1, 0x81, 0x5a, 0xe7, 0x57, 0x74, 0xff, 0x29, 0xb9, 0x8d, 0xd2, 0x01, 0xf0, 0x17, 0xc2, 0x08,
0xf4, 0xc3, 0x11, 0x8e, 0xfd, 0x97, 0xa4, 0x89, 0x62, 0xbe, 0x77, 0xd3, 0xfb, 0xa4, 0xea, 0x9b,
0x7a, 0x18, 0xd0, 0x81, 0xfa, 0xe5, 0xec, 0xec, 0xff, 0xe0, 0x97, 0x29, 0xb1, 0x90, 0x91, 0x5b,
0x1b, 0xef, 0x88, 0x4c, 0x66, 0x02, 0xfb, 0xf5, 0x46, 0x9b, 0x4c, 0x66, 0xc7, 0x40, 0xff, 0xcc,
0x89, 0xe5, 0x9f, 0x39, 0xb1, 0xff, 0xaf, 0x12, 0xa9, 0x07, 0x6d, 0xff, 0x4e, 0xfb, 0x64, 0xdb,
0x5d, 0x16, 0x7e, 0xdc, 0x77, 0x86, 0x9d, 0xc1, 0x86, 0x21, 0x00, 0xe5, 0xc8, 0xa3, 0x8f, 0xc8,
0x36, 0xcc, 0x7d, 0x7c, 0xa9, 0x39, 0x24, 0x83, 0xab, 0x4d, 0x80, 0x23, 0x7e, 0x7d, 0x46, 0xad,
0xe3, 0x18, 0xf6, 0xb8, 0xad, 0x1b, 0x33, 0xca, 0x83, 0xa0, 0xf3, 0x4a, 0xca, 0x42, 0xe4, 0x85,
0xd4, 0x61, 0xb2, 0xd7, 0x01, 0x98, 0x16, 0x52, 0xd3, 0x5d, 0x52, 0xdf, 0x18, 0x87, 0x13, 0xbd,
0xb9, 0xd1, 0x65, 0x83, 0xf2, 0x2b, 0x7e, 0xff, 0x3f, 0xe5, 0xb0, 0x8d, 0xa0, 0x9b, 0x7f, 0x8b,
0x05, 0x8c, 0xd4, 0x36, 0xaa, 0xc1, 0xde, 0x53, 0xe7, 0x1b, 0x92, 0x3e, 0x21, 0xdb, 0x10, 0x62,
0xd4, 0xf8, 0x6a, 0x12, 0x5d, 0x05, 0x9d, 0x23, 0x93, 0x3e, 0x23, 0xb5, 0x10, 0x59, 0xd4, 0xbb,
0x39, 0xa4, 0x83, 0x5f, 0x84, 0x9b, 0x6f, 0x44, 0xe8, 0xe7, 0xa4, 0xea, 0x0d, 0x0f, 0x86, 0xb4,
0x06, 0xd7, 0x82, 0xce, 0x03, 0x2f, 0x2c, 0x00, 0xd5, 0xff, 0xbb, 0x00, 0x3c, 0x80, 0x60, 0x09,
0x69, 0x8c, 0xce, 0x71, 0x3d, 0xa9, 0xf0, 0x5a, 0x6c, 0x46, 0x40, 0xde, 0xf0, 0x59, 0xfd, 0x7f,
0xfb, 0x0c, 0x9c, 0xef, 0x9f, 0xc9, 0xec, 0x12, 0x57, 0x95, 0x06, 0xaf, 0xe3, 0x3b, 0x99, 0x5d,
0xc2, 0x1c, 0x3c, 0x97, 0xc6, 0xaa, 0x5c, 0xe3, 0x9a, 0xd2, 0xdc, 0x74, 0xdc, 0x00, 0xf2, 0x0d,
0xb7, 0xff, 0x8f, 0x12, 0x69, 0x5d, 0xe7, 0xc0, 0xba, 0x98, 0x45, 0xef, 0x72, 0x13, 0xb2, 0xdc,
0x13, 0x88, 0x2a, 0x9d, 0x9b, 0xb0, 0x99, 0x7a, 0x02, 0xd0, 0xa5, 0x72, 0x61, 0x77, 0x6f, 0x70,
0x4f, 0x40, 0x59, 0xd9, 0xf5, 0xa9, 0x5f, 0xa1, 0xb6, 0x43, 0x45, 0x07, 0x1a, 0x6e, 0xe0, 0x2a,
0x8c, 0x8e, 0xac, 0x70, 0x4f, 0xc0, 0xae, 0x03, 0xcd, 0x14, 0x7d, 0xd7, 0xe0, 0x78, 0xde, 0x15,
0x41, 0xaf, 0x30, 0x23, 0x28, 0x21, 0xd5, 0xc9, 0x9b, 0xa3, 0x29, 0x1f, 0x75, 0x3f, 0xa2, 0x4d,
0x52, 0xdb, 0x7b, 0x23, 0x8e, 0xa6, 0x47, 0xa3, 0x6e, 0x89, 0x36, 0x48, 0x65, 0xc6, 0xa7, 0xb3,
0x79, 0xb7, 0x4c, 0xeb, 0x64, 0x7b, 0x3e, 0x1d, 0x1f, 0x77, 0xb7, 0xe0, 0x34, 0x3e, 0x39, 0x38,
0xe8, 0x6e, 0xc3, 0xbd, 0xf9, 0x31, 0x9f, 0xec, 0x1d, 0x77, 0x2b, 0x70, 0x6f, 0x7f, 0x34, 0x7e,
0x7d, 0x72, 0x70, 0xdc, 0xad, 0xee, 0xfe, 0xb3, 0x14, 0x4a, 0x70, 0x93, 0x59, 0xf0, 0xd2, 0xe8,
0x70, 0x76, 0xfc, 0x63, 0xf7, 0x23, 0xb8, 0xbf, 0x7f, 0x72, 0x38, 0xeb, 0x96, 0xe0, 0x0e, 0x1f,
0xcd, 0x8f, 0xe1, 0xe3, 0x32, 0x48, 0xec, 0xfd, 0x75, 0xb4, 0xf7, 0x43, 0x77, 0x8b, 0xb6, 0x48,
0x7d, 0xc6, 0x47, 0x02, 0xa5, 0xb6, 0xe9, 0x2d, 0xd2, 0x9c, 0xbd, 0x7e, 0x33, 0x12, 0xf3, 0x11,
0x7f, 0x3b, 0xe2, 0xdd, 0x0a, 0x7c, 0x7b, 0x34, 0x3d, 0x9e, 0x8c, 0x7f, 0xec, 0x56, 0x69, 0x97,
0xb4, 0xf6, 0x66, 0x27, 0x93, 0xa3, 0xf1, 0xd4, 0x8b, 0xd7, 0xe8, 0x6d, 0xd2, 0xde, 0x20, 0xfe,
0xbd, 0x3a, 0x40, 0xe3, 0xd1, 0xeb, 0xe3, 0x13, 0x3e, 0x0a, 0x50, 0x03, 0xbe, 0x7e, 0x3b, 0xe2,
0xf3, 0xc9, 0xf4, 0xa8, 0x4b, 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xc2, 0x38, 0x55, 0x41, 0x7c,
0x0d, 0x00, 0x00,
// 1835 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x56, 0xeb, 0x72, 0x5b, 0xb7,
0x11, 0x0e, 0x29, 0xf1, 0x06, 0x5e, 0x7c, 0x0c, 0x5f, 0x02, 0xc7, 0xb5, 0xad, 0xd0, 0x51, 0xa2,
0x2a, 0x2e, 0x93, 0x30, 0x76, 0x5c, 0x67, 0xda, 0x1f, 0x1e, 0x8a, 0x74, 0xd8, 0x48, 0x22, 0x07,
0xa4, 0xdc, 0xc9, 0x2f, 0xcc, 0xd1, 0x39, 0x20, 0x05, 0xf3, 0xdc, 0x0a, 0x80, 0x8a, 0xe4, 0x97,
0xe8, 0xbf, 0x3e, 0x57, 0xde, 0xa4, 0xaf, 0xd0, 0xd9, 0x05, 0x28, 0x4b, 0x49, 0x66, 0xd2, 0x7f,
0xd8, 0x0f, 0xbb, 0xc0, 0xde, 0x77, 0x49, 0x5b, 0x17, 0xd1, 0x57, 0xba, 0x88, 0x7a, 0x85, 0xce,
0x6d, 0xde, 0x5d, 0x92, 0x7b, 0x91, 0x56, 0x6b, 0x51, 0x84, 0x4b, 0x29, 0x8c, 0xd4, 0xe7, 0x52,
0x0b, 0x95, 0x2d, 0x72, 0xca, 0x48, 0x2d, 0x8c, 0x63, 0x2d, 0x8d, 0x61, 0xa5, 0x9d, 0xd2, 0x5e,
0x83, 0x6f, 0x48, 0x4a, 0xc9, 0x76, 0x91, 0x6b, 0xcb, 0xca, 0x3b, 0xa5, 0xbd, 0x0a, 0xc7, 0x33,
0x0d, 0xc8, 0x56, 0xa1, 0x62, 0xb6, 0x85, 0x10, 0x1c, 0x69, 0x87, 0x94, 0x17, 0x31, 0xdb, 0x46,
0xa0, 0xbc, 0x88, 0xbb, 0x7f, 0x23, 0x1d, 0xfc, 0xe8, 0x5c, 0xda, 0x33, 0x51, 0x84, 0x4a, 0xd3,
0x3b, 0xa4, 0xa2, 0x16, 0x42, 0x65, 0xac, 0xb4, 0x53, 0xde, 0x6b, 0xf0, 0x6d, 0xb5, 0x18, 0x67,
0xf4, 0x1e, 0xa9, 0xaa, 0x85, 0xc8, 0xd7, 0xf0, 0x3c, 0xa0, 0x15, 0xb5, 0x98, 0xac, 0x6d, 0xf7,
0x5b, 0xd2, 0x96, 0x17, 0x56, 0xa4, 0xf9, 0x3a, 0xb3, 0x22, 0x0d, 0x0b, 0xf8, 0x70, 0x25, 0x2f,
0xbd, 0x28, 0x1c, 0x01, 0x39, 0x0f, 0x13, 0x2f, 0x06, 0xc7, 0xee, 0x5b, 0xd2, 0x79, 0x97, 0xab,
0x4c, 0x64, 0x61, 0x2a, 0x4d, 0x11, 0x46, 0x12, 0x94, 0xca, 0x8c, 0x17, 0x2a, 0x67, 0x86, 0x7e,
0x4c, 0x6a, 0x99, 0x11, 0x0b, 0x95, 0x48, 0x2f, 0x57, 0xcd, 0xcc, 0x48, 0x25, 0x92, 0x3e, 0x24,
0x0d, 0x79, 0x61, 0x75, 0x28, 0xf2, 0xc2, 0xa2, 0x55, 0x0d, 0x5e, 0x47, 0x60, 0x52, 0xd8, 0x6e,
0x8f, 0x10, 0x95, 0x9d, 0x49, 0xad, 0xac, 0x58, 0xc4, 0xbf, 0xa3, 0x89, 0x33, 0x1d, 0x1e, 0x74,
0xa6, 0xbf, 0x20, 0xcd, 0x68, 0xa9, 0xf3, 0x75, 0x21, 0x74, 0x9e, 0x5b, 0xf0, 0x5f, 0x64, 0x75,
0xe2, 0xdd, 0x8a, 0x67, 0xf4, 0x69, 0x68, 0xcf, 0xbc, 0x16, 0x78, 0xee, 0x3e, 0x21, 0xb5, 0x75,
0xa6, 0x2e, 0x84, 0x59, 0xd1, 0xbb, 0xa4, 0xa2, 0xb2, 0x3c, 0x96, 0xf8, 0x4b, 0x9b, 0x3b, 0xa2,
0xfb, 0xdf, 0x36, 0x69, 0xa0, 0x4f, 0xf3, 0xc2, 0x1a, 0xda, 0x25, 0x6d, 0x95, 0x86, 0x4b, 0x69,
0x44, 0xac, 0xb4, 0x58, 0xc4, 0xc8, 0x5b, 0xe1, 0x4d, 0x07, 0x1e, 0x28, 0x3d, 0x8a, 0x37, 0x61,
0x2a, 0x7f, 0x08, 0xd3, 0x53, 0xd2, 0x4e, 0x64, 0x78, 0x2e, 0x85, 0x5e, 0x67, 0x99, 0xca, 0x96,
0x68, 0x6c, 0x9d, 0xb7, 0x10, 0xe4, 0x0e, 0xa3, 0x8f, 0x49, 0x13, 0xbc, 0xef, 0xb5, 0xc1, 0xa0,
0xd6, 0x39, 0x38, 0xe8, 0x24, 0x53, 0x17, 0xb3, 0x15, 0xfd, 0x82, 0xdc, 0xb2, 0x51, 0x21, 0xa4,
0xb1, 0xe1, 0x69, 0xa2, 0xcc, 0x99, 0x8c, 0x59, 0x05, 0x79, 0x3a, 0x36, 0x2a, 0x86, 0x1f, 0x50,
0x60, 0x94, 0xe7, 0xa1, 0x51, 0xe7, 0x52, 0xc4, 0xf2, 0x5c, 0x45, 0xd2, 0xb0, 0xaa, 0x63, 0xf4,
0xf0, 0x81, 0x43, 0xc1, 0xff, 0xe6, 0x4c, 0x26, 0x89, 0x78, 0x97, 0x9f, 0xb2, 0x1a, 0xb2, 0xd4,
0x11, 0xf8, 0x47, 0x7e, 0x4a, 0x1f, 0x11, 0x02, 0x21, 0x13, 0x49, 0x1e, 0xad, 0x0c, 0xab, 0x3b,
0x6d, 0x00, 0x39, 0x04, 0x80, 0x3e, 0x26, 0x8d, 0x24, 0x5f, 0x8a, 0x44, 0x9e, 0xcb, 0x84, 0x35,
0xc0, 0xd4, 0xef, 0x4b, 0x7d, 0x5e, 0x4f, 0xf2, 0xe5, 0x21, 0x40, 0xf4, 0x01, 0x81, 0xb3, 0x8b,
0x3a, 0x71, 0xa9, 0x9d, 0xe4, 0x4b, 0x0c, 0xfb, 0xe7, 0xa4, 0x5c, 0x18, 0xd6, 0xdc, 0x29, 0xed,
0x35, 0xfb, 0xf7, 0x7b, 0xbf, 0x5b, 0x18, 0xbc, 0x5c, 0x18, 0xba, 0x4b, 0x3a, 0x59, 0x6e, 0xd5,
0xe2, 0x52, 0x98, 0x48, 0xab, 0xc2, 0x1a, 0xd6, 0x42, 0x2d, 0xda, 0x0e, 0x9d, 0x39, 0x10, 0xa2,
0x0a, 0x11, 0x67, 0x6d, 0x17, 0x69, 0x8c, 0xfe, 0x23, 0x42, 0x8a, 0x50, 0xcb, 0xcc, 0x0a, 0x95,
0x2e, 0x59, 0x07, 0x6f, 0x1a, 0x0e, 0x19, 0xa7, 0x4b, 0x30, 0xdc, 0xea, 0x30, 0x5a, 0x89, 0x54,
0xa6, 0xec, 0x96, 0x33, 0x1c, 0x81, 0x23, 0x99, 0x82, 0x6c, 0xb8, 0xb6, 0xb9, 0x88, 0x65, 0xbc,
0x2e, 0x58, 0xe0, 0x0c, 0x07, 0xe4, 0x00, 0x00, 0x08, 0xd3, 0xcf, 0xb9, 0x5e, 0x6d, 0xe2, 0x7f,
0x1b, 0xa3, 0xdc, 0x00, 0xc8, 0x45, 0xff, 0x11, 0x21, 0x89, 0xca, 0x56, 0x42, 0xcb, 0x34, 0x2c,
0x18, 0x75, 0xe2, 0x80, 0x70, 0x00, 0xe8, 0x2e, 0xa9, 0x40, 0x71, 0x1a, 0x76, 0x67, 0x67, 0x6b,
0xaf, 0xd9, 0xbf, 0xd5, 0xbb, 0x59, 0xaf, 0xdc, 0xdd, 0xd2, 0xa7, 0xa4, 0x16, 0x15, 0x6b, 0x11,
0x85, 0x05, 0xbb, 0xbb, 0x53, 0xda, 0x6b, 0x7f, 0x4f, 0x9e, 0xf7, 0x5f, 0x3d, 0x7f, 0xf5, 0xdd,
0xcb, 0xfe, 0xab, 0x17, 0xbc, 0x1a, 0x15, 0xeb, 0x41, 0x58, 0xd0, 0x27, 0xa4, 0xb9, 0xc8, 0x75,
0x24, 0x85, 0xd2, 0xf0, 0xd7, 0x3d, 0xfc, 0x8b, 0x20, 0x34, 0x06, 0x04, 0x82, 0x20, 0x2f, 0x64,
0x24, 0xa2, 0x34, 0x66, 0xf7, 0x77, 0xb6, 0x20, 0x08, 0x40, 0x0f, 0x52, 0x48, 0x92, 0x1a, 0xd6,
0x7a, 0x66, 0xd9, 0xc7, 0xa8, 0x49, 0xa7, 0x77, 0xa3, 0xf6, 0x79, 0x55, 0x5e, 0xd8, 0xa3, 0xcc,
0x42, 0x14, 0xd2, 0x30, 0x83, 0xf8, 0xb8, 0xf2, 0x32, 0x8c, 0xb9, 0x28, 0x38, 0x74, 0xe0, 0x40,
0xba, 0x4b, 0x6a, 0xd1, 0x12, 0x4b, 0x8f, 0x3d, 0xc0, 0xf7, 0x5a, 0xbd, 0x6b, 0xe5, 0xc8, 0xab,
0xd1, 0x92, 0x43, 0x60, 0x9e, 0x90, 0xa6, 0x36, 0x56, 0x18, 0x75, 0x9a, 0x40, 0x1d, 0x7c, 0xe2,
0x54, 0xd6, 0xc6, 0xce, 0x1c, 0x42, 0xf7, 0xaf, 0x97, 0x3d, 0x7b, 0x88, 0x4f, 0x35, 0x7b, 0x1f,
0x20, 0xde, 0xf0, 0xe7, 0x51, 0x4c, 0x77, 0x48, 0x0b, 0x23, 0xb5, 0x31, 0xe4, 0x4f, 0xee, 0x35,
0xc0, 0x86, 0x4e, 0xf9, 0x27, 0xae, 0xa6, 0xcc, 0x59, 0xa8, 0xe1, 0xbb, 0x47, 0x8e, 0x41, 0x5e,
0xd8, 0x99, 0x43, 0x36, 0x0c, 0x69, 0x68, 0xac, 0xd4, 0x86, 0x3d, 0xbe, 0x62, 0x38, 0x72, 0x08,
0xb8, 0xd0, 0xac, 0x54, 0x81, 0xef, 0x3f, 0x71, 0x2e, 0x04, 0x1a, 0x1e, 0x87, 0xf6, 0x95, 0x85,
0xa7, 0x89, 0x14, 0x0b, 0xc3, 0x76, 0xf0, 0xae, 0xee, 0x80, 0x91, 0xa1, 0x7b, 0xa4, 0xe9, 0x2b,
0x59, 0xa8, 0x2c, 0x67, 0x9f, 0xa2, 0x21, 0xf5, 0x9e, 0xc7, 0x78, 0x63, 0x8d, 0x45, 0x3d, 0xce,
0x72, 0xfa, 0x77, 0x72, 0xe7, 0xa6, 0x83, 0x45, 0x0a, 0x4d, 0xa8, 0xbb, 0x53, 0xda, 0xeb, 0xf4,
0xdb, 0x2e, 0x3f, 0xa2, 0x25, 0x82, 0xfc, 0xf6, 0x0d, 0xa7, 0x1f, 0xe5, 0xb1, 0x84, 0x8f, 0x96,
0x67, 0xb9, 0xb1, 0x22, 0x51, 0xa9, 0xb2, 0xec, 0x29, 0x66, 0x4b, 0xed, 0x9b, 0xaf, 0x9f, 0xff,
0xf5, 0xc5, 0xcb, 0xef, 0x38, 0xc1, 0xbb, 0x43, 0xb8, 0xa2, 0x7b, 0x24, 0xc0, 0x44, 0x11, 0x26,
0x0a, 0x33, 0x01, 0xdd, 0xcf, 0xb0, 0xcf, 0x50, 0xed, 0x0e, 0xe2, 0xb3, 0x28, 0xcc, 0xa6, 0x80,
0xd2, 0x4f, 0x20, 0x6f, 0xac, 0xd4, 0x59, 0x98, 0xb0, 0x5d, 0x6f, 0x98, 0xa7, 0x31, 0xa7, 0xd2,
0xc2, 0x5e, 0x8a, 0xcc, 0xb0, 0xcf, 0xe1, 0x33, 0x5e, 0x43, 0xfa, 0x18, 0x6c, 0xae, 0xb9, 0x51,
0x60, 0xd8, 0x17, 0x3e, 0xbb, 0x6f, 0x8e, 0x06, 0x5e, 0x05, 0xfa, 0xd8, 0xd0, 0x4f, 0x49, 0xcb,
0x67, 0x47, 0xa1, 0xf3, 0xc2, 0xb0, 0x3f, 0x63, 0x85, 0xfa, 0x06, 0x3e, 0x05, 0x88, 0xee, 0x93,
0xdb, 0xd7, 0x59, 0x5c, 0x27, 0xd9, 0x47, 0xbe, 0x5b, 0xd7, 0xf8, 0xb0, 0xa3, 0x3c, 0x27, 0xf7,
0x3d, 0x6f, 0xbc, 0x4e, 0x0b, 0x11, 0xe5, 0x99, 0xd5, 0x79, 0x92, 0x48, 0xcd, 0xbe, 0x44, 0xed,
0xef, 0xba, 0xdb, 0x83, 0x75, 0x5a, 0x0c, 0xae, 0xee, 0xa0, 0x2b, 0x2f, 0xb4, 0x94, 0xef, 0x37,
0x8e, 0x67, 0xcf, 0xf0, 0xf5, 0x96, 0x03, 0x9d, 0x8f, 0x61, 0x42, 0x5b, 0x95, 0x4a, 0x98, 0x95,
0x7f, 0x71, 0xd6, 0x7a, 0x92, 0x7e, 0x49, 0x28, 0xf4, 0x63, 0xcc, 0x0e, 0x95, 0x89, 0x45, 0xa2,
0x96, 0x67, 0x96, 0xf5, 0x30, 0x83, 0xa0, 0x53, 0xcf, 0x56, 0xaa, 0x18, 0x67, 0x23, 0x84, 0xc1,
0xe0, 0x9f, 0x65, 0xb8, 0x12, 0xe6, 0xd2, 0x44, 0x36, 0x31, 0xec, 0x2b, 0x64, 0x6b, 0x02, 0x36,
0x73, 0x10, 0x36, 0x8e, 0xf0, 0xfd, 0x25, 0xf6, 0x42, 0xc3, 0xbe, 0xf6, 0x8d, 0x23, 0x7c, 0x7f,
0x39, 0x05, 0x00, 0x9b, 0xb5, 0x0d, 0xed, 0xda, 0x40, 0x5d, 0x7c, 0x83, 0x5d, 0xa7, 0xee, 0x80,
0x51, 0x0c, 0xce, 0xca, 0x75, 0x71, 0x06, 0x61, 0xb5, 0xc6, 0x67, 0x33, 0xeb, 0x3b, 0x55, 0xdc,
0xc5, 0xd4, 0x1a, 0x97, 0xd2, 0x90, 0xf2, 0x51, 0x9e, 0x2d, 0x94, 0x6f, 0xce, 0xdf, 0xa2, 0xd1,
0xc4, 0x41, 0xe0, 0xcd, 0xee, 0x33, 0xbf, 0x44, 0xa0, 0x2f, 0xb5, 0x34, 0x05, 0xe4, 0x83, 0x96,
0xc6, 0xe6, 0x5a, 0xc6, 0x38, 0x50, 0xeb, 0xfc, 0x8a, 0xee, 0xee, 0x92, 0xdb, 0xc8, 0xed, 0x01,
0x27, 0xe0, 0x47, 0xa0, 0x1b, 0x8e, 0x70, 0xec, 0xbe, 0x24, 0x4d, 0x64, 0x73, 0xbd, 0x9b, 0xde,
0x27, 0x55, 0xd7, 0xd4, 0xfd, 0x80, 0xf6, 0xd4, 0x6f, 0x67, 0x67, 0xf7, 0x47, 0xd2, 0x46, 0xc1,
0x85, 0x0c, 0xed, 0x5a, 0x3b, 0x47, 0xa4, 0x32, 0x15, 0xd8, 0xaf, 0x37, 0xda, 0xa4, 0x32, 0x9d,
0x03, 0xfd, 0x2b, 0x27, 0x96, 0x7f, 0xe5, 0xc4, 0xee, 0x2f, 0x25, 0x52, 0xf7, 0xda, 0xfe, 0x8b,
0x76, 0xc9, 0xb6, 0xbd, 0x2c, 0xdc, 0xb8, 0xef, 0xf4, 0x3b, 0xbd, 0xcd, 0x85, 0x00, 0x94, 0xe3,
0x1d, 0x7d, 0x4c, 0xb6, 0x61, 0xee, 0xe3, 0x4b, 0xcd, 0x3e, 0xe9, 0x5d, 0x6d, 0x02, 0x1c, 0xf1,
0xeb, 0x33, 0x6a, 0x1d, 0x45, 0xb0, 0xc7, 0x6d, 0xdd, 0x98, 0x51, 0x0e, 0x04, 0x9d, 0x57, 0x52,
0x16, 0x22, 0x2f, 0x64, 0xe6, 0x27, 0x7b, 0x1d, 0x80, 0x49, 0x21, 0x33, 0xba, 0x4f, 0xea, 0x1b,
0xe3, 0x70, 0xa2, 0x37, 0x37, 0xba, 0x6c, 0x50, 0x7e, 0x75, 0xbf, 0xf1, 0x4f, 0x15, 0x53, 0x11,
0xfd, 0xf3, 0xef, 0x2d, 0xbf, 0x9f, 0xa0, 0xe3, 0xff, 0x1f, 0x9b, 0x18, 0xa9, 0x6d, 0x94, 0x85,
0x4d, 0xa8, 0xce, 0x37, 0x24, 0x7d, 0x4a, 0xb6, 0x21, 0xe8, 0x68, 0xc3, 0xd5, 0x6c, 0xba, 0x4a,
0x03, 0x8e, 0x97, 0xf4, 0x19, 0xa9, 0xf9, 0x58, 0xa3, 0x25, 0xcd, 0x3e, 0xed, 0xfd, 0x26, 0x01,
0xf8, 0x86, 0x85, 0x7e, 0x46, 0xaa, 0xce, 0x15, 0xde, 0xb4, 0x56, 0xef, 0x5a, 0x1a, 0x70, 0x7f,
0xe7, 0x57, 0x82, 0xea, 0x1f, 0xae, 0x04, 0x0f, 0x20, 0x7c, 0x42, 0x6a, 0x9d, 0xe5, 0xb8, 0xb0,
0x54, 0x78, 0x2d, 0xd2, 0x43, 0x20, 0x6f, 0x78, 0xb1, 0xfe, 0x07, 0x5e, 0x7c, 0x08, 0x2e, 0x83,
0x67, 0x52, 0xb3, 0xc4, 0xe5, 0xa5, 0xc1, 0xeb, 0xf8, 0x4e, 0x6a, 0x96, 0x30, 0x19, 0xcf, 0xa5,
0x36, 0x2a, 0xcf, 0x70, 0x71, 0x69, 0x6e, 0x7a, 0xb0, 0x07, 0xf9, 0xe6, 0x16, 0x73, 0x18, 0x0b,
0x10, 0x77, 0x99, 0x0a, 0xf7, 0x54, 0xf7, 0x3f, 0x25, 0xd2, 0xba, 0x2e, 0x01, 0x8b, 0x65, 0x1a,
0xbe, 0xcb, 0xb5, 0xaf, 0x07, 0x47, 0x20, 0xaa, 0xb2, 0x5c, 0xfb, 0x1d, 0xd6, 0x11, 0x80, 0x2e,
0x95, 0xf5, 0x5b, 0x7e, 0x83, 0x3b, 0x02, 0x0a, 0xd0, 0xac, 0x4f, 0xdd, 0xb2, 0xb5, 0xed, 0x6b,
0xdf, 0xd3, 0x20, 0x81, 0x4b, 0x33, 0x3a, 0xb8, 0xc2, 0x1d, 0x01, 0x5b, 0x11, 0xb4, 0x5d, 0xf4,
0x69, 0x83, 0xe3, 0x79, 0x5f, 0x78, 0xbd, 0xfc, 0x34, 0xa1, 0x84, 0x54, 0xc7, 0x6f, 0x8e, 0x27,
0x7c, 0x18, 0x7c, 0x44, 0x9b, 0xa4, 0x36, 0x78, 0x23, 0x8e, 0x27, 0xc7, 0xc3, 0xa0, 0x44, 0x1b,
0xa4, 0x32, 0xe5, 0x93, 0xe9, 0x2c, 0x28, 0xd3, 0x3a, 0xd9, 0x9e, 0x4d, 0x46, 0xf3, 0x60, 0x0b,
0x4e, 0xa3, 0x93, 0xc3, 0xc3, 0x60, 0x1b, 0xe4, 0x66, 0x73, 0x3e, 0x1e, 0xcc, 0x83, 0x0a, 0xc8,
0x1d, 0x0c, 0x47, 0xaf, 0x4f, 0x0e, 0xe7, 0x41, 0x75, 0xff, 0x97, 0x92, 0x2f, 0xd6, 0x4d, 0xc6,
0xc1, 0x4b, 0xc3, 0xa3, 0xe9, 0xfc, 0xa7, 0xe0, 0x23, 0x90, 0x3f, 0x38, 0x39, 0x9a, 0x06, 0x25,
0x90, 0xe1, 0xc3, 0xd9, 0x1c, 0x3e, 0x2e, 0x03, 0xc7, 0xe0, 0x87, 0xe1, 0xe0, 0xc7, 0x60, 0x8b,
0xb6, 0x48, 0x7d, 0xca, 0x87, 0x02, 0xb9, 0xb6, 0xe9, 0x2d, 0xd2, 0x9c, 0xbe, 0x7e, 0x33, 0x14,
0xb3, 0x21, 0x7f, 0x3b, 0xe4, 0x41, 0x05, 0xbe, 0x3d, 0x9e, 0xcc, 0xc7, 0xa3, 0x9f, 0x82, 0x2a,
0x0d, 0x48, 0x6b, 0x30, 0x3d, 0x19, 0x1f, 0x8f, 0x26, 0x8e, 0xbd, 0x46, 0x6f, 0x93, 0xf6, 0x06,
0x71, 0xef, 0xd5, 0x01, 0x1a, 0x0d, 0x5f, 0xcf, 0x4f, 0xf8, 0xd0, 0x43, 0x0d, 0xf8, 0xfa, 0xed,
0x90, 0xcf, 0xc6, 0x93, 0xe3, 0x80, 0xc0, 0x7f, 0xff, 0x7c, 0x3d, 0x9e, 0x8b, 0xe9, 0xf8, 0x20,
0x68, 0xd2, 0xbb, 0x24, 0xb8, 0xf6, 0x9f, 0x18, 0xfc, 0x70, 0x78, 0x10, 0xb4, 0xfe, 0x17, 0x00,
0x00, 0xff, 0xff, 0xf8, 0x9f, 0x0e, 0x7d, 0xca, 0x0d, 0x00, 0x00,
}

View file

@ -1,10 +1,14 @@
# How to Contribute
This document outlines some of the requirements and conventions for contributing to the Container Storage Interface, including development workflow, commit message formatting, contact points, and other resources to make it easier to get your contribution accepted.
## Licence and CLA
CSI is under [Apache 2.0](LICENSE) and accepts contributions via GitHub pull requests.
Contributions require signing an individual or Corporate CLA available [here](https://github.com/container-storage-interface/spec/blob/master/CCLA.pdf) which should be signed and mailed to the [mailing list]( https://groups.google.com/forum/#!topic/container-storage-interface-community/).
This document outlines some of the conventions on development workflow, commit message formatting, contact points and other resources to make it easier to get your contribution accepted.
Before contributing to the Container Storage Interface, contributors MUST sign the CLA available [here](https://github.com/container-storage-interface/spec/blob/master/CCLA.pdf).
The CLA MAY be signed on behalf of a company, possibly covering multiple contributors, or as an individual (put "Individual" for "Corporation name").
The completed CLA MUST be mailed to the CSI Approvers [mailing list](container-storage-interface-approvers@googlegroups.com).
## Markdown style

View file

@ -1 +1 @@
1.0.0
1.1.0

View file

@ -57,6 +57,9 @@ service Controller {
rpc ListSnapshots (ListSnapshotsRequest)
returns (ListSnapshotsResponse) {}
rpc ControllerExpandVolume (ControllerExpandVolumeRequest)
returns (ControllerExpandVolumeResponse) {}
}
service Node {
@ -75,6 +78,11 @@ service Node {
rpc NodeGetVolumeStats (NodeGetVolumeStatsRequest)
returns (NodeGetVolumeStatsResponse) {}
rpc NodeExpandVolume(NodeExpandVolumeRequest)
returns (NodeExpandVolumeResponse) {}
rpc NodeGetCapabilities (NodeGetCapabilitiesRequest)
returns (NodeGetCapabilitiesResponse) {}
@ -116,7 +124,6 @@ message PluginCapability {
message Service {
enum Type {
UNKNOWN = 0;
// CONTROLLER_SERVICE indicates that the Plugin provides RPCs for
// the ControllerService. Plugins SHOULD provide this capability.
// In rare cases certain plugins MAY wish to omit the
@ -138,9 +145,56 @@ message PluginCapability {
Type type = 1;
}
message VolumeExpansion {
enum Type {
UNKNOWN = 0;
// ONLINE indicates that volumes may be expanded when published to
// a node. When a Plugin implements this capability it MUST
// implement either the EXPAND_VOLUME controller capability or the
// EXPAND_VOLUME node capability or both. When a plugin supports
// ONLINE volume expansion and also has the EXPAND_VOLUME
// controller capability then the plugin MUST support expansion of
// volumes currently published and available on a node. When a
// plugin supports ONLINE volume expansion and also has the
// EXPAND_VOLUME node capability then the plugin MAY support
// expansion of node-published volume via NodeExpandVolume.
//
// Example 1: Given a shared filesystem volume (e.g. GlusterFs),
// the Plugin may set the ONLINE volume expansion capability and
// implement ControllerExpandVolume but not NodeExpandVolume.
//
// Example 2: Given a block storage volume type (e.g. EBS), the
// Plugin may set the ONLINE volume expansion capability and
// implement both ControllerExpandVolume and NodeExpandVolume.
//
// Example 3: Given a Plugin that supports volume expansion only
// upon a node, the Plugin may set the ONLINE volume
// expansion capability and implement NodeExpandVolume but not
// ControllerExpandVolume.
ONLINE = 1;
// OFFLINE indicates that volumes currently published and
// available on a node SHALL NOT be expanded via
// ControllerExpandVolume. When a plugin supports OFFLINE volume
// expansion it MUST implement either the EXPAND_VOLUME controller
// capability or both the EXPAND_VOLUME controller capability and
// the EXPAND_VOLUME node capability.
//
// Example 1: Given a block storage volume type (e.g. Azure Disk)
// that does not support expansion of "node-attached" (i.e.
// controller-published) volumes, the Plugin may indicate
// OFFLINE volume expansion support and implement both
// ControllerExpandVolume and NodeExpandVolume.
OFFLINE = 2;
}
Type type = 1;
}
oneof type {
// Service that the plugin supports.
Service service = 1;
VolumeExpansion volume_expansion = 2;
}
}
message ProbeRequest {
@ -236,7 +290,7 @@ message CreateVolumeRequest {
// If specified, the new volume will be pre-populated with data from
// this source. This field is OPTIONAL.
VolumeContentSource volume_content_source = 6;
// Specifies where (regions, zones, racks, etc.) the provisioned
// volume MUST be accessible from.
// An SP SHALL advertise the requirements for topological
@ -420,7 +474,7 @@ message Volume {
// Example 2:
// accessible_topology =
// {"region": "R1", "zone": "Z2"},
// {"region": "R1", "zone": "Z3"}
// {"region": "R1", "zone": "Z3"}
// Indicates a volume accessible from both "zone" "Z2" and "zone" "Z3"
// in the "region" "R1".
repeated Topology accessible_topology = 5;
@ -431,15 +485,15 @@ message TopologyRequirement {
// accessible from.
// This field is OPTIONAL. If TopologyRequirement is specified either
// requisite or preferred or both MUST be specified.
//
//
// If requisite is specified, the provisioned volume MUST be
// accessible from at least one of the requisite topologies.
//
//
// Given
// x = number of topologies provisioned volume is accessible from
// n = number of requisite topologies
// The CO MUST ensure n >= 1. The SP MUST ensure x >= 1
// If x==n, than the SP MUST make the provisioned volume available to
// If x==n, then the SP MUST make the provisioned volume available to
// all topologies from the list of requisite topologies. If it is
// unable to do so, the SP MUST fail the CreateVolume call.
// For example, if a volume should be accessible from a single zone,
@ -454,7 +508,7 @@ message TopologyRequirement {
// then the provisioned volume MUST be accessible from the "region"
// "R1" and both "zone" "Z2" and "zone" "Z3".
//
// If x<n, than the SP SHALL choose x unique topologies from the list
// If x<n, then the SP SHALL choose x unique topologies from the list
// of requisite topologies. If it is unable to do so, the SP MUST fail
// the CreateVolume call.
// For example, if a volume should be accessible from a single zone,
@ -472,7 +526,7 @@ message TopologyRequirement {
// of two unique topologies: e.g. "R1/Z2" and "R1/Z3", or "R1/Z2" and
// "R1/Z4", or "R1/Z3" and "R1/Z4".
//
// If x>n, than the SP MUST make the provisioned volume available from
// If x>n, then the SP MUST make the provisioned volume available from
// all topologies from the list of requisite topologies and MAY choose
// the remaining x-n unique topologies from the list of all possible
// topologies. If it is unable to do so, the SP MUST fail the
@ -490,7 +544,7 @@ message TopologyRequirement {
//
// This field is OPTIONAL. If TopologyRequirement is specified either
// requisite or preferred or both MUST be specified.
//
//
// An SP MUST attempt to make the provisioned volume available using
// the preferred topologies in order from first to last.
//
@ -505,7 +559,7 @@ message TopologyRequirement {
// If the list of requisite topologies is specified and the SP is
// unable to to make the provisioned volume available from any of the
// requisite topologies it MUST fail the CreateVolume call.
//
//
// Example 1:
// Given a volume should be accessible from a single zone, and
// requisite =
@ -817,14 +871,19 @@ message ControllerServiceCapability {
// snapshot.
CREATE_DELETE_SNAPSHOT = 5;
LIST_SNAPSHOTS = 6;
// Plugins supporting volume cloning at the storage level MAY
// report this capability. The source volume MUST be managed by
// the same plugin. Not all volume sources and parameters
// combinations MAY work.
CLONE_VOLUME = 7;
// Indicates the SP supports ControllerPublishVolume.readonly
// field.
PUBLISH_READONLY = 8;
// See VolumeExpansion for details.
EXPAND_VOLUME = 9;
}
Type type = 1;
@ -967,6 +1026,28 @@ message ListSnapshotsResponse {
// An empty string is equal to an unspecified field value.
string next_token = 2;
}
message ControllerExpandVolumeRequest {
// The ID of the volume to expand. This field is REQUIRED.
string volume_id = 1;
// This allows CO to specify the capacity requirements of the volume
// after expansion. This field is REQUIRED.
CapacityRange capacity_range = 2;
// Secrets required by the plugin for expanding the volume.
// This field is OPTIONAL.
map<string, string> secrets = 3 [(csi_secret) = true];
}
message ControllerExpandVolumeResponse {
// Capacity of volume after expansion. This field is REQUIRED.
int64 capacity_bytes = 1;
// Whether node expansion is required for the volume. When true
// the CO MUST make NodeExpandVolume RPC call on the node. This field
// is REQUIRED.
bool node_expansion_required = 2;
}
message NodeStageVolumeRequest {
// The ID of the volume to publish. This field is REQUIRED.
string volume_id = 1;
@ -1151,6 +1232,8 @@ message NodeServiceCapability {
// then it MUST implement NodeGetVolumeStats RPC
// call for fetching volume statistics.
GET_VOLUME_STATS = 2;
// See VolumeExpansion for details.
EXPAND_VOLUME = 3;
}
Type type = 1;
@ -1196,8 +1279,28 @@ message NodeGetInfoResponse {
//
// Example 1:
// accessible_topology =
// {"region": "R1", "zone": "R2"}
// {"region": "R1", "zone": "Z2"}
// Indicates the node exists within the "region" "R1" and the "zone"
// "Z2".
Topology accessible_topology = 3;
}
message NodeExpandVolumeRequest {
// The ID of the volume. This field is REQUIRED.
string volume_id = 1;
// The path on which volume is available. This field is REQUIRED.
string volume_path = 2;
// This allows CO to specify the capacity requirements of the volume
// after expansion. If capacity_range is omitted then a plugin MAY
// inspect the file system of the volume to determine the maximum
// capacity to which the volume can be expanded. In such cases a
// plugin MAY expand the volume to its maximum capacity.
// This field is OPTIONAL.
CapacityRange capacity_range = 3;
}
message NodeExpandVolumeResponse {
// The capacity of the volume in bytes. This field is OPTIONAL.
int64 capacity_bytes = 1;
}

File diff suppressed because it is too large Load diff

View file

@ -338,6 +338,9 @@ service Controller {
rpc ListSnapshots (ListSnapshotsRequest)
returns (ListSnapshotsResponse) {}
rpc ControllerExpandVolume (ControllerExpandVolumeRequest)
returns (ControllerExpandVolumeResponse) {}
}
service Node {
@ -356,6 +359,11 @@ service Node {
rpc NodeGetVolumeStats (NodeGetVolumeStatsRequest)
returns (NodeGetVolumeStatsResponse) {}
rpc NodeExpandVolume(NodeExpandVolumeRequest)
returns (NodeExpandVolumeResponse) {}
rpc NodeGetCapabilities (NodeGetCapabilitiesRequest)
returns (NodeGetCapabilitiesResponse) {}
@ -417,7 +425,7 @@ The status `code` MUST contain a [canonical error code](https://github.com/grpc/
| Condition | gRPC Code | Description | Recovery Behavior |
|-----------|-----------|-------------|-------------------|
| Missing required field | 3 INVALID_ARGUMENT | Indicates that a required field is missing from the request. More human-readable information MAY be provided in the `status.message` field. | Caller MUST fix the request by adding the missing required field before retrying. |
| Invalid or unsupported field in the request | 3 INVALID_ARGUMENT | Indicates that the one ore more fields in this field is either not allowed by the Plugin or has an invalid value. More human-readable information MAY be provided in the gRPC `status.message` field. | Caller MUST fix the field before retrying. |
| Invalid or unsupported field in the request | 3 INVALID_ARGUMENT | Indicates that the one or more fields in this field is either not allowed by the Plugin or has an invalid value. More human-readable information MAY be provided in the gRPC `status.message` field. | Caller MUST fix the field before retrying. |
| Permission denied | 7 PERMISSION_DENIED | The Plugin is able to derive or otherwise infer an identity from the secrets present within an RPC, but that identity does not have permission to invoke the RPC. | System administrator SHOULD ensure that requisite permissions are granted, after which point the caller MAY retry the attempted RPC. |
| Operation pending for volume | 10 ABORTED | Indicates that there is already an operation pending for the specified volume. In general the Cluster Orchestrator (CO) is responsible for ensuring that there is no more than one call "in-flight" per volume at a given time. However, in some circumstances, the CO MAY lose state (for example when the CO crashes and restarts), and MAY issue multiple calls simultaneously for the same volume. The Plugin, SHOULD handle this as gracefully as possible, and MAY return this error code to reject secondary calls. | Caller SHOULD ensure that there are no other calls pending for the specified volume, and then retry with exponential back off. |
| Call not implemented | 12 UNIMPLEMENTED | The invoked RPC is not implemented by the Plugin or disabled in the Plugin's current mode of operation. | Caller MUST NOT retry. Caller MAY call `GetPluginCapabilities`, `ControllerGetCapabilities`, or `NodeGetCapabilities` to discover Plugin capabilities. |
@ -526,7 +534,6 @@ message PluginCapability {
message Service {
enum Type {
UNKNOWN = 0;
// CONTROLLER_SERVICE indicates that the Plugin provides RPCs for
// the ControllerService. Plugins SHOULD provide this capability.
// In rare cases certain plugins MAY wish to omit the
@ -548,9 +555,56 @@ message PluginCapability {
Type type = 1;
}
message VolumeExpansion {
enum Type {
UNKNOWN = 0;
// ONLINE indicates that volumes may be expanded when published to
// a node. When a Plugin implements this capability it MUST
// implement either the EXPAND_VOLUME controller capability or the
// EXPAND_VOLUME node capability or both. When a plugin supports
// ONLINE volume expansion and also has the EXPAND_VOLUME
// controller capability then the plugin MUST support expansion of
// volumes currently published and available on a node. When a
// plugin supports ONLINE volume expansion and also has the
// EXPAND_VOLUME node capability then the plugin MAY support
// expansion of node-published volume via NodeExpandVolume.
//
// Example 1: Given a shared filesystem volume (e.g. GlusterFs),
// the Plugin may set the ONLINE volume expansion capability and
// implement ControllerExpandVolume but not NodeExpandVolume.
//
// Example 2: Given a block storage volume type (e.g. EBS), the
// Plugin may set the ONLINE volume expansion capability and
// implement both ControllerExpandVolume and NodeExpandVolume.
//
// Example 3: Given a Plugin that supports volume expansion only
// upon a node, the Plugin may set the ONLINE volume
// expansion capability and implement NodeExpandVolume but not
// ControllerExpandVolume.
ONLINE = 1;
// OFFLINE indicates that volumes currently published and
// available on a node SHALL NOT be expanded via
// ControllerExpandVolume. When a plugin supports OFFLINE volume
// expansion it MUST implement either the EXPAND_VOLUME controller
// capability or both the EXPAND_VOLUME controller capability and
// the EXPAND_VOLUME node capability.
//
// Example 1: Given a block storage volume type (e.g. Azure Disk)
// that does not support expansion of "node-attached" (i.e.
// controller-published) volumes, the Plugin may indicate
// OFFLINE volume expansion support and implement both
// ControllerExpandVolume and NodeExpandVolume.
OFFLINE = 2;
}
Type type = 1;
}
oneof type {
// Service that the plugin supports.
Service service = 1;
VolumeExpansion volume_expansion = 2;
}
}
```
@ -700,7 +754,7 @@ message CreateVolumeRequest {
// If specified, the new volume will be pre-populated with data from
// this source. This field is OPTIONAL.
VolumeContentSource volume_content_source = 6;
// Specifies where (regions, zones, racks, etc.) the provisioned
// volume MUST be accessible from.
// An SP SHALL advertise the requirements for topological
@ -884,7 +938,7 @@ message Volume {
// Example 2:
// accessible_topology =
// {"region": "R1", "zone": "Z2"},
// {"region": "R1", "zone": "Z3"}
// {"region": "R1", "zone": "Z3"}
// Indicates a volume accessible from both "zone" "Z2" and "zone" "Z3"
// in the "region" "R1".
repeated Topology accessible_topology = 5;
@ -895,15 +949,15 @@ message TopologyRequirement {
// accessible from.
// This field is OPTIONAL. If TopologyRequirement is specified either
// requisite or preferred or both MUST be specified.
//
//
// If requisite is specified, the provisioned volume MUST be
// accessible from at least one of the requisite topologies.
//
//
// Given
// x = number of topologies provisioned volume is accessible from
// n = number of requisite topologies
// The CO MUST ensure n >= 1. The SP MUST ensure x >= 1
// If x==n, than the SP MUST make the provisioned volume available to
// If x==n, then the SP MUST make the provisioned volume available to
// all topologies from the list of requisite topologies. If it is
// unable to do so, the SP MUST fail the CreateVolume call.
// For example, if a volume should be accessible from a single zone,
@ -918,7 +972,7 @@ message TopologyRequirement {
// then the provisioned volume MUST be accessible from the "region"
// "R1" and both "zone" "Z2" and "zone" "Z3".
//
// If x<n, than the SP SHALL choose x unique topologies from the list
// If x<n, then the SP SHALL choose x unique topologies from the list
// of requisite topologies. If it is unable to do so, the SP MUST fail
// the CreateVolume call.
// For example, if a volume should be accessible from a single zone,
@ -936,7 +990,7 @@ message TopologyRequirement {
// of two unique topologies: e.g. "R1/Z2" and "R1/Z3", or "R1/Z2" and
// "R1/Z4", or "R1/Z3" and "R1/Z4".
//
// If x>n, than the SP MUST make the provisioned volume available from
// If x>n, then the SP MUST make the provisioned volume available from
// all topologies from the list of requisite topologies and MAY choose
// the remaining x-n unique topologies from the list of all possible
// topologies. If it is unable to do so, the SP MUST fail the
@ -954,7 +1008,7 @@ message TopologyRequirement {
//
// This field is OPTIONAL. If TopologyRequirement is specified either
// requisite or preferred or both MUST be specified.
//
//
// An SP MUST attempt to make the provisioned volume available using
// the preferred topologies in order from first to last.
//
@ -969,7 +1023,7 @@ message TopologyRequirement {
// If the list of requisite topologies is specified and the SP is
// unable to to make the provisioned volume available from any of the
// requisite topologies it MUST fail the CreateVolume call.
//
//
// Example 1:
// Given a volume should be accessible from a single zone, and
// requisite =
@ -1181,7 +1235,7 @@ The CO MUST implement the specified error recovery behavior when it encounters t
|-----------|-----------|-------------|-------------------|
| Volume does not exist | 5 NOT_FOUND | Indicates that a volume corresponding to the specified `volume_id` does not exist. | Caller MUST verify that the `volume_id` is correct and that the volume is accessible and has not been deleted before retrying with exponential back off. |
| Node does not exist | 5 NOT_FOUND | Indicates that a node corresponding to the specified `node_id` does not exist. | Caller MUST verify that the `node_id` is correct and that the node is available and has not been terminated or deleted before retrying with exponential backoff. |
| Volume published but is incompatible | 6 ALREADY_EXISTS | Indicates that a volume corresponding to the specified `volume_id` has already been published at the node corresponding to the specified `volume_id` but is incompatible with the specified `volume_capability` or `readonly` flag . | Caller MUST fix the arguments before retying. |
| Volume published but is incompatible | 6 ALREADY_EXISTS | Indicates that a volume corresponding to the specified `volume_id` has already been published at the node corresponding to the specified `node_id` but is incompatible with the specified `volume_capability` or `readonly` flag . | Caller MUST fix the arguments before retrying. |
| Volume published to another node | 9 FAILED_PRECONDITION | Indicates that a volume corresponding to the specified `volume_id` has already been published at another node and does not have MULTI_NODE volume capability. If this error code is returned, the Plugin SHOULD specify the `node_id` of the node at which the volume is published as part of the gRPC `status.message`. | Caller SHOULD ensure the specified volume is not published at any other node before retrying with exponential back off. |
| Max volumes attached | 8 RESOURCE_EXHAUSTED | Indicates that the maximum supported number of volumes that can be attached to the specified node are already attached. Therefore, this operation will fail until at least one of the existing attached volumes is detached from the node. | Caller MUST ensure that the number of volumes already attached to the node is less then the maximum supported number of volumes before retrying with exponential backoff. |
@ -1442,14 +1496,19 @@ message ControllerServiceCapability {
// snapshot.
CREATE_DELETE_SNAPSHOT = 5;
LIST_SNAPSHOTS = 6;
// Plugins supporting volume cloning at the storage level MAY
// report this capability. The source volume MUST be managed by
// the same plugin. Not all volume sources and parameters
// combinations MAY work.
CLONE_VOLUME = 7;
// Indicates the SP supports ControllerPublishVolume.readonly
// field.
PUBLISH_READONLY = 8;
// See VolumeExpansion for details.
EXPAND_VOLUME = 9;
}
Type type = 1;
@ -1702,6 +1761,75 @@ The CO MUST implement the specified error recovery behavior when it encounters t
| Invalid `starting_token` | 10 ABORTED | Indicates that `starting_token` is not valid. | Caller SHOULD start the `ListSnapshots` operation again with an empty `starting_token`. |
#### `ControllerExpandVolume`
A Controller plugin MUST implement this RPC call if plugin has `EXPAND_VOLUME` controller capability.
This RPC allows the CO to expand the size of a volume.
This call MAY be made by the CO during any time in the lifecycle of the volume after creation if plugin has `VolumeExpansion.ONLINE` capability.
If plugin has `EXPAND_VOLUME` node capability, then `NodeExpandVolume` MUST be called after successful `ControllerExpandVolume` and `node_expansion_required` in `ControllerExpandVolumeResponse` is `true`.
If the plugin has only `VolumeExpansion.OFFLINE` expansion capability and volume is currently published or available on a node then `ControllerExpandVolume` MUST be called ONLY after either:
- The plugin has controller `PUBLISH_UNPUBLISH_VOLUME` capability and `ControllerUnpublishVolume` has been invoked successfully.
OR ELSE
- The plugin does NOT have controller `PUBLISH_UNPUBLISH_VOLUME` capability, the plugin has node `STAGE_UNSTAGE_VOLUME` capability, and `NodeUnstageVolume` has been completed successfully.
OR ELSE
- The plugin does NOT have controller `PUBLISH_UNPUBLISH_VOLUME` capability, nor node `STAGE_UNSTAGE_VOLUME` capability, and `NodeUnpublishVolume` has completed successfully.
Examples:
* Offline Volume Expansion:
Given an ElasticSearch process that runs on Azure Disk and needs more space.
- The administrator takes the Elasticsearch server offline by stopping the workload and CO calls `ControllerUnpublishVolume`.
- The administrator requests more space for the volume from CO.
- The CO in turn first makes `ControllerExpandVolume` RPC call which results in requesting more space from Azure cloud provider for volume ID that was being used by ElasticSearch.
- Once `ControllerExpandVolume` is completed and successful, the CO will inform administrator about it and administrator will resume the ElasticSearch workload.
- On the node where the ElasticSearch workload is scheduled, the CO calls `NodeExpandVolume` after calling `NodeStageVolume`.
- Calling `NodeExpandVolume` on volume results in expanding the underlying file system and added space becomes available to workload when it starts up.
* Online Volume Expansion:
Given a Mysql server running on Openstack Cinder and needs more space.
- The administrator requests more space for volume from the CO.
- The CO in turn first makes `ControllerExpandVolume` RPC call which results in requesting more space from Openstack Cinder for given volume.
- On the node where the mysql workload is running, the CO calls `NodeExpandVolume` while volume is in-use using the path where the volume is staged.
- Calling `NodeExpandVolume` on volume results in expanding the underlying file system and added space automatically becomes available to mysql workload without any downtime.
```protobuf
message ControllerExpandVolumeRequest {
// The ID of the volume to expand. This field is REQUIRED.
string volume_id = 1;
// This allows CO to specify the capacity requirements of the volume
// after expansion. This field is REQUIRED.
CapacityRange capacity_range = 2;
// Secrets required by the plugin for expanding the volume.
// This field is OPTIONAL.
map<string, string> secrets = 3 [(csi_secret) = true];
}
message ControllerExpandVolumeResponse {
// Capacity of volume after expansion. This field is REQUIRED.
int64 capacity_bytes = 1;
// Whether node expansion is required for the volume. When true
// the CO MUST make NodeExpandVolume RPC call on the node. This field
// is REQUIRED.
bool node_expansion_required = 2;
}
```
##### ControllerExpandVolume Errors
| Condition | gRPC Code | Description | Recovery Behavior |
|-----------|-----------|-------------|-------------------|
| Volume does not exist | 5 NOT FOUND | Indicates that a volume corresponding to the specified volume_id does not exist. | Caller MUST verify that the volume_id is correct and that the volume is accessible and has not been deleted before retrying with exponential back off. |
| Volume in use | 9 FAILED_PRECONDITION | Indicates that the volume corresponding to the specified `volume_id` could not be expanded because it is currently published on a node but the plugin does not have ONLINE expansion capability. | Caller SHOULD ensure that volume is not published and retry with exponential back off. |
| Unsupported `capacity_range` | 11 OUT_OF_RANGE | Indicates that the capacity range is not allowed by the Plugin. More human-readable information MAY be provided in the gRPC `status.message` field. | Caller MUST fix the capacity range before retrying. |
#### RPC Interactions
##### `CreateVolume`, `DeleteVolume`, `ListVolumes`
@ -1802,7 +1930,7 @@ The CO MUST implement the specified error recovery behavior when it encounters t
| Condition | gRPC Code | Description | Recovery Behavior |
|-----------|-----------|-------------|-------------------|
| Volume does not exist | 5 NOT_FOUND | Indicates that a volume corresponding to the specified `volume_id` does not exist. | Caller MUST verify that the `volume_id` is correct and that the volume is accessible and has not been deleted before retrying with exponential back off. |
| Volume published but is incompatible | 6 ALREADY_EXISTS | Indicates that a volume corresponding to the specified `volume_id` has already been published at the specified `staging_target_path` but is incompatible with the specified `volume_capability` flag. | Caller MUST fix the arguments before retying. |
| Volume published but is incompatible | 6 ALREADY_EXISTS | Indicates that a volume corresponding to the specified `volume_id` has already been published at the specified `staging_target_path` but is incompatible with the specified `volume_capability` flag. | Caller MUST fix the arguments before retrying. |
| Exceeds capabilities | 9 FAILED_PRECONDITION | Indicates that the CO has exceeded the volume's capabilities because the volume does not have MULTI_NODE capability. | Caller MAY choose to call `ValidateVolumeCapabilities` to validate the volume capabilities, or wait for the volume to be unpublished on the node. |
#### `NodeUnstageVolume`
@ -1951,7 +2079,7 @@ The CO MUST implement the specified error recovery behavior when it encounters t
| Condition | gRPC Code | Description | Recovery Behavior |
|-----------|-----------|-------------|-------------------|
| Volume does not exist | 5 NOT_FOUND | Indicates that a volume corresponding to the specified `volume_id` does not exist. | Caller MUST verify that the `volume_id` is correct and that the volume is accessible and has not been deleted before retrying with exponential back off. |
| Volume published but is incompatible | 6 ALREADY_EXISTS | Indicates that a volume corresponding to the specified `volume_id` has already been published at the specified `target_path` but is incompatible with the specified `volume_capability` or `readonly` flag. | Caller MUST fix the arguments before retying. |
| Volume published but is incompatible | 6 ALREADY_EXISTS | Indicates that a volume corresponding to the specified `volume_id` has already been published at the specified `target_path` but is incompatible with the specified `volume_capability` or `readonly` flag. | Caller MUST fix the arguments before retrying. |
| Exceeds capabilities | 9 FAILED_PRECONDITION | Indicates that the CO has exceeded the volume's capabilities because the volume does not have MULTI_NODE capability. | Caller MAY choose to call `ValidateVolumeCapabilities` to validate the volume capabilities, or wait for the volume to be unpublished on the node. |
| Staging target path not set | 9 FAILED_PRECONDITION | Indicates that `STAGE_UNSTAGE_VOLUME` capability is set but no `staging_target_path` was set. | Caller MUST make sure call to `NodeStageVolume` is made and returns success before retrying with valid `staging_target_path`. |
@ -2085,6 +2213,8 @@ message NodeServiceCapability {
// then it MUST implement NodeGetVolumeStats RPC
// call for fetching volume statistics.
GET_VOLUME_STATS = 2;
// See VolumeExpansion for details.
EXPAND_VOLUME = 3;
}
Type type = 1;
@ -2101,7 +2231,6 @@ message NodeServiceCapability {
If the plugin is unable to complete the NodeGetCapabilities call successfully, it MUST return a non-ok gRPC code in the gRPC status.
#### `NodeGetInfo`
A Node Plugin MUST implement this RPC call if the plugin has `PUBLISH_UNPUBLISH_VOLUME` controller capability.
@ -2147,7 +2276,7 @@ message NodeGetInfoResponse {
//
// Example 1:
// accessible_topology =
// {"region": "R1", "zone": "R2"}
// {"region": "R1", "zone": "Z2"}
// Indicates the node exists within the "region" "R1" and the "zone"
// "Z2".
Topology accessible_topology = 3;
@ -2159,6 +2288,52 @@ message NodeGetInfoResponse {
If the plugin is unable to complete the NodeGetInfo call successfully, it MUST return a non-ok gRPC code in the gRPC status.
The CO MUST implement the specified error recovery behavior when it encounters the gRPC error code.
#### `NodeExpandVolume`
A Node Plugin MUST implement this RPC call if it has `EXPAND_VOLUME` node capability.
This RPC call allows CO to expand volume on a node.
`NodeExpandVolume` ONLY supports expansion of already node-published or node-staged volumes on the given `volume_path`.
If plugin has `STAGE_UNSTAGE_VOLUME` node capability then:
* `NodeExpandVolume` MUST be called after successful `NodeStageVolume`.
* `NodeExpandVolume` MAY be called before or after `NodePublishVolume`.
Otherwise `NodeExpandVolume` MUST be called after successful `NodePublishVolume`.
If a plugin only supports expansion via the `VolumeExpansion.OFFLINE` capability, then the volume MUST first be taken offline and expanded via `ControllerExpandVolume` (see `ControllerExpandVolume` for more details), and then node-staged or node-published before it can be expanded on the node via `NodeExpandVolume`.
```protobuf
message NodeExpandVolumeRequest {
// The ID of the volume. This field is REQUIRED.
string volume_id = 1;
// The path on which volume is available. This field is REQUIRED.
string volume_path = 2;
// This allows CO to specify the capacity requirements of the volume
// after expansion. If capacity_range is omitted then a plugin MAY
// inspect the file system of the volume to determine the maximum
// capacity to which the volume can be expanded. In such cases a
// plugin MAY expand the volume to its maximum capacity.
// This field is OPTIONAL.
CapacityRange capacity_range = 3;
}
message NodeExpandVolumeResponse {
// The capacity of the volume in bytes. This field is OPTIONAL.
int64 capacity_bytes = 1;
}
```
##### NodeExpandVolume Errors
| Condition | gRPC code | Description | Recovery Behavior |
|-----------------------|-----------|-----------------------|-----------------------------------|
| Volume does not exist | 5 NOT FOUND | Indicates that a volume corresponding to the specified volume_id does not exist. | Caller MUST verify that the volume_id is correct and that the volume is accessible and has not been deleted before retrying with exponential back off. |
| Volume in use | 9 FAILED_PRECONDITION | Indicates that the volume corresponding to the specified `volume_id` could not be expanded because it is node-published or node-staged and the underlying filesystem does not support expansion of published or staged volumes. | Caller MUST NOT retry. |
| Unsupported capacity_range | 11 OUT_OF_RANGE | Indicates that the capacity range is not allowed by the Plugin. More human-readable information MAY be provided in the gRPC `status.message` field. | Caller MUST fix the capacity range before retrying. |
## Protocol
### Connectivity

View file

@ -1,15 +1,24 @@
language: go
go:
- 1.10.x
- tip
- 1.11.x
install:
- mkdir -p $GOPATH/src/github.com/prometheus $GOPATH/src/github.com/opencontainers
- mkdir -p $GOPATH/src/github.com/prometheus $GOPATH/src/github.com/opencontainers $GOPATH/src/github.com/coreos $GOPATH/src/github.com/godbus
- cd $GOPATH/src/github.com/opencontainers && git clone https://github.com/opencontainers/runtime-spec && cd runtime-spec && git checkout fa4b36aa9c99e00c2ef7b5c0013c84100ede5f4e
- cd $GOPATH/src/github.com/coreos && git clone https://github.com/coreos/go-systemd && cd go-systemd && git checkout 48702e0da86bd25e76cfef347e2adeb434a0d0a6
- cd $GOPATH/src/github.com/godbus && git clone https://github.com/godbus/dbus && cd dbus && git checkout c7fdd8b5cd55e87b4e1f4e372cdb1db61dd6c66f
- cd $GOPATH/src/github.com/containerd/cgroups
- go get -t ./...
- go get -d -t ./...
- go get -u github.com/vbatts/git-validation
- go get -u github.com/kunalkushwaha/ltag
before_script:
- pushd ..; git clone https://github.com/containerd/project; popd
script:
- DCO_VERBOSITY=-q ../project/script/validate/dco
- ../project/script/validate/fileheader ../project/
- go test -race -coverprofile=coverage.txt -covermode=atomic
after_success:

View file

@ -1,8 +1,9 @@
# cgroups
[![Build Status](https://travis-ci.org/containerd/cgroups.svg?branch=master)](https://travis-ci.org/containerd/cgroups)
[![codecov](https://codecov.io/gh/containerd/cgroups/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/cgroups)
[![GoDoc](https://godoc.org/github.com/containerd/cgroups?status.svg)](https://godoc.org/github.com/containerd/cgroups)
[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/cgroups)](https://goreportcard.com/report/github.com/containerd/cgroups)
Go package for creating, managing, inspecting, and destroying cgroups.
The resources format for settings on the cgroup uses the OCI runtime-spec found
@ -110,3 +111,14 @@ err := control.MoveTo(destination)
```go
subCgroup, err := control.New("child", resources)
```
## Project details
Cgroups is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
As a containerd sub-project, you will find the:
* [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md),
* [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS),
* and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md)
information in our [`containerd/project`](https://github.com/containerd/project) repository.

View file

@ -191,31 +191,42 @@ func (b *blkioController) readEntry(devices map[deviceKey]string, path, name str
}
func createBlkioSettings(blkio *specs.LinuxBlockIO) []blkioSettings {
settings := []blkioSettings{
{
name: "weight",
value: blkio.Weight,
format: uintf,
},
{
name: "leaf_weight",
value: blkio.LeafWeight,
format: uintf,
},
}
for _, wd := range blkio.WeightDevice {
settings := []blkioSettings{}
if blkio.Weight != nil {
settings = append(settings,
blkioSettings{
name: "weight_device",
value: wd,
format: weightdev,
},
blkioSettings{
name: "leaf_weight_device",
value: wd,
format: weightleafdev,
name: "weight",
value: blkio.Weight,
format: uintf,
})
}
if blkio.LeafWeight != nil {
settings = append(settings,
blkioSettings{
name: "leaf_weight",
value: blkio.LeafWeight,
format: uintf,
})
}
for _, wd := range blkio.WeightDevice {
if wd.Weight != nil {
settings = append(settings,
blkioSettings{
name: "weight_device",
value: wd,
format: weightdev,
})
}
if wd.LeafWeight != nil {
settings = append(settings,
blkioSettings{
name: "leaf_weight_device",
value: wd,
format: weightleafdev,
})
}
}
for _, t := range []struct {
name string
list []specs.LinuxThrottleDevice
@ -265,12 +276,12 @@ func uintf(v interface{}) []byte {
func weightdev(v interface{}) []byte {
wd := v.(specs.LinuxWeightDevice)
return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, wd.Weight))
return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, *wd.Weight))
}
func weightleafdev(v interface{}) []byte {
wd := v.(specs.LinuxWeightDevice)
return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, wd.LeafWeight))
return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, *wd.LeafWeight))
}
func throttleddev(v interface{}) []byte {

View file

@ -30,47 +30,88 @@ import (
)
// New returns a new control via the cgroup cgroups interface
func New(hierarchy Hierarchy, path Path, resources *specs.LinuxResources) (Cgroup, error) {
func New(hierarchy Hierarchy, path Path, resources *specs.LinuxResources, opts ...InitOpts) (Cgroup, error) {
config := newInitConfig()
for _, o := range opts {
if err := o(config); err != nil {
return nil, err
}
}
subsystems, err := hierarchy()
if err != nil {
return nil, err
}
var active []Subsystem
for _, s := range subsystems {
// check if subsystem exists
if err := initializeSubsystem(s, path, resources); err != nil {
if err == ErrControllerNotActive {
if config.InitCheck != nil {
if skerr := config.InitCheck(s, path, err); skerr != nil {
if skerr != ErrIgnoreSubsystem {
return nil, skerr
}
}
}
continue
}
return nil, err
}
active = append(active, s)
}
return &cgroup{
path: path,
subsystems: subsystems,
subsystems: active,
}, nil
}
// Load will load an existing cgroup and allow it to be controlled
func Load(hierarchy Hierarchy, path Path) (Cgroup, error) {
func Load(hierarchy Hierarchy, path Path, opts ...InitOpts) (Cgroup, error) {
config := newInitConfig()
for _, o := range opts {
if err := o(config); err != nil {
return nil, err
}
}
var activeSubsystems []Subsystem
subsystems, err := hierarchy()
if err != nil {
return nil, err
}
// check the the subsystems still exist
// check that the subsystems still exist, and keep only those that actually exist
for _, s := range pathers(subsystems) {
p, err := path(s.Name())
if err != nil {
if os.IsNotExist(errors.Cause(err)) {
return nil, ErrCgroupDeleted
}
if err == ErrControllerNotActive {
if config.InitCheck != nil {
if skerr := config.InitCheck(s, path, err); skerr != nil {
if skerr != ErrIgnoreSubsystem {
return nil, skerr
}
}
}
continue
}
return nil, err
}
if _, err := os.Lstat(s.Path(p)); err != nil {
if os.IsNotExist(err) {
return nil, ErrCgroupDeleted
continue
}
return nil, err
}
activeSubsystems = append(activeSubsystems, s)
}
// if we do not have any active systems then the cgroup is deleted
if len(activeSubsystems) == 0 {
return nil, ErrCgroupDeleted
}
return &cgroup{
path: path,
subsystems: subsystems,
subsystems: activeSubsystems,
}, nil
}
@ -319,6 +360,49 @@ func (c *cgroup) processes(subsystem Name, recursive bool) ([]Process, error) {
return processes, err
}
// Tasks returns the tasks running inside the cgroup along
// with the subsystem used, pid, and path
func (c *cgroup) Tasks(subsystem Name, recursive bool) ([]Task, error) {
c.mu.Lock()
defer c.mu.Unlock()
if c.err != nil {
return nil, c.err
}
return c.tasks(subsystem, recursive)
}
func (c *cgroup) tasks(subsystem Name, recursive bool) ([]Task, error) {
s := c.getSubsystem(subsystem)
sp, err := c.path(subsystem)
if err != nil {
return nil, err
}
path := s.(pather).Path(sp)
var tasks []Task
err = filepath.Walk(path, func(p string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !recursive && info.IsDir() {
if p == path {
return nil
}
return filepath.SkipDir
}
dir, name := filepath.Split(p)
if name != cgroupTasks {
return nil
}
procs, err := readTasksPids(dir, subsystem)
if err != nil {
return err
}
tasks = append(tasks, procs...)
return nil
})
return tasks, err
}
// Freeze freezes the entire cgroup and all the processes inside it
func (c *cgroup) Freeze() error {
c.mu.Lock()

View file

@ -44,6 +44,15 @@ type Process struct {
Path string
}
type Task struct {
// Subsystem is the name of the subsystem that the task is in
Subsystem Name
// Pid is the process id of the task
Pid int
// Path is the full path of the subsystem and location that the task is in
Path string
}
// Cgroup handles interactions with the individual groups to perform
// actions on them as them main interface to this cgroup package
type Cgroup interface {
@ -64,6 +73,8 @@ type Cgroup interface {
Update(resources *specs.LinuxResources) error
// Processes returns all the processes in a select subsystem for the cgroup
Processes(Name, bool) ([]Process, error)
// Tasks returns all the tasks in a select subsystem for the cgroup
Tasks(Name, bool) ([]Task, error)
// Freeze freezes or pauses all processes inside the cgroup
Freeze() error
// Thaw thaw or resumes all processes inside the cgroup

View file

@ -57,21 +57,21 @@ func (c *cpusetController) Create(path string, resources *specs.LinuxResources)
if resources.CPU != nil {
for _, t := range []struct {
name string
value *string
value string
}{
{
name: "cpus",
value: &resources.CPU.Cpus,
value: resources.CPU.Cpus,
},
{
name: "mems",
value: &resources.CPU.Mems,
value: resources.CPU.Mems,
},
} {
if t.value != nil {
if t.value != "" {
if err := ioutil.WriteFile(
filepath.Join(c.Path(path), fmt.Sprintf("cpuset.%s", t.name)),
[]byte(*t.value),
[]byte(t.value),
defaultFilePerm,
); err != nil {
return err

View file

@ -58,6 +58,9 @@ func (d *devicesController) Create(path string, resources *specs.LinuxResources)
if device.Allow {
file = allowDeviceFile
}
if device.Type == "" {
device.Type = "a"
}
if err := ioutil.WriteFile(
filepath.Join(d.Path(path), file),
[]byte(deviceString(device)),

View file

@ -50,7 +50,7 @@ func (n *netprioController) Create(path string, resources *specs.LinuxResources)
if resources.Network != nil {
for _, prio := range resources.Network.Priorities {
if err := ioutil.WriteFile(
filepath.Join(n.Path(path), "net_prio_ifpriomap"),
filepath.Join(n.Path(path), "net_prio.ifpriomap"),
formatPrio(prio.Name, prio.Priority),
defaultFilePerm,
); err != nil {

61
vendor/github.com/containerd/cgroups/opts.go generated vendored Normal file
View file

@ -0,0 +1,61 @@
/*
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 cgroups
import (
"github.com/pkg/errors"
)
var (
// ErrIgnoreSubsystem allows the specific subsystem to be skipped
ErrIgnoreSubsystem = errors.New("skip subsystem")
// ErrDevicesRequired is returned when the devices subsystem is required but
// does not exist or is not active
ErrDevicesRequired = errors.New("devices subsystem is required")
)
// InitOpts allows configuration for the creation or loading of a cgroup
type InitOpts func(*InitConfig) error
// InitConfig provides configuration options for the creation
// or loading of a cgroup and its subsystems
type InitConfig struct {
// InitCheck can be used to check initialization errors from the subsystem
InitCheck InitCheck
}
func newInitConfig() *InitConfig {
return &InitConfig{
InitCheck: RequireDevices,
}
}
// InitCheck allows subsystems errors to be checked when initialized or loaded
type InitCheck func(Subsystem, Path, error) error
// AllowAny allows any subsystem errors to be skipped
func AllowAny(s Subsystem, p Path, err error) error {
return ErrIgnoreSubsystem
}
// RequireDevices requires the device subsystem but no others
func RequireDevices(s Subsystem, p Path, err error) error {
if s.Name() == Devices {
return ErrDevicesRequired
}
return ErrIgnoreSubsystem
}

View file

@ -57,6 +57,9 @@ func PidPath(pid int) Path {
return existingPath(paths, "")
}
// ErrControllerNotActive is returned when a controller is not supported or enabled
var ErrControllerNotActive = errors.New("controller is not supported")
func existingPath(paths map[string]string, suffix string) Path {
// localize the paths based on the root mount dest for nested cgroups
for n, p := range paths {
@ -77,7 +80,7 @@ func existingPath(paths map[string]string, suffix string) Path {
root, ok := paths[string(name)]
if !ok {
if root, ok = paths[fmt.Sprintf("name=%s", name)]; !ok {
return "", fmt.Errorf("unable to find %q in controller set", name)
return "", ErrControllerNotActive
}
}
if suffix != "" {

View file

@ -42,7 +42,7 @@ const (
)
// Subsystems returns a complete list of the default cgroups
// avaliable on most linux systems
// available on most linux systems
func Subsystems() []Name {
n := []Name{
Hugetlb,

View file

@ -32,6 +32,11 @@ const (
defaultSlice = "system.slice"
)
var (
canDelegate bool
once sync.Once
)
func Systemd() ([]Subsystem, error) {
root, err := v1MountPoint()
if err != nil {
@ -54,7 +59,7 @@ func Slice(slice, name string) Path {
slice = defaultSlice
}
return func(subsystem Name) (string, error) {
return filepath.Join(slice, unitName(name)), nil
return filepath.Join(slice, name), nil
}
}
@ -80,15 +85,39 @@ func (s *SystemdController) Create(path string, resources *specs.LinuxResources)
}
defer conn.Close()
slice, name := splitName(path)
// We need to see if systemd can handle the delegate property
// Systemd will return an error if it cannot handle delegate regardless
// of its bool setting.
checkDelegate := func() {
canDelegate = true
dlSlice := newProperty("Delegate", true)
if _, err := conn.StartTransientUnit(slice, "testdelegate", []systemdDbus.Property{dlSlice}, nil); err != nil {
if dbusError, ok := err.(dbus.Error); ok {
// Starting with systemd v237, Delegate is not even a property of slices anymore,
// so the D-Bus call fails with "InvalidArgs" error.
if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") || strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.InvalidArgs") {
canDelegate = false
}
}
}
conn.StopUnit(slice, "testDelegate", nil)
}
once.Do(checkDelegate)
properties := []systemdDbus.Property{
systemdDbus.PropDescription(fmt.Sprintf("cgroup %s", name)),
systemdDbus.PropWants(slice),
newProperty("DefaultDependencies", false),
newProperty("Delegate", true),
newProperty("MemoryAccounting", true),
newProperty("CPUAccounting", true),
newProperty("BlockIOAccounting", true),
}
// If we can delegate, we add the property back in
if canDelegate {
properties = append(properties, newProperty("Delegate", true))
}
ch := make(chan string)
_, err = conn.StartTransientUnit(name, "replace", properties, ch)
if err != nil {

View file

@ -111,7 +111,7 @@ func remove(path string) error {
return fmt.Errorf("cgroups: unable to remove path %q", path)
}
// readPids will read all the pids in a cgroup by the provided path
// readPids will read all the pids of processes in a cgroup by the provided path
func readPids(path string, subsystem Name) ([]Process, error) {
f, err := os.Open(filepath.Join(path, cgroupProcs))
if err != nil {
@ -138,6 +138,33 @@ func readPids(path string, subsystem Name) ([]Process, error) {
return out, nil
}
// readTasksPids will read all the pids of tasks in a cgroup by the provided path
func readTasksPids(path string, subsystem Name) ([]Task, error) {
f, err := os.Open(filepath.Join(path, cgroupTasks))
if err != nil {
return nil, err
}
defer f.Close()
var (
out []Task
s = bufio.NewScanner(f)
)
for s.Scan() {
if t := s.Text(); t != "" {
pid, err := strconv.Atoi(t)
if err != nil {
return nil, err
}
out = append(out, Task{
Pid: pid,
Subsystem: subsystem,
Path: path,
})
}
}
return out, nil
}
func hugePageSizes() ([]string, error) {
var (
pageSizes []string

View file

@ -13,7 +13,7 @@ environment:
GOPATH: C:\gopath
CGO_ENABLED: 1
matrix:
- GO_VERSION: 1.10
- GO_VERSION: 1.11
before_build:
- choco install -y mingw --version 5.3.0

View file

@ -2,7 +2,9 @@ Abhinandan Prativadi <abhi@docker.com> Abhinandan Prativadi <aprativadi@gmail.co
Abhinandan Prativadi <abhi@docker.com> abhi <abhi@docker.com>
Akihiro Suda <suda.akihiro@lab.ntt.co.jp> Akihiro Suda <suda.kyoto@gmail.com>
Andrei Vagin <avagin@virtuozzo.com> Andrei Vagin <avagin@openvz.org>
Brent Baude <bbaude@redhat.com> baude <bbaude@redhat.com>
Frank Yang <yyb196@gmail.com> frank yang <yyb196@gmail.com>
Georgia Panoutsakopoulou <gpanoutsak@gmail.com> gpanouts <gpanoutsak@gmail.com>
Jie Zhang <iamkadisi@163.com> kadisi <iamkadisi@163.com>
John Howard <john.howard@microsoft.com> John Howard <jhoward@microsoft.com>
Justin Terry <juterry@microsoft.com> Justin Terry (VM) <juterry@microsoft.com>

View file

@ -7,7 +7,7 @@ services:
language: go
go:
- "1.10.x"
- "1.11.x"
go_import_path: github.com/containerd/containerd

View file

@ -22,6 +22,7 @@ DESTDIR=/usr/local
# Used to populate variables in version package.
VERSION=$(shell git describe --match 'v[0-9]*' --dirty='.m' --always)
REVISION=$(shell git rev-parse HEAD)$(shell if ! git diff --no-ext-diff --quiet --exit-code; then echo .m; fi)
PACKAGE=github.com/containerd/containerd
ifneq "$(strip $(shell command -v go 2>/dev/null))" ""
GOOS ?= $(shell go env GOOS)
@ -77,8 +78,8 @@ MANPAGES=ctr.1 containerd.1 containerd-config.1 containerd-config.toml.5
# Build tags seccomp and apparmor are needed by CRI plugin.
BUILDTAGS ?= seccomp apparmor
GO_TAGS=$(if $(BUILDTAGS),-tags "$(BUILDTAGS)",)
GO_LDFLAGS=-ldflags '-s -w -X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PKG) $(EXTRA_LDFLAGS)'
SHIM_GO_LDFLAGS=-ldflags '-s -w -X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PKG) -extldflags "-static"'
GO_LDFLAGS=-ldflags '-s -w -X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PACKAGE) $(EXTRA_LDFLAGS)'
SHIM_GO_LDFLAGS=-ldflags '-s -w -X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PACKAGE) -extldflags "-static"'
#Replaces ":" (*nix), ";" (windows) with newline for easy parsing
GOPATHS=$(shell echo ${GOPATH} | tr ":" "\n" | tr ";" "\n")

View file

@ -194,7 +194,7 @@ func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyO
parentPath = filepath.Dir(path)
}
if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) {
err = mkdirAll(parentPath, 0700)
err = mkdirAll(parentPath, 0755)
if err != nil {
return 0, err
}

View file

@ -7,19 +7,19 @@
#
# Install proto3
FROM golang:1.10 AS proto3
FROM golang:1.11 AS proto3
RUN apt-get update && apt-get install -y autoconf automake g++ libtool unzip
COPY script/setup/install-protobuf install-protobuf
RUN ./install-protobuf
# Install runc
FROM golang:1.10 AS runc
FROM golang:1.11 AS runc
RUN apt-get update && apt-get install -y curl libseccomp-dev
COPY vendor.conf /go/src/github.com/containerd/containerd/vendor.conf
COPY script/setup/install-runc install-runc
RUN ./install-runc
FROM golang:1.10
FROM golang:1.11
RUN apt-get update && apt-get install -y btrfs-tools gcc git libseccomp-dev make xfsprogs
COPY --from=proto3 /usr/local/bin/protoc /usr/local/bin/protoc

View file

@ -161,6 +161,7 @@ func DefaultProfile(sp *specs.Spec) *specs.LinuxSeccomp {
"ioctl",
"io_destroy",
"io_getevents",
"io_pgetevents",
"ioprio_get",
"ioprio_set",
"io_setup",
@ -319,6 +320,7 @@ func DefaultProfile(sp *specs.Spec) *specs.LinuxSeccomp {
"stat64",
"statfs",
"statfs64",
"statx",
"symlink",
"symlinkat",
"sync",

View file

@ -170,26 +170,22 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string) error {
chain = append(chain, layer.Diff.Digest)
}
if unpacked {
desc, err := i.i.Config(ctx, cs, i.platform)
if err != nil {
return err
}
rootfs := identity.ChainID(chain).String()
cinfo := content.Info{
Digest: desc.Digest,
Labels: map[string]string{
fmt.Sprintf("containerd.io/gc.ref.snapshot.%s", snapshotterName): rootfs,
},
}
if _, err := cs.Update(ctx, cinfo, fmt.Sprintf("labels.containerd.io/gc.ref.snapshot.%s", snapshotterName)); err != nil {
return err
}
desc, err := i.i.Config(ctx, cs, i.platform)
if err != nil {
return err
}
return nil
rootfs := identity.ChainID(chain).String()
cinfo := content.Info{
Digest: desc.Digest,
Labels: map[string]string{
fmt.Sprintf("containerd.io/gc.ref.snapshot.%s", snapshotterName): rootfs,
},
}
_, err = cs.Update(ctx, cinfo, fmt.Sprintf("labels.containerd.io/gc.ref.snapshot.%s", snapshotterName))
return err
}
func (i *image) getLayers(ctx context.Context, platform platforms.MatchComparer) ([]rootfs.Layer, error) {

View file

@ -64,6 +64,18 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
// iterate through each namespace
v1c := v1bkt.Cursor()
// cerr indicates the scan did not successfully send all
// the roots. The scan does not need to be cancelled but
// must return error at the end.
var cerr error
fn := func(n gc.Node) {
select {
case nc <- n:
case <-ctx.Done():
cerr = ctx.Err()
}
}
for k, v := v1c.First(); k != nil; k, v = v1c.Next() {
if v != nil {
continue
@ -92,11 +104,7 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
}
}
select {
case nc <- gcnode(ResourceLease, ns, string(k)):
case <-ctx.Done():
return ctx.Err()
}
fn(gcnode(ResourceLease, ns, string(k)))
// Emit content and snapshots as roots instead of implementing
// in references. Since leases cannot be referenced there is
@ -106,11 +114,7 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
cbkt := libkt.Bucket(bucketKeyObjectContent)
if cbkt != nil {
if err := cbkt.ForEach(func(k, v []byte) error {
select {
case nc <- gcnode(ResourceContent, ns, string(k)):
case <-ctx.Done():
return ctx.Err()
}
fn(gcnode(ResourceContent, ns, string(k)))
return nil
}); err != nil {
return err
@ -126,11 +130,7 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
snbkt := sbkt.Bucket(sk)
return snbkt.ForEach(func(k, v []byte) error {
select {
case nc <- gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", sk, k)):
case <-ctx.Done():
return ctx.Err()
}
fn(gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", sk, k)))
return nil
})
}); err != nil {
@ -141,11 +141,7 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
ibkt := libkt.Bucket(bucketKeyObjectIngests)
if ibkt != nil {
if err := ibkt.ForEach(func(k, v []byte) error {
select {
case nc <- gcnode(ResourceIngest, ns, string(k)):
case <-ctx.Done():
return ctx.Err()
}
fn(gcnode(ResourceIngest, ns, string(k)))
return nil
}); err != nil {
return err
@ -168,18 +164,9 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
target := ibkt.Bucket(k).Bucket(bucketKeyTarget)
if target != nil {
contentKey := string(target.Get(bucketKeyDigest))
select {
case nc <- gcnode(ResourceContent, ns, contentKey):
case <-ctx.Done():
return ctx.Err()
}
fn(gcnode(ResourceContent, ns, contentKey))
}
return sendSnapshotRefs(ns, ibkt.Bucket(k), func(n gc.Node) {
select {
case nc <- n:
case <-ctx.Done():
}
})
return sendLabelRefs(ns, ibkt.Bucket(k), fn)
}); err != nil {
return err
}
@ -200,11 +187,7 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
if ea == nil || expThreshold.After(*ea) {
return nil
}
select {
case nc <- gcnode(ResourceIngest, ns, string(k)):
case <-ctx.Done():
return ctx.Err()
}
fn(gcnode(ResourceIngest, ns, string(k)))
return nil
}); err != nil {
return err
@ -216,7 +199,12 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
if v != nil {
return nil
}
return sendRootRef(ctx, nc, gcnode(ResourceContent, ns, string(k)), cbkt.Bucket(k))
if isRootRef(cbkt.Bucket(k)) {
fn(gcnode(ResourceContent, ns, string(k)))
}
return nil
}); err != nil {
return err
}
@ -229,23 +217,15 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
if v != nil {
return nil
}
snapshotter := string(cbkt.Bucket(k).Get(bucketKeySnapshotter))
cibkt := cbkt.Bucket(k)
snapshotter := string(cibkt.Get(bucketKeySnapshotter))
if snapshotter != "" {
ss := string(cbkt.Bucket(k).Get(bucketKeySnapshotKey))
select {
case nc <- gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", snapshotter, ss)):
case <-ctx.Done():
return ctx.Err()
}
ss := string(cibkt.Get(bucketKeySnapshotKey))
fn(gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", snapshotter, ss)))
}
// TODO: Send additional snapshot refs through labels
return sendSnapshotRefs(ns, cbkt.Bucket(k), func(n gc.Node) {
select {
case nc <- n:
case <-ctx.Done():
}
})
return sendLabelRefs(ns, cibkt, fn)
}); err != nil {
return err
}
@ -263,15 +243,17 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
if v != nil {
return nil
}
return sendRootRef(ctx, nc, gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", sk, k)), snbkt.Bucket(k))
if isRootRef(snbkt.Bucket(k)) {
fn(gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", sk, k)))
}
return nil
})
}); err != nil {
return err
}
}
}
return nil
return cerr
}
func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)) error {
@ -282,10 +264,7 @@ func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)
return nil
}
if err := sendSnapshotRefs(node.Namespace, bkt, fn); err != nil {
return err
}
return sendContentRefs(node.Namespace, bkt, fn)
return sendLabelRefs(node.Namespace, bkt, fn)
} else if node.Type == ResourceSnapshot {
parts := strings.SplitN(node.Key, "/", 2)
if len(parts) != 2 {
@ -304,7 +283,7 @@ func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)
fn(gcnode(ResourceSnapshot, node.Namespace, fmt.Sprintf("%s/%s", ss, pv)))
}
return sendSnapshotRefs(node.Namespace, bkt, fn)
return sendLabelRefs(node.Namespace, bkt, fn)
} else if node.Type == ResourceIngest {
// Send expected value
bkt := getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectContent, bucketKeyObjectIngests, []byte(node.Key))
@ -456,25 +435,8 @@ func remove(ctx context.Context, tx *bolt.Tx, node gc.Node) error {
return nil
}
// sendSnapshotRefs sends all snapshot references referred to by the labels in the bkt
func sendSnapshotRefs(ns string, bkt *bolt.Bucket, fn func(gc.Node)) error {
lbkt := bkt.Bucket(bucketKeyObjectLabels)
if lbkt != nil {
lc := lbkt.Cursor()
for k, v := lc.Seek(labelGCSnapRef); k != nil && strings.HasPrefix(string(k), string(labelGCSnapRef)); k, v = lc.Next() {
snapshotter := k[len(labelGCSnapRef):]
if i := bytes.IndexByte(snapshotter, '/'); i >= 0 {
snapshotter = snapshotter[:i]
}
fn(gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", snapshotter, v)))
}
}
return nil
}
// sendContentRefs sends all content references referred to by the labels in the bkt
func sendContentRefs(ns string, bkt *bolt.Bucket, fn func(gc.Node)) error {
// sendLabelRefs sends all snapshot and content references referred to by the labels in the bkt
func sendLabelRefs(ns string, bkt *bolt.Bucket, fn func(gc.Node)) error {
lbkt := bkt.Bucket(bucketKeyObjectLabels)
if lbkt != nil {
lc := lbkt.Cursor()
@ -490,6 +452,15 @@ func sendContentRefs(ns string, bkt *bolt.Bucket, fn func(gc.Node)) error {
fn(gcnode(ResourceContent, ns, string(v)))
}
for k, v := lc.Seek(labelGCSnapRef); k != nil && strings.HasPrefix(string(k), string(labelGCSnapRef)); k, v = lc.Next() {
snapshotter := k[len(labelGCSnapRef):]
if i := bytes.IndexByte(snapshotter, '/'); i >= 0 {
snapshotter = snapshotter[:i]
}
fn(gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", snapshotter, v)))
}
}
return nil
}
@ -506,17 +477,6 @@ func isRootRef(bkt *bolt.Bucket) bool {
return false
}
func sendRootRef(ctx context.Context, nc chan<- gc.Node, n gc.Node, bkt *bolt.Bucket) error {
if isRootRef(bkt) {
select {
case nc <- n:
case <-ctx.Done():
return ctx.Err()
}
}
return nil
}
func gcnode(t gc.ResourceType, ns, key string) gc.Node {
return gc.Node{
Type: t,

View file

@ -25,6 +25,8 @@ import (
"os"
"strconv"
"strings"
"github.com/pkg/errors"
)
// Self retrieves a list of mounts for the current running process.
@ -41,13 +43,15 @@ func Self() ([]Info, error) {
func parseInfoFile(r io.Reader) ([]Info, error) {
s := bufio.NewScanner(r)
out := []Info{}
var err error
for s.Scan() {
if err := s.Err(); err != nil {
if err = s.Err(); err != nil {
return nil, err
}
/*
See http://man7.org/linux/man-pages/man5/proc.5.html
36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
(1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
(1) mount ID: unique identifier of the mount (may be reused after umount)
@ -68,7 +72,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, errors.Errorf("parsing '%s' failed: not enough fields (%d)", text, numFields)
}
p := Info{}
// ignore any numbers parsing errors, as there should not be any
@ -76,13 +80,19 @@ 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, errors.Errorf("parsing '%s' failed: unexpected minor:major pair %s", text, mm)
}
p.Major, _ = strconv.Atoi(mm[0])
p.Minor, _ = strconv.Atoi(mm[1])
p.Root = fields[3]
p.Mountpoint = fields[4]
p.Root, err = strconv.Unquote(`"` + fields[3] + `"`)
if err != nil {
return nil, errors.Wrapf(err, "parsing '%s' failed: unable to unquote root field", fields[3])
}
p.Mountpoint, err = strconv.Unquote(`"` + fields[4] + `"`)
if err != nil {
return nil, errors.Wrapf(err, "parsing '%s' failed: unable to unquote mount point field", fields[4])
}
p.Options = fields[5]
// one or more optional fields, when a separator (-)
@ -101,11 +111,11 @@ func parseInfoFile(r io.Reader) ([]Info, error) {
}
}
if i == numFields {
return nil, fmt.Errorf("parsing '%s' failed: missing separator ('-')", text)
return nil, errors.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, errors.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

View file

@ -733,7 +733,9 @@ func WithCapabilities(caps []string) SpecOpts {
}
// WithAllCapabilities sets all linux capabilities for the process
var WithAllCapabilities = WithCapabilities(getAllCapabilities())
var WithAllCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
return WithCapabilities(getAllCapabilities())(ctx, client, c, s)
}
func getAllCapabilities() []string {
last := capability.CAP_LAST_CAP

View file

@ -24,8 +24,10 @@ import (
"io"
"os"
"sync"
"sync/atomic"
"syscall"
"github.com/containerd/containerd/log"
"github.com/containerd/fifo"
runc "github.com/containerd/go-runc"
)
@ -38,7 +40,7 @@ var bufPool = sync.Pool{
}
func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, wg, cwg *sync.WaitGroup) error {
var sameFile io.WriteCloser
var sameFile *countingWriteCloser
for _, i := range []struct {
name string
dest func(wc io.WriteCloser, rc io.Closer)
@ -52,7 +54,9 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
cwg.Done()
p := bufPool.Get().(*[]byte)
defer bufPool.Put(p)
io.CopyBuffer(wc, rio.Stdout(), *p)
if _, err := io.CopyBuffer(wc, rio.Stdout(), *p); err != nil {
log.G(ctx).Warn("error copying stdout")
}
wg.Done()
wc.Close()
if rc != nil {
@ -69,7 +73,9 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
cwg.Done()
p := bufPool.Get().(*[]byte)
defer bufPool.Put(p)
io.CopyBuffer(wc, rio.Stderr(), *p)
if _, err := io.CopyBuffer(wc, rio.Stderr(), *p); err != nil {
log.G(ctx).Warn("error copying stderr")
}
wg.Done()
wc.Close()
if rc != nil {
@ -96,6 +102,7 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
}
} else {
if sameFile != nil {
sameFile.count++
i.dest(sameFile, nil)
continue
}
@ -103,7 +110,10 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
return fmt.Errorf("containerd-shim: opening %s failed: %s", i.name, err)
}
if stdout == stderr {
sameFile = fw
sameFile = &countingWriteCloser{
WriteCloser: fw,
count: 1,
}
}
}
i.dest(fw, fr)
@ -128,6 +138,19 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
return nil
}
// countingWriteCloser masks io.Closer() until close has been invoked a certain number of times.
type countingWriteCloser struct {
io.WriteCloser
count int64
}
func (c *countingWriteCloser) Close() error {
if atomic.AddInt64(&c.count, -1) > 0 {
return nil
}
return c.WriteCloser.Close()
}
// isFifo checks if a file is a fifo
// if the file does not exist then it returns false
func isFifo(path string) (bool, error) {

View file

@ -1,6 +1,6 @@
github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3
github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2
github.com/containerd/cgroups 4994991857f9b0ae8dc439551e8bebdbb4bf66c1
github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
github.com/containerd/btrfs 2e1aa0ddf94f91fa282b6ed87c23bf0d64911244
@ -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 6635b4f0c6af3810594d2770f662f34ddc15b40d
github.com/opencontainers/runc 029124da7af7360afa781a0234d1b083550f797c # v1.0.0-rc7-6-g029124da
github.com/sirupsen/logrus v1.0.0
github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac
@ -43,11 +43,11 @@ github.com/google/go-cmp v0.1.0
go.etcd.io/bbolt v1.3.1-etcd.8
# cri dependencies
github.com/containerd/cri da0c016c830b2ea97fd1d737c49a568a816bf964 # release/1.2 branch
github.com/containerd/cri eb926cd79d3bac188dcc4ed7694fc9298f8831be # release/1.2 branch
github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90
github.com/blang/semver v3.1.0
github.com/containernetworking/cni v0.6.0
github.com/containernetworking/plugins v0.7.0
github.com/containernetworking/plugins v0.7.5
github.com/davecgh/go-spew v1.1.0
github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580
github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00
@ -62,7 +62,7 @@ github.com/json-iterator/go 1.1.5
github.com/modern-go/reflect2 1.0.1
github.com/modern-go/concurrent 1.0.3
github.com/opencontainers/runtime-tools v0.6.0
github.com/opencontainers/selinux b6fa367ed7f534f9ba25391cc2d467085dbb445a
github.com/opencontainers/selinux v1.2.1
github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
github.com/tchap/go-patricia v2.2.6
github.com/xeipuuv/gojsonpointer 4e3ac2762d5f479393488629ee9370b50873b3a6

View file

@ -21,7 +21,7 @@ var (
Package = "github.com/containerd/containerd"
// Version holds the complete version number. Filled in at linking time.
Version = "1.2.4+unknown"
Version = "1.2.5+unknown"
// Revision is filled with the VCS (e.g. git) revision being used to build
// the program at linking time.

View file

@ -32,6 +32,15 @@ const (
// SandboxID is the sandbox ID annotation
SandboxID = "io.kubernetes.cri.sandbox-id"
// SandboxLogDir is the pod log directory annotation.
// If the sandbox needs to generate any log, it will put it into this directory.
// Kubelet will be responsible for:
// 1) Monitoring the disk usage of the log, and including it as part of the pod
// ephemeral storage usage.
// 2) Cleaning up the logs when the pod is deleted.
// NOTE: Kubelet is not responsible for rotating the logs.
SandboxLogDir = "io.kubernetes.cri.sandbox-log-directory"
// UntrustedWorkload is the sandbox annotation for untrusted workload. Untrusted
// workload can only run on dedicated runtime for untrusted workload.
UntrustedWorkload = "io.kubernetes.cri.untrusted-workload"

View file

@ -35,7 +35,6 @@ import (
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/opencontainers/runc/libcontainer/devices"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/runtime-tools/validate"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
@ -76,6 +75,7 @@ func init() {
// CreateContainer creates a new container in the given PodSandbox.
func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateContainerRequest) (_ *runtime.CreateContainerResponse, retErr error) {
config := r.GetConfig()
logrus.Debugf("Container config %+v", config)
sandboxConfig := r.GetSandboxConfig()
sandbox, err := c.sandboxStore.Get(r.GetPodSandboxId())
if err != nil {
@ -182,7 +182,7 @@ func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateConta
if len(volumeMounts) > 0 {
mountMap := make(map[string]string)
for _, v := range volumeMounts {
mountMap[v.HostPath] = v.ContainerPath
mountMap[filepath.Clean(v.HostPath)] = v.ContainerPath
}
opts = append(opts, customopts.WithVolumes(mountMap))
}
@ -191,7 +191,7 @@ func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateConta
// Get container log path.
if config.GetLogPath() != "" {
meta.LogPath = filepath.Join(sandbox.Config.GetLogDirectory(), config.GetLogPath())
meta.LogPath = filepath.Join(sandboxConfig.GetLogDirectory(), config.GetLogPath())
}
containerIO, err := cio.NewContainerIO(id,
@ -335,8 +335,7 @@ func (c *criService) generateContainerSpec(id string, sandboxID string, sandboxP
// Add HOSTNAME env.
hostname := sandboxConfig.GetHostname()
if sandboxConfig.GetLinux().GetSecurityContext().GetNamespaceOptions().GetNetwork() == runtime.NamespaceMode_NODE &&
hostname == "" {
if sandboxConfig.GetHostname() == "" {
hostname, err = c.os.Hostname()
if err != nil {
return nil, err
@ -473,6 +472,22 @@ func (c *criService) generateVolumeMounts(containerRootDir string, criMounts []*
func (c *criService) generateContainerMounts(sandboxID string, config *runtime.ContainerConfig) []*runtime.Mount {
var mounts []*runtime.Mount
securityContext := config.GetLinux().GetSecurityContext()
if !isInCRIMounts(etcHostname, config.GetMounts()) {
// /etc/hostname is added since 1.1.6, 1.2.4 and 1.3.
// For in-place upgrade, the old sandbox doesn't have the hostname file,
// do not mount this in that case.
// TODO(random-liu): Remove the check and always mount this when
// containerd 1.1 and 1.2 are deprecated.
hostpath := c.getSandboxHostname(sandboxID)
if _, err := c.os.Stat(hostpath); err == nil {
mounts = append(mounts, &runtime.Mount{
ContainerPath: etcHostname,
HostPath: hostpath,
Readonly: securityContext.GetReadonlyRootfs(),
})
}
}
if !isInCRIMounts(etcHosts, config.GetMounts()) {
mounts = append(mounts, &runtime.Mount{
ContainerPath: etcHosts,
@ -507,7 +522,7 @@ func (c *criService) generateContainerMounts(sandboxID string, config *runtime.C
// setOCIProcessArgs sets process args. It returns error if the final arg list
// is empty.
func setOCIProcessArgs(g *generate.Generator, config *runtime.ContainerConfig, imageConfig *imagespec.ImageConfig) error {
func setOCIProcessArgs(g *generator, config *runtime.ContainerConfig, imageConfig *imagespec.ImageConfig) error {
command, args := config.GetCommand(), config.GetArgs()
// The following logic is migrated from https://github.com/moby/moby/blob/master/daemon/commit.go
// TODO(random-liu): Clearly define the commands overwrite behavior.
@ -529,7 +544,7 @@ func setOCIProcessArgs(g *generate.Generator, config *runtime.ContainerConfig, i
// addImageEnvs adds environment variables from image config. It returns error if
// an invalid environment variable is encountered.
func addImageEnvs(g *generate.Generator, imageEnvs []string) error {
func addImageEnvs(g *generator, imageEnvs []string) error {
for _, e := range imageEnvs {
kv := strings.SplitN(e, "=", 2)
if len(kv) != 2 {
@ -540,7 +555,7 @@ func addImageEnvs(g *generate.Generator, imageEnvs []string) error {
return nil
}
func setOCIPrivileged(g *generate.Generator, config *runtime.ContainerConfig) error {
func setOCIPrivileged(g *generator, config *runtime.ContainerConfig) error {
// Add all capabilities in privileged mode.
g.SetupPrivileged(true)
setOCIBindMountsPrivileged(g)
@ -561,7 +576,7 @@ func clearReadOnly(m *runtimespec.Mount) {
}
// addDevices set device mapping without privilege.
func (c *criService) addOCIDevices(g *generate.Generator, devs []*runtime.Device) error {
func (c *criService) addOCIDevices(g *generator, devs []*runtime.Device) error {
spec := g.Config
for _, device := range devs {
path, err := c.os.ResolveSymbolicLink(device.HostPath)
@ -593,7 +608,7 @@ func (c *criService) addOCIDevices(g *generate.Generator, devs []*runtime.Device
}
// addDevices set device mapping with privilege.
func setOCIDevicesPrivileged(g *generate.Generator) error {
func setOCIDevicesPrivileged(g *generator) error {
spec := g.Config
hostDevices, err := devices.HostDevices()
if err != nil {
@ -624,7 +639,7 @@ func setOCIDevicesPrivileged(g *generate.Generator) error {
}
// addOCIBindMounts adds bind mounts.
func (c *criService) addOCIBindMounts(g *generate.Generator, mounts []*runtime.Mount, mountLabel string) error {
func (c *criService) addOCIBindMounts(g *generator, mounts []*runtime.Mount, mountLabel string) error {
// Sort mounts in number of parts. This ensures that high level mounts don't
// shadow other mounts.
sort.Sort(orderedMounts(mounts))
@ -729,11 +744,11 @@ func (c *criService) addOCIBindMounts(g *generate.Generator, mounts []*runtime.M
return nil
}
func setOCIBindMountsPrivileged(g *generate.Generator) {
func setOCIBindMountsPrivileged(g *generator) {
spec := g.Config
// clear readonly for /sys and cgroup
for i, m := range spec.Mounts {
if spec.Mounts[i].Destination == "/sys" {
if filepath.Clean(spec.Mounts[i].Destination) == "/sys" {
clearReadOnly(&spec.Mounts[i])
}
if m.Type == "cgroup" {
@ -745,7 +760,7 @@ func setOCIBindMountsPrivileged(g *generate.Generator) {
}
// setOCILinuxResource set container resource limit.
func setOCILinuxResource(g *generate.Generator, resources *runtime.LinuxContainerResources) {
func setOCILinuxResource(g *generator, resources *runtime.LinuxContainerResources) {
if resources == nil {
return
}
@ -771,7 +786,7 @@ func getOCICapabilitiesList() []string {
}
// Adds capabilities to all sets relevant to root (bounding, permitted, effective, inheritable)
func addProcessRootCapability(g *generate.Generator, c string) error {
func addProcessRootCapability(g *generator, c string) error {
if err := g.AddProcessCapabilityBounding(c); err != nil {
return err
}
@ -788,7 +803,7 @@ func addProcessRootCapability(g *generate.Generator, c string) error {
}
// Drops capabilities to all sets relevant to root (bounding, permitted, effective, inheritable)
func dropProcessRootCapability(g *generate.Generator, c string) error {
func dropProcessRootCapability(g *generator, c string) error {
if err := g.DropProcessCapabilityBounding(c); err != nil {
return err
}
@ -805,7 +820,7 @@ func dropProcessRootCapability(g *generate.Generator, c string) error {
}
// setOCICapabilities adds/drops process capabilities.
func setOCICapabilities(g *generate.Generator, capabilities *runtime.Capability) error {
func setOCICapabilities(g *generator, capabilities *runtime.Capability) error {
if capabilities == nil {
return nil
}
@ -851,7 +866,7 @@ func setOCICapabilities(g *generate.Generator, capabilities *runtime.Capability)
}
// setOCINamespaces sets namespaces.
func setOCINamespaces(g *generate.Generator, namespaces *runtime.NamespaceOption, sandboxPid uint32) {
func setOCINamespaces(g *generator, namespaces *runtime.NamespaceOption, sandboxPid uint32) {
g.AddOrReplaceLinuxNamespace(string(runtimespec.NetworkNamespace), getNetworkNamespace(sandboxPid)) // nolint: errcheck
g.AddOrReplaceLinuxNamespace(string(runtimespec.IPCNamespace), getIPCNamespace(sandboxPid)) // nolint: errcheck
g.AddOrReplaceLinuxNamespace(string(runtimespec.UTSNamespace), getUTSNamespace(sandboxPid)) // nolint: errcheck
@ -874,7 +889,7 @@ func defaultRuntimeSpec(id string) (*runtimespec.Spec, error) {
// TODO(random-liu): Mount tmpfs for /run and handle copy-up.
var mounts []runtimespec.Mount
for _, mount := range spec.Mounts {
if mount.Destination == "/run" {
if filepath.Clean(mount.Destination) == "/run" {
continue
}
mounts = append(mounts, mount)

View file

@ -143,8 +143,9 @@ func (c *criService) stopContainer(ctx context.Context, container containerstore
return errors.Wrapf(err, "failed to stop container %q", id)
}
if err = c.waitContainerStop(ctx, container, timeout); err == nil {
return nil
if err = c.waitContainerStop(ctx, container, timeout); err == nil || errors.Cause(err) == ctx.Err() {
// Do not SIGKILL container if the context is cancelled.
return err
}
logrus.WithError(err).Errorf("An error occurs during waiting for container %q to be stopped", id)
}
@ -167,7 +168,7 @@ func (c *criService) waitContainerStop(ctx context.Context, container containers
defer timeoutTimer.Stop()
select {
case <-ctx.Done():
return errors.Errorf("wait container %q is cancelled", container.ID)
return errors.Wrapf(ctx.Err(), "wait container %q is cancelled", container.ID)
case <-timeoutTimer.C:
return errors.Errorf("wait container %q stop timeout", container.ID)
case <-container.Stopped():

View file

@ -37,7 +37,6 @@ import (
imagedigest "github.com/opencontainers/go-digest"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/selinux/go-selinux"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"golang.org/x/net/context"
@ -97,6 +96,8 @@ const (
devShm = "/dev/shm"
// etcHosts is the default path of /etc/hosts file.
etcHosts = "/etc/hosts"
// etcHostname is the default path of /etc/hostname file.
etcHostname = "/etc/hostname"
// resolvConfPath is the abs path of resolv.conf on host or container.
resolvConfPath = "/etc/resolv.conf"
// hostnameEnv is the key for HOSTNAME env.
@ -197,6 +198,11 @@ func (c *criService) getVolatileContainerRootDir(id string) string {
return filepath.Join(c.config.StateDir, containersDir, id)
}
// getSandboxHostname returns the hostname file path inside the sandbox root directory.
func (c *criService) getSandboxHostname(id string) string {
return filepath.Join(c.getSandboxRootDir(id), "hostname")
}
// getSandboxHosts returns the hosts file path inside the sandbox root directory.
func (c *criService) getSandboxHosts(id string) string {
return filepath.Join(c.getSandboxRootDir(id), "hosts")
@ -348,7 +354,12 @@ func initSelinuxOpts(selinuxOpt *runtime.SELinuxOption) (string, string, error)
selinuxOpt.GetRole(),
selinuxOpt.GetType(),
selinuxOpt.GetLevel())
return label.InitLabels(selinux.DupSecOpt(labelOpts))
options, err := label.DupSecOpt(labelOpts)
if err != nil {
return "", "", err
}
return label.InitLabels(options)
}
func checkSelinuxLevel(level string) (bool, error) {
@ -366,7 +377,7 @@ func checkSelinuxLevel(level string) (bool, error) {
// isInCRIMounts checks whether a destination is in CRI mount list.
func isInCRIMounts(dst string, mounts []*runtime.Mount) bool {
for _, m := range mounts {
if m.ContainerPath == dst {
if filepath.Clean(m.ContainerPath) == filepath.Clean(dst) {
return true
}
}
@ -390,10 +401,51 @@ func buildLabels(configLabels map[string]string, containerType string) map[strin
}
// newSpecGenerator creates a new spec generator for the runtime spec.
func newSpecGenerator(spec *runtimespec.Spec) generate.Generator {
func newSpecGenerator(spec *runtimespec.Spec) generator {
g := generate.NewFromSpec(spec)
g.HostSpecific = true
return g
return newCustomGenerator(g)
}
// generator is a custom generator with some functions overridden
// used by the cri plugin.
// TODO(random-liu): Upstream this fix.
type generator struct {
generate.Generator
envCache map[string]int
}
func newCustomGenerator(g generate.Generator) generator {
cg := generator{
Generator: g,
envCache: make(map[string]int),
}
if g.Config != nil && g.Config.Process != nil {
for i, env := range g.Config.Process.Env {
kv := strings.SplitN(env, "=", 2)
cg.envCache[kv[0]] = i
}
}
return cg
}
// AddProcessEnv overrides the original AddProcessEnv. It uses
// a map to cache and override envs.
func (g *generator) AddProcessEnv(key, value string) {
if len(g.envCache) == 0 {
// Call AddProccessEnv once to initialize the spec.
g.Generator.AddProcessEnv(key, value)
g.envCache[key] = 0
return
}
spec := g.Config
env := fmt.Sprintf("%s=%s", key, value)
if idx, ok := g.envCache[key]; !ok {
spec.Process.Env = append(spec.Process.Env, env)
g.envCache[key] = len(spec.Process.Env) - 1
} else {
spec.Process.Env[idx] = env
}
}
func getPodCNILabels(id string, config *runtime.PodSandboxConfig) map[string]string {

View file

@ -52,7 +52,7 @@ func (in *instrumentedService) RunPodSandbox(ctx context.Context, r *runtime.Run
if err := in.checkInitialized(); err != nil {
return nil, err
}
logrus.Infof("RunPodSandbox with config %+v", r.GetConfig())
logrus.Infof("RunPodsandbox for %+v", r.GetConfig().GetMetadata())
defer func() {
if err != nil {
logrus.WithError(err).Errorf("RunPodSandbox for %+v failed, error", r.GetConfig().GetMetadata())
@ -142,8 +142,8 @@ func (in *instrumentedService) CreateContainer(ctx context.Context, r *runtime.C
if err := in.checkInitialized(); err != nil {
return nil, err
}
logrus.Infof("CreateContainer within sandbox %q with container config %+v and sandbox config %+v",
r.GetPodSandboxId(), r.GetConfig(), r.GetSandboxConfig())
logrus.Infof("CreateContainer within sandbox %q for container %+v",
r.GetPodSandboxId(), r.GetConfig().GetMetadata())
defer func() {
if err != nil {
logrus.WithError(err).Errorf("CreateContainer within sandbox %q for %+v failed",

View file

@ -27,6 +27,7 @@ import (
"github.com/containerd/containerd/oci"
cni "github.com/containerd/go-cni"
"github.com/containerd/typeurl"
"github.com/davecgh/go-spew/spew"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
@ -54,6 +55,7 @@ func init() {
// the sandbox is in ready state.
func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandboxRequest) (_ *runtime.RunPodSandboxResponse, retErr error) {
config := r.GetConfig()
logrus.Debugf("Sandbox config %+v", config)
// Generate unique id and name for the sandbox and reserve the name.
id := util.GenerateID()
@ -143,7 +145,7 @@ func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandbox
if err != nil {
return nil, errors.Wrap(err, "failed to generate sandbox container spec")
}
logrus.Debugf("Sandbox container spec: %+v", spec)
logrus.Debugf("Sandbox container %q spec: %#+v", id, spew.NewFormatter(spec))
var specOpts []oci.SpecOpts
userstr, err := generateUserString(
@ -227,7 +229,7 @@ func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandbox
}
}()
// Setup sandbox /dev/shm, /etc/hosts and /etc/resolv.conf.
// Setup sandbox /dev/shm, /etc/hosts, /etc/resolv.conf and /etc/hostname.
if err = c.setupSandboxFiles(id, config); err != nil {
return nil, errors.Wrapf(err, "failed to setup sandbox files")
}
@ -383,6 +385,7 @@ func (c *criService) generateSandboxContainerSpec(id string, config *runtime.Pod
nsOptions := securityContext.GetNamespaceOptions()
if nsOptions.GetNetwork() == runtime.NamespaceMode_NODE {
g.RemoveLinuxNamespace(string(runtimespec.NetworkNamespace)) // nolint: errcheck
g.RemoveLinuxNamespace(string(runtimespec.UTSNamespace)) // nolint: errcheck
} else {
//TODO(Abhi): May be move this to containerd spec opts (WithLinuxSpaceOption)
g.AddOrReplaceLinuxNamespace(string(runtimespec.NetworkNamespace), nsPath) // nolint: errcheck
@ -433,13 +436,27 @@ func (c *criService) generateSandboxContainerSpec(id string, config *runtime.Pod
g.AddAnnotation(annotations.ContainerType, annotations.ContainerTypeSandbox)
g.AddAnnotation(annotations.SandboxID, id)
g.AddAnnotation(annotations.SandboxLogDir, config.GetLogDirectory())
return g.Config, nil
}
// setupSandboxFiles sets up necessary sandbox files including /dev/shm, /etc/hosts
// and /etc/resolv.conf.
// setupSandboxFiles sets up necessary sandbox files including /dev/shm, /etc/hosts,
// /etc/resolv.conf and /etc/hostname.
func (c *criService) setupSandboxFiles(id string, config *runtime.PodSandboxConfig) error {
sandboxEtcHostname := c.getSandboxHostname(id)
hostname := config.GetHostname()
if hostname == "" {
var err error
hostname, err = c.os.Hostname()
if err != nil {
return errors.Wrap(err, "failed to get hostname")
}
}
if err := c.os.WriteFile(sandboxEtcHostname, []byte(hostname+"\n"), 0644); err != nil {
return errors.Wrapf(err, "failed to write hostname to %q", sandboxEtcHostname)
}
// TODO(random-liu): Consider whether we should maintain /etc/hosts and /etc/resolv.conf in kubelet.
sandboxEtcHosts := c.getSandboxHosts(id)
if err := c.os.CopyFile(etcHosts, sandboxEtcHosts, 0644); err != nil {

View file

@ -144,7 +144,7 @@ func (c *criService) waitSandboxStop(ctx context.Context, sandbox sandboxstore.S
defer timeoutTimer.Stop()
select {
case <-ctx.Done():
return errors.Errorf("wait sandbox container %q is cancelled", sandbox.ID)
return errors.Wrapf(ctx.Err(), "wait sandbox container %q is cancelled", sandbox.ID)
case <-timeoutTimer.C:
return errors.Errorf("wait sandbox container %q stop timeout", sandbox.ID)
case <-sandbox.Stopped():

View file

@ -1,9 +1,9 @@
github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
github.com/blang/semver v3.1.0
github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2
github.com/containerd/cgroups dbea6f2bd41658b84b00417ceefa416b979cbf10
github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
github.com/containerd/containerd 0137339c8c1d55de5545ffdd723199dfba27cb24
github.com/containerd/containerd v1.2.5
github.com/containerd/continuity bd77b46c8352f74eb12c85bdc01f4b90f69d66b4
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90
@ -11,10 +11,10 @@ github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3
github.com/containerd/ttrpc 2a805f71863501300ae1976d29f0454ae003e85a
github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
github.com/containernetworking/cni v0.6.0
github.com/containernetworking/plugins v0.7.0
github.com/containernetworking/plugins v0.7.5
github.com/coreos/go-systemd v14
github.com/davecgh/go-spew v1.1.0
github.com/docker/distribution b38e5838b7b2f2ad48e06ec4b500011976080621
github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580
github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
github.com/docker/go-metrics 4ea375f7759c82740c893fc030bc37088d2ec098
@ -39,10 +39,10 @@ github.com/modern-go/concurrent 1.0.3
github.com/modern-go/reflect2 1.0.1
github.com/opencontainers/go-digest c9281466c8b2f606084ac71339773efd177436e7
github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/runc 12f6a991201fdb8f82579582d5e00e28fba06d0a
github.com/opencontainers/runc 2b18fe1d885ee5083ef9f0838fee39b62d653e30
github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353
github.com/opencontainers/runtime-tools v0.6.0
github.com/opencontainers/selinux b6fa367ed7f534f9ba25391cc2d467085dbb445a
github.com/opencontainers/selinux v1.2.1
github.com/pkg/errors v0.8.0
github.com/pmezard/go-difflib v1.0.0
github.com/prometheus/client_golang f4fb1b73fb099f396a7f0036bf86aa8def4ed823
@ -63,7 +63,7 @@ golang.org/x/crypto 49796115aa4b964c318aad4f3084fdb41e9aa067
golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac
golang.org/x/oauth2 a6bd8cefa1811bd24b86f8902872e4e8225f74c4
golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
golang.org/x/sys 1b2967e3c290b7c545b3db0deeda16e9be4f98a2 https://github.com/golang/sys
golang.org/x/sys 41f3e6584952bb034a481797859f6ab34b6803bd https://github.com/golang/sys
golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
golang.org/x/time f51c12702a4d776e4c1fa9b0fabab841babae631
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944

View file

@ -1,5 +1,13 @@
# Changelog
### 0.33.0 (2019-02-26)
- Add --raw_cgroup_prefix_whitelist flag to allow configuring which raw cgroup trees cAdvisor monitors
- Replace `du` and `find` with a golang implementation
- Periodically update MachineInfo to support hot-add/remove
- Add explicit timestamps to prometheus metrics to fix rate calculations
- Add --url_base_prefix flag to provide better support for reverse proxies
- Add --white_listed_container_labels flag to allow specifying the container labels added as prometheus labels
### 0.32.0 (2018-11-12)
- Add container process and file descriptor metrics (disabled by default)
- Rename `type` label to `failure_type` for prometheus `memory_failures_total` metric

View file

@ -51,7 +51,6 @@ type realFsHandler struct {
}
const (
timeout = 2 * time.Minute
maxBackoffFactor = 20
)
@ -74,17 +73,16 @@ func NewFsHandler(period time.Duration, rootfs, extraDir string, fsInfo fs.FsInf
func (fh *realFsHandler) update() error {
var (
baseUsage, extraDirUsage, inodeUsage uint64
rootDiskErr, rootInodeErr, extraDiskErr error
rootUsage, extraUsage fs.UsageInfo
rootErr, extraErr error
)
// TODO(vishh): Add support for external mounts.
if fh.rootfs != "" {
baseUsage, rootDiskErr = fh.fsInfo.GetDirDiskUsage(fh.rootfs, timeout)
inodeUsage, rootInodeErr = fh.fsInfo.GetDirInodeUsage(fh.rootfs, timeout)
rootUsage, rootErr = fh.fsInfo.GetDirUsage(fh.rootfs)
}
if fh.extraDir != "" {
extraDirUsage, extraDiskErr = fh.fsInfo.GetDirDiskUsage(fh.extraDir, timeout)
extraUsage, extraErr = fh.fsInfo.GetDirUsage(fh.extraDir)
}
// Wait to handle errors until after all operartions are run.
@ -92,18 +90,17 @@ func (fh *realFsHandler) update() error {
fh.Lock()
defer fh.Unlock()
fh.lastUpdate = time.Now()
if rootInodeErr == nil && fh.rootfs != "" {
fh.usage.InodeUsage = inodeUsage
if fh.rootfs != "" && rootErr == nil {
fh.usage.InodeUsage = rootUsage.Inodes
fh.usage.TotalUsageBytes = rootUsage.Bytes + extraUsage.Bytes
}
if rootDiskErr == nil && fh.rootfs != "" {
fh.usage.TotalUsageBytes = baseUsage + extraDirUsage
}
if extraDiskErr == nil && fh.extraDir != "" {
fh.usage.BaseUsageBytes = baseUsage
if fh.extraDir != "" && extraErr == nil {
fh.usage.BaseUsageBytes = rootUsage.Bytes
}
// Combine errors into a single error to return
if rootDiskErr != nil || rootInodeErr != nil || extraDiskErr != nil {
return fmt.Errorf("rootDiskErr: %v, rootInodeErr: %v, extraDiskErr: %v", rootDiskErr, rootInodeErr, extraDiskErr)
if rootErr != nil || extraErr != nil {
return fmt.Errorf("rootDiskErr: %v, extraDiskErr: %v", rootErr, extraErr)
}
return nil
}
@ -132,7 +129,7 @@ func (fh *realFsHandler) trackUsage() {
// if the long duration is persistent either because of slow
// disk or lots of containers.
longOp = longOp + time.Second
klog.V(2).Infof("du and find on following dirs took %v: %v; will not log again for this container unless duration exceeds %v", duration, []string{fh.rootfs, fh.extraDir}, longOp)
klog.V(2).Infof("fs: disk usage and inodes count on following dirs took %v: %v; will not log again for this container unless duration exceeds %v", duration, []string{fh.rootfs, fh.extraDir}, longOp)
}
}
}

View file

@ -134,7 +134,7 @@ func readString(dirpath string, file string) string {
if err != nil {
// Ignore non-existent files
if !os.IsNotExist(err) {
klog.Errorf("readString: Failed to read %q: %s", cgroupFile, err)
klog.Warningf("readString: Failed to read %q: %s", cgroupFile, err)
}
return ""
}

View file

@ -128,7 +128,7 @@ func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics
return fmt.Errorf("failed to fetch containerd client version: %v", err)
}
cgroupSubsystems, err := libcontainer.GetCgroupSubsystems()
cgroupSubsystems, err := libcontainer.GetCgroupSubsystems(includedMetrics)
if err != nil {
return fmt.Errorf("failed to get cgroup subsystems: %v", err)
}

View file

@ -18,7 +18,6 @@ package containerd
import (
"encoding/json"
"fmt"
"path"
"strings"
"time"
@ -67,10 +66,7 @@ func newContainerdContainerHandler(
includedMetrics container.MetricSet,
) (container.ContainerHandler, error) {
// Create the cgroup paths.
cgroupPaths := make(map[string]string, len(cgroupSubsystems.MountPoints))
for key, val := range cgroupSubsystems.MountPoints {
cgroupPaths[key] = path.Join(val, name)
}
cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems.MountPoints, name)
// Generate the equivalent cgroup manager for this container.
cgroupManager := &cgroupfs.Manager{

View file

@ -0,0 +1,130 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// 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 crio
import (
"encoding/json"
"fmt"
"net"
"net/http"
"syscall"
"time"
)
const (
CrioSocket = "/var/run/crio/crio.sock"
maxUnixSocketPathSize = len(syscall.RawSockaddrUnix{}.Path)
)
// Info represents CRI-O information as sent by the CRI-O server
type Info struct {
StorageDriver string `json:"storage_driver"`
StorageRoot string `json:"storage_root"`
}
// ContainerInfo represents a given container information
type ContainerInfo struct {
Name string `json:"name"`
Pid int `json:"pid"`
Image string `json:"image"`
CreatedTime int64 `json:"created_time"`
Labels map[string]string `json:"labels"`
Annotations map[string]string `json:"annotations"`
LogPath string `json:"log_path"`
Root string `json:"root"`
IP string `json:"ip_address"`
}
type crioClient interface {
Info() (Info, error)
ContainerInfo(string) (*ContainerInfo, error)
}
type crioClientImpl struct {
client *http.Client
}
func configureUnixTransport(tr *http.Transport, proto, addr string) error {
if len(addr) > maxUnixSocketPathSize {
return fmt.Errorf("Unix socket path %q is too long", addr)
}
// No need for compression in local communications.
tr.DisableCompression = true
tr.Dial = func(_, _ string) (net.Conn, error) {
return net.DialTimeout(proto, addr, 32*time.Second)
}
return nil
}
// Client returns a new configured CRI-O client
func Client() (crioClient, error) {
tr := new(http.Transport)
configureUnixTransport(tr, "unix", CrioSocket)
c := &http.Client{
Transport: tr,
}
return &crioClientImpl{
client: c,
}, nil
}
func getRequest(path string) (*http.Request, error) {
req, err := http.NewRequest("GET", path, nil)
if err != nil {
return nil, err
}
// For local communications over a unix socket, it doesn't matter what
// the host is. We just need a valid and meaningful host name.
req.Host = "crio"
req.URL.Host = CrioSocket
req.URL.Scheme = "http"
return req, nil
}
// Info returns generic info from the CRI-O server
func (c *crioClientImpl) Info() (Info, error) {
info := Info{}
req, err := getRequest("/info")
if err != nil {
return info, err
}
resp, err := c.client.Do(req)
if err != nil {
return info, err
}
defer resp.Body.Close()
if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
return info, err
}
return info, nil
}
// ContainerInfo returns information about a given container
func (c *crioClientImpl) ContainerInfo(id string) (*ContainerInfo, error) {
req, err := getRequest("/containers/" + id)
if err != nil {
return nil, err
}
resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
cInfo := ContainerInfo{}
if err := json.NewDecoder(resp.Body).Decode(&cInfo); err != nil {
return nil, err
}
return &cInfo, nil
}

View file

@ -0,0 +1,170 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// 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 crio
import (
"fmt"
"path"
"regexp"
"strings"
"github.com/google/cadvisor/container"
"github.com/google/cadvisor/container/libcontainer"
"github.com/google/cadvisor/fs"
info "github.com/google/cadvisor/info/v1"
"github.com/google/cadvisor/manager/watcher"
"k8s.io/klog"
)
// The namespace under which crio aliases are unique.
const CrioNamespace = "crio"
// Regexp that identifies CRI-O cgroups
var crioCgroupRegexp = regexp.MustCompile(`([a-z0-9]{64})`)
type storageDriver string
const (
// TODO add full set of supported drivers in future..
overlayStorageDriver storageDriver = "overlay"
overlay2StorageDriver storageDriver = "overlay2"
)
type crioFactory struct {
machineInfoFactory info.MachineInfoFactory
storageDriver storageDriver
storageDir string
// Information about the mounted cgroup subsystems.
cgroupSubsystems libcontainer.CgroupSubsystems
// Information about mounted filesystems.
fsInfo fs.FsInfo
includedMetrics container.MetricSet
client crioClient
}
func (self *crioFactory) String() string {
return CrioNamespace
}
func (self *crioFactory) NewContainerHandler(name string, inHostNamespace bool) (handler container.ContainerHandler, err error) {
client, err := Client()
if err != nil {
return
}
// TODO are there any env vars we need to white list, if so, do it here...
metadataEnvs := []string{}
handler, err = newCrioContainerHandler(
client,
name,
self.machineInfoFactory,
self.fsInfo,
self.storageDriver,
self.storageDir,
&self.cgroupSubsystems,
inHostNamespace,
metadataEnvs,
self.includedMetrics,
)
return
}
// Returns the CRIO ID from the full container name.
func ContainerNameToCrioId(name string) string {
id := path.Base(name)
if matches := crioCgroupRegexp.FindStringSubmatch(id); matches != nil {
return matches[1]
}
return id
}
// isContainerName returns true if the cgroup with associated name
// corresponds to a crio container.
func isContainerName(name string) bool {
// always ignore .mount cgroup even if associated with crio and delegate to systemd
if strings.HasSuffix(name, ".mount") {
return false
}
return crioCgroupRegexp.MatchString(path.Base(name))
}
// crio handles all containers under /crio
func (self *crioFactory) CanHandleAndAccept(name string) (bool, bool, error) {
if strings.HasPrefix(path.Base(name), "crio-conmon") {
// TODO(runcom): should we include crio-conmon cgroups?
return false, false, nil
}
if !strings.HasPrefix(path.Base(name), CrioNamespace) {
return false, false, nil
}
// if the container is not associated with CRI-O, we can't handle it or accept it.
if !isContainerName(name) {
return false, false, nil
}
return true, true, nil
}
func (self *crioFactory) DebugInfo() map[string][]string {
return map[string][]string{}
}
var (
// TODO(runcom): handle versioning in CRI-O
version_regexp_string = `(\d+)\.(\d+)\.(\d+)`
version_re = regexp.MustCompile(version_regexp_string)
apiversion_regexp_string = `(\d+)\.(\d+)`
apiversion_re = regexp.MustCompile(apiversion_regexp_string)
)
// Register root container before running this function!
func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) error {
client, err := Client()
if err != nil {
return err
}
info, err := client.Info()
if err != nil {
return err
}
// TODO determine crio version so we can work differently w/ future versions if needed
cgroupSubsystems, err := libcontainer.GetCgroupSubsystems(includedMetrics)
if err != nil {
return fmt.Errorf("failed to get cgroup subsystems: %v", err)
}
klog.V(1).Infof("Registering CRI-O factory")
f := &crioFactory{
client: client,
cgroupSubsystems: cgroupSubsystems,
fsInfo: fsInfo,
machineInfoFactory: factory,
storageDriver: storageDriver(info.StorageDriver),
storageDir: info.StorageRoot,
includedMetrics: includedMetrics,
}
container.RegisterContainerHandlerFactory(f, []watcher.ContainerWatchSource{watcher.Raw})
return nil
}

View file

@ -0,0 +1,319 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// 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.
// Handler for CRI-O containers.
package crio
import (
"fmt"
"path"
"path/filepath"
"strconv"
"strings"
"github.com/google/cadvisor/container"
"github.com/google/cadvisor/container/common"
containerlibcontainer "github.com/google/cadvisor/container/libcontainer"
"github.com/google/cadvisor/fs"
info "github.com/google/cadvisor/info/v1"
cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs"
libcontainerconfigs "github.com/opencontainers/runc/libcontainer/configs"
)
type crioContainerHandler struct {
machineInfoFactory info.MachineInfoFactory
// Absolute path to the cgroup hierarchies of this container.
// (e.g.: "cpu" -> "/sys/fs/cgroup/cpu/test")
cgroupPaths map[string]string
// the CRI-O storage driver
storageDriver storageDriver
fsInfo fs.FsInfo
rootfsStorageDir string
// Metadata associated with the container.
envs map[string]string
labels map[string]string
// TODO
// crio version handling...
// Image name used for this container.
image string
// The network mode of the container
// TODO
// Filesystem handler.
fsHandler common.FsHandler
// The IP address of the container
ipAddress string
includedMetrics container.MetricSet
reference info.ContainerReference
libcontainerHandler *containerlibcontainer.Handler
}
var _ container.ContainerHandler = &crioContainerHandler{}
// newCrioContainerHandler returns a new container.ContainerHandler
func newCrioContainerHandler(
client crioClient,
name string,
machineInfoFactory info.MachineInfoFactory,
fsInfo fs.FsInfo,
storageDriver storageDriver,
storageDir string,
cgroupSubsystems *containerlibcontainer.CgroupSubsystems,
inHostNamespace bool,
metadataEnvs []string,
includedMetrics container.MetricSet,
) (container.ContainerHandler, error) {
// Create the cgroup paths.
cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems.MountPoints, name)
// Generate the equivalent cgroup manager for this container.
cgroupManager := &cgroupfs.Manager{
Cgroups: &libcontainerconfigs.Cgroup{
Name: name,
},
Paths: cgroupPaths,
}
rootFs := "/"
if !inHostNamespace {
rootFs = "/rootfs"
storageDir = path.Join(rootFs, storageDir)
}
id := ContainerNameToCrioId(name)
cInfo, err := client.ContainerInfo(id)
if err != nil {
return nil, err
}
// passed to fs handler below ...
// XXX: this is using the full container logpath, as constructed by the CRI
// /var/log/pods/<pod_uuid>/container_instance.log
// It's not actually a log dir, as the CRI doesn't have per-container dirs
// under /var/log/pods/<pod_uuid>/
// We can't use /var/log/pods/<pod_uuid>/ to count per-container log usage.
// We use the container log file directly.
storageLogDir := cInfo.LogPath
// Determine the rootfs storage dir
rootfsStorageDir := cInfo.Root
// TODO(runcom): CRI-O doesn't strip /merged but we need to in order to
// get device ID from root, otherwise, it's going to error out as overlay
// mounts doesn't have fixed dev ids.
rootfsStorageDir = strings.TrimSuffix(rootfsStorageDir, "/merged")
switch storageDriver {
case overlayStorageDriver, overlay2StorageDriver:
// overlay and overlay2 driver are the same "overlay2" driver so treat
// them the same.
rootfsStorageDir = filepath.Join(rootfsStorageDir, "diff")
}
containerReference := info.ContainerReference{
Id: id,
Name: name,
Aliases: []string{cInfo.Name, id},
Namespace: CrioNamespace,
}
libcontainerHandler := containerlibcontainer.NewHandler(cgroupManager, rootFs, cInfo.Pid, includedMetrics)
// TODO: extract object mother method
handler := &crioContainerHandler{
machineInfoFactory: machineInfoFactory,
cgroupPaths: cgroupPaths,
storageDriver: storageDriver,
fsInfo: fsInfo,
rootfsStorageDir: rootfsStorageDir,
envs: make(map[string]string),
labels: cInfo.Labels,
includedMetrics: includedMetrics,
reference: containerReference,
libcontainerHandler: libcontainerHandler,
}
handler.image = cInfo.Image
// TODO: we wantd to know graph driver DeviceId (dont think this is needed now)
// ignore err and get zero as default, this happens with sandboxes, not sure why...
// kube isn't sending restart count in labels for sandboxes.
restartCount, _ := strconv.Atoi(cInfo.Annotations["io.kubernetes.container.restartCount"])
// Only adds restartcount label if it's greater than 0
if restartCount > 0 {
handler.labels["restartcount"] = strconv.Itoa(restartCount)
}
handler.ipAddress = cInfo.IP
// we optionally collect disk usage metrics
if includedMetrics.Has(container.DiskUsageMetrics) {
handler.fsHandler = common.NewFsHandler(common.DefaultPeriod, rootfsStorageDir, storageLogDir, fsInfo)
}
// TODO for env vars we wanted to show from container.Config.Env from whitelist
//for _, exposedEnv := range metadataEnvs {
//klog.V(4).Infof("TODO env whitelist: %v", exposedEnv)
//}
return handler, nil
}
func (self *crioContainerHandler) Start() {
if self.fsHandler != nil {
self.fsHandler.Start()
}
}
func (self *crioContainerHandler) Cleanup() {
if self.fsHandler != nil {
self.fsHandler.Stop()
}
}
func (self *crioContainerHandler) ContainerReference() (info.ContainerReference, error) {
return self.reference, nil
}
func (self *crioContainerHandler) needNet() bool {
if self.includedMetrics.Has(container.NetworkUsageMetrics) {
return self.labels["io.kubernetes.container.name"] == "POD"
}
return false
}
func (self *crioContainerHandler) GetSpec() (info.ContainerSpec, error) {
hasFilesystem := self.includedMetrics.Has(container.DiskUsageMetrics)
spec, err := common.GetSpec(self.cgroupPaths, self.machineInfoFactory, self.needNet(), hasFilesystem)
spec.Labels = self.labels
spec.Envs = self.envs
spec.Image = self.image
return spec, err
}
func (self *crioContainerHandler) getFsStats(stats *info.ContainerStats) error {
mi, err := self.machineInfoFactory.GetMachineInfo()
if err != nil {
return err
}
if self.includedMetrics.Has(container.DiskIOMetrics) {
common.AssignDeviceNamesToDiskStats((*common.MachineInfoNamer)(mi), &stats.DiskIo)
}
if !self.includedMetrics.Has(container.DiskUsageMetrics) {
return nil
}
var device string
switch self.storageDriver {
case overlay2StorageDriver, overlayStorageDriver:
deviceInfo, err := self.fsInfo.GetDirFsDevice(self.rootfsStorageDir)
if err != nil {
return fmt.Errorf("unable to determine device info for dir: %v: %v", self.rootfsStorageDir, err)
}
device = deviceInfo.Device
default:
return nil
}
var (
limit uint64
fsType string
)
// crio does not impose any filesystem limits for containers. So use capacity as limit.
for _, fs := range mi.Filesystems {
if fs.Device == device {
limit = fs.Capacity
fsType = fs.Type
break
}
}
fsStat := info.FsStats{Device: device, Type: fsType, Limit: limit}
usage := self.fsHandler.Usage()
fsStat.BaseUsage = usage.BaseUsageBytes
fsStat.Usage = usage.TotalUsageBytes
fsStat.Inodes = usage.InodeUsage
stats.Filesystem = append(stats.Filesystem, fsStat)
return nil
}
func (self *crioContainerHandler) GetStats() (*info.ContainerStats, error) {
stats, err := self.libcontainerHandler.GetStats()
if err != nil {
return stats, err
}
// Clean up stats for containers that don't have their own network - this
// includes containers running in Kubernetes pods that use the network of the
// infrastructure container. This stops metrics being reported multiple times
// for each container in a pod.
if !self.needNet() {
stats.Network = info.NetworkStats{}
}
// Get filesystem stats.
err = self.getFsStats(stats)
if err != nil {
return stats, err
}
return stats, nil
}
func (self *crioContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) {
// No-op for Docker driver.
return []info.ContainerReference{}, nil
}
func (self *crioContainerHandler) GetCgroupPath(resource string) (string, error) {
path, ok := self.cgroupPaths[resource]
if !ok {
return "", fmt.Errorf("could not find path for resource %q for container %q\n", resource, self.reference.Name)
}
return path, nil
}
func (self *crioContainerHandler) GetContainerLabels() map[string]string {
return self.labels
}
func (self *crioContainerHandler) GetContainerIPAddress() string {
return self.ipAddress
}
func (self *crioContainerHandler) ListProcesses(listType container.ListType) ([]int, error) {
return self.libcontainerHandler.GetProcesses()
}
func (self *crioContainerHandler) Exists() bool {
return common.CgroupExists(self.cgroupPaths)
}
func (self *crioContainerHandler) Type() container.ContainerType {
return container.ContainerTypeCrio
}

View file

@ -325,7 +325,7 @@ func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics
dockerAPIVersion, _ := APIVersion()
cgroupSubsystems, err := libcontainer.GetCgroupSubsystems()
cgroupSubsystems, err := libcontainer.GetCgroupSubsystems(includedMetrics)
if err != nil {
return fmt.Errorf("failed to get cgroup subsystems: %v", err)
}

View file

@ -134,10 +134,7 @@ func newDockerContainerHandler(
zfsWatcher *zfs.ZfsWatcher,
) (container.ContainerHandler, error) {
// Create the cgroup paths.
cgroupPaths := make(map[string]string, len(cgroupSubsystems.MountPoints))
for key, val := range cgroupSubsystems.MountPoints {
cgroupPaths[key] = path.Join(val, name)
}
cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems.MountPoints, name)
// Generate the equivalent cgroup manager for this container.
cgroupManager := &cgroupfs.Manager{

View file

@ -66,8 +66,7 @@ func (h *Handler) GetStats() (*info.ContainerStats, error) {
libcontainerStats := &libcontainer.Stats{
CgroupStats: cgroupStats,
}
withPerCPU := h.includedMetrics.Has(container.PerCpuUsageMetrics)
stats := newContainerStats(libcontainerStats, withPerCPU)
stats := newContainerStats(libcontainerStats, h.includedMetrics)
if h.includedMetrics.Has(container.ProcessSchedulerMetrics) {
pids, err := h.cgroupManager.GetAllPids()
@ -599,14 +598,16 @@ func setNetworkStats(libcontainerStats *libcontainer.Stats, ret *info.ContainerS
}
}
func newContainerStats(libcontainerStats *libcontainer.Stats, withPerCPU bool) *info.ContainerStats {
func newContainerStats(libcontainerStats *libcontainer.Stats, includedMetrics container.MetricSet) *info.ContainerStats {
ret := &info.ContainerStats{
Timestamp: time.Now(),
}
if s := libcontainerStats.CgroupStats; s != nil {
setCpuStats(s, ret, withPerCPU)
setDiskIoStats(s, ret)
setCpuStats(s, ret, includedMetrics.Has(container.PerCpuUsageMetrics))
if includedMetrics.Has(container.DiskIOMetrics) {
setDiskIoStats(s, ret)
}
setMemoryStats(s, ret)
}
if len(libcontainerStats.Interfaces) > 0 {

View file

@ -19,6 +19,7 @@ import (
info "github.com/google/cadvisor/info/v1"
"github.com/google/cadvisor/container"
"github.com/opencontainers/runc/libcontainer/cgroups"
"k8s.io/klog"
)
@ -33,18 +34,36 @@ type CgroupSubsystems struct {
MountPoints map[string]string
}
// Get information about the cgroup subsystems.
func GetCgroupSubsystems() (CgroupSubsystems, error) {
// Get information about the cgroup subsystems those we want
func GetCgroupSubsystems(includedMetrics container.MetricSet) (CgroupSubsystems, error) {
// Get all cgroup mounts.
allCgroups, err := cgroups.GetCgroupMounts(true)
if err != nil {
return CgroupSubsystems{}, err
}
return getCgroupSubsystemsHelper(allCgroups)
disableCgroups := map[string]struct{}{}
//currently we only support disable blkio subsystem
if !includedMetrics.Has(container.DiskIOMetrics) {
disableCgroups["blkio"] = struct{}{}
}
return getCgroupSubsystemsHelper(allCgroups, disableCgroups)
}
func getCgroupSubsystemsHelper(allCgroups []cgroups.Mount) (CgroupSubsystems, error) {
// Get information about all the cgroup subsystems.
func GetAllCgroupSubsystems() (CgroupSubsystems, error) {
// Get all cgroup mounts.
allCgroups, err := cgroups.GetCgroupMounts(true)
if err != nil {
return CgroupSubsystems{}, err
}
emptyDisableCgroups := map[string]struct{}{}
return getCgroupSubsystemsHelper(allCgroups, emptyDisableCgroups)
}
func getCgroupSubsystemsHelper(allCgroups []cgroups.Mount, disableCgroups map[string]struct{}) (CgroupSubsystems, error) {
if len(allCgroups) == 0 {
return CgroupSubsystems{}, fmt.Errorf("failed to find cgroup mounts")
}
@ -55,6 +74,9 @@ func getCgroupSubsystemsHelper(allCgroups []cgroups.Mount) (CgroupSubsystems, er
mountPoints := make(map[string]string, len(allCgroups))
for _, mount := range allCgroups {
for _, subsystem := range mount.Subsystems {
if _, exists := disableCgroups[subsystem]; exists {
continue
}
if _, ok := supportedSubsystems[subsystem]; !ok {
// Unsupported subsystem
continue

View file

@ -63,17 +63,20 @@ func (self *rawFactory) NewContainerHandler(name string, inHostNamespace bool) (
return newRawContainerHandler(name, self.cgroupSubsystems, self.machineInfoFactory, self.fsInfo, self.watcher, rootFs, self.includedMetrics)
}
// The raw factory can handle any container. If --docker_only is set to false, non-docker containers are ignored.
// The raw factory can handle any container. If --docker_only is set to true, non-docker containers are ignored except for "/" and those whitelisted by raw_cgroup_prefix_whitelist flag.
func (self *rawFactory) CanHandleAndAccept(name string) (bool, bool, error) {
accept := name == "/" || !*dockerOnly
if name == "/" {
return true, true, nil
}
if *dockerOnly && self.rawPrefixWhiteList[0] == "" {
return true, false, nil
}
for _, prefix := range self.rawPrefixWhiteList {
if strings.HasPrefix(name, prefix) {
accept = true
break
return true, true, nil
}
}
return true, accept, nil
return true, false, nil
}
func (self *rawFactory) DebugInfo() map[string][]string {
@ -81,7 +84,7 @@ func (self *rawFactory) DebugInfo() map[string][]string {
}
func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics map[container.MetricKind]struct{}, rawPrefixWhiteList []string) error {
cgroupSubsystems, err := libcontainer.GetCgroupSubsystems()
cgroupSubsystems, err := libcontainer.GetCgroupSubsystems(includedMetrics)
if err != nil {
return fmt.Errorf("failed to get cgroup subsystems: %v", err)
}

View file

@ -39,8 +39,9 @@ type rawContainerHandler struct {
// (e.g.: "cpu" -> "/sys/fs/cgroup/cpu/test")
cgroupPaths map[string]string
fsInfo fs.FsInfo
externalMounts []common.Mount
fsInfo fs.FsInfo
externalMounts []common.Mount
includedMetrics container.MetricSet
libcontainerHandler *libcontainer.Handler
}
@ -86,6 +87,7 @@ func newRawContainerHandler(name string, cgroupSubsystems *libcontainer.CgroupSu
cgroupPaths: cgroupPaths,
fsInfo: fsInfo,
externalMounts: externalMounts,
includedMetrics: includedMetrics,
libcontainerHandler: handler,
}, nil
}
@ -185,36 +187,39 @@ func fsToFsStats(fs *fs.Fs) info.FsStats {
}
func (self *rawContainerHandler) getFsStats(stats *info.ContainerStats) error {
var allFs []fs.Fs
var filesystems []fs.Fs
var err error
// Get Filesystem information only for the root cgroup.
if isRootCgroup(self.name) {
filesystems, err := self.fsInfo.GetGlobalFsInfo()
filesystems, err = self.fsInfo.GetGlobalFsInfo()
if err != nil {
return err
}
for i := range filesystems {
fs := filesystems[i]
stats.Filesystem = append(stats.Filesystem, fsToFsStats(&fs))
} else if self.includedMetrics.Has(container.DiskUsageMetrics) || self.includedMetrics.Has(container.DiskIOMetrics) {
if len(self.externalMounts) > 0 {
var mountSet map[string]struct{}
mountSet = make(map[string]struct{})
for _, mount := range self.externalMounts {
mountSet[mount.HostDir] = struct{}{}
}
filesystems, err = self.fsInfo.GetFsInfoForPath(mountSet)
if err != nil {
return err
}
}
allFs = filesystems
} else if len(self.externalMounts) > 0 {
var mountSet map[string]struct{}
mountSet = make(map[string]struct{})
for _, mount := range self.externalMounts {
mountSet[mount.HostDir] = struct{}{}
}
filesystems, err := self.fsInfo.GetFsInfoForPath(mountSet)
if err != nil {
return err
}
for i := range filesystems {
fs := filesystems[i]
stats.Filesystem = append(stats.Filesystem, fsToFsStats(&fs))
}
allFs = filesystems
}
common.AssignDeviceNamesToDiskStats(&fsNamer{fs: allFs, factory: self.machineInfoFactory}, &stats.DiskIo)
if isRootCgroup(self.name) || self.includedMetrics.Has(container.DiskUsageMetrics) {
for i := range filesystems {
fs := filesystems[i]
stats.Filesystem = append(stats.Filesystem, fsToFsStats(&fs))
}
}
if isRootCgroup(self.name) || self.includedMetrics.Has(container.DiskIOMetrics) {
common.AssignDeviceNamesToDiskStats(&fsNamer{fs: filesystems, factory: self.machineInfoFactory}, &stats.DiskIo)
}
return nil
}

View file

@ -0,0 +1,58 @@
// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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 systemd
import (
"fmt"
"strings"
"github.com/google/cadvisor/container"
"github.com/google/cadvisor/fs"
info "github.com/google/cadvisor/info/v1"
"github.com/google/cadvisor/manager/watcher"
"k8s.io/klog"
)
type systemdFactory struct{}
func (f *systemdFactory) String() string {
return "systemd"
}
func (f *systemdFactory) NewContainerHandler(name string, inHostNamespace bool) (container.ContainerHandler, error) {
return nil, fmt.Errorf("Not yet supported")
}
func (f *systemdFactory) CanHandleAndAccept(name string) (bool, bool, error) {
// on systemd using devicemapper each mount into the container has an associated cgroup that we ignore.
// for details on .mount units: http://man7.org/linux/man-pages/man5/systemd.mount.5.html
if strings.HasSuffix(name, ".mount") {
return true, false, nil
}
return false, false, fmt.Errorf("%s not handled by systemd handler", name)
}
func (f *systemdFactory) DebugInfo() map[string][]string {
return map[string][]string{}
}
// Register registers the systemd container factory.
func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) error {
klog.V(1).Infof("Registering systemd factory")
factory := &systemdFactory{}
container.RegisterContainerHandlerFactory(factory, []watcher.ContainerWatchSource{watcher.Raw})
return nil
}

View file

@ -19,7 +19,6 @@ package fs
import (
"bufio"
"bytes"
"fmt"
"io/ioutil"
"os"
@ -30,7 +29,6 @@ import (
"strconv"
"strings"
"syscall"
"time"
"github.com/docker/docker/pkg/mount"
"github.com/google/cadvisor/devicemapper"
@ -47,8 +45,12 @@ const (
LabelCrioImages = "crio-images"
)
// The maximum number of `du` and `find` tasks that can be running at once.
const maxConcurrentOps = 20
const (
// The block size in bytes.
statBlockSize uint64 = 512
// The maximum number of `disk usage` tasks that can be running at once.
maxConcurrentOps = 20
)
// A pool for restricting the number of consecutive `du` and `find` tasks running.
var pool = make(chan struct{}, maxConcurrentOps)
@ -559,78 +561,73 @@ func (self *RealFsInfo) GetDirFsDevice(dir string) (*DeviceInfo, error) {
return nil, fmt.Errorf("could not find device with major: %d, minor: %d in cached partitions map", major, minor)
}
func (self *RealFsInfo) GetDirDiskUsage(dir string, timeout time.Duration) (uint64, error) {
func GetDirUsage(dir string) (UsageInfo, error) {
var usage UsageInfo
if dir == "" {
return usage, fmt.Errorf("invalid directory")
}
rootInfo, err := os.Stat(dir)
if err != nil {
return usage, fmt.Errorf("could not stat %q to get inode usage: %v", dir, err)
}
rootStat, ok := rootInfo.Sys().(*syscall.Stat_t)
if !ok {
return usage, fmt.Errorf("unsuported fileinfo for getting inode usage of %q", dir)
}
rootDevId := rootStat.Dev
// dedupedInode stores inodes that could be duplicates (nlink > 1)
dedupedInodes := make(map[uint64]struct{})
err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if os.IsNotExist(err) {
// expected if files appear/vanish
return nil
}
if err != nil {
return fmt.Errorf("unable to count inodes for part of dir %s: %s", dir, err)
}
// according to the docs, Sys can be nil
if info.Sys() == nil {
return fmt.Errorf("fileinfo Sys is nil")
}
s, ok := info.Sys().(*syscall.Stat_t)
if !ok {
return fmt.Errorf("unsupported fileinfo; could not convert to stat_t")
}
if s.Dev != rootDevId {
// don't descend into directories on other devices
return filepath.SkipDir
}
if s.Nlink > 1 {
if _, ok := dedupedInodes[s.Ino]; !ok {
// Dedupe things that could be hardlinks
dedupedInodes[s.Ino] = struct{}{}
usage.Bytes += uint64(s.Blocks) * statBlockSize
usage.Inodes++
}
} else {
usage.Bytes += uint64(s.Blocks) * statBlockSize
usage.Inodes++
}
return nil
})
return usage, nil
}
func (self *RealFsInfo) GetDirUsage(dir string) (UsageInfo, error) {
claimToken()
defer releaseToken()
return GetDirDiskUsage(dir, timeout)
}
func GetDirDiskUsage(dir string, timeout time.Duration) (uint64, error) {
if dir == "" {
return 0, fmt.Errorf("invalid directory")
}
cmd := exec.Command("ionice", "-c3", "nice", "-n", "19", "du", "-s", dir)
stdoutp, err := cmd.StdoutPipe()
if err != nil {
return 0, fmt.Errorf("failed to setup stdout for cmd %v - %v", cmd.Args, err)
}
stderrp, err := cmd.StderrPipe()
if err != nil {
return 0, fmt.Errorf("failed to setup stderr for cmd %v - %v", cmd.Args, err)
}
if err := cmd.Start(); err != nil {
return 0, fmt.Errorf("failed to exec du - %v", err)
}
timer := time.AfterFunc(timeout, func() {
klog.Warningf("Killing cmd %v due to timeout(%s)", cmd.Args, timeout.String())
cmd.Process.Kill()
})
stdoutb, souterr := ioutil.ReadAll(stdoutp)
if souterr != nil {
klog.Errorf("Failed to read from stdout for cmd %v - %v", cmd.Args, souterr)
}
stderrb, _ := ioutil.ReadAll(stderrp)
err = cmd.Wait()
timer.Stop()
if err != nil {
return 0, fmt.Errorf("du command failed on %s with output stdout: %s, stderr: %s - %v", dir, string(stdoutb), string(stderrb), err)
}
stdout := string(stdoutb)
usageInKb, err := strconv.ParseUint(strings.Fields(stdout)[0], 10, 64)
if err != nil {
return 0, fmt.Errorf("cannot parse 'du' output %s - %s", stdout, err)
}
return usageInKb * 1024, nil
}
func (self *RealFsInfo) GetDirInodeUsage(dir string, timeout time.Duration) (uint64, error) {
claimToken()
defer releaseToken()
return GetDirInodeUsage(dir, timeout)
}
func GetDirInodeUsage(dir string, timeout time.Duration) (uint64, error) {
if dir == "" {
return 0, fmt.Errorf("invalid directory")
}
var counter byteCounter
var stderr bytes.Buffer
findCmd := exec.Command("ionice", "-c3", "nice", "-n", "19", "find", dir, "-xdev", "-printf", ".")
findCmd.Stdout, findCmd.Stderr = &counter, &stderr
if err := findCmd.Start(); err != nil {
return 0, fmt.Errorf("failed to exec cmd %v - %v; stderr: %v", findCmd.Args, err, stderr.String())
}
timer := time.AfterFunc(timeout, func() {
klog.Warningf("Killing cmd %v due to timeout(%s)", findCmd.Args, timeout.String())
findCmd.Process.Kill()
})
err := findCmd.Wait()
timer.Stop()
if err != nil {
return 0, fmt.Errorf("cmd %v failed. stderr: %s; err: %v", findCmd.Args, stderr.String(), err)
}
return counter.bytesWritten, nil
return GetDirUsage(dir)
}
func getVfsStats(path string) (total uint64, free uint64, avail uint64, inodes uint64, inodesFree uint64, err error) {

View file

@ -16,7 +16,6 @@ package fs
import (
"errors"
"time"
)
type DeviceInfo struct {
@ -62,6 +61,11 @@ type DiskStats struct {
WeightedIoTime uint64
}
type UsageInfo struct {
Bytes uint64
Inodes uint64
}
// ErrNoSuchDevice is the error indicating the requested device does not exist.
var ErrNoSuchDevice = errors.New("cadvisor: no such device")
@ -72,11 +76,8 @@ type FsInfo interface {
// Returns capacity and free space, in bytes, of the set of mounts passed.
GetFsInfoForPath(mountSet map[string]struct{}) ([]Fs, error)
// Returns number of bytes occupied by 'dir'.
GetDirDiskUsage(dir string, timeout time.Duration) (uint64, error)
// Returns number of inodes used by 'dir'.
GetDirInodeUsage(dir string, timeout time.Duration) (uint64, error)
// GetDirUsage returns a usage information for 'dir'.
GetDirUsage(dir string) (UsageInfo, error)
// GetDeviceInfoByFsUUID returns the information of the device with the
// specified filesystem uuid. If no such device exists, this function will

View file

@ -16,12 +16,13 @@
package machine
import (
"bytes"
"fmt"
"io/ioutil"
"path/filepath"
"regexp"
"strconv"
"strings"
// s390/s390x changes
"runtime"
@ -36,9 +37,10 @@ import (
)
var (
cpuRegExp = regexp.MustCompile(`^processor\s*:\s*([0-9]+)$`)
coreRegExp = regexp.MustCompile(`^core id\s*:\s*([0-9]+)$`)
nodeRegExp = regexp.MustCompile(`^physical id\s*:\s*([0-9]+)$`)
cpuRegExp = regexp.MustCompile(`^processor\s*:\s*([0-9]+)$`)
coreRegExp = regexp.MustCompile(`^core id\s*:\s*([0-9]+)$`)
nodeRegExp = regexp.MustCompile(`^physical id\s*:\s*([0-9]+)$`)
nodeBusRegExp = regexp.MustCompile(`^node([0-9]+)$`)
// Power systems have a different format so cater for both
cpuClockSpeedMHz = regexp.MustCompile(`(?:cpu MHz|clock)\s*:\s*([0-9]+\.[0-9]+)(?:MHz)?`)
memoryCapacityRegexp = regexp.MustCompile(`MemTotal:\s*([0-9]+) kB`)
@ -46,6 +48,7 @@ var (
)
const maxFreqFile = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"
const cpuBusPath = "/sys/bus/cpu/devices/"
// GetClockSpeed returns the CPU clock speed, given a []byte formatted as the /proc/cpuinfo file.
func GetClockSpeed(procInfo []byte) (uint64, error) {
@ -127,6 +130,67 @@ func parseCapacity(b []byte, r *regexp.Regexp) (uint64, error) {
return m * 1024, err
}
/* Look for sysfs cpu path containing core_id */
/* Such as: sys/bus/cpu/devices/cpu0/topology/core_id */
func getCoreIdFromCpuBus(cpuBusPath string, threadId int) (int, error) {
path := filepath.Join(cpuBusPath, fmt.Sprintf("cpu%d/topology", threadId))
file := filepath.Join(path, "core_id")
num, err := ioutil.ReadFile(file)
if err != nil {
return threadId, err
}
coreId, err := strconv.ParseInt(string(bytes.TrimSpace(num)), 10, 32)
if err != nil {
return threadId, err
}
if coreId < 0 {
// report threadId if found coreId < 0
coreId = int64(threadId)
}
return int(coreId), nil
}
/* Look for sysfs cpu path containing node id */
/* Such as: /sys/bus/cpu/devices/cpu0/node%d */
func getNodeIdFromCpuBus(cpuBusPath string, threadId int) (int, error) {
path := filepath.Join(cpuBusPath, fmt.Sprintf("cpu%d", threadId))
files, err := ioutil.ReadDir(path)
if err != nil {
return 0, err
}
nodeId := 0
for _, file := range files {
filename := file.Name()
isNode, error := regexp.MatchString("^node([0-9]+)$", filename)
if error != nil {
continue
}
if !isNode {
continue
}
ok, val, _ := extractValue(filename, nodeBusRegExp)
if err != nil {
continue
}
if ok {
if val < 0 {
continue
}
nodeId = val
}
}
return nodeId, nil
}
func GetTopology(sysFs sysfs.SysFs, cpuinfo string) ([]info.Node, int, error) {
nodes := []info.Node{}
@ -161,8 +225,36 @@ func GetTopology(sysFs sysfs.SysFs, cpuinfo string) ([]info.Node, int, error) {
lastNode = -1
}
lastThread = thread
/* On Arm platform, no 'core id' and 'physical id' in '/proc/cpuinfo'. */
/* So we search sysfs cpu path directly. */
/* This method can also be used on other platforms, such as x86, ppc64le... */
/* /sys/bus/cpu/devices/cpu%d contains the information of 'core_id' & 'node_id'. */
/* Such as: /sys/bus/cpu/devices/cpu0/topology/core_id */
/* Such as: /sys/bus/cpu/devices/cpu0/node0 */
if isAArch64() {
val, err = getCoreIdFromCpuBus(cpuBusPath, lastThread)
if err != nil {
// Report thread id if no NUMA
val = lastThread
}
lastCore = val
val, err = getNodeIdFromCpuBus(cpuBusPath, lastThread)
if err != nil {
// Report node 0 if no NUMA
val = 0
}
lastNode = val
}
continue
}
if isAArch64() {
/* On Arm platform, no 'core id' and 'physical id' in '/proc/cpuinfo'. */
continue
}
ok, val, err = extractValue(line, coreRegExp)
if err != nil {
return nil, -1, fmt.Errorf("could not parse core info from %q: %v", line, err)
@ -171,6 +263,7 @@ func GetTopology(sysFs sysfs.SysFs, cpuinfo string) ([]info.Node, int, error) {
lastCore = val
continue
}
ok, val, err = extractValue(line, nodeRegExp)
if err != nil {
return nil, -1, fmt.Errorf("could not parse node info from %q: %v", line, err)
@ -180,6 +273,7 @@ func GetTopology(sysFs sysfs.SysFs, cpuinfo string) ([]info.Node, int, error) {
continue
}
}
nodeIdx, err := addNode(&nodes, lastNode)
if err != nil {
return nil, -1, fmt.Errorf("failed to add node %d: %v", lastNode, err)

View file

@ -31,8 +31,10 @@ import (
"github.com/google/cadvisor/collector"
"github.com/google/cadvisor/container"
"github.com/google/cadvisor/container/containerd"
"github.com/google/cadvisor/container/crio"
"github.com/google/cadvisor/container/docker"
"github.com/google/cadvisor/container/raw"
"github.com/google/cadvisor/container/systemd"
"github.com/google/cadvisor/events"
"github.com/google/cadvisor/fs"
info "github.com/google/cadvisor/info/v1"
@ -51,6 +53,7 @@ import (
)
var globalHousekeepingInterval = flag.Duration("global_housekeeping_interval", 1*time.Minute, "Interval between global housekeepings")
var updateMachineInfoInterval = flag.Duration("update_machine_info_interval", 5*time.Minute, "Interval between machine info updates.")
var logCadvisorUsage = flag.Bool("log_cadvisor_usage", false, "Whether to log the usage of the cAdvisor container")
var eventStorageAgeLimit = flag.String("event_storage_age_limit", "default=24h", "Max length of time for which to store events (per type). Value is a comma separated list of key values, where the keys are event types (e.g.: creation, oom) or \"default\" and the value is a duration. Default is applied to all non-specified event types")
var eventStorageEventLimit = flag.String("event_storage_event_limit", "default=100000", "Max number of events to store (per type). Value is a comma separated list of key values, where the keys are event types (e.g.: creation, oom) or \"default\" and the value is an integer. Default is applied to all non-specified event types")
@ -156,12 +159,24 @@ func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs, maxHousekeepingIn
// Try to connect to docker indefinitely on startup.
dockerStatus = retryDockerStatus()
crioClient, err := crio.Client()
if err != nil {
return nil, err
}
crioInfo, err := crioClient.Info()
if err != nil {
klog.V(5).Infof("CRI-O not connected: %v", err)
}
context := fs.Context{
Docker: fs.DockerContext{
Root: docker.RootDir(),
Driver: dockerStatus.Driver,
DriverStatus: dockerStatus.DriverStatus,
},
Crio: fs.CrioContext{
Root: crioInfo.StorageRoot,
},
}
fsInfo, err := fs.NewFsInfo(context)
if err != nil {
@ -183,6 +198,7 @@ func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs, maxHousekeepingIn
quitChannels: make([]chan error, 0, 2),
memoryCache: memoryCache,
fsInfo: fsInfo,
sysFs: sysfs,
cadvisorContainer: selfContainer,
inHostNamespace: inHostNamespace,
startupTime: time.Now(),
@ -252,6 +268,8 @@ type manager struct {
containersLock sync.RWMutex
memoryCache *memory.InMemoryCache
fsInfo fs.FsInfo
sysFs sysfs.SysFs
machineMu sync.RWMutex // protects machineInfo
machineInfo info.MachineInfo
quitChannels []chan error
cadvisorContainer string
@ -281,6 +299,16 @@ func (self *manager) Start() error {
klog.V(5).Infof("Registration of the containerd container factory failed: %v", err)
}
err = crio.Register(self, self.fsInfo, self.includedMetrics)
if err != nil {
klog.V(5).Infof("Registration of the crio container factory failed: %v", err)
}
err = systemd.Register(self, self.fsInfo, self.includedMetrics)
if err != nil {
klog.V(5).Infof("Registration of the systemd container factory failed: %v", err)
}
err = raw.Register(self, self.fsInfo, self.includedMetrics, self.rawContainerCgroupPathPrefixWhiteList)
if err != nil {
klog.Errorf("Registration of the raw container factory failed: %v", err)
@ -331,6 +359,10 @@ func (self *manager) Start() error {
self.quitChannels = append(self.quitChannels, quitGlobalHousekeeping)
go self.globalHousekeeping(quitGlobalHousekeeping)
quitUpdateMachineInfo := make(chan error)
self.quitChannels = append(self.quitChannels, quitUpdateMachineInfo)
go self.updateMachineInfo(quitUpdateMachineInfo)
return nil
}
@ -351,6 +383,28 @@ func (self *manager) Stop() error {
return nil
}
func (self *manager) updateMachineInfo(quit chan error) {
ticker := time.NewTicker(*updateMachineInfoInterval)
for {
select {
case <-ticker.C:
info, err := machine.Info(self.sysFs, self.fsInfo, self.inHostNamespace)
if err != nil {
klog.Errorf("Could not get machine info: %v", err)
break
}
self.machineMu.Lock()
self.machineInfo = *info
self.machineMu.Unlock()
klog.V(5).Infof("Update machine info: %+v", *info)
case <-quit:
ticker.Stop()
quit <- nil
return
}
}
}
func (self *manager) globalHousekeeping(quit chan error) {
// Long housekeeping is either 100ms or half of the housekeeping interval.
longHousekeeping := 100 * time.Millisecond
@ -450,7 +504,9 @@ func (self *manager) getAdjustedSpec(cinfo *containerInfo) info.ContainerSpec {
if spec.HasMemory {
// Memory.Limit is 0 means there's no limit
if spec.Memory.Limit == 0 {
self.machineMu.RLock()
spec.Memory.Limit = uint64(self.machineInfo.MemoryCapacity)
self.machineMu.RUnlock()
}
}
return spec
@ -783,6 +839,8 @@ func (self *manager) GetFsInfo(label string) ([]v2.FsInfo, error) {
}
func (m *manager) GetMachineInfo() (*info.MachineInfo, error) {
m.machineMu.RLock()
defer m.machineMu.RUnlock()
// Copy and return the MachineInfo.
return &m.machineInfo, nil
}

View file

@ -45,7 +45,7 @@ type rawContainerWatcher struct {
}
func NewRawContainerWatcher() (watcher.ContainerWatcher, error) {
cgroupSubsystems, err := libcontainer.GetCgroupSubsystems()
cgroupSubsystems, err := libcontainer.GetAllCgroupSubsystems()
if err != nil {
return nil, fmt.Errorf("failed to get cgroup subsystems: %v", err)
}

View file

@ -21,7 +21,6 @@ import (
"github.com/google/cadvisor/container"
info "github.com/google/cadvisor/info/v1"
"github.com/prometheus/client_golang/prometheus"
"k8s.io/klog"
)
@ -40,8 +39,9 @@ type infoProvider interface {
// metricValue describes a single metric value for a given set of label values
// within a parent containerMetric.
type metricValue struct {
value float64
labels []string
value float64
labels []string
timestamp time.Time
}
type metricValues []metricValue
@ -55,30 +55,35 @@ func asNanosecondsToSeconds(v uint64) float64 {
}
// fsValues is a helper method for assembling per-filesystem stats.
func fsValues(fsStats []info.FsStats, valueFn func(*info.FsStats) float64) metricValues {
func fsValues(fsStats []info.FsStats, valueFn func(*info.FsStats) float64, timestamp time.Time) metricValues {
values := make(metricValues, 0, len(fsStats))
for _, stat := range fsStats {
values = append(values, metricValue{
value: valueFn(&stat),
labels: []string{stat.Device},
value: valueFn(&stat),
labels: []string{stat.Device},
timestamp: timestamp,
})
}
return values
}
// ioValues is a helper method for assembling per-disk and per-filesystem stats.
func ioValues(ioStats []info.PerDiskStats, ioType string, ioValueFn func(uint64) float64, fsStats []info.FsStats, valueFn func(*info.FsStats) float64) metricValues {
func ioValues(ioStats []info.PerDiskStats, ioType string, ioValueFn func(uint64) float64,
fsStats []info.FsStats, valueFn func(*info.FsStats) float64, timestamp time.Time) metricValues {
values := make(metricValues, 0, len(ioStats)+len(fsStats))
for _, stat := range ioStats {
values = append(values, metricValue{
value: ioValueFn(stat.Stats[ioType]),
labels: []string{stat.Device},
value: ioValueFn(stat.Stats[ioType]),
labels: []string{stat.Device},
timestamp: timestamp,
})
}
for _, stat := range fsStats {
values = append(values, metricValue{
value: valueFn(&stat),
labels: []string{stat.Device},
value: valueFn(&stat),
labels: []string{stat.Device},
timestamp: timestamp,
})
}
return values
@ -134,7 +139,10 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
help: "Last time a container was seen by the exporter",
valueType: prometheus.GaugeValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(time.Now().Unix())}}
return metricValues{{
value: float64(time.Now().Unix()),
timestamp: time.Now(),
}}
},
},
},
@ -147,14 +155,24 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
help: "Cumulative user cpu time consumed in seconds.",
valueType: prometheus.CounterValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Cpu.Usage.User) / float64(time.Second)}}
return metricValues{
{
value: float64(s.Cpu.Usage.User) / float64(time.Second),
timestamp: s.Timestamp,
},
}
},
}, {
name: "container_cpu_system_seconds_total",
help: "Cumulative system cpu time consumed in seconds.",
valueType: prometheus.CounterValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Cpu.Usage.System) / float64(time.Second)}}
return metricValues{
{
value: float64(s.Cpu.Usage.System) / float64(time.Second),
timestamp: s.Timestamp,
},
}
},
}, {
name: "container_cpu_usage_seconds_total",
@ -165,8 +183,9 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
if len(s.Cpu.Usage.PerCpu) == 0 {
if s.Cpu.Usage.Total > 0 {
return metricValues{{
value: float64(s.Cpu.Usage.Total) / float64(time.Second),
labels: []string{"total"},
value: float64(s.Cpu.Usage.Total) / float64(time.Second),
labels: []string{"total"},
timestamp: s.Timestamp,
}}
}
}
@ -174,8 +193,9 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
for i, value := range s.Cpu.Usage.PerCpu {
if value > 0 {
values = append(values, metricValue{
value: float64(value) / float64(time.Second),
labels: []string{fmt.Sprintf("cpu%02d", i)},
value: float64(value) / float64(time.Second),
labels: []string{fmt.Sprintf("cpu%02d", i)},
timestamp: s.Timestamp,
})
}
}
@ -187,7 +207,11 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
valueType: prometheus.CounterValue,
condition: func(s info.ContainerSpec) bool { return s.Cpu.Quota != 0 },
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Cpu.CFS.Periods)}}
return metricValues{
{
value: float64(s.Cpu.CFS.Periods),
timestamp: s.Timestamp,
}}
},
}, {
name: "container_cpu_cfs_throttled_periods_total",
@ -195,7 +219,11 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
valueType: prometheus.CounterValue,
condition: func(s info.ContainerSpec) bool { return s.Cpu.Quota != 0 },
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Cpu.CFS.ThrottledPeriods)}}
return metricValues{
{
value: float64(s.Cpu.CFS.ThrottledPeriods),
timestamp: s.Timestamp,
}}
},
}, {
name: "container_cpu_cfs_throttled_seconds_total",
@ -203,7 +231,11 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
valueType: prometheus.CounterValue,
condition: func(s info.ContainerSpec) bool { return s.Cpu.Quota != 0 },
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Cpu.CFS.ThrottledTime) / float64(time.Second)}}
return metricValues{
{
value: float64(s.Cpu.CFS.ThrottledTime) / float64(time.Second),
timestamp: s.Timestamp,
}}
},
},
}...)
@ -215,21 +247,30 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
help: "Time duration the processes of the container have run on the CPU.",
valueType: prometheus.CounterValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Cpu.Schedstat.RunTime) / float64(time.Second)}}
return metricValues{{
value: float64(s.Cpu.Schedstat.RunTime) / float64(time.Second),
timestamp: s.Timestamp,
}}
},
}, {
name: "container_cpu_schedstat_runqueue_seconds_total",
help: "Time duration processes of the container have been waiting on a runqueue.",
valueType: prometheus.CounterValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Cpu.Schedstat.RunqueueTime) / float64(time.Second)}}
return metricValues{{
value: float64(s.Cpu.Schedstat.RunqueueTime) / float64(time.Second),
timestamp: s.Timestamp,
}}
},
}, {
name: "container_cpu_schedstat_run_periods_total",
help: "Number of times processes of the cgroup have run on the cpu",
valueType: prometheus.CounterValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Cpu.Schedstat.RunPeriods)}}
return metricValues{{
value: float64(s.Cpu.Schedstat.RunPeriods),
timestamp: s.Timestamp,
}}
},
},
}...)
@ -241,7 +282,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
help: "Value of container cpu load average over the last 10 seconds.",
valueType: prometheus.GaugeValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Cpu.LoadAverage)}}
return metricValues{{value: float64(s.Cpu.LoadAverage), timestamp: s.Timestamp}}
},
}, {
name: "container_tasks_state",
@ -251,24 +292,29 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{
{
value: float64(s.TaskStats.NrSleeping),
labels: []string{"sleeping"},
value: float64(s.TaskStats.NrSleeping),
labels: []string{"sleeping"},
timestamp: s.Timestamp,
},
{
value: float64(s.TaskStats.NrRunning),
labels: []string{"running"},
value: float64(s.TaskStats.NrRunning),
labels: []string{"running"},
timestamp: s.Timestamp,
},
{
value: float64(s.TaskStats.NrStopped),
labels: []string{"stopped"},
value: float64(s.TaskStats.NrStopped),
labels: []string{"stopped"},
timestamp: s.Timestamp,
},
{
value: float64(s.TaskStats.NrUninterruptible),
labels: []string{"uninterruptible"},
value: float64(s.TaskStats.NrUninterruptible),
labels: []string{"uninterruptible"},
timestamp: s.Timestamp,
},
{
value: float64(s.TaskStats.NrIoWait),
labels: []string{"iowaiting"},
value: float64(s.TaskStats.NrIoWait),
labels: []string{"iowaiting"},
timestamp: s.Timestamp,
},
}
},
@ -282,42 +328,45 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
help: "Number of bytes of page cache memory.",
valueType: prometheus.GaugeValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Memory.Cache)}}
return metricValues{{value: float64(s.Memory.Cache), timestamp: s.Timestamp}}
},
}, {
name: "container_memory_rss",
help: "Size of RSS in bytes.",
valueType: prometheus.GaugeValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Memory.RSS)}}
return metricValues{{value: float64(s.Memory.RSS), timestamp: s.Timestamp}}
},
}, {
name: "container_memory_mapped_file",
help: "Size of memory mapped files in bytes.",
valueType: prometheus.GaugeValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Memory.MappedFile)}}
return metricValues{{value: float64(s.Memory.MappedFile), timestamp: s.Timestamp}}
},
}, {
name: "container_memory_swap",
help: "Container swap usage in bytes.",
valueType: prometheus.GaugeValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Memory.Swap)}}
return metricValues{{value: float64(s.Memory.Swap), timestamp: s.Timestamp}}
},
}, {
name: "container_memory_failcnt",
help: "Number of memory usage hits limits",
valueType: prometheus.CounterValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Memory.Failcnt)}}
return metricValues{{
value: float64(s.Memory.Failcnt),
timestamp: s.Timestamp,
}}
},
}, {
name: "container_memory_usage_bytes",
help: "Current memory usage in bytes, including all memory regardless of when it was accessed",
valueType: prometheus.GaugeValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Memory.Usage)}}
return metricValues{{value: float64(s.Memory.Usage), timestamp: s.Timestamp}}
},
},
{
@ -325,14 +374,14 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
help: "Maximum memory usage recorded in bytes",
valueType: prometheus.GaugeValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Memory.MaxUsage)}}
return metricValues{{value: float64(s.Memory.MaxUsage), timestamp: s.Timestamp}}
},
}, {
name: "container_memory_working_set_bytes",
help: "Current working set in bytes.",
valueType: prometheus.GaugeValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Memory.WorkingSet)}}
return metricValues{{value: float64(s.Memory.WorkingSet), timestamp: s.Timestamp}}
},
}, {
name: "container_memory_failures_total",
@ -342,20 +391,24 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{
{
value: float64(s.Memory.ContainerData.Pgfault),
labels: []string{"pgfault", "container"},
value: float64(s.Memory.ContainerData.Pgfault),
labels: []string{"pgfault", "container"},
timestamp: s.Timestamp,
},
{
value: float64(s.Memory.ContainerData.Pgmajfault),
labels: []string{"pgmajfault", "container"},
value: float64(s.Memory.ContainerData.Pgmajfault),
labels: []string{"pgmajfault", "container"},
timestamp: s.Timestamp,
},
{
value: float64(s.Memory.HierarchicalData.Pgfault),
labels: []string{"pgfault", "hierarchy"},
value: float64(s.Memory.HierarchicalData.Pgfault),
labels: []string{"pgfault", "hierarchy"},
timestamp: s.Timestamp,
},
{
value: float64(s.Memory.HierarchicalData.Pgmajfault),
labels: []string{"pgmajfault", "hierarchy"},
value: float64(s.Memory.HierarchicalData.Pgmajfault),
labels: []string{"pgmajfault", "hierarchy"},
timestamp: s.Timestamp,
},
}
},
@ -373,8 +426,9 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
values := make(metricValues, 0, len(s.Accelerators))
for _, value := range s.Accelerators {
values = append(values, metricValue{
value: float64(value.MemoryTotal),
labels: []string{value.Make, value.Model, value.ID},
value: float64(value.MemoryTotal),
labels: []string{value.Make, value.Model, value.ID},
timestamp: s.Timestamp,
})
}
return values
@ -388,8 +442,9 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
values := make(metricValues, 0, len(s.Accelerators))
for _, value := range s.Accelerators {
values = append(values, metricValue{
value: float64(value.MemoryUsed),
labels: []string{value.Make, value.Model, value.ID},
value: float64(value.MemoryUsed),
labels: []string{value.Make, value.Model, value.ID},
timestamp: s.Timestamp,
})
}
return values
@ -403,8 +458,9 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
values := make(metricValues, 0, len(s.Accelerators))
for _, value := range s.Accelerators {
values = append(values, metricValue{
value: float64(value.DutyCycle),
labels: []string{value.Make, value.Model, value.ID},
value: float64(value.DutyCycle),
labels: []string{value.Make, value.Model, value.ID},
timestamp: s.Timestamp,
})
}
return values
@ -422,7 +478,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
getValues: func(s *info.ContainerStats) metricValues {
return fsValues(s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.InodesFree)
})
}, s.Timestamp)
},
}, {
name: "container_fs_inodes_total",
@ -432,7 +488,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
getValues: func(s *info.ContainerStats) metricValues {
return fsValues(s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.Inodes)
})
}, s.Timestamp)
},
}, {
name: "container_fs_limit_bytes",
@ -442,7 +498,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
getValues: func(s *info.ContainerStats) metricValues {
return fsValues(s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.Limit)
})
}, s.Timestamp)
},
}, {
name: "container_fs_usage_bytes",
@ -452,7 +508,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
getValues: func(s *info.ContainerStats) metricValues {
return fsValues(s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.Usage)
})
}, s.Timestamp)
},
},
}...)
@ -468,6 +524,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
return ioValues(
s.DiskIo.IoServiceBytes, "Read", asFloat64,
nil, nil,
s.Timestamp,
)
},
}, {
@ -481,6 +538,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.ReadsCompleted)
},
s.Timestamp,
)
},
}, {
@ -494,6 +552,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.SectorsRead)
},
s.Timestamp,
)
},
}, {
@ -507,6 +566,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.ReadsMerged)
},
s.Timestamp,
)
},
}, {
@ -520,6 +580,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.ReadTime) / float64(time.Second)
},
s.Timestamp,
)
},
}, {
@ -531,6 +592,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
return ioValues(
s.DiskIo.IoServiceBytes, "Write", asFloat64,
nil, nil,
s.Timestamp,
)
},
}, {
@ -544,6 +606,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.WritesCompleted)
},
s.Timestamp,
)
},
}, {
@ -557,6 +620,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.SectorsWritten)
},
s.Timestamp,
)
},
}, {
@ -570,6 +634,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.WritesMerged)
},
s.Timestamp,
)
},
}, {
@ -583,6 +648,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.WriteTime) / float64(time.Second)
},
s.Timestamp,
)
},
}, {
@ -596,6 +662,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.IoInProgress)
},
s.Timestamp,
)
},
}, {
@ -609,6 +676,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
s.Filesystem, func(fs *info.FsStats) float64 {
return float64(float64(fs.IoTime) / float64(time.Second))
},
s.Timestamp,
)
},
}, {
@ -619,7 +687,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
getValues: func(s *info.ContainerStats) metricValues {
return fsValues(s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.WeightedIoTime) / float64(time.Second)
})
}, s.Timestamp)
},
},
}...)
@ -635,8 +703,9 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
values := make(metricValues, 0, len(s.Network.Interfaces))
for _, value := range s.Network.Interfaces {
values = append(values, metricValue{
value: float64(value.RxBytes),
labels: []string{value.Name},
value: float64(value.RxBytes),
labels: []string{value.Name},
timestamp: s.Timestamp,
})
}
return values
@ -650,8 +719,9 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
values := make(metricValues, 0, len(s.Network.Interfaces))
for _, value := range s.Network.Interfaces {
values = append(values, metricValue{
value: float64(value.RxPackets),
labels: []string{value.Name},
value: float64(value.RxPackets),
labels: []string{value.Name},
timestamp: s.Timestamp,
})
}
return values
@ -665,8 +735,9 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
values := make(metricValues, 0, len(s.Network.Interfaces))
for _, value := range s.Network.Interfaces {
values = append(values, metricValue{
value: float64(value.RxDropped),
labels: []string{value.Name},
value: float64(value.RxDropped),
labels: []string{value.Name},
timestamp: s.Timestamp,
})
}
return values
@ -680,8 +751,9 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
values := make(metricValues, 0, len(s.Network.Interfaces))
for _, value := range s.Network.Interfaces {
values = append(values, metricValue{
value: float64(value.RxErrors),
labels: []string{value.Name},
value: float64(value.RxErrors),
labels: []string{value.Name},
timestamp: s.Timestamp,
})
}
return values
@ -695,8 +767,9 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
values := make(metricValues, 0, len(s.Network.Interfaces))
for _, value := range s.Network.Interfaces {
values = append(values, metricValue{
value: float64(value.TxBytes),
labels: []string{value.Name},
value: float64(value.TxBytes),
labels: []string{value.Name},
timestamp: s.Timestamp,
})
}
return values
@ -710,8 +783,9 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
values := make(metricValues, 0, len(s.Network.Interfaces))
for _, value := range s.Network.Interfaces {
values = append(values, metricValue{
value: float64(value.TxPackets),
labels: []string{value.Name},
value: float64(value.TxPackets),
labels: []string{value.Name},
timestamp: s.Timestamp,
})
}
return values
@ -725,8 +799,9 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
values := make(metricValues, 0, len(s.Network.Interfaces))
for _, value := range s.Network.Interfaces {
values = append(values, metricValue{
value: float64(value.TxDropped),
labels: []string{value.Name},
value: float64(value.TxDropped),
labels: []string{value.Name},
timestamp: s.Timestamp,
})
}
return values
@ -740,8 +815,9 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
values := make(metricValues, 0, len(s.Network.Interfaces))
for _, value := range s.Network.Interfaces {
values = append(values, metricValue{
value: float64(value.TxErrors),
labels: []string{value.Name},
value: float64(value.TxErrors),
labels: []string{value.Name},
timestamp: s.Timestamp,
})
}
return values
@ -759,48 +835,126 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{
{
value: float64(s.Network.Tcp.Established),
labels: []string{"established"},
value: float64(s.Network.Tcp.Established),
labels: []string{"established"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp.SynSent),
labels: []string{"synsent"},
value: float64(s.Network.Tcp.SynSent),
labels: []string{"synsent"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp.SynRecv),
labels: []string{"synrecv"},
value: float64(s.Network.Tcp.SynRecv),
labels: []string{"synrecv"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp.FinWait1),
labels: []string{"finwait1"},
value: float64(s.Network.Tcp.FinWait1),
labels: []string{"finwait1"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp.FinWait2),
labels: []string{"finwait2"},
value: float64(s.Network.Tcp.FinWait2),
labels: []string{"finwait2"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp.TimeWait),
labels: []string{"timewait"},
value: float64(s.Network.Tcp.TimeWait),
labels: []string{"timewait"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp.Close),
labels: []string{"close"},
value: float64(s.Network.Tcp.Close),
labels: []string{"close"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp.CloseWait),
labels: []string{"closewait"},
value: float64(s.Network.Tcp.CloseWait),
labels: []string{"closewait"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp.LastAck),
labels: []string{"lastack"},
value: float64(s.Network.Tcp.LastAck),
labels: []string{"lastack"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp.Listen),
labels: []string{"listen"},
value: float64(s.Network.Tcp.Listen),
labels: []string{"listen"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp.Closing),
labels: []string{"closing"},
value: float64(s.Network.Tcp.Closing),
labels: []string{"closing"},
timestamp: s.Timestamp,
},
}
},
},
}...)
c.containerMetrics = append(c.containerMetrics, []containerMetric{
{
name: "container_network_tcp6_usage_total",
help: "tcp6 connection usage statistic for container",
valueType: prometheus.GaugeValue,
extraLabels: []string{"tcp_state"},
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{
{
value: float64(s.Network.Tcp6.Established),
labels: []string{"established"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp6.SynSent),
labels: []string{"synsent"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp6.SynRecv),
labels: []string{"synrecv"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp6.FinWait1),
labels: []string{"finwait1"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp6.FinWait2),
labels: []string{"finwait2"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp6.TimeWait),
labels: []string{"timewait"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp6.Close),
labels: []string{"close"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp6.CloseWait),
labels: []string{"closewait"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp6.LastAck),
labels: []string{"lastack"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp6.Listen),
labels: []string{"listen"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Tcp6.Closing),
labels: []string{"closing"},
timestamp: s.Timestamp,
},
}
},
@ -808,6 +962,38 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
}...)
}
if includedMetrics.Has(container.NetworkUdpUsageMetrics) {
c.containerMetrics = append(c.containerMetrics, []containerMetric{
{
name: "container_network_udp6_usage_total",
help: "udp6 connection usage statistic for container",
valueType: prometheus.GaugeValue,
extraLabels: []string{"udp_state"},
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{
{
value: float64(s.Network.Udp6.Listen),
labels: []string{"listen"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Udp6.Dropped),
labels: []string{"dropped"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Udp6.RxQueued),
labels: []string{"rxqueued"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Udp6.TxQueued),
labels: []string{"txqueued"},
timestamp: s.Timestamp,
},
}
},
},
}...)
c.containerMetrics = append(c.containerMetrics, []containerMetric{
{
name: "container_network_udp_usage_total",
@ -817,20 +1003,24 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{
{
value: float64(s.Network.Udp.Listen),
labels: []string{"listen"},
value: float64(s.Network.Udp.Listen),
labels: []string{"listen"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Udp.Dropped),
labels: []string{"dropped"},
value: float64(s.Network.Udp.Dropped),
labels: []string{"dropped"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Udp.RxQueued),
labels: []string{"rxqueued"},
value: float64(s.Network.Udp.RxQueued),
labels: []string{"rxqueued"},
timestamp: s.Timestamp,
},
{
value: float64(s.Network.Udp.TxQueued),
labels: []string{"txqueued"},
value: float64(s.Network.Udp.TxQueued),
labels: []string{"txqueued"},
timestamp: s.Timestamp,
},
}
},
@ -844,7 +1034,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
help: "Number of processes running inside the container.",
valueType: prometheus.GaugeValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Processes.ProcessCount)}}
return metricValues{{value: float64(s.Processes.ProcessCount), timestamp: s.Timestamp}}
},
},
{
@ -852,7 +1042,7 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
help: "Number of open file descriptors for the container.",
valueType: prometheus.GaugeValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{{value: float64(s.Processes.FdCount)}}
return metricValues{{value: float64(s.Processes.FdCount), timestamp: s.Timestamp}}
},
},
}...)
@ -922,17 +1112,29 @@ func DefaultContainerLabels(container *info.ContainerInfo) map[string]string {
return set
}
// BaseContainerLabels implements ContainerLabelsFunc. It only exports the
// container name, first alias, and image name.
func BaseContainerLabels(container *info.ContainerInfo) map[string]string {
set := map[string]string{LabelID: container.Name}
if len(container.Aliases) > 0 {
set[LabelName] = container.Aliases[0]
// BaseContainerLabels returns a ContainerLabelsFunc that exports the container
// name, first alias, image name as well as white listed label values.
func BaseContainerLabels(whiteList []string) func(container *info.ContainerInfo) map[string]string {
whiteListMap := make(map[string]struct{}, len(whiteList))
for _, k := range whiteList {
whiteListMap[k] = struct{}{}
}
if image := container.Spec.Image; len(image) > 0 {
set[LabelImage] = image
return func(container *info.ContainerInfo) map[string]string {
set := map[string]string{LabelID: container.Name}
if len(container.Aliases) > 0 {
set[LabelName] = container.Aliases[0]
}
if image := container.Spec.Image; len(image) > 0 {
set[LabelImage] = image
}
for k, v := range container.Spec.Labels {
if _, ok := whiteListMap[k]; ok {
set[ContainerLabelPrefix+k] = v
}
}
return set
}
return set
}
func (c *PrometheusCollector) collectContainersInfo(ch chan<- prometheus.Metric) {
@ -993,7 +1195,10 @@ func (c *PrometheusCollector) collectContainersInfo(ch chan<- prometheus.Metric)
}
desc := cm.desc(labels)
for _, metricValue := range cm.getValues(stats) {
ch <- prometheus.MustNewConstMetric(desc, cm.valueType, float64(metricValue.value), append(values, metricValue.labels...)...)
ch <- prometheus.NewMetricWithTimestamp(
metricValue.timestamp,
prometheus.MustNewConstMetric(desc, cm.valueType, float64(metricValue.value), append(values, metricValue.labels...)...),
)
}
}
}

View file

@ -101,8 +101,9 @@ func (self *OomParser) StreamOoms(outStream chan<- *OomInstance) {
in_oom_kernel_log := checkIfStartOfOomMessages(msg.Message)
if in_oom_kernel_log {
oomCurrentInstance := &OomInstance{
ContainerName: "/",
TimeOfDeath: msg.Timestamp,
ContainerName: "/",
VictimContainerName: "/",
TimeOfDeath: msg.Timestamp,
}
for msg := range kmsgEntries {
err := getContainerName(msg.Message, oomCurrentInstance)

View file

@ -30,9 +30,9 @@ type TwoQueueCache struct {
size int
recentSize int
recent *simplelru.LRU
frequent *simplelru.LRU
recentEvict *simplelru.LRU
recent simplelru.LRUCache
frequent simplelru.LRUCache
recentEvict simplelru.LRUCache
lock sync.RWMutex
}
@ -84,7 +84,8 @@ func New2QParams(size int, recentRatio float64, ghostRatio float64) (*TwoQueueCa
return c, nil
}
func (c *TwoQueueCache) Get(key interface{}) (interface{}, bool) {
// Get looks up a key's value from the cache.
func (c *TwoQueueCache) Get(key interface{}) (value interface{}, ok bool) {
c.lock.Lock()
defer c.lock.Unlock()
@ -105,6 +106,7 @@ func (c *TwoQueueCache) Get(key interface{}) (interface{}, bool) {
return nil, false
}
// Add adds a value to the cache.
func (c *TwoQueueCache) Add(key, value interface{}) {
c.lock.Lock()
defer c.lock.Unlock()
@ -160,12 +162,15 @@ func (c *TwoQueueCache) ensureSpace(recentEvict bool) {
c.frequent.RemoveOldest()
}
// Len returns the number of items in the cache.
func (c *TwoQueueCache) Len() int {
c.lock.RLock()
defer c.lock.RUnlock()
return c.recent.Len() + c.frequent.Len()
}
// Keys returns a slice of the keys in the cache.
// The frequently used keys are first in the returned slice.
func (c *TwoQueueCache) Keys() []interface{} {
c.lock.RLock()
defer c.lock.RUnlock()
@ -174,6 +179,7 @@ func (c *TwoQueueCache) Keys() []interface{} {
return append(k1, k2...)
}
// Remove removes the provided key from the cache.
func (c *TwoQueueCache) Remove(key interface{}) {
c.lock.Lock()
defer c.lock.Unlock()
@ -188,6 +194,7 @@ func (c *TwoQueueCache) Remove(key interface{}) {
}
}
// Purge is used to completely clear the cache.
func (c *TwoQueueCache) Purge() {
c.lock.Lock()
defer c.lock.Unlock()
@ -196,13 +203,17 @@ func (c *TwoQueueCache) Purge() {
c.recentEvict.Purge()
}
// Contains is used to check if the cache contains a key
// without updating recency or frequency.
func (c *TwoQueueCache) Contains(key interface{}) bool {
c.lock.RLock()
defer c.lock.RUnlock()
return c.frequent.Contains(key) || c.recent.Contains(key)
}
func (c *TwoQueueCache) Peek(key interface{}) (interface{}, bool) {
// Peek is used to inspect the cache value of a key
// without updating recency or frequency.
func (c *TwoQueueCache) Peek(key interface{}) (value interface{}, ok bool) {
c.lock.RLock()
defer c.lock.RUnlock()
if val, ok := c.frequent.Peek(key); ok {

View file

@ -18,11 +18,11 @@ type ARCCache struct {
size int // Size is the total capacity of the cache
p int // P is the dynamic preference towards T1 or T2
t1 *simplelru.LRU // T1 is the LRU for recently accessed items
b1 *simplelru.LRU // B1 is the LRU for evictions from t1
t1 simplelru.LRUCache // T1 is the LRU for recently accessed items
b1 simplelru.LRUCache // B1 is the LRU for evictions from t1
t2 *simplelru.LRU // T2 is the LRU for frequently accessed items
b2 *simplelru.LRU // B2 is the LRU for evictions from t2
t2 simplelru.LRUCache // T2 is the LRU for frequently accessed items
b2 simplelru.LRUCache // B2 is the LRU for evictions from t2
lock sync.RWMutex
}
@ -60,11 +60,11 @@ func NewARC(size int) (*ARCCache, error) {
}
// Get looks up a key's value from the cache.
func (c *ARCCache) Get(key interface{}) (interface{}, bool) {
func (c *ARCCache) Get(key interface{}) (value interface{}, ok bool) {
c.lock.Lock()
defer c.lock.Unlock()
// Ff the value is contained in T1 (recent), then
// If the value is contained in T1 (recent), then
// promote it to T2 (frequent)
if val, ok := c.t1.Peek(key); ok {
c.t1.Remove(key)
@ -153,7 +153,7 @@ func (c *ARCCache) Add(key, value interface{}) {
// Remove from B2
c.b2.Remove(key)
// Add the key to the frequntly used list
// Add the key to the frequently used list
c.t2.Add(key, value)
return
}
@ -247,7 +247,7 @@ func (c *ARCCache) Contains(key interface{}) bool {
// Peek is used to inspect the cache value of a key
// without updating recency or frequency.
func (c *ARCCache) Peek(key interface{}) (interface{}, bool) {
func (c *ARCCache) Peek(key interface{}) (value interface{}, ok bool) {
c.lock.RLock()
defer c.lock.RUnlock()
if val, ok := c.t1.Peek(key); ok {

21
vendor/github.com/hashicorp/golang-lru/doc.go generated vendored Normal file
View file

@ -0,0 +1,21 @@
// Package lru provides three different LRU caches of varying sophistication.
//
// Cache is a simple LRU cache. It is based on the
// LRU implementation in groupcache:
// https://github.com/golang/groupcache/tree/master/lru
//
// TwoQueueCache tracks frequently used and recently used entries separately.
// This avoids a burst of accesses from taking out frequently used entries,
// at the cost of about 2x computational overhead and some extra bookkeeping.
//
// ARCCache is an adaptive replacement cache. It tracks recent evictions as
// well as recent usage in both the frequent and recent caches. Its
// computational overhead is comparable to TwoQueueCache, but the memory
// overhead is linear with the size of the cache.
//
// ARC has been patented by IBM, so do not use it if that is problematic for
// your program.
//
// All caches in this package take locks while operating, and are therefore
// thread-safe for consumers.
package lru

1
vendor/github.com/hashicorp/golang-lru/go.mod generated vendored Normal file
View file

@ -0,0 +1 @@
module github.com/hashicorp/golang-lru

View file

@ -1,6 +1,3 @@
// This package provides a simple LRU cache. It is based on the
// LRU implementation in groupcache:
// https://github.com/golang/groupcache/tree/master/lru
package lru
import (
@ -11,11 +8,11 @@ import (
// Cache is a thread-safe fixed size LRU cache.
type Cache struct {
lru *simplelru.LRU
lru simplelru.LRUCache
lock sync.RWMutex
}
// New creates an LRU of the given size
// New creates an LRU of the given size.
func New(size int) (*Cache, error) {
return NewWithEvict(size, nil)
}
@ -33,7 +30,7 @@ func NewWithEvict(size int, onEvicted func(key interface{}, value interface{}))
return c, nil
}
// Purge is used to completely clear the cache
// Purge is used to completely clear the cache.
func (c *Cache) Purge() {
c.lock.Lock()
c.lru.Purge()
@ -41,30 +38,30 @@ func (c *Cache) Purge() {
}
// Add adds a value to the cache. Returns true if an eviction occurred.
func (c *Cache) Add(key, value interface{}) bool {
func (c *Cache) Add(key, value interface{}) (evicted bool) {
c.lock.Lock()
defer c.lock.Unlock()
return c.lru.Add(key, value)
}
// Get looks up a key's value from the cache.
func (c *Cache) Get(key interface{}) (interface{}, bool) {
func (c *Cache) Get(key interface{}) (value interface{}, ok bool) {
c.lock.Lock()
defer c.lock.Unlock()
return c.lru.Get(key)
}
// Check if a key is in the cache, without updating the recent-ness
// or deleting it for being stale.
// Contains checks if a key is in the cache, without updating the
// recent-ness or deleting it for being stale.
func (c *Cache) Contains(key interface{}) bool {
c.lock.RLock()
defer c.lock.RUnlock()
return c.lru.Contains(key)
}
// Returns the key value (or undefined if not found) without updating
// Peek returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key.
func (c *Cache) Peek(key interface{}) (interface{}, bool) {
func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) {
c.lock.RLock()
defer c.lock.RUnlock()
return c.lru.Peek(key)
@ -73,16 +70,15 @@ func (c *Cache) Peek(key interface{}) (interface{}, bool) {
// ContainsOrAdd checks if a key is in the cache without updating the
// recent-ness or deleting it for being stale, and if not, adds the value.
// Returns whether found and whether an eviction occurred.
func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evict bool) {
func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evicted bool) {
c.lock.Lock()
defer c.lock.Unlock()
if c.lru.Contains(key) {
return true, false
} else {
evict := c.lru.Add(key, value)
return false, evict
}
evicted = c.lru.Add(key, value)
return false, evicted
}
// Remove removes the provided key from the cache.

View file

@ -36,7 +36,7 @@ func NewLRU(size int, onEvict EvictCallback) (*LRU, error) {
return c, nil
}
// Purge is used to completely clear the cache
// Purge is used to completely clear the cache.
func (c *LRU) Purge() {
for k, v := range c.items {
if c.onEvict != nil {
@ -47,8 +47,8 @@ func (c *LRU) Purge() {
c.evictList.Init()
}
// Add adds a value to the cache. Returns true if an eviction occured.
func (c *LRU) Add(key, value interface{}) bool {
// Add adds a value to the cache. Returns true if an eviction occurred.
func (c *LRU) Add(key, value interface{}) (evicted bool) {
// Check for existing item
if ent, ok := c.items[key]; ok {
c.evictList.MoveToFront(ent)
@ -78,17 +78,18 @@ func (c *LRU) Get(key interface{}) (value interface{}, ok bool) {
return
}
// Check if a key is in the cache, without updating the recent-ness
// Contains checks if a key is in the cache, without updating the recent-ness
// or deleting it for being stale.
func (c *LRU) Contains(key interface{}) (ok bool) {
_, ok = c.items[key]
return ok
}
// Returns the key value (or undefined if not found) without updating
// Peek returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key.
func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) {
if ent, ok := c.items[key]; ok {
var ent *list.Element
if ent, ok = c.items[key]; ok {
return ent.Value.(*entry).value, true
}
return nil, ok
@ -96,7 +97,7 @@ func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) {
// Remove removes the provided key from the cache, returning if the
// key was contained.
func (c *LRU) Remove(key interface{}) bool {
func (c *LRU) Remove(key interface{}) (present bool) {
if ent, ok := c.items[key]; ok {
c.removeElement(ent)
return true
@ -105,7 +106,7 @@ func (c *LRU) Remove(key interface{}) bool {
}
// RemoveOldest removes the oldest item from the cache.
func (c *LRU) RemoveOldest() (interface{}, interface{}, bool) {
func (c *LRU) RemoveOldest() (key interface{}, value interface{}, ok bool) {
ent := c.evictList.Back()
if ent != nil {
c.removeElement(ent)
@ -116,7 +117,7 @@ func (c *LRU) RemoveOldest() (interface{}, interface{}, bool) {
}
// GetOldest returns the oldest entry
func (c *LRU) GetOldest() (interface{}, interface{}, bool) {
func (c *LRU) GetOldest() (key interface{}, value interface{}, ok bool) {
ent := c.evictList.Back()
if ent != nil {
kv := ent.Value.(*entry)

View file

@ -0,0 +1,36 @@
package simplelru
// LRUCache is the interface for simple LRU cache.
type LRUCache interface {
// Adds a value to the cache, returns true if an eviction occurred and
// updates the "recently used"-ness of the key.
Add(key, value interface{}) bool
// Returns key's value from the cache and
// updates the "recently used"-ness of the key. #value, isFound
Get(key interface{}) (value interface{}, ok bool)
// Check if a key exsists in cache without updating the recent-ness.
Contains(key interface{}) (ok bool)
// Returns key's value without updating the "recently used"-ness of the key.
Peek(key interface{}) (value interface{}, ok bool)
// Removes a key from the cache.
Remove(key interface{}) bool
// Removes the oldest entry from cache.
RemoveOldest() (interface{}, interface{}, bool)
// Returns the oldest entry from the cache. #key, value, isFound
GetOldest() (interface{}, interface{}, bool)
// Returns a slice of the keys in the cache, from oldest to newest.
Keys() []interface{}
// Returns the number of items in the cache.
Len() int
// Clear all cache entries
Purge()
}

View file

@ -11,7 +11,7 @@ import (
"github.com/ibuildthecloud/kvsql/pkg/broadcast"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
utiltrace "k8s.io/apiserver/pkg/util/trace"
utiltrace "k8s.io/utils/trace"
)
type Generic struct {

View file

@ -21,7 +21,7 @@ import (
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
"golang.org/x/net/context"
utiltrace "k8s.io/apiserver/pkg/util/trace"
utiltrace "k8s.io/utils/trace"
)
type Txn interface {

View file

@ -66,7 +66,7 @@ func NewKVSQLHealthCheck(c storagebackend.Config) (func() error, error) {
func newETCD3Client(c storagebackend.Config) (*clientv3.Client, error) {
cfg := clientv3.Config{
Endpoints: c.ServerList,
Endpoints: c.Transport.ServerList,
}
if len(cfg.Endpoints) == 0 {

View file

@ -39,7 +39,7 @@ import (
"k8s.io/apiserver/pkg/storage"
"k8s.io/apiserver/pkg/storage/etcd"
"k8s.io/apiserver/pkg/storage/value"
utiltrace "k8s.io/apiserver/pkg/util/trace"
utiltrace "k8s.io/utils/trace"
)
// authenticatedDataString satisfies the value.Context interface. It uses the key to

11
vendor/github.com/liggitt/tabwriter/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,11 @@
language: go
go:
- "1.8"
- "1.9"
- "1.10"
- "1.11"
- "1.12"
- master
script: go test -v ./...

27
vendor/github.com/liggitt/tabwriter/LICENSE generated vendored Normal file
View file

@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

7
vendor/github.com/liggitt/tabwriter/README.md generated vendored Normal file
View file

@ -0,0 +1,7 @@
This repo is a drop-in replacement for the golang [text/tabwriter](https://golang.org/pkg/text/tabwriter/) package.
It is based on that package at [cf2c2ea8](https://github.com/golang/go/tree/cf2c2ea89d09d486bb018b1817c5874388038c3a/src/text/tabwriter) and inherits its license.
The following additional features are supported:
* `RememberWidths` flag allows remembering maximum widths seen per column even after Flush() is called.
* `RememberedWidths() []int` and `SetRememberedWidths([]int) *Writer` allows obtaining and transferring remembered column width between writers.

637
vendor/github.com/liggitt/tabwriter/tabwriter.go generated vendored Normal file
View file

@ -0,0 +1,637 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package tabwriter implements a write filter (tabwriter.Writer) that
// translates tabbed columns in input into properly aligned text.
//
// It is a drop-in replacement for the golang text/tabwriter package (https://golang.org/pkg/text/tabwriter),
// based on that package at https://github.com/golang/go/tree/cf2c2ea89d09d486bb018b1817c5874388038c3a
// with support for additional features.
//
// The package is using the Elastic Tabstops algorithm described at
// http://nickgravgaard.com/elastictabstops/index.html.
package tabwriter
import (
"io"
"unicode/utf8"
)
// ----------------------------------------------------------------------------
// Filter implementation
// A cell represents a segment of text terminated by tabs or line breaks.
// The text itself is stored in a separate buffer; cell only describes the
// segment's size in bytes, its width in runes, and whether it's an htab
// ('\t') terminated cell.
//
type cell struct {
size int // cell size in bytes
width int // cell width in runes
htab bool // true if the cell is terminated by an htab ('\t')
}
// A Writer is a filter that inserts padding around tab-delimited
// columns in its input to align them in the output.
//
// The Writer treats incoming bytes as UTF-8-encoded text consisting
// of cells terminated by horizontal ('\t') or vertical ('\v') tabs,
// and newline ('\n') or formfeed ('\f') characters; both newline and
// formfeed act as line breaks.
//
// Tab-terminated cells in contiguous lines constitute a column. The
// Writer inserts padding as needed to make all cells in a column have
// the same width, effectively aligning the columns. It assumes that
// all characters have the same width, except for tabs for which a
// tabwidth must be specified. Column cells must be tab-terminated, not
// tab-separated: non-tab terminated trailing text at the end of a line
// forms a cell but that cell is not part of an aligned column.
// For instance, in this example (where | stands for a horizontal tab):
//
// aaaa|bbb|d
// aa |b |dd
// a |
// aa |cccc|eee
//
// the b and c are in distinct columns (the b column is not contiguous
// all the way). The d and e are not in a column at all (there's no
// terminating tab, nor would the column be contiguous).
//
// The Writer assumes that all Unicode code points have the same width;
// this may not be true in some fonts or if the string contains combining
// characters.
//
// If DiscardEmptyColumns is set, empty columns that are terminated
// entirely by vertical (or "soft") tabs are discarded. Columns
// terminated by horizontal (or "hard") tabs are not affected by
// this flag.
//
// If a Writer is configured to filter HTML, HTML tags and entities
// are passed through. The widths of tags and entities are
// assumed to be zero (tags) and one (entities) for formatting purposes.
//
// A segment of text may be escaped by bracketing it with Escape
// characters. The tabwriter passes escaped text segments through
// unchanged. In particular, it does not interpret any tabs or line
// breaks within the segment. If the StripEscape flag is set, the
// Escape characters are stripped from the output; otherwise they
// are passed through as well. For the purpose of formatting, the
// width of the escaped text is always computed excluding the Escape
// characters.
//
// The formfeed character acts like a newline but it also terminates
// all columns in the current line (effectively calling Flush). Tab-
// terminated cells in the next line start new columns. Unless found
// inside an HTML tag or inside an escaped text segment, formfeed
// characters appear as newlines in the output.
//
// The Writer must buffer input internally, because proper spacing
// of one line may depend on the cells in future lines. Clients must
// call Flush when done calling Write.
//
type Writer struct {
// configuration
output io.Writer
minwidth int
tabwidth int
padding int
padbytes [8]byte
flags uint
// current state
buf []byte // collected text excluding tabs or line breaks
pos int // buffer position up to which cell.width of incomplete cell has been computed
cell cell // current incomplete cell; cell.width is up to buf[pos] excluding ignored sections
endChar byte // terminating char of escaped sequence (Escape for escapes, '>', ';' for HTML tags/entities, or 0)
lines [][]cell // list of lines; each line is a list of cells
widths []int // list of column widths in runes - re-used during formatting
maxwidths []int // list of max column widths in runes
}
// addLine adds a new line.
// flushed is a hint indicating whether the underlying writer was just flushed.
// If so, the previous line is not likely to be a good indicator of the new line's cells.
func (b *Writer) addLine(flushed bool) {
// Grow slice instead of appending,
// as that gives us an opportunity
// to re-use an existing []cell.
if n := len(b.lines) + 1; n <= cap(b.lines) {
b.lines = b.lines[:n]
b.lines[n-1] = b.lines[n-1][:0]
} else {
b.lines = append(b.lines, nil)
}
if !flushed {
// The previous line is probably a good indicator
// of how many cells the current line will have.
// If the current line's capacity is smaller than that,
// abandon it and make a new one.
if n := len(b.lines); n >= 2 {
if prev := len(b.lines[n-2]); prev > cap(b.lines[n-1]) {
b.lines[n-1] = make([]cell, 0, prev)
}
}
}
}
// Reset the current state.
func (b *Writer) reset() {
b.buf = b.buf[:0]
b.pos = 0
b.cell = cell{}
b.endChar = 0
b.lines = b.lines[0:0]
b.widths = b.widths[0:0]
b.addLine(true)
}
// Internal representation (current state):
//
// - all text written is appended to buf; tabs and line breaks are stripped away
// - at any given time there is a (possibly empty) incomplete cell at the end
// (the cell starts after a tab or line break)
// - cell.size is the number of bytes belonging to the cell so far
// - cell.width is text width in runes of that cell from the start of the cell to
// position pos; html tags and entities are excluded from this width if html
// filtering is enabled
// - the sizes and widths of processed text are kept in the lines list
// which contains a list of cells for each line
// - the widths list is a temporary list with current widths used during
// formatting; it is kept in Writer because it's re-used
//
// |<---------- size ---------->|
// | |
// |<- width ->|<- ignored ->| |
// | | | |
// [---processed---tab------------<tag>...</tag>...]
// ^ ^ ^
// | | |
// buf start of incomplete cell pos
// Formatting can be controlled with these flags.
const (
// Ignore html tags and treat entities (starting with '&'
// and ending in ';') as single characters (width = 1).
FilterHTML uint = 1 << iota
// Strip Escape characters bracketing escaped text segments
// instead of passing them through unchanged with the text.
StripEscape
// Force right-alignment of cell content.
// Default is left-alignment.
AlignRight
// Handle empty columns as if they were not present in
// the input in the first place.
DiscardEmptyColumns
// Always use tabs for indentation columns (i.e., padding of
// leading empty cells on the left) independent of padchar.
TabIndent
// Print a vertical bar ('|') between columns (after formatting).
// Discarded columns appear as zero-width columns ("||").
Debug
// Remember maximum widths seen per column even after Flush() is called.
RememberWidths
)
// A Writer must be initialized with a call to Init. The first parameter (output)
// specifies the filter output. The remaining parameters control the formatting:
//
// minwidth minimal cell width including any padding
// tabwidth width of tab characters (equivalent number of spaces)
// padding padding added to a cell before computing its width
// padchar ASCII char used for padding
// if padchar == '\t', the Writer will assume that the
// width of a '\t' in the formatted output is tabwidth,
// and cells are left-aligned independent of align_left
// (for correct-looking results, tabwidth must correspond
// to the tab width in the viewer displaying the result)
// flags formatting control
//
func (b *Writer) Init(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
if minwidth < 0 || tabwidth < 0 || padding < 0 {
panic("negative minwidth, tabwidth, or padding")
}
b.output = output
b.minwidth = minwidth
b.tabwidth = tabwidth
b.padding = padding
for i := range b.padbytes {
b.padbytes[i] = padchar
}
if padchar == '\t' {
// tab padding enforces left-alignment
flags &^= AlignRight
}
b.flags = flags
b.reset()
return b
}
// debugging support (keep code around)
func (b *Writer) dump() {
pos := 0
for i, line := range b.lines {
print("(", i, ") ")
for _, c := range line {
print("[", string(b.buf[pos:pos+c.size]), "]")
pos += c.size
}
print("\n")
}
print("\n")
}
// local error wrapper so we can distinguish errors we want to return
// as errors from genuine panics (which we don't want to return as errors)
type osError struct {
err error
}
func (b *Writer) write0(buf []byte) {
n, err := b.output.Write(buf)
if n != len(buf) && err == nil {
err = io.ErrShortWrite
}
if err != nil {
panic(osError{err})
}
}
func (b *Writer) writeN(src []byte, n int) {
for n > len(src) {
b.write0(src)
n -= len(src)
}
b.write0(src[0:n])
}
var (
newline = []byte{'\n'}
tabs = []byte("\t\t\t\t\t\t\t\t")
)
func (b *Writer) writePadding(textw, cellw int, useTabs bool) {
if b.padbytes[0] == '\t' || useTabs {
// padding is done with tabs
if b.tabwidth == 0 {
return // tabs have no width - can't do any padding
}
// make cellw the smallest multiple of b.tabwidth
cellw = (cellw + b.tabwidth - 1) / b.tabwidth * b.tabwidth
n := cellw - textw // amount of padding
if n < 0 {
panic("internal error")
}
b.writeN(tabs, (n+b.tabwidth-1)/b.tabwidth)
return
}
// padding is done with non-tab characters
b.writeN(b.padbytes[0:], cellw-textw)
}
var vbar = []byte{'|'}
func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) {
pos = pos0
for i := line0; i < line1; i++ {
line := b.lines[i]
// if TabIndent is set, use tabs to pad leading empty cells
useTabs := b.flags&TabIndent != 0
for j, c := range line {
if j > 0 && b.flags&Debug != 0 {
// indicate column break
b.write0(vbar)
}
if c.size == 0 {
// empty cell
if j < len(b.widths) {
b.writePadding(c.width, b.widths[j], useTabs)
}
} else {
// non-empty cell
useTabs = false
if b.flags&AlignRight == 0 { // align left
b.write0(b.buf[pos : pos+c.size])
pos += c.size
if j < len(b.widths) {
b.writePadding(c.width, b.widths[j], false)
}
} else { // align right
if j < len(b.widths) {
b.writePadding(c.width, b.widths[j], false)
}
b.write0(b.buf[pos : pos+c.size])
pos += c.size
}
}
}
if i+1 == len(b.lines) {
// last buffered line - we don't have a newline, so just write
// any outstanding buffered data
b.write0(b.buf[pos : pos+b.cell.size])
pos += b.cell.size
} else {
// not the last line - write newline
b.write0(newline)
}
}
return
}
// Format the text between line0 and line1 (excluding line1); pos
// is the buffer position corresponding to the beginning of line0.
// Returns the buffer position corresponding to the beginning of
// line1 and an error, if any.
//
func (b *Writer) format(pos0 int, line0, line1 int) (pos int) {
pos = pos0
column := len(b.widths)
for this := line0; this < line1; this++ {
line := b.lines[this]
if column >= len(line)-1 {
continue
}
// cell exists in this column => this line
// has more cells than the previous line
// (the last cell per line is ignored because cells are
// tab-terminated; the last cell per line describes the
// text before the newline/formfeed and does not belong
// to a column)
// print unprinted lines until beginning of block
pos = b.writeLines(pos, line0, this)
line0 = this
// column block begin
width := b.minwidth // minimal column width
discardable := true // true if all cells in this column are empty and "soft"
for ; this < line1; this++ {
line = b.lines[this]
if column >= len(line)-1 {
break
}
// cell exists in this column
c := line[column]
// update width
if w := c.width + b.padding; w > width {
width = w
}
// update discardable
if c.width > 0 || c.htab {
discardable = false
}
}
// column block end
// discard empty columns if necessary
if discardable && b.flags&DiscardEmptyColumns != 0 {
width = 0
}
if b.flags&RememberWidths != 0 {
if len(b.maxwidths) < len(b.widths) {
b.maxwidths = append(b.maxwidths, b.widths[len(b.maxwidths):]...)
}
switch {
case len(b.maxwidths) == len(b.widths):
b.maxwidths = append(b.maxwidths, width)
case b.maxwidths[len(b.widths)] > width:
width = b.maxwidths[len(b.widths)]
case b.maxwidths[len(b.widths)] < width:
b.maxwidths[len(b.widths)] = width
}
}
// format and print all columns to the right of this column
// (we know the widths of this column and all columns to the left)
b.widths = append(b.widths, width) // push width
pos = b.format(pos, line0, this)
b.widths = b.widths[0 : len(b.widths)-1] // pop width
line0 = this
}
// print unprinted lines until end
return b.writeLines(pos, line0, line1)
}
// Append text to current cell.
func (b *Writer) append(text []byte) {
b.buf = append(b.buf, text...)
b.cell.size += len(text)
}
// Update the cell width.
func (b *Writer) updateWidth() {
b.cell.width += utf8.RuneCount(b.buf[b.pos:])
b.pos = len(b.buf)
}
// To escape a text segment, bracket it with Escape characters.
// For instance, the tab in this string "Ignore this tab: \xff\t\xff"
// does not terminate a cell and constitutes a single character of
// width one for formatting purposes.
//
// The value 0xff was chosen because it cannot appear in a valid UTF-8 sequence.
//
const Escape = '\xff'
// Start escaped mode.
func (b *Writer) startEscape(ch byte) {
switch ch {
case Escape:
b.endChar = Escape
case '<':
b.endChar = '>'
case '&':
b.endChar = ';'
}
}
// Terminate escaped mode. If the escaped text was an HTML tag, its width
// is assumed to be zero for formatting purposes; if it was an HTML entity,
// its width is assumed to be one. In all other cases, the width is the
// unicode width of the text.
//
func (b *Writer) endEscape() {
switch b.endChar {
case Escape:
b.updateWidth()
if b.flags&StripEscape == 0 {
b.cell.width -= 2 // don't count the Escape chars
}
case '>': // tag of zero width
case ';':
b.cell.width++ // entity, count as one rune
}
b.pos = len(b.buf)
b.endChar = 0
}
// Terminate the current cell by adding it to the list of cells of the
// current line. Returns the number of cells in that line.
//
func (b *Writer) terminateCell(htab bool) int {
b.cell.htab = htab
line := &b.lines[len(b.lines)-1]
*line = append(*line, b.cell)
b.cell = cell{}
return len(*line)
}
func handlePanic(err *error, op string) {
if e := recover(); e != nil {
if nerr, ok := e.(osError); ok {
*err = nerr.err
return
}
panic("tabwriter: panic during " + op)
}
}
// RememberedWidths returns a copy of the remembered per-column maximum widths.
// Requires use of the RememberWidths flag, and is not threadsafe.
func (b *Writer) RememberedWidths() []int {
retval := make([]int, len(b.maxwidths))
copy(retval, b.maxwidths)
return retval
}
// SetRememberedWidths sets the remembered per-column maximum widths.
// Requires use of the RememberWidths flag, and is not threadsafe.
func (b *Writer) SetRememberedWidths(widths []int) *Writer {
b.maxwidths = make([]int, len(widths))
copy(b.maxwidths, widths)
return b
}
// Flush should be called after the last call to Write to ensure
// that any data buffered in the Writer is written to output. Any
// incomplete escape sequence at the end is considered
// complete for formatting purposes.
func (b *Writer) Flush() error {
return b.flush()
}
func (b *Writer) flush() (err error) {
defer b.reset() // even in the presence of errors
defer handlePanic(&err, "Flush")
// add current cell if not empty
if b.cell.size > 0 {
if b.endChar != 0 {
// inside escape - terminate it even if incomplete
b.endEscape()
}
b.terminateCell(false)
}
// format contents of buffer
b.format(0, 0, len(b.lines))
return nil
}
var hbar = []byte("---\n")
// Write writes buf to the writer b.
// The only errors returned are ones encountered
// while writing to the underlying output stream.
//
func (b *Writer) Write(buf []byte) (n int, err error) {
defer handlePanic(&err, "Write")
// split text into cells
n = 0
for i, ch := range buf {
if b.endChar == 0 {
// outside escape
switch ch {
case '\t', '\v', '\n', '\f':
// end of cell
b.append(buf[n:i])
b.updateWidth()
n = i + 1 // ch consumed
ncells := b.terminateCell(ch == '\t')
if ch == '\n' || ch == '\f' {
// terminate line
b.addLine(ch == '\f')
if ch == '\f' || ncells == 1 {
// A '\f' always forces a flush. Otherwise, if the previous
// line has only one cell which does not have an impact on
// the formatting of the following lines (the last cell per
// line is ignored by format()), thus we can flush the
// Writer contents.
if err = b.Flush(); err != nil {
return
}
if ch == '\f' && b.flags&Debug != 0 {
// indicate section break
b.write0(hbar)
}
}
}
case Escape:
// start of escaped sequence
b.append(buf[n:i])
b.updateWidth()
n = i
if b.flags&StripEscape != 0 {
n++ // strip Escape
}
b.startEscape(Escape)
case '<', '&':
// possibly an html tag/entity
if b.flags&FilterHTML != 0 {
// begin of tag/entity
b.append(buf[n:i])
b.updateWidth()
n = i
b.startEscape(ch)
}
}
} else {
// inside escape
if ch == b.endChar {
// end of tag/entity
j := i + 1
if ch == Escape && b.flags&StripEscape != 0 {
j = i // strip Escape
}
b.append(buf[n:j])
n = i + 1 // ch consumed
b.endEscape()
}
}
}
// append leftover text
b.append(buf[n:])
n = len(buf)
return
}
// NewWriter allocates and initializes a new tabwriter.Writer.
// The parameters are the same as for the Init function.
//
func NewWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
return new(Writer).Init(output, minwidth, tabwidth, padding, padchar, flags)
}

11
vendor/github.com/lithammer/dedent/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,11 @@
language: go
go:
- "1.6"
- "1.7"
- "1.8"
- "1.9"
- "1.10"
- "1.11"
sudo: false

View file

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015 Peter Renström
Copyright (c) 2018 Peter Lithammer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -1,7 +1,7 @@
# Dedent
[![Build Status](https://travis-ci.org/renstrom/dedent.svg?branch=master)](https://travis-ci.org/renstrom/dedent)
[![Godoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/renstrom/dedent)
[![Build Status](https://travis-ci.org/lithammer/dedent.svg?branch=master)](https://travis-ci.org/lithammer/dedent)
[![Godoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/lithammer/dedent)
Removes common leading whitespace from multiline strings. Inspired by [`textwrap.dedent`](https://docs.python.org/3/library/textwrap.html#textwrap.dedent) in Python.
@ -13,19 +13,20 @@ Imagine the following snippet that prints a multiline string. You want the inden
package main
import (
"fmt"
"fmt"
"github.com/renstrom/dedent"
"github.com/lithammer/dedent"
)
func main() {
s := `Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
Curabitur justo tellus, facilisis nec efficitur dictum,
fermentum vitae ligula. Sed eu convallis sapien.`
fmt.Println(dedent.Dedent(s))
fmt.Println("-------------")
fmt.Println(s)
s := `
Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
Curabitur justo tellus, facilisis nec efficitur dictum,
fermentum vitae ligula. Sed eu convallis sapien.`
fmt.Println(Dedent(s))
fmt.Println("-------------")
fmt.Println(s)
}
```
@ -39,10 +40,11 @@ consectetur adipiscing elit.
Curabitur justo tellus, facilisis nec efficitur dictum,
fermentum vitae ligula. Sed eu convallis sapien.
-------------
Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
Curabitur justo tellus, facilisis nec efficitur dictum,
fermentum vitae ligula. Sed eu convallis sapien.
Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
Curabitur justo tellus, facilisis nec efficitur dictum,
fermentum vitae ligula. Sed eu convallis sapien.
```
## License

1
vendor/github.com/lithammer/dedent/go.mod generated vendored Normal file
View file

@ -0,0 +1 @@
module github.com/lithammer/dedent

View file

@ -1,3 +1,4 @@
dist: xenial
language: go
go:
- 1.9.x
@ -6,6 +7,13 @@ go:
- tip
matrix:
include:
- go: 1.11.x
env:
- RUNC_USE_SYSTEMD=1
script:
- make BUILDTAGS="${BUILDTAGS}" all
- sudo PATH="$PATH" make localintegration RUNC_USE_SYSTEMD=1
allow_failures:
- go: tip
@ -21,9 +29,8 @@ env:
- BUILDTAGS="seccomp apparmor selinux ambient"
before_install:
- echo "deb http://archive.ubuntu.com/ubuntu trusty-backports main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list
- sudo apt-get -qq update
- sudo apt-get install -y libseccomp-dev/trusty-backports
- sudo apt-get install -y libseccomp-dev
- go get -u golang.org/x/lint/golint
- go get -u github.com/vbatts/git-validation
- env | grep TRAVIS_

View file

@ -16,10 +16,9 @@ This means that `runc` 1.0.0 should implement the 1.0 version of the specificati
You can find official releases of `runc` on the [release](https://github.com/opencontainers/runc/releases) page.
### Security
## Security
If you wish to report a security issue, please disclose the issue responsibly
to security@opencontainers.org.
Reporting process and disclosure communications are outlined in [/org/security](https://github.com/opencontainers/org/blob/master/security/)
## Building

Some files were not shown because too many files have changed in this diff Show more