mirror of https://github.com/k3s-io/k3s
Merge pull request #68431 from dashpole/cadvisor_godep_update
Update cAdvisor godeps to v0.31.0pull/8/head
commit
37ef6eeb6d
|
@ -26,12 +26,12 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "cloud.google.com/go/compute/metadata",
|
||||
"Comment": "v0.1.0-115-g3b1ae45",
|
||||
"Comment": "v0.1.0-115-g3b1ae453",
|
||||
"Rev": "3b1ae45394a234c385be014e9a488f2bb6eef821"
|
||||
},
|
||||
{
|
||||
"ImportPath": "cloud.google.com/go/internal",
|
||||
"Comment": "v0.1.0-115-g3b1ae45",
|
||||
"Comment": "v0.1.0-115-g3b1ae453",
|
||||
"Rev": "3b1ae45394a234c385be014e9a488f2bb6eef821"
|
||||
},
|
||||
{
|
||||
|
@ -150,6 +150,26 @@
|
|||
"ImportPath": "github.com/PuerkitoBio/urlesc",
|
||||
"Rev": "5bd2802263f21d8788851d5305584c82a5c75d7e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/Rican7/retry",
|
||||
"Comment": "v0.1.0-9-g272ad12",
|
||||
"Rev": "272ad122d6e5ce1be757544007cf8bcd1c9c9ab0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/Rican7/retry/backoff",
|
||||
"Comment": "v0.1.0-9-g272ad12",
|
||||
"Rev": "272ad122d6e5ce1be757544007cf8bcd1c9c9ab0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/Rican7/retry/jitter",
|
||||
"Comment": "v0.1.0-9-g272ad12",
|
||||
"Rev": "272ad122d6e5ce1be757544007cf8bcd1c9c9ab0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/Rican7/retry/strategy",
|
||||
"Comment": "v0.1.0-9-g272ad12",
|
||||
"Rev": "272ad122d6e5ce1be757544007cf8bcd1c9c9ab0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/armon/circbuf",
|
||||
"Rev": "bbbad097214e2918d8543d5201d12bfd7bca254d"
|
||||
|
@ -1320,142 +1340,142 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/distribution/digestset",
|
||||
"Comment": "v2.6.0-rc.1-209-gedc3ab2",
|
||||
"Comment": "v2.6.0-rc.1-209-gedc3ab29",
|
||||
"Rev": "edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/distribution/reference",
|
||||
"Comment": "v2.6.0-rc.1-209-gedc3ab2",
|
||||
"Comment": "v2.6.0-rc.1-209-gedc3ab29",
|
||||
"Rev": "edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/blkiodev",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/container",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/events",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/filters",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/image",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/mount",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/network",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/registry",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/strslice",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/swarm",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/swarm/runtime",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/time",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/versions",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/api/types/volume",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/client",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/daemon/logger/jsonfilelog/jsonlog",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/jsonmessage",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/mount",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/parsers",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/parsers/operatingsystem",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/stdcopy",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/sysinfo",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/term",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/term/windows",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc",
|
||||
"Comment": "docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8d",
|
||||
"Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d"
|
||||
},
|
||||
{
|
||||
|
@ -1480,7 +1500,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/libnetwork/ipvs",
|
||||
"Comment": "v0.8.0-dev.2-910-gba46b92",
|
||||
"Comment": "v0.8.0-dev.2-910-gba46b928",
|
||||
"Rev": "ba46b928444931e6865d8618dc03622cac79aa6f"
|
||||
},
|
||||
{
|
||||
|
@ -1599,132 +1619,132 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/gogoproto",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/compare",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/defaultcheck",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/description",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/embedcheck",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/enumstringer",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/equal",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/face",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/gostring",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/marshalto",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/oneofcheck",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/populate",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/size",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/stringer",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/testgen",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/union",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/plugin/unmarshal",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/proto",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/descriptor",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/generator",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/grpc",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/plugin",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/sortkeys",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/types",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/vanity",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/vanity/command",
|
||||
"Comment": "v0.4-3-gc0656ed",
|
||||
"Comment": "v0.4-3-gc0656edd",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
|
@ -1790,183 +1810,188 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/accelerators",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/cache/memory",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/client/v2",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/collector",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/container",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/container/common",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/container/containerd",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/container/crio",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/container/docker",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/container/libcontainer",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/container/mesos",
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/container/raw",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/container/rkt",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/container/systemd",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/devicemapper",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/events",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/fs",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/info/v1",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/info/v2",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/machine",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/manager",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/manager/watcher",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/manager/watcher/raw",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/manager/watcher/rkt",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/metrics",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/storage",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/summary",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/utils",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/utils/cloudinfo",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/utils/cpuload",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/utils/cpuload/netlink",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/utils/docker",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/utils/oomparser",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/utils/sysfs",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/utils/sysinfo",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/version",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/cadvisor/zfs",
|
||||
"Comment": "v0.30.0-12-gf834c0f",
|
||||
"Rev": "f834c0f4c100ae524db33139dce953e0003f23ad"
|
||||
"Comment": "v0.31.0",
|
||||
"Rev": "fc17731afdcf184832482e324913c8f1a91b54ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/certificate-transparency-go",
|
||||
|
@ -2392,6 +2417,76 @@
|
|||
"Comment": "v1.0.1",
|
||||
"Rev": "c12348ce28de40eed0136aa2b644d0ee0650e56c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/api/v1/lib",
|
||||
"Comment": "mesos-1.6.x-12-gff8175b",
|
||||
"Rev": "ff8175bfda54b1eb1f1954c8102a9dc612aa2312"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/api/v1/lib/agent",
|
||||
"Comment": "mesos-1.6.x-12-gff8175b",
|
||||
"Rev": "ff8175bfda54b1eb1f1954c8102a9dc612aa2312"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/api/v1/lib/agent/calls",
|
||||
"Comment": "mesos-1.6.x-12-gff8175b",
|
||||
"Rev": "ff8175bfda54b1eb1f1954c8102a9dc612aa2312"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/api/v1/lib/client",
|
||||
"Comment": "mesos-1.6.x-12-gff8175b",
|
||||
"Rev": "ff8175bfda54b1eb1f1954c8102a9dc612aa2312"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/api/v1/lib/debug",
|
||||
"Comment": "mesos-1.6.x-12-gff8175b",
|
||||
"Rev": "ff8175bfda54b1eb1f1954c8102a9dc612aa2312"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/api/v1/lib/encoding",
|
||||
"Comment": "mesos-1.6.x-12-gff8175b",
|
||||
"Rev": "ff8175bfda54b1eb1f1954c8102a9dc612aa2312"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/api/v1/lib/encoding/codecs",
|
||||
"Comment": "mesos-1.6.x-12-gff8175b",
|
||||
"Rev": "ff8175bfda54b1eb1f1954c8102a9dc612aa2312"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/api/v1/lib/encoding/framing",
|
||||
"Comment": "mesos-1.6.x-12-gff8175b",
|
||||
"Rev": "ff8175bfda54b1eb1f1954c8102a9dc612aa2312"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/api/v1/lib/encoding/json",
|
||||
"Comment": "mesos-1.6.x-12-gff8175b",
|
||||
"Rev": "ff8175bfda54b1eb1f1954c8102a9dc612aa2312"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/api/v1/lib/encoding/proto",
|
||||
"Comment": "mesos-1.6.x-12-gff8175b",
|
||||
"Rev": "ff8175bfda54b1eb1f1954c8102a9dc612aa2312"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/api/v1/lib/httpcli",
|
||||
"Comment": "mesos-1.6.x-12-gff8175b",
|
||||
"Rev": "ff8175bfda54b1eb1f1954c8102a9dc612aa2312"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors",
|
||||
"Comment": "mesos-1.6.x-12-gff8175b",
|
||||
"Rev": "ff8175bfda54b1eb1f1954c8102a9dc612aa2312"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/api/v1/lib/recordio",
|
||||
"Comment": "mesos-1.6.x-12-gff8175b",
|
||||
"Rev": "ff8175bfda54b1eb1f1954c8102a9dc612aa2312"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/api/v1/lib/roles",
|
||||
"Comment": "mesos-1.6.x-12-gff8175b",
|
||||
"Rev": "ff8175bfda54b1eb1f1954c8102a9dc612aa2312"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mholt/caddy/caddyfile",
|
||||
"Comment": "v0.10.10-57-g2de4950",
|
||||
|
@ -2656,82 +2751,82 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/apparmor",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/cgroups",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/cgroups/fs",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/cgroups/systemd",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/configs",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/configs/validate",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/criurpc",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/intelrdt",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/keys",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/mount",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/seccomp",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/stacktrace",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/system",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/user",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer/utils",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e",
|
||||
"Comment": "v1.0.0-rc5-46-g871ba2e5",
|
||||
"Rev": "871ba2e58e24314d1fab4517a80410191ba5ad01"
|
||||
},
|
||||
{
|
||||
|
@ -2784,6 +2879,14 @@
|
|||
"ImportPath": "github.com/pquerna/cachecontrol/cacheobject",
|
||||
"Rev": "0dec1b30a0215bb68605dfc568e8855066c9202d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/pquerna/ffjson/fflib/v1",
|
||||
"Rev": "af8b230fcd2007c7095168ca8ab94c68b60840c6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/pquerna/ffjson/fflib/v1/internal",
|
||||
"Rev": "af8b230fcd2007c7095168ca8ab94c68b60840c6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/prometheus/client_golang/prometheus",
|
||||
"Comment": "v0.8.0-83-ge7e9030",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -104,18 +104,23 @@ func containerLabels(c *cadvisorapi.ContainerInfo) map[string]string {
|
|||
func New(imageFsInfoProvider ImageFsInfoProvider, rootPath string, usingLegacyStats bool) (Interface, error) {
|
||||
sysFs := sysfs.NewRealSysFs()
|
||||
|
||||
ignoreMetrics := cadvisormetrics.MetricSet{
|
||||
cadvisormetrics.NetworkTcpUsageMetrics: struct{}{},
|
||||
cadvisormetrics.NetworkUdpUsageMetrics: struct{}{},
|
||||
cadvisormetrics.PerCpuUsageMetrics: struct{}{},
|
||||
cadvisormetrics.ProcessSchedulerMetrics: struct{}{},
|
||||
includedMetrics := cadvisormetrics.MetricSet{
|
||||
cadvisormetrics.CpuUsageMetrics: struct{}{},
|
||||
cadvisormetrics.MemoryUsageMetrics: struct{}{},
|
||||
cadvisormetrics.CpuLoadMetrics: struct{}{},
|
||||
cadvisormetrics.DiskIOMetrics: struct{}{},
|
||||
cadvisormetrics.NetworkUsageMetrics: struct{}{},
|
||||
cadvisormetrics.AcceleratorUsageMetrics: struct{}{},
|
||||
cadvisormetrics.AppMetrics: struct{}{},
|
||||
}
|
||||
if !usingLegacyStats {
|
||||
ignoreMetrics[cadvisormetrics.DiskUsageMetrics] = struct{}{}
|
||||
if usingLegacyStats {
|
||||
includedMetrics[cadvisormetrics.DiskUsageMetrics] = struct{}{}
|
||||
}
|
||||
|
||||
// collect metrics for all cgroups
|
||||
rawContainerCgroupPathPrefixWhiteList := []string{"/"}
|
||||
// Create and start the cAdvisor container manager.
|
||||
m, err := manager.New(memory.New(statsCacheDuration, nil), sysFs, maxHousekeepingInterval, allowDynamicHousekeeping, ignoreMetrics, http.DefaultClient)
|
||||
m, err := manager.New(memory.New(statsCacheDuration, nil), sysFs, maxHousekeepingInterval, allowDynamicHousekeeping, includedMetrics, http.DefaultClient, rawContainerCgroupPathPrefixWhiteList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ go_library(
|
|||
"//staging/src/k8s.io/apiserver/pkg/util/logs:go_default_library",
|
||||
"//vendor/github.com/emicklei/go-restful:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/container:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/info/v1:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/metrics:go_default_library",
|
||||
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
|
||||
|
|
|
@ -33,6 +33,7 @@ import (
|
|||
|
||||
restful "github.com/emicklei/go-restful"
|
||||
"github.com/golang/glog"
|
||||
cadvisormetrics "github.com/google/cadvisor/container"
|
||||
cadvisorapi "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/metrics"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
@ -276,7 +277,18 @@ func (s *Server) InstallDefaultHandlers() {
|
|||
|
||||
// cAdvisor metrics are exposed under the secured handler as well
|
||||
r := prometheus.NewRegistry()
|
||||
r.MustRegister(metrics.NewPrometheusCollector(prometheusHostAdapter{s.host}, containerPrometheusLabelsFunc(s.host)))
|
||||
|
||||
includedMetrics := cadvisormetrics.MetricSet{
|
||||
cadvisormetrics.CpuUsageMetrics: struct{}{},
|
||||
cadvisormetrics.MemoryUsageMetrics: struct{}{},
|
||||
cadvisormetrics.CpuLoadMetrics: struct{}{},
|
||||
cadvisormetrics.DiskIOMetrics: struct{}{},
|
||||
cadvisormetrics.DiskUsageMetrics: struct{}{},
|
||||
cadvisormetrics.NetworkUsageMetrics: struct{}{},
|
||||
cadvisormetrics.AcceleratorUsageMetrics: struct{}{},
|
||||
cadvisormetrics.AppMetrics: struct{}{},
|
||||
}
|
||||
r.MustRegister(metrics.NewPrometheusCollector(prometheusHostAdapter{s.host}, containerPrometheusLabelsFunc(s.host), includedMetrics))
|
||||
s.restfulCont.Handle(cadvisorMetricsPath,
|
||||
promhttp.HandlerFor(r, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError}),
|
||||
)
|
||||
|
|
|
@ -33,6 +33,7 @@ filegroup(
|
|||
"//vendor/github.com/Nvveen/Gotty:all-srcs",
|
||||
"//vendor/github.com/PuerkitoBio/purell:all-srcs",
|
||||
"//vendor/github.com/PuerkitoBio/urlesc:all-srcs",
|
||||
"//vendor/github.com/Rican7/retry:all-srcs",
|
||||
"//vendor/github.com/armon/circbuf:all-srcs",
|
||||
"//vendor/github.com/asaskevich/govalidator:all-srcs",
|
||||
"//vendor/github.com/aws/aws-sdk-go/aws:all-srcs",
|
||||
|
@ -302,6 +303,7 @@ filegroup(
|
|||
"//vendor/github.com/mattn/go-shellwords:all-srcs",
|
||||
"//vendor/github.com/mattn/go-sqlite3:all-srcs",
|
||||
"//vendor/github.com/matttproud/golang_protobuf_extensions/pbutil:all-srcs",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib:all-srcs",
|
||||
"//vendor/github.com/mholt/caddy/caddyfile:all-srcs",
|
||||
"//vendor/github.com/miekg/dns:all-srcs",
|
||||
"//vendor/github.com/mindprince/gonvml:all-srcs",
|
||||
|
@ -328,6 +330,7 @@ filegroup(
|
|||
"//vendor/github.com/pkg/sftp:all-srcs",
|
||||
"//vendor/github.com/pmezard/go-difflib/difflib:all-srcs",
|
||||
"//vendor/github.com/pquerna/cachecontrol:all-srcs",
|
||||
"//vendor/github.com/pquerna/ffjson/fflib/v1:all-srcs",
|
||||
"//vendor/github.com/prometheus/client_golang/prometheus:all-srcs",
|
||||
"//vendor/github.com/prometheus/client_model/go:all-srcs",
|
||||
"//vendor/github.com/prometheus/common/expfmt:all-srcs",
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.6
|
||||
- tip
|
||||
|
||||
sudo: false
|
||||
|
||||
before_install:
|
||||
# Install tools necessary to report code-coverage to Coveralls.io
|
||||
- go get github.com/mattn/goveralls
|
||||
|
||||
# Export some environment variables
|
||||
- export GO_TEST_COVERAGE_FILE_NAME='coverage.out'
|
||||
|
||||
install:
|
||||
# Get all imported packages
|
||||
- make install-deps install-deps-dev
|
||||
|
||||
# Basic build errors
|
||||
- make build
|
||||
|
||||
script:
|
||||
# Lint
|
||||
- make format-lint
|
||||
- make import-lint
|
||||
- make copyright-lint
|
||||
|
||||
# Run tests
|
||||
- make test-with-coverage-profile
|
||||
|
||||
after_success:
|
||||
# Report our code-coverage to Coveralls.io
|
||||
- goveralls -service=travis-ci -coverprofile="${GO_TEST_COVERAGE_FILE_NAME}"
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
fast_finish: true
|
|
@ -0,0 +1,29 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["retry.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/Rican7/retry",
|
||||
importpath = "github.com/Rican7/retry",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//vendor/github.com/Rican7/retry/strategy:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//vendor/github.com/Rican7/retry/backoff:all-srcs",
|
||||
"//vendor/github.com/Rican7/retry/jitter:all-srcs",
|
||||
"//vendor/github.com/Rican7/retry/strategy:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (C) 2016 Trevor N. Suarez (Rican7)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,83 @@
|
|||
# Define some VCS context
|
||||
PARENT_BRANCH ?= master
|
||||
|
||||
# Set the mode for code-coverage
|
||||
GO_TEST_COVERAGE_MODE ?= count
|
||||
GO_TEST_COVERAGE_FILE_NAME ?= coverage.out
|
||||
|
||||
# Set flags for `gofmt`
|
||||
GOFMT_FLAGS ?= -s
|
||||
|
||||
# Set a default `min_confidence` value for `golint`
|
||||
GOLINT_MIN_CONFIDENCE ?= 0.3
|
||||
|
||||
|
||||
all: install-deps build install
|
||||
|
||||
clean:
|
||||
go clean -i -x ./...
|
||||
|
||||
build:
|
||||
go build -v ./...
|
||||
|
||||
install:
|
||||
go install ./...
|
||||
|
||||
install-deps:
|
||||
go get -d -t ./...
|
||||
|
||||
install-deps-dev: install-deps
|
||||
go get github.com/golang/lint/golint
|
||||
go get golang.org/x/tools/cmd/goimports
|
||||
|
||||
update-deps:
|
||||
go get -d -t -u ./...
|
||||
|
||||
update-deps-dev: update-deps
|
||||
go get -u github.com/golang/lint/golint
|
||||
go get -u golang.org/x/tools/cmd/goimports
|
||||
|
||||
test:
|
||||
go test -v ./...
|
||||
|
||||
test-with-coverage:
|
||||
go test -cover ./...
|
||||
|
||||
test-with-coverage-formatted:
|
||||
go test -cover ./... | column -t | sort -r
|
||||
|
||||
test-with-coverage-profile:
|
||||
echo "mode: ${GO_TEST_COVERAGE_MODE}" > ${GO_TEST_COVERAGE_FILE_NAME}
|
||||
for package in $$(go list ./...); do \
|
||||
go test -covermode ${GO_TEST_COVERAGE_MODE} -coverprofile "coverage_$${package##*/}.out" "$${package}"; \
|
||||
sed '1d' "coverage_$${package##*/}.out" >> ${GO_TEST_COVERAGE_FILE_NAME}; \
|
||||
done
|
||||
|
||||
format-lint:
|
||||
errors=$$(gofmt -l ${GOFMT_FLAGS} .); if [ "$${errors}" != "" ]; then echo "$${errors}"; exit 1; fi
|
||||
|
||||
import-lint:
|
||||
errors=$$(goimports -l .); if [ "$${errors}" != "" ]; then echo "$${errors}"; exit 1; fi
|
||||
|
||||
style-lint:
|
||||
errors=$$(golint -min_confidence=${GOLINT_MIN_CONFIDENCE} ./...); if [ "$${errors}" != "" ]; then echo "$${errors}"; exit 1; fi
|
||||
|
||||
copyright-lint:
|
||||
@old_dates=$$(git diff --diff-filter=ACMRTUXB --name-only "${PARENT_BRANCH}" | xargs grep -E '[Cc]opyright(\s+)[©Cc]?(\s+)[0-9]{4}' | grep -E -v "[Cc]opyright(\s+)[©Cc]?(\s+)$$(date '+%Y')"); if [ "$${old_dates}" != "" ]; then printf "The following files contain outdated copyrights:\n$${old_dates}\n\nThis can be fixed with 'make copyright-fix'\n"; exit 1; fi
|
||||
|
||||
lint: install-deps-dev format-lint import-lint style-lint copyright-lint
|
||||
|
||||
format-fix:
|
||||
gofmt -w ${GOFMT_FLAGS} .
|
||||
|
||||
import-fix:
|
||||
goimports -w .
|
||||
|
||||
copyright-fix:
|
||||
@git diff --diff-filter=ACMRTUXB --name-only "${PARENT_BRANCH}" | xargs -I '_FILENAME' -- sh -c 'sed -i.bak "s/\([Cc]opyright\([[:space:]][©Cc]\{0,1\}[[:space:]]*\)\)[0-9]\{4\}/\1"$$(date '+%Y')"/g" _FILENAME && rm _FILENAME.bak'
|
||||
|
||||
vet:
|
||||
go vet ./...
|
||||
|
||||
|
||||
.PHONY: all clean build install install-deps install-deps-dev update-deps update-deps-dev test test-with-coverage test-with-coverage-formatted test-with-coverage-profile format-lint import-lint style-lint copyright-lint lint format-fix import-fix copyright-fix vet
|
|
@ -0,0 +1,101 @@
|
|||
# retry
|
||||
|
||||
[![Build Status](https://travis-ci.org/Rican7/retry.svg?branch=master)](https://travis-ci.org/Rican7/retry)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/Rican7/retry/badge.svg)](https://coveralls.io/github/Rican7/retry)
|
||||
[![Go Report Card](https://goreportcard.com/badge/Rican7/retry)](http://goreportcard.com/report/Rican7/retry)
|
||||
[![GoDoc](https://godoc.org/github.com/Rican7/retry?status.png)](https://godoc.org/github.com/Rican7/retry)
|
||||
[![Latest Stable Version](https://img.shields.io/github/release/Rican7/retry.svg?style=flat)](https://github.com/Rican7/retry/releases)
|
||||
|
||||
A simple, stateless, functional mechanism to perform actions repetitively until successful.
|
||||
|
||||
|
||||
## Project Status
|
||||
|
||||
This project is currently in "pre-release". While the code is heavily tested, the API may change.
|
||||
Vendor (commit or lock) this dependency if you plan on using it.
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
`go get github.com/Rican7/retry`
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
```go
|
||||
retry.Retry(func(attempt uint) error {
|
||||
return nil // Do something that may or may not cause an error
|
||||
})
|
||||
```
|
||||
|
||||
### File Open
|
||||
|
||||
```go
|
||||
const logFilePath = "/var/log/myapp.log"
|
||||
|
||||
var logFile *os.File
|
||||
|
||||
err := retry.Retry(func(attempt uint) error {
|
||||
var err error
|
||||
|
||||
logFile, err = os.Open(logFilePath)
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
if nil != err {
|
||||
log.Fatalf("Unable to open file %q with error %q", logFilePath, err)
|
||||
}
|
||||
|
||||
logFile.Chdir() // Do something with the file
|
||||
```
|
||||
|
||||
### HTTP request with strategies and backoff
|
||||
|
||||
```go
|
||||
var response *http.Response
|
||||
|
||||
action := func(attempt uint) error {
|
||||
var err error
|
||||
|
||||
response, err = http.Get("https://api.github.com/repos/Rican7/retry")
|
||||
|
||||
if nil == err && nil != response && response.StatusCode > 200 {
|
||||
err = fmt.Errorf("failed to fetch (attempt #%d) with status code: %d", attempt, response.StatusCode)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
err := retry.Retry(
|
||||
action,
|
||||
strategy.Limit(5),
|
||||
strategy.Backoff(backoff.Fibonacci(10*time.Millisecond)),
|
||||
)
|
||||
|
||||
if nil != err {
|
||||
log.Fatalf("Failed to fetch repository with error %q", err)
|
||||
}
|
||||
```
|
||||
|
||||
### Retry with backoff jitter
|
||||
|
||||
```go
|
||||
action := func(attempt uint) error {
|
||||
return errors.New("something happened")
|
||||
}
|
||||
|
||||
seed := time.Now().UnixNano()
|
||||
random := rand.New(rand.NewSource(seed))
|
||||
|
||||
retry.Retry(
|
||||
action,
|
||||
strategy.Limit(5),
|
||||
strategy.BackoffWithJitter(
|
||||
backoff.BinaryExponential(10*time.Millisecond),
|
||||
jitter.Deviation(random, 0.5),
|
||||
),
|
||||
)
|
||||
```
|
|
@ -0,0 +1,23 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["backoff.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/Rican7/retry/backoff",
|
||||
importpath = "github.com/Rican7/retry/backoff",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,67 @@
|
|||
// Package backoff provides stateless methods of calculating durations based on
|
||||
// a number of attempts made.
|
||||
//
|
||||
// Copyright © 2016 Trevor N. Suarez (Rican7)
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Algorithm defines a function that calculates a time.Duration based on
|
||||
// the given retry attempt number.
|
||||
type Algorithm func(attempt uint) time.Duration
|
||||
|
||||
// Incremental creates a Algorithm that increments the initial duration
|
||||
// by the given increment for each attempt.
|
||||
func Incremental(initial, increment time.Duration) Algorithm {
|
||||
return func(attempt uint) time.Duration {
|
||||
return initial + (increment * time.Duration(attempt))
|
||||
}
|
||||
}
|
||||
|
||||
// Linear creates a Algorithm that linearly multiplies the factor
|
||||
// duration by the attempt number for each attempt.
|
||||
func Linear(factor time.Duration) Algorithm {
|
||||
return func(attempt uint) time.Duration {
|
||||
return (factor * time.Duration(attempt))
|
||||
}
|
||||
}
|
||||
|
||||
// Exponential creates a Algorithm that multiplies the factor duration by
|
||||
// an exponentially increasing factor for each attempt, where the factor is
|
||||
// calculated as the given base raised to the attempt number.
|
||||
func Exponential(factor time.Duration, base float64) Algorithm {
|
||||
return func(attempt uint) time.Duration {
|
||||
return (factor * time.Duration(math.Pow(base, float64(attempt))))
|
||||
}
|
||||
}
|
||||
|
||||
// BinaryExponential creates a Algorithm that multiplies the factor
|
||||
// duration by an exponentially increasing factor for each attempt, where the
|
||||
// factor is calculated as `2` raised to the attempt number (2^attempt).
|
||||
func BinaryExponential(factor time.Duration) Algorithm {
|
||||
return Exponential(factor, 2)
|
||||
}
|
||||
|
||||
// Fibonacci creates a Algorithm that multiplies the factor duration by
|
||||
// an increasing factor for each attempt, where the factor is the Nth number in
|
||||
// the Fibonacci sequence.
|
||||
func Fibonacci(factor time.Duration) Algorithm {
|
||||
return func(attempt uint) time.Duration {
|
||||
return (factor * time.Duration(fibonacciNumber(attempt)))
|
||||
}
|
||||
}
|
||||
|
||||
// fibonacciNumber calculates the Fibonacci sequence number for the given
|
||||
// sequence position.
|
||||
func fibonacciNumber(n uint) uint {
|
||||
if 0 == n {
|
||||
return 0
|
||||
} else if 1 == n {
|
||||
return 1
|
||||
} else {
|
||||
return fibonacciNumber(n-1) + fibonacciNumber(n-2)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["jitter.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/Rican7/retry/jitter",
|
||||
importpath = "github.com/Rican7/retry/jitter",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,89 @@
|
|||
// Package jitter provides methods of transforming durations.
|
||||
//
|
||||
// Copyright © 2016 Trevor N. Suarez (Rican7)
|
||||
package jitter
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Transformation defines a function that calculates a time.Duration based on
|
||||
// the given duration.
|
||||
type Transformation func(duration time.Duration) time.Duration
|
||||
|
||||
// Full creates a Transformation that transforms a duration into a result
|
||||
// duration in [0, n) randomly, where n is the given duration.
|
||||
//
|
||||
// The given generator is what is used to determine the random transformation.
|
||||
// If a nil generator is passed, a default one will be provided.
|
||||
//
|
||||
// Inspired by https://www.awsarchitectureblog.com/2015/03/backoff.html
|
||||
func Full(generator *rand.Rand) Transformation {
|
||||
random := fallbackNewRandom(generator)
|
||||
|
||||
return func(duration time.Duration) time.Duration {
|
||||
return time.Duration(random.Int63n(int64(duration)))
|
||||
}
|
||||
}
|
||||
|
||||
// Equal creates a Transformation that transforms a duration into a result
|
||||
// duration in [n/2, n) randomly, where n is the given duration.
|
||||
//
|
||||
// The given generator is what is used to determine the random transformation.
|
||||
// If a nil generator is passed, a default one will be provided.
|
||||
//
|
||||
// Inspired by https://www.awsarchitectureblog.com/2015/03/backoff.html
|
||||
func Equal(generator *rand.Rand) Transformation {
|
||||
random := fallbackNewRandom(generator)
|
||||
|
||||
return func(duration time.Duration) time.Duration {
|
||||
return (duration / 2) + time.Duration(random.Int63n(int64(duration))/2)
|
||||
}
|
||||
}
|
||||
|
||||
// Deviation creates a Transformation that transforms a duration into a result
|
||||
// duration that deviates from the input randomly by a given factor.
|
||||
//
|
||||
// The given generator is what is used to determine the random transformation.
|
||||
// If a nil generator is passed, a default one will be provided.
|
||||
//
|
||||
// Inspired by https://developers.google.com/api-client-library/java/google-http-java-client/backoff
|
||||
func Deviation(generator *rand.Rand, factor float64) Transformation {
|
||||
random := fallbackNewRandom(generator)
|
||||
|
||||
return func(duration time.Duration) time.Duration {
|
||||
min := int64(math.Floor(float64(duration) * (1 - factor)))
|
||||
max := int64(math.Ceil(float64(duration) * (1 + factor)))
|
||||
|
||||
return time.Duration(random.Int63n(max-min) + min)
|
||||
}
|
||||
}
|
||||
|
||||
// NormalDistribution creates a Transformation that transforms a duration into a
|
||||
// result duration based on a normal distribution of the input and the given
|
||||
// standard deviation.
|
||||
//
|
||||
// The given generator is what is used to determine the random transformation.
|
||||
// If a nil generator is passed, a default one will be provided.
|
||||
func NormalDistribution(generator *rand.Rand, standardDeviation float64) Transformation {
|
||||
random := fallbackNewRandom(generator)
|
||||
|
||||
return func(duration time.Duration) time.Duration {
|
||||
return time.Duration(random.NormFloat64()*standardDeviation + float64(duration))
|
||||
}
|
||||
}
|
||||
|
||||
// fallbackNewRandom returns the passed in random instance if it's not nil,
|
||||
// and otherwise returns a new random instance seeded with the current time.
|
||||
func fallbackNewRandom(random *rand.Rand) *rand.Rand {
|
||||
// Return the passed in value if it's already not null
|
||||
if nil != random {
|
||||
return random
|
||||
}
|
||||
|
||||
seed := time.Now().UnixNano()
|
||||
|
||||
return rand.New(rand.NewSource(seed))
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
// Package retry provides a simple, stateless, functional mechanism to perform
|
||||
// actions repetitively until successful.
|
||||
//
|
||||
// Copyright © 2016 Trevor N. Suarez (Rican7)
|
||||
package retry
|
||||
|
||||
import "github.com/Rican7/retry/strategy"
|
||||
|
||||
// Action defines a callable function that package retry can handle.
|
||||
type Action func(attempt uint) error
|
||||
|
||||
// Retry takes an action and performs it, repetitively, until successful.
|
||||
//
|
||||
// Optionally, strategies may be passed that assess whether or not an attempt
|
||||
// should be made.
|
||||
func Retry(action Action, strategies ...strategy.Strategy) error {
|
||||
var err error
|
||||
|
||||
for attempt := uint(0); (0 == attempt || nil != err) && shouldAttempt(attempt, strategies...); attempt++ {
|
||||
err = action(attempt)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// shouldAttempt evaluates the provided strategies with the given attempt to
|
||||
// determine if the Retry loop should make another attempt.
|
||||
func shouldAttempt(attempt uint, strategies ...strategy.Strategy) bool {
|
||||
shouldAttempt := true
|
||||
|
||||
for i := 0; shouldAttempt && i < len(strategies); i++ {
|
||||
shouldAttempt = shouldAttempt && strategies[i](attempt)
|
||||
}
|
||||
|
||||
return shouldAttempt
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["strategy.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/Rican7/retry/strategy",
|
||||
importpath = "github.com/Rican7/retry/strategy",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/Rican7/retry/backoff:go_default_library",
|
||||
"//vendor/github.com/Rican7/retry/jitter:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,85 @@
|
|||
// Package strategy provides a way to change the way that retry is performed.
|
||||
//
|
||||
// Copyright © 2016 Trevor N. Suarez (Rican7)
|
||||
package strategy
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/Rican7/retry/backoff"
|
||||
"github.com/Rican7/retry/jitter"
|
||||
)
|
||||
|
||||
// Strategy defines a function that Retry calls before every successive attempt
|
||||
// to determine whether it should make the next attempt or not. Returning `true`
|
||||
// allows for the next attempt to be made. Returning `false` halts the retrying
|
||||
// process and returns the last error returned by the called Action.
|
||||
//
|
||||
// The strategy will be passed an "attempt" number on each successive retry
|
||||
// iteration, starting with a `0` value before the first attempt is actually
|
||||
// made. This allows for a pre-action delay, etc.
|
||||
type Strategy func(attempt uint) bool
|
||||
|
||||
// Limit creates a Strategy that limits the number of attempts that Retry will
|
||||
// make.
|
||||
func Limit(attemptLimit uint) Strategy {
|
||||
return func(attempt uint) bool {
|
||||
return (attempt <= attemptLimit)
|
||||
}
|
||||
}
|
||||
|
||||
// Delay creates a Strategy that waits the given duration before the first
|
||||
// attempt is made.
|
||||
func Delay(duration time.Duration) Strategy {
|
||||
return func(attempt uint) bool {
|
||||
if 0 == attempt {
|
||||
time.Sleep(duration)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Wait creates a Strategy that waits the given durations for each attempt after
|
||||
// the first. If the number of attempts is greater than the number of durations
|
||||
// provided, then the strategy uses the last duration provided.
|
||||
func Wait(durations ...time.Duration) Strategy {
|
||||
return func(attempt uint) bool {
|
||||
if 0 < attempt && 0 < len(durations) {
|
||||
durationIndex := int(attempt - 1)
|
||||
|
||||
if len(durations) <= durationIndex {
|
||||
durationIndex = len(durations) - 1
|
||||
}
|
||||
|
||||
time.Sleep(durations[durationIndex])
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Backoff creates a Strategy that waits before each attempt, with a duration as
|
||||
// defined by the given backoff.Algorithm.
|
||||
func Backoff(algorithm backoff.Algorithm) Strategy {
|
||||
return BackoffWithJitter(algorithm, noJitter())
|
||||
}
|
||||
|
||||
// BackoffWithJitter creates a Strategy that waits before each attempt, with a
|
||||
// duration as defined by the given backoff.Algorithm and jitter.Transformation.
|
||||
func BackoffWithJitter(algorithm backoff.Algorithm, transformation jitter.Transformation) Strategy {
|
||||
return func(attempt uint) bool {
|
||||
if 0 < attempt {
|
||||
time.Sleep(transformation(algorithm(attempt)))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// noJitter creates a jitter.Transformation that simply returns the input.
|
||||
func noJitter() jitter.Transformation {
|
||||
return func(duration time.Duration) time.Duration {
|
||||
return duration
|
||||
}
|
||||
}
|
|
@ -31,7 +31,10 @@ import (
|
|||
)
|
||||
|
||||
type NvidiaManager struct {
|
||||
sync.RWMutex
|
||||
sync.Mutex
|
||||
|
||||
// true if there are NVIDIA devices present on the node
|
||||
devicesPresent bool
|
||||
|
||||
// true if the NVML library (libnvidia-ml.so.1) was loaded successfully
|
||||
nvmlInitialized bool
|
||||
|
@ -51,20 +54,9 @@ func (nm *NvidiaManager) Setup() {
|
|||
return
|
||||
}
|
||||
|
||||
nm.initializeNVML()
|
||||
if nm.nvmlInitialized {
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
glog.V(2).Info("Starting goroutine to initialize NVML")
|
||||
// TODO: use globalHousekeepingInterval
|
||||
for range time.Tick(time.Minute) {
|
||||
nm.initializeNVML()
|
||||
if nm.nvmlInitialized {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
nm.devicesPresent = true
|
||||
|
||||
initializeNVML(nm)
|
||||
}
|
||||
|
||||
// detectDevices returns true if a device with given pci id is present on the node.
|
||||
|
@ -91,20 +83,18 @@ func detectDevices(vendorId string) bool {
|
|||
}
|
||||
|
||||
// initializeNVML initializes the NVML library and sets up the nvmlDevices map.
|
||||
func (nm *NvidiaManager) initializeNVML() {
|
||||
// This is defined as a variable to help in testing.
|
||||
var initializeNVML = func(nm *NvidiaManager) {
|
||||
if err := gonvml.Initialize(); err != nil {
|
||||
// This is under a logging level because otherwise we may cause
|
||||
// log spam if the drivers/nvml is not installed on the system.
|
||||
glog.V(4).Infof("Could not initialize NVML: %v", err)
|
||||
return
|
||||
}
|
||||
nm.nvmlInitialized = true
|
||||
numDevices, err := gonvml.DeviceCount()
|
||||
if err != nil {
|
||||
glog.Warningf("GPU metrics would not be available. Failed to get the number of nvidia devices: %v", err)
|
||||
nm.Lock()
|
||||
// Even though we won't have GPU metrics, the library was initialized and should be shutdown when exiting.
|
||||
nm.nvmlInitialized = true
|
||||
nm.Unlock()
|
||||
return
|
||||
}
|
||||
glog.V(1).Infof("NVML initialized. Number of nvidia devices: %v", numDevices)
|
||||
|
@ -122,10 +112,6 @@ func (nm *NvidiaManager) initializeNVML() {
|
|||
}
|
||||
nm.nvidiaDevices[int(minorNumber)] = device
|
||||
}
|
||||
nm.Lock()
|
||||
// Doing this at the end to avoid race in accessing nvidiaDevices in GetCollector.
|
||||
nm.nvmlInitialized = true
|
||||
nm.Unlock()
|
||||
}
|
||||
|
||||
// Destroy shuts down NVML.
|
||||
|
@ -139,12 +125,21 @@ func (nm *NvidiaManager) Destroy() {
|
|||
// present in the devices.list file in the given devicesCgroupPath.
|
||||
func (nm *NvidiaManager) GetCollector(devicesCgroupPath string) (AcceleratorCollector, error) {
|
||||
nc := &NvidiaCollector{}
|
||||
nm.RLock()
|
||||
if !nm.nvmlInitialized || len(nm.nvidiaDevices) == 0 {
|
||||
nm.RUnlock()
|
||||
|
||||
if !nm.devicesPresent {
|
||||
return nc, nil
|
||||
}
|
||||
nm.RUnlock()
|
||||
// Makes sure that we don't call initializeNVML() concurrently and
|
||||
// that we only call initializeNVML() when it's not initialized.
|
||||
nm.Lock()
|
||||
if !nm.nvmlInitialized {
|
||||
initializeNVML(nm)
|
||||
}
|
||||
if !nm.nvmlInitialized || len(nm.nvidiaDevices) == 0 {
|
||||
nm.Unlock()
|
||||
return nc, nil
|
||||
}
|
||||
nm.Unlock()
|
||||
nvidiaMinorNumbers, err := parseDevicesCgroup(devicesCgroupPath)
|
||||
if err != nil {
|
||||
return nc, err
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
package memory
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -26,6 +26,9 @@ import (
|
|||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// ErrDataNotFound is the error resulting if failed to find a container in memory cache.
|
||||
var ErrDataNotFound = errors.New("unable to find data in memory cache")
|
||||
|
||||
// TODO(vmarmol): See about refactoring this class, we have an unecessary redirection of containerCache and InMemoryCache.
|
||||
// containerCache is used to store per-container information
|
||||
type containerCache struct {
|
||||
|
@ -101,7 +104,7 @@ func (self *InMemoryCache) RecentStats(name string, start, end time.Time, maxSta
|
|||
self.lock.RLock()
|
||||
defer self.lock.RUnlock()
|
||||
if cstore, ok = self.containerCacheMap[name]; !ok {
|
||||
return fmt.Errorf("unable to find data for container %v", name)
|
||||
return ErrDataNotFound
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
|
|
|
@ -32,6 +32,7 @@ filegroup(
|
|||
"//vendor/github.com/google/cadvisor/container/crio:all-srcs",
|
||||
"//vendor/github.com/google/cadvisor/container/docker:all-srcs",
|
||||
"//vendor/github.com/google/cadvisor/container/libcontainer:all-srcs",
|
||||
"//vendor/github.com/google/cadvisor/container/mesos:all-srcs",
|
||||
"//vendor/github.com/google/cadvisor/container/raw:all-srcs",
|
||||
"//vendor/github.com/google/cadvisor/container/rkt:all-srcs",
|
||||
"//vendor/github.com/google/cadvisor/container/systemd:all-srcs",
|
||||
|
|
|
@ -36,6 +36,7 @@ const (
|
|||
ContainerTypeSystemd
|
||||
ContainerTypeCrio
|
||||
ContainerTypeContainerd
|
||||
ContainerTypeMesos
|
||||
)
|
||||
|
||||
// Interface for container operation handlers.
|
||||
|
|
|
@ -47,8 +47,8 @@ type containerdFactory struct {
|
|||
// Information about the mounted cgroup subsystems.
|
||||
cgroupSubsystems libcontainer.CgroupSubsystems
|
||||
// Information about mounted filesystems.
|
||||
fsInfo fs.FsInfo
|
||||
ignoreMetrics container.MetricSet
|
||||
fsInfo fs.FsInfo
|
||||
includedMetrics container.MetricSet
|
||||
}
|
||||
|
||||
func (self *containerdFactory) String() string {
|
||||
|
@ -70,7 +70,7 @@ func (self *containerdFactory) NewContainerHandler(name string, inHostNamespace
|
|||
&self.cgroupSubsystems,
|
||||
inHostNamespace,
|
||||
metadataEnvs,
|
||||
self.ignoreMetrics,
|
||||
self.includedMetrics,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ func (self *containerdFactory) DebugInfo() map[string][]string {
|
|||
}
|
||||
|
||||
// Register root container before running this function!
|
||||
func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics container.MetricSet) error {
|
||||
func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) error {
|
||||
client, err := Client()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create containerd client: %v", err)
|
||||
|
@ -140,7 +140,7 @@ func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics c
|
|||
fsInfo: fsInfo,
|
||||
machineInfoFactory: factory,
|
||||
version: containerdVersion,
|
||||
ignoreMetrics: ignoreMetrics,
|
||||
includedMetrics: includedMetrics,
|
||||
}
|
||||
|
||||
container.RegisterContainerHandlerFactory(f, []watcher.ContainerWatchSource{watcher.Raw})
|
||||
|
|
|
@ -48,7 +48,7 @@ type containerdContainerHandler struct {
|
|||
// Image name used for this container.
|
||||
image string
|
||||
// Filesystem handler.
|
||||
ignoreMetrics container.MetricSet
|
||||
includedMetrics container.MetricSet
|
||||
|
||||
libcontainerHandler *containerlibcontainer.Handler
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ func newContainerdContainerHandler(
|
|||
cgroupSubsystems *containerlibcontainer.CgroupSubsystems,
|
||||
inHostNamespace bool,
|
||||
metadataEnvs []string,
|
||||
ignoreMetrics container.MetricSet,
|
||||
includedMetrics container.MetricSet,
|
||||
) (container.ContainerHandler, error) {
|
||||
// Create the cgroup paths.
|
||||
cgroupPaths := make(map[string]string, len(cgroupSubsystems.MountPoints))
|
||||
|
@ -127,7 +127,7 @@ func newContainerdContainerHandler(
|
|||
Aliases: []string{id, name},
|
||||
}
|
||||
|
||||
libcontainerHandler := containerlibcontainer.NewHandler(cgroupManager, rootfs, int(taskPid), ignoreMetrics)
|
||||
libcontainerHandler := containerlibcontainer.NewHandler(cgroupManager, rootfs, int(taskPid), includedMetrics)
|
||||
|
||||
handler := &containerdContainerHandler{
|
||||
machineInfoFactory: machineInfoFactory,
|
||||
|
@ -135,7 +135,7 @@ func newContainerdContainerHandler(
|
|||
fsInfo: fsInfo,
|
||||
envs: make(map[string]string),
|
||||
labels: cntr.Labels,
|
||||
ignoreMetrics: ignoreMetrics,
|
||||
includedMetrics: includedMetrics,
|
||||
reference: containerReference,
|
||||
libcontainerHandler: libcontainerHandler,
|
||||
}
|
||||
|
@ -159,9 +159,9 @@ func (self *containerdContainerHandler) ContainerReference() (info.ContainerRefe
|
|||
|
||||
func (self *containerdContainerHandler) needNet() bool {
|
||||
// Since containerd does not handle networking ideally we need to return based
|
||||
// on ignoreMetrics list. Here the assumption is the presence of cri-containerd
|
||||
// on includedMetrics list. Here the assumption is the presence of cri-containerd
|
||||
// label
|
||||
if !self.ignoreMetrics.Has(container.NetworkUsageMetrics) {
|
||||
if self.includedMetrics.Has(container.NetworkUsageMetrics) {
|
||||
//TODO change it to exported cri-containerd constants
|
||||
return self.labels["io.cri-containerd.kind"] == "sandbox"
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ func (self *containerdContainerHandler) getFsStats(stats *info.ContainerStats) e
|
|||
return err
|
||||
}
|
||||
|
||||
if !self.ignoreMetrics.Has(container.DiskIOMetrics) {
|
||||
if self.includedMetrics.Has(container.DiskIOMetrics) {
|
||||
common.AssignDeviceNamesToDiskStats((*common.MachineInfoNamer)(mi), &stats.DiskIo)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -55,7 +55,7 @@ type crioFactory struct {
|
|||
// Information about mounted filesystems.
|
||||
fsInfo fs.FsInfo
|
||||
|
||||
ignoreMetrics container.MetricSet
|
||||
includedMetrics container.MetricSet
|
||||
|
||||
client crioClient
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ func (self *crioFactory) NewContainerHandler(name string, inHostNamespace bool)
|
|||
&self.cgroupSubsystems,
|
||||
inHostNamespace,
|
||||
metadataEnvs,
|
||||
self.ignoreMetrics,
|
||||
self.includedMetrics,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ var (
|
|||
)
|
||||
|
||||
// Register root container before running this function!
|
||||
func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics container.MetricSet) error {
|
||||
func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) error {
|
||||
client, err := Client()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -162,7 +162,7 @@ func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics c
|
|||
machineInfoFactory: factory,
|
||||
storageDriver: storageDriver(info.StorageDriver),
|
||||
storageDir: info.StorageRoot,
|
||||
ignoreMetrics: ignoreMetrics,
|
||||
includedMetrics: includedMetrics,
|
||||
}
|
||||
|
||||
container.RegisterContainerHandlerFactory(f, []watcher.ContainerWatchSource{watcher.Raw})
|
||||
|
|
|
@ -63,7 +63,7 @@ type crioContainerHandler struct {
|
|||
// The IP address of the container
|
||||
ipAddress string
|
||||
|
||||
ignoreMetrics container.MetricSet
|
||||
includedMetrics container.MetricSet
|
||||
|
||||
reference info.ContainerReference
|
||||
|
||||
|
@ -83,7 +83,7 @@ func newCrioContainerHandler(
|
|||
cgroupSubsystems *containerlibcontainer.CgroupSubsystems,
|
||||
inHostNamespace bool,
|
||||
metadataEnvs []string,
|
||||
ignoreMetrics container.MetricSet,
|
||||
includedMetrics container.MetricSet,
|
||||
) (container.ContainerHandler, error) {
|
||||
// Create the cgroup paths.
|
||||
cgroupPaths := make(map[string]string, len(cgroupSubsystems.MountPoints))
|
||||
|
@ -141,7 +141,7 @@ func newCrioContainerHandler(
|
|||
Namespace: CrioNamespace,
|
||||
}
|
||||
|
||||
libcontainerHandler := containerlibcontainer.NewHandler(cgroupManager, rootFs, cInfo.Pid, ignoreMetrics)
|
||||
libcontainerHandler := containerlibcontainer.NewHandler(cgroupManager, rootFs, cInfo.Pid, includedMetrics)
|
||||
|
||||
// TODO: extract object mother method
|
||||
handler := &crioContainerHandler{
|
||||
|
@ -152,7 +152,7 @@ func newCrioContainerHandler(
|
|||
rootfsStorageDir: rootfsStorageDir,
|
||||
envs: make(map[string]string),
|
||||
labels: cInfo.Labels,
|
||||
ignoreMetrics: ignoreMetrics,
|
||||
includedMetrics: includedMetrics,
|
||||
reference: containerReference,
|
||||
libcontainerHandler: libcontainerHandler,
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ func newCrioContainerHandler(
|
|||
handler.ipAddress = cInfo.IP
|
||||
|
||||
// we optionally collect disk usage metrics
|
||||
if !ignoreMetrics.Has(container.DiskUsageMetrics) {
|
||||
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
|
||||
|
@ -199,14 +199,14 @@ func (self *crioContainerHandler) ContainerReference() (info.ContainerReference,
|
|||
}
|
||||
|
||||
func (self *crioContainerHandler) needNet() bool {
|
||||
if !self.ignoreMetrics.Has(container.NetworkUsageMetrics) {
|
||||
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.ignoreMetrics.Has(container.DiskUsageMetrics)
|
||||
hasFilesystem := self.includedMetrics.Has(container.DiskUsageMetrics)
|
||||
spec, err := common.GetSpec(self.cgroupPaths, self.machineInfoFactory, self.needNet(), hasFilesystem)
|
||||
|
||||
spec.Labels = self.labels
|
||||
|
@ -222,11 +222,11 @@ func (self *crioContainerHandler) getFsStats(stats *info.ContainerStats) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if !self.ignoreMetrics.Has(container.DiskIOMetrics) {
|
||||
if self.includedMetrics.Has(container.DiskIOMetrics) {
|
||||
common.AssignDeviceNamesToDiskStats((*common.MachineInfoNamer)(mi), &stats.DiskIo)
|
||||
}
|
||||
|
||||
if self.ignoreMetrics.Has(container.DiskUsageMetrics) {
|
||||
if !self.includedMetrics.Has(container.DiskUsageMetrics) {
|
||||
return nil
|
||||
}
|
||||
var device string
|
||||
|
|
|
@ -110,7 +110,7 @@ type dockerFactory struct {
|
|||
|
||||
dockerAPIVersion []int
|
||||
|
||||
ignoreMetrics container.MetricSet
|
||||
includedMetrics container.MetricSet
|
||||
|
||||
thinPoolName string
|
||||
thinPoolWatcher *devicemapper.ThinPoolWatcher
|
||||
|
@ -141,7 +141,7 @@ func (self *dockerFactory) NewContainerHandler(name string, inHostNamespace bool
|
|||
inHostNamespace,
|
||||
metadataEnvs,
|
||||
self.dockerVersion,
|
||||
self.ignoreMetrics,
|
||||
self.includedMetrics,
|
||||
self.thinPoolName,
|
||||
self.thinPoolWatcher,
|
||||
self.zfsWatcher,
|
||||
|
@ -309,7 +309,7 @@ func ensureThinLsKernelVersion(kernelVersion string) error {
|
|||
}
|
||||
|
||||
// Register root container before running this function!
|
||||
func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics container.MetricSet) error {
|
||||
func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) error {
|
||||
client, err := Client()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to communicate with docker daemon: %v", err)
|
||||
|
@ -363,7 +363,7 @@ func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics c
|
|||
machineInfoFactory: factory,
|
||||
storageDriver: storageDriver(dockerInfo.Driver),
|
||||
storageDir: RootDir(),
|
||||
ignoreMetrics: ignoreMetrics,
|
||||
includedMetrics: includedMetrics,
|
||||
thinPoolName: thinPoolName,
|
||||
thinPoolWatcher: thinPoolWatcher,
|
||||
zfsWatcher: zfsWatcher,
|
||||
|
|
|
@ -83,7 +83,7 @@ type dockerContainerHandler struct {
|
|||
// The IP address of the container
|
||||
ipAddress string
|
||||
|
||||
ignoreMetrics container.MetricSet
|
||||
includedMetrics container.MetricSet
|
||||
|
||||
// the devicemapper poolname
|
||||
poolName string
|
||||
|
@ -128,7 +128,7 @@ func newDockerContainerHandler(
|
|||
inHostNamespace bool,
|
||||
metadataEnvs []string,
|
||||
dockerVersion []int,
|
||||
ignoreMetrics container.MetricSet,
|
||||
includedMetrics container.MetricSet,
|
||||
thinPoolName string,
|
||||
thinPoolWatcher *devicemapper.ThinPoolWatcher,
|
||||
zfsWatcher *zfs.ZfsWatcher,
|
||||
|
@ -203,7 +203,7 @@ func newDockerContainerHandler(
|
|||
rootfsStorageDir: rootfsStorageDir,
|
||||
envs: make(map[string]string),
|
||||
labels: ctnr.Config.Labels,
|
||||
ignoreMetrics: ignoreMetrics,
|
||||
includedMetrics: includedMetrics,
|
||||
zfsParent: zfsParent,
|
||||
}
|
||||
// Timestamp returned by Docker is in time.RFC3339Nano format.
|
||||
|
@ -212,7 +212,7 @@ func newDockerContainerHandler(
|
|||
// This should not happen, report the error just in case
|
||||
return nil, fmt.Errorf("failed to parse the create timestamp %q for container %q: %v", ctnr.Created, id, err)
|
||||
}
|
||||
handler.libcontainerHandler = containerlibcontainer.NewHandler(cgroupManager, rootFs, ctnr.State.Pid, ignoreMetrics)
|
||||
handler.libcontainerHandler = containerlibcontainer.NewHandler(cgroupManager, rootFs, ctnr.State.Pid, includedMetrics)
|
||||
|
||||
// Add the name and bare ID as aliases of the container.
|
||||
handler.reference = info.ContainerReference{
|
||||
|
@ -244,7 +244,7 @@ func newDockerContainerHandler(
|
|||
|
||||
handler.ipAddress = ipAddress
|
||||
|
||||
if !ignoreMetrics.Has(container.DiskUsageMetrics) {
|
||||
if includedMetrics.Has(container.DiskUsageMetrics) {
|
||||
handler.fsHandler = &dockerFsHandler{
|
||||
fsHandler: common.NewFsHandler(common.DefaultPeriod, rootfsStorageDir, otherStorageDir, fsInfo),
|
||||
thinPoolWatcher: thinPoolWatcher,
|
||||
|
@ -345,14 +345,14 @@ func (self *dockerContainerHandler) ContainerReference() (info.ContainerReferenc
|
|||
}
|
||||
|
||||
func (self *dockerContainerHandler) needNet() bool {
|
||||
if !self.ignoreMetrics.Has(container.NetworkUsageMetrics) {
|
||||
if self.includedMetrics.Has(container.NetworkUsageMetrics) {
|
||||
return !self.networkMode.IsContainer()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *dockerContainerHandler) GetSpec() (info.ContainerSpec, error) {
|
||||
hasFilesystem := !self.ignoreMetrics.Has(container.DiskUsageMetrics)
|
||||
hasFilesystem := self.includedMetrics.Has(container.DiskUsageMetrics)
|
||||
spec, err := common.GetSpec(self.cgroupPaths, self.machineInfoFactory, self.needNet(), hasFilesystem)
|
||||
|
||||
spec.Labels = self.labels
|
||||
|
@ -369,11 +369,11 @@ func (self *dockerContainerHandler) getFsStats(stats *info.ContainerStats) error
|
|||
return err
|
||||
}
|
||||
|
||||
if !self.ignoreMetrics.Has(container.DiskIOMetrics) {
|
||||
if self.includedMetrics.Has(container.DiskIOMetrics) {
|
||||
common.AssignDeviceNamesToDiskStats((*common.MachineInfoNamer)(mi), &stats.DiskIo)
|
||||
}
|
||||
|
||||
if self.ignoreMetrics.Has(container.DiskUsageMetrics) {
|
||||
if !self.includedMetrics.Has(container.DiskUsageMetrics) {
|
||||
return nil
|
||||
}
|
||||
var device string
|
||||
|
|
|
@ -51,6 +51,7 @@ const (
|
|||
NetworkUsageMetrics MetricKind = "network"
|
||||
NetworkTcpUsageMetrics MetricKind = "tcp"
|
||||
NetworkUdpUsageMetrics MetricKind = "udp"
|
||||
AcceleratorUsageMetrics MetricKind = "accelerator"
|
||||
AppMetrics MetricKind = "app"
|
||||
)
|
||||
|
||||
|
|
|
@ -43,16 +43,16 @@ type Handler struct {
|
|||
cgroupManager cgroups.Manager
|
||||
rootFs string
|
||||
pid int
|
||||
ignoreMetrics container.MetricSet
|
||||
includedMetrics container.MetricSet
|
||||
pidMetricsCache map[int]*info.CpuSchedstat
|
||||
}
|
||||
|
||||
func NewHandler(cgroupManager cgroups.Manager, rootFs string, pid int, ignoreMetrics container.MetricSet) *Handler {
|
||||
func NewHandler(cgroupManager cgroups.Manager, rootFs string, pid int, includedMetrics container.MetricSet) *Handler {
|
||||
return &Handler{
|
||||
cgroupManager: cgroupManager,
|
||||
rootFs: rootFs,
|
||||
pid: pid,
|
||||
ignoreMetrics: ignoreMetrics,
|
||||
includedMetrics: includedMetrics,
|
||||
pidMetricsCache: make(map[int]*info.CpuSchedstat),
|
||||
}
|
||||
}
|
||||
|
@ -66,10 +66,10 @@ func (h *Handler) GetStats() (*info.ContainerStats, error) {
|
|||
libcontainerStats := &libcontainer.Stats{
|
||||
CgroupStats: cgroupStats,
|
||||
}
|
||||
withPerCPU := !h.ignoreMetrics.Has(container.PerCpuUsageMetrics)
|
||||
withPerCPU := h.includedMetrics.Has(container.PerCpuUsageMetrics)
|
||||
stats := newContainerStats(libcontainerStats, withPerCPU)
|
||||
|
||||
if !h.ignoreMetrics.Has(container.ProcessSchedulerMetrics) {
|
||||
if h.includedMetrics.Has(container.ProcessSchedulerMetrics) {
|
||||
pids, err := h.cgroupManager.GetAllPids()
|
||||
if err != nil {
|
||||
glog.V(4).Infof("Could not get PIDs for container %d: %v", h.pid, err)
|
||||
|
@ -85,7 +85,7 @@ func (h *Handler) GetStats() (*info.ContainerStats, error) {
|
|||
if h.pid == 0 {
|
||||
return stats, nil
|
||||
}
|
||||
if !h.ignoreMetrics.Has(container.NetworkUsageMetrics) {
|
||||
if h.includedMetrics.Has(container.NetworkUsageMetrics) {
|
||||
netStats, err := networkStatsFromProc(h.rootFs, h.pid)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("Unable to get network stats from pid %d: %v", h.pid, err)
|
||||
|
@ -93,7 +93,7 @@ func (h *Handler) GetStats() (*info.ContainerStats, error) {
|
|||
stats.Network.Interfaces = append(stats.Network.Interfaces, netStats...)
|
||||
}
|
||||
}
|
||||
if !h.ignoreMetrics.Has(container.NetworkTcpUsageMetrics) {
|
||||
if h.includedMetrics.Has(container.NetworkTcpUsageMetrics) {
|
||||
t, err := tcpStatsFromProc(h.rootFs, h.pid, "net/tcp")
|
||||
if err != nil {
|
||||
glog.V(4).Infof("Unable to get tcp stats from pid %d: %v", h.pid, err)
|
||||
|
@ -108,7 +108,7 @@ func (h *Handler) GetStats() (*info.ContainerStats, error) {
|
|||
stats.Network.Tcp6 = t6
|
||||
}
|
||||
}
|
||||
if !h.ignoreMetrics.Has(container.NetworkUdpUsageMetrics) {
|
||||
if h.includedMetrics.Has(container.NetworkUdpUsageMetrics) {
|
||||
u, err := udpStatsFromProc(h.rootFs, h.pid, "net/udp")
|
||||
if err != nil {
|
||||
glog.V(4).Infof("Unable to get udp stats from pid %d: %v", h.pid, err)
|
||||
|
@ -498,14 +498,17 @@ func setMemoryStats(s *cgroups.Stats, ret *info.ContainerStats) {
|
|||
ret.Memory.Usage = s.MemoryStats.Usage.Usage
|
||||
ret.Memory.MaxUsage = s.MemoryStats.Usage.MaxUsage
|
||||
ret.Memory.Failcnt = s.MemoryStats.Usage.Failcnt
|
||||
ret.Memory.Cache = s.MemoryStats.Stats["cache"]
|
||||
|
||||
if s.MemoryStats.UseHierarchy {
|
||||
ret.Memory.Cache = s.MemoryStats.Stats["total_cache"]
|
||||
ret.Memory.RSS = s.MemoryStats.Stats["total_rss"]
|
||||
ret.Memory.Swap = s.MemoryStats.Stats["total_swap"]
|
||||
ret.Memory.MappedFile = s.MemoryStats.Stats["total_mapped_file"]
|
||||
} else {
|
||||
ret.Memory.Cache = s.MemoryStats.Stats["cache"]
|
||||
ret.Memory.RSS = s.MemoryStats.Stats["rss"]
|
||||
ret.Memory.Swap = s.MemoryStats.Stats["swap"]
|
||||
ret.Memory.MappedFile = s.MemoryStats.Stats["mapped_file"]
|
||||
}
|
||||
if v, ok := s.MemoryStats.Stats["pgfault"]; ok {
|
||||
ret.Memory.ContainerData.Pgfault = v
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"client.go",
|
||||
"factory.go",
|
||||
"handler.go",
|
||||
"mesos_agent.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/google/cadvisor/container/mesos",
|
||||
importpath = "github.com/google/cadvisor/container/mesos",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/Rican7/retry:go_default_library",
|
||||
"//vendor/github.com/Rican7/retry/strategy:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/container:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/container/common:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/container/libcontainer:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/fs:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/info/v1:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/manager/watcher:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/agent:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/agent/calls:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/client:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/codecs:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli:go_default_library",
|
||||
"//vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs:go_default_library",
|
||||
"//vendor/github.com/opencontainers/runc/libcontainer/configs:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,190 @@
|
|||
// Copyright 2018 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 mesos
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Rican7/retry"
|
||||
"github.com/Rican7/retry/strategy"
|
||||
"github.com/mesos/mesos-go/api/v1/lib"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/agent"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/agent/calls"
|
||||
mclient "github.com/mesos/mesos-go/api/v1/lib/client"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding/codecs"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/httpcli"
|
||||
"net/url"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
maxRetryAttempts = 3
|
||||
invalidPID = -1
|
||||
)
|
||||
|
||||
var (
|
||||
mesosClientOnce sync.Once
|
||||
mesosClient *client
|
||||
)
|
||||
|
||||
type client struct {
|
||||
hc *httpcli.Client
|
||||
}
|
||||
|
||||
type mesosAgentClient interface {
|
||||
ContainerInfo(id string) (*containerInfo, error)
|
||||
ContainerPid(id string) (int, error)
|
||||
}
|
||||
|
||||
type containerInfo struct {
|
||||
cntr *mContainer
|
||||
labels map[string]string
|
||||
}
|
||||
|
||||
// Client is an interface to query mesos agent http endpoints
|
||||
func Client() (mesosAgentClient, error) {
|
||||
mesosClientOnce.Do(func() {
|
||||
// Start Client
|
||||
apiURL := url.URL{
|
||||
Scheme: "http",
|
||||
Host: *MesosAgentAddress,
|
||||
Path: "/api/v1",
|
||||
}
|
||||
|
||||
mesosClient = &client{
|
||||
hc: httpcli.New(
|
||||
httpcli.Endpoint(apiURL.String()),
|
||||
httpcli.Codec(codecs.ByMediaType[codecs.MediaTypeProtobuf]),
|
||||
httpcli.Do(httpcli.With(httpcli.Timeout(*MesosAgentTimeout))),
|
||||
),
|
||||
}
|
||||
})
|
||||
return mesosClient, nil
|
||||
}
|
||||
|
||||
// ContainerInfo returns the container information of the given container id
|
||||
func (self *client) ContainerInfo(id string) (*containerInfo, error) {
|
||||
c, err := self.getContainer(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get labels of the container
|
||||
l, err := self.getLabels(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &containerInfo{
|
||||
cntr: c,
|
||||
labels: l,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Get the Pid of the container
|
||||
func (self *client) ContainerPid(id string) (int, error) {
|
||||
var pid int
|
||||
var err error
|
||||
err = retry.Retry(
|
||||
func(attempt uint) error {
|
||||
c, err := self.ContainerInfo(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.cntr.ContainerStatus != nil {
|
||||
pid = int(*c.cntr.ContainerStatus.ExecutorPID)
|
||||
} else {
|
||||
err = fmt.Errorf("error fetching Pid")
|
||||
}
|
||||
return err
|
||||
},
|
||||
strategy.Limit(maxRetryAttempts),
|
||||
)
|
||||
if err != nil {
|
||||
return invalidPID, fmt.Errorf("failed to fetch pid")
|
||||
}
|
||||
return pid, err
|
||||
}
|
||||
|
||||
func (self *client) getContainer(id string) (*mContainer, error) {
|
||||
// Get all containers
|
||||
cntrs, err := self.getContainers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check if there is a container with given id and return the container
|
||||
for _, c := range cntrs.Containers {
|
||||
if c.ContainerID.Value == id {
|
||||
return &c, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("can't locate container %s", id)
|
||||
}
|
||||
|
||||
func (self *client) getContainers() (mContainers, error) {
|
||||
req := calls.NonStreaming(calls.GetContainers())
|
||||
result, err := self.fetchAndDecode(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get mesos containers: %v", err)
|
||||
}
|
||||
cntrs := result.GetContainers
|
||||
return cntrs, nil
|
||||
}
|
||||
|
||||
func (self *client) getLabels(c *mContainer) (map[string]string, error) {
|
||||
// Get mesos agent state which contains all containers labels
|
||||
var s state
|
||||
req := calls.NonStreaming(calls.GetState())
|
||||
result, err := self.fetchAndDecode(req)
|
||||
if err != nil {
|
||||
return map[string]string{}, fmt.Errorf("failed to get mesos agent state: %v", err)
|
||||
}
|
||||
s.st = result.GetState
|
||||
|
||||
// Fetch labels from state object
|
||||
labels, err := s.FetchLabels(c.FrameworkID.Value, c.ExecutorID.Value)
|
||||
if err != nil {
|
||||
return labels, fmt.Errorf("error while fetching labels from executor: %v", err)
|
||||
}
|
||||
|
||||
return labels, nil
|
||||
}
|
||||
|
||||
func (self *client) fetchAndDecode(req calls.RequestFunc) (*agent.Response, error) {
|
||||
var res mesos.Response
|
||||
var err error
|
||||
|
||||
// Send request
|
||||
err = retry.Retry(
|
||||
func(attempt uint) error {
|
||||
res, err = mesosClient.hc.Send(req, mclient.ResponseClassSingleton, nil)
|
||||
return err
|
||||
},
|
||||
strategy.Limit(maxRetryAttempts),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching %s: %s", req.Call(), err)
|
||||
}
|
||||
|
||||
// Decode the result
|
||||
var target agent.Response
|
||||
err = res.Decode(&target)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while decoding response body from %s: %s", res, err)
|
||||
}
|
||||
|
||||
return &target, nil
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
// Copyright 2018 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 mesos
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"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"
|
||||
)
|
||||
|
||||
var MesosAgentAddress = flag.String("mesos_agent", "127.0.0.1:5051", "Mesos agent address")
|
||||
var MesosAgentTimeout = flag.Duration("mesos_agent_timeout", 10*time.Second, "Mesos agent timeout")
|
||||
|
||||
// The namespace under which mesos aliases are unique.
|
||||
const MesosNamespace = "mesos"
|
||||
|
||||
// Regexp that identifies mesos cgroups, containers started with
|
||||
// --cgroup-parent have another prefix than 'mesos'
|
||||
var mesosCgroupRegexp = regexp.MustCompile(`([a-z-0-9]{36})`)
|
||||
|
||||
// mesosFactory implements the interface ContainerHandlerFactory
|
||||
type mesosFactory struct {
|
||||
machineInfoFactory info.MachineInfoFactory
|
||||
|
||||
// Information about the cgroup subsystems.
|
||||
cgroupSubsystems libcontainer.CgroupSubsystems
|
||||
|
||||
// Information about mounted filesystems.
|
||||
fsInfo fs.FsInfo
|
||||
|
||||
includedMetrics map[container.MetricKind]struct{}
|
||||
|
||||
client mesosAgentClient
|
||||
}
|
||||
|
||||
func (self *mesosFactory) String() string {
|
||||
return MesosNamespace
|
||||
}
|
||||
|
||||
func (self *mesosFactory) NewContainerHandler(name string, inHostNamespace bool) (container.ContainerHandler, error) {
|
||||
client, err := Client()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newMesosContainerHandler(
|
||||
name,
|
||||
&self.cgroupSubsystems,
|
||||
self.machineInfoFactory,
|
||||
self.fsInfo,
|
||||
self.includedMetrics,
|
||||
inHostNamespace,
|
||||
client,
|
||||
)
|
||||
}
|
||||
|
||||
// ContainerNameToMesosId returns the Mesos ID from the full container name.
|
||||
func ContainerNameToMesosId(name string) string {
|
||||
id := path.Base(name)
|
||||
|
||||
if matches := mesosCgroupRegexp.FindStringSubmatch(id); matches != nil {
|
||||
return matches[1]
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
// isContainerName returns true if the cgroup with associated name
|
||||
// corresponds to a mesos container.
|
||||
func isContainerName(name string) bool {
|
||||
// always ignore .mount cgroup even if associated with mesos and delegate to systemd
|
||||
if strings.HasSuffix(name, ".mount") {
|
||||
return false
|
||||
}
|
||||
return mesosCgroupRegexp.MatchString(path.Base(name))
|
||||
}
|
||||
|
||||
// The mesos factory can handle any container.
|
||||
func (self *mesosFactory) CanHandleAndAccept(name string) (handle bool, accept bool, err error) {
|
||||
// if the container is not associated with mesos, we can't handle it or accept it.
|
||||
if !isContainerName(name) {
|
||||
return false, false, nil
|
||||
}
|
||||
|
||||
// Check if the container is known to mesos and it is active.
|
||||
id := ContainerNameToMesosId(name)
|
||||
|
||||
_, err = self.client.ContainerInfo(id)
|
||||
if err != nil {
|
||||
return false, true, fmt.Errorf("error getting running container: %v", err)
|
||||
}
|
||||
|
||||
return true, true, nil
|
||||
}
|
||||
|
||||
func (self *mesosFactory) DebugInfo() map[string][]string {
|
||||
return map[string][]string{}
|
||||
}
|
||||
|
||||
func Register(
|
||||
machineInfoFactory info.MachineInfoFactory,
|
||||
fsInfo fs.FsInfo,
|
||||
includedMetrics container.MetricSet,
|
||||
) error {
|
||||
client, err := Client()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create mesos agent client: %v", err)
|
||||
}
|
||||
|
||||
cgroupSubsystems, err := libcontainer.GetCgroupSubsystems()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get cgroup subsystems: %v", err)
|
||||
}
|
||||
|
||||
glog.V(1).Infof("Registering mesos factory")
|
||||
factory := &mesosFactory{
|
||||
machineInfoFactory: machineInfoFactory,
|
||||
cgroupSubsystems: cgroupSubsystems,
|
||||
fsInfo: fsInfo,
|
||||
includedMetrics: includedMetrics,
|
||||
client: client,
|
||||
}
|
||||
container.RegisterContainerHandlerFactory(factory, []watcher.ContainerWatchSource{watcher.Raw})
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,213 @@
|
|||
// Copyright 2018 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 "mesos" containers.
|
||||
package mesos
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"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 mesosContainerHandler struct {
|
||||
// Name of the container for this handler.
|
||||
name string
|
||||
|
||||
// machineInfoFactory provides info.MachineInfo
|
||||
machineInfoFactory info.MachineInfoFactory
|
||||
|
||||
// Absolute path to the cgroup hierarchies of this container.
|
||||
// (e.g.: "cpu" -> "/sys/fs/cgroup/cpu/test")
|
||||
cgroupPaths map[string]string
|
||||
|
||||
// File System Info
|
||||
fsInfo fs.FsInfo
|
||||
|
||||
// Metrics to be included.
|
||||
includedMetrics container.MetricSet
|
||||
|
||||
labels map[string]string
|
||||
|
||||
// Reference to the container
|
||||
reference info.ContainerReference
|
||||
|
||||
libcontainerHandler *containerlibcontainer.Handler
|
||||
}
|
||||
|
||||
func isRootCgroup(name string) bool {
|
||||
return name == "/"
|
||||
}
|
||||
|
||||
func newMesosContainerHandler(
|
||||
name string,
|
||||
cgroupSubsystems *containerlibcontainer.CgroupSubsystems,
|
||||
machineInfoFactory info.MachineInfoFactory,
|
||||
fsInfo fs.FsInfo,
|
||||
includedMetrics container.MetricSet,
|
||||
inHostNamespace bool,
|
||||
client mesosAgentClient,
|
||||
) (container.ContainerHandler, error) {
|
||||
cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems.MountPoints, name)
|
||||
for key, val := range cgroupSubsystems.MountPoints {
|
||||
cgroupPaths[key] = path.Join(val, name)
|
||||
}
|
||||
|
||||
// Generate the equivalent cgroup manager for this container.
|
||||
cgroupManager := &cgroupfs.Manager{
|
||||
Cgroups: &libcontainerconfigs.Cgroup{
|
||||
Name: name,
|
||||
},
|
||||
Paths: cgroupPaths,
|
||||
}
|
||||
|
||||
rootFs := "/"
|
||||
if !inHostNamespace {
|
||||
rootFs = "/rootfs"
|
||||
}
|
||||
|
||||
id := ContainerNameToMesosId(name)
|
||||
|
||||
cinfo, err := client.ContainerInfo(id)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
labels := cinfo.labels
|
||||
pid, err := client.ContainerPid(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
libcontainerHandler := containerlibcontainer.NewHandler(cgroupManager, rootFs, pid, includedMetrics)
|
||||
|
||||
reference := info.ContainerReference{
|
||||
Id: id,
|
||||
Name: name,
|
||||
Namespace: MesosNamespace,
|
||||
Aliases: []string{id, name},
|
||||
}
|
||||
|
||||
handler := &mesosContainerHandler{
|
||||
name: name,
|
||||
machineInfoFactory: machineInfoFactory,
|
||||
cgroupPaths: cgroupPaths,
|
||||
fsInfo: fsInfo,
|
||||
includedMetrics: includedMetrics,
|
||||
labels: labels,
|
||||
reference: reference,
|
||||
libcontainerHandler: libcontainerHandler,
|
||||
}
|
||||
|
||||
return handler, nil
|
||||
}
|
||||
|
||||
func (self *mesosContainerHandler) ContainerReference() (info.ContainerReference, error) {
|
||||
// We only know the container by its one name.
|
||||
return self.reference, nil
|
||||
}
|
||||
|
||||
// Nothing to start up.
|
||||
func (self *mesosContainerHandler) Start() {}
|
||||
|
||||
// Nothing to clean up.
|
||||
func (self *mesosContainerHandler) Cleanup() {}
|
||||
|
||||
func (self *mesosContainerHandler) GetSpec() (info.ContainerSpec, error) {
|
||||
// TODO: Since we dont collect disk usage and network stats for mesos containers, we set
|
||||
// hasFilesystem and hasNetwork to false. Revisit when we support disk usage, network
|
||||
// stats for mesos containers.
|
||||
hasNetwork := false
|
||||
hasFilesystem := false
|
||||
|
||||
spec, err := common.GetSpec(self.cgroupPaths, self.machineInfoFactory, hasNetwork, hasFilesystem)
|
||||
if err != nil {
|
||||
return spec, err
|
||||
}
|
||||
|
||||
spec.Labels = self.labels
|
||||
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
func (self *mesosContainerHandler) 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)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *mesosContainerHandler) GetStats() (*info.ContainerStats, error) {
|
||||
stats, err := self.libcontainerHandler.GetStats()
|
||||
if err != nil {
|
||||
return stats, err
|
||||
}
|
||||
|
||||
// Get filesystem stats.
|
||||
err = self.getFsStats(stats)
|
||||
if err != nil {
|
||||
return stats, err
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func (self *mesosContainerHandler) 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.name)
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func (self *mesosContainerHandler) GetContainerLabels() map[string]string {
|
||||
return self.labels
|
||||
}
|
||||
|
||||
func (self *mesosContainerHandler) GetContainerIPAddress() string {
|
||||
// the IP address for the mesos container corresponds to the system ip address.
|
||||
return "127.0.0.1"
|
||||
}
|
||||
|
||||
func (self *mesosContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) {
|
||||
return common.ListContainers(self.name, self.cgroupPaths, listType)
|
||||
}
|
||||
|
||||
func (self *mesosContainerHandler) ListProcesses(listType container.ListType) ([]int, error) {
|
||||
return self.libcontainerHandler.GetProcesses()
|
||||
}
|
||||
|
||||
func (self *mesosContainerHandler) Exists() bool {
|
||||
return common.CgroupExists(self.cgroupPaths)
|
||||
}
|
||||
|
||||
func (self *mesosContainerHandler) Type() container.ContainerType {
|
||||
return container.ContainerTypeMesos
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
// Copyright 2018 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 mesos
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mesos/mesos-go/api/v1/lib"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/agent"
|
||||
)
|
||||
|
||||
const (
|
||||
cpus = "cpus"
|
||||
schedulerSLA = "scheduler_sla"
|
||||
framework = "framework"
|
||||
source = "source"
|
||||
revocable = "revocable"
|
||||
nonRevocable = "non_revocable"
|
||||
)
|
||||
|
||||
type mContainers *agent.Response_GetContainers
|
||||
type mContainer = agent.Response_GetContainers_Container
|
||||
|
||||
type (
|
||||
state struct {
|
||||
st *agent.Response_GetState
|
||||
}
|
||||
)
|
||||
|
||||
// GetFramework finds a framework with the given id and returns nil if not found. Note that
|
||||
// this is different from the framework name.
|
||||
func (s *state) GetFramework(id string) (*mesos.FrameworkInfo, error) {
|
||||
for _, fw := range s.st.GetFrameworks.Frameworks {
|
||||
if fw.FrameworkInfo.ID.Value == id {
|
||||
return &fw.FrameworkInfo, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("unable to find framework id %s", id)
|
||||
}
|
||||
|
||||
// GetExecutor finds an executor with the given ID and returns nil if not found. Note that
|
||||
// this is different from the executor name.
|
||||
func (s *state) GetExecutor(id string) (*mesos.ExecutorInfo, error) {
|
||||
for _, exec := range s.st.GetExecutors.Executors {
|
||||
if exec.ExecutorInfo.ExecutorID.Value == id {
|
||||
return &exec.ExecutorInfo, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("unable to find executor with id %s", id)
|
||||
}
|
||||
|
||||
// GetTask returns a task launched by given executor.
|
||||
func (s *state) GetTask(exID string) (*mesos.Task, error) {
|
||||
// Check if task is in Launched Tasks list
|
||||
for _, t := range s.st.GetTasks.LaunchedTasks {
|
||||
if s.isMatchingTask(&t, exID) {
|
||||
return &t, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Check if task is in Queued Tasks list
|
||||
for _, t := range s.st.GetTasks.QueuedTasks {
|
||||
if s.isMatchingTask(&t, exID) {
|
||||
return &t, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("unable to find task matching executor id %s", exID)
|
||||
}
|
||||
|
||||
func (s *state) isMatchingTask(t *mesos.Task, exID string) bool {
|
||||
// MESOS-9111: For tasks launched through mesos command/default executor, the
|
||||
// executorID(which is same as the taskID) field is not filled in the TaskInfo object.
|
||||
// The workaround is compare with taskID field if executorID is empty
|
||||
if t.ExecutorID != nil {
|
||||
if t.ExecutorID.Value == exID {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
if t.TaskID.Value == exID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *state) fetchLabelsFromTask(exID string, labels map[string]string) error {
|
||||
t, err := s.GetTask(exID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Identify revocability. Can be removed once we have a proper label
|
||||
for _, resource := range t.Resources {
|
||||
if resource.Name == cpus {
|
||||
if resource.Revocable != nil {
|
||||
labels[schedulerSLA] = revocable
|
||||
} else {
|
||||
labels[schedulerSLA] = nonRevocable
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, l := range t.Labels.Labels {
|
||||
labels[l.Key] = *l.Value
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *state) FetchLabels(fwID string, exID string) (map[string]string, error) {
|
||||
labels := make(map[string]string)
|
||||
|
||||
// Look for the framework which launched the container.
|
||||
fw, err := s.GetFramework(fwID)
|
||||
if err != nil {
|
||||
return labels, fmt.Errorf("framework ID %q not found: %v", fwID, err)
|
||||
}
|
||||
labels[framework] = fw.Name
|
||||
|
||||
// Get the executor info of the container which contains all the task info.
|
||||
exec, err := s.GetExecutor(exID)
|
||||
if err != nil {
|
||||
return labels, fmt.Errorf("executor ID %q not found: %v", exID, err)
|
||||
}
|
||||
|
||||
labels[source] = *exec.Source
|
||||
|
||||
err = s.fetchLabelsFromTask(exID, labels)
|
||||
if err != nil {
|
||||
return labels, fmt.Errorf("failed to fetch labels from task with executor ID %s", exID)
|
||||
}
|
||||
|
||||
return labels, nil
|
||||
}
|
|
@ -17,6 +17,7 @@ package raw
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/google/cadvisor/container"
|
||||
"github.com/google/cadvisor/container/common"
|
||||
|
@ -43,8 +44,11 @@ type rawFactory struct {
|
|||
// Watcher for inotify events.
|
||||
watcher *common.InotifyWatcher
|
||||
|
||||
// List of metrics to be ignored.
|
||||
ignoreMetrics map[container.MetricKind]struct{}
|
||||
// List of metrics to be included.
|
||||
includedMetrics map[container.MetricKind]struct{}
|
||||
|
||||
// List of raw container cgroup path prefix whitelist.
|
||||
rawPrefixWhiteList []string
|
||||
}
|
||||
|
||||
func (self *rawFactory) String() string {
|
||||
|
@ -56,12 +60,19 @@ func (self *rawFactory) NewContainerHandler(name string, inHostNamespace bool) (
|
|||
if !inHostNamespace {
|
||||
rootFs = "/rootfs"
|
||||
}
|
||||
return newRawContainerHandler(name, self.cgroupSubsystems, self.machineInfoFactory, self.fsInfo, self.watcher, rootFs, self.ignoreMetrics)
|
||||
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.
|
||||
func (self *rawFactory) CanHandleAndAccept(name string) (bool, bool, error) {
|
||||
accept := name == "/" || !*dockerOnly
|
||||
|
||||
for _, prefix := range self.rawPrefixWhiteList {
|
||||
if strings.HasPrefix(name, prefix) {
|
||||
accept = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return true, accept, nil
|
||||
}
|
||||
|
||||
|
@ -69,7 +80,7 @@ func (self *rawFactory) DebugInfo() map[string][]string {
|
|||
return common.DebugInfo(self.watcher.GetWatches())
|
||||
}
|
||||
|
||||
func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics map[container.MetricKind]struct{}) error {
|
||||
func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics map[container.MetricKind]struct{}, rawPrefixWhiteList []string) error {
|
||||
cgroupSubsystems, err := libcontainer.GetCgroupSubsystems()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get cgroup subsystems: %v", err)
|
||||
|
@ -89,7 +100,8 @@ func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, igno
|
|||
fsInfo: fsInfo,
|
||||
cgroupSubsystems: &cgroupSubsystems,
|
||||
watcher: watcher,
|
||||
ignoreMetrics: ignoreMetrics,
|
||||
includedMetrics: includedMetrics,
|
||||
rawPrefixWhiteList: rawPrefixWhiteList,
|
||||
}
|
||||
container.RegisterContainerHandlerFactory(factory, []watch.ContainerWatchSource{watch.Raw})
|
||||
return nil
|
||||
|
|
|
@ -49,7 +49,7 @@ func isRootCgroup(name string) bool {
|
|||
return name == "/"
|
||||
}
|
||||
|
||||
func newRawContainerHandler(name string, cgroupSubsystems *libcontainer.CgroupSubsystems, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, watcher *common.InotifyWatcher, rootFs string, ignoreMetrics container.MetricSet) (container.ContainerHandler, error) {
|
||||
func newRawContainerHandler(name string, cgroupSubsystems *libcontainer.CgroupSubsystems, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, watcher *common.InotifyWatcher, rootFs string, includedMetrics container.MetricSet) (container.ContainerHandler, error) {
|
||||
cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems.MountPoints, name)
|
||||
|
||||
cHints, err := common.GetContainerHintsFromFile(*common.ArgContainerHints)
|
||||
|
@ -78,7 +78,7 @@ func newRawContainerHandler(name string, cgroupSubsystems *libcontainer.CgroupSu
|
|||
pid = 1
|
||||
}
|
||||
|
||||
handler := libcontainer.NewHandler(cgroupManager, rootFs, pid, ignoreMetrics)
|
||||
handler := libcontainer.NewHandler(cgroupManager, rootFs, pid, includedMetrics)
|
||||
|
||||
return &rawContainerHandler{
|
||||
name: name,
|
||||
|
|
|
@ -35,7 +35,7 @@ type rktFactory struct {
|
|||
|
||||
fsInfo fs.FsInfo
|
||||
|
||||
ignoreMetrics container.MetricSet
|
||||
includedMetrics container.MetricSet
|
||||
|
||||
rktPath string
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ func (self *rktFactory) NewContainerHandler(name string, inHostNamespace bool) (
|
|||
if !inHostNamespace {
|
||||
rootFs = "/rootfs"
|
||||
}
|
||||
return newRktContainerHandler(name, client, self.rktPath, self.cgroupSubsystems, self.machineInfoFactory, self.fsInfo, rootFs, self.ignoreMetrics)
|
||||
return newRktContainerHandler(name, client, self.rktPath, self.cgroupSubsystems, self.machineInfoFactory, self.fsInfo, rootFs, self.includedMetrics)
|
||||
}
|
||||
|
||||
func (self *rktFactory) CanHandleAndAccept(name string) (bool, bool, error) {
|
||||
|
@ -67,7 +67,7 @@ func (self *rktFactory) DebugInfo() map[string][]string {
|
|||
return map[string][]string{}
|
||||
}
|
||||
|
||||
func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics container.MetricSet) error {
|
||||
func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) error {
|
||||
_, err := Client()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to communicate with Rkt api service: %v", err)
|
||||
|
@ -91,7 +91,7 @@ func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, igno
|
|||
machineInfoFactory: machineInfoFactory,
|
||||
fsInfo: fsInfo,
|
||||
cgroupSubsystems: &cgroupSubsystems,
|
||||
ignoreMetrics: ignoreMetrics,
|
||||
includedMetrics: includedMetrics,
|
||||
rktPath: rktPath,
|
||||
}
|
||||
container.RegisterContainerHandlerFactory(factory, []watcher.ContainerWatchSource{watcher.Rkt})
|
||||
|
|
|
@ -48,7 +48,7 @@ type rktContainerHandler struct {
|
|||
// Filesystem handler.
|
||||
fsHandler common.FsHandler
|
||||
|
||||
ignoreMetrics container.MetricSet
|
||||
includedMetrics container.MetricSet
|
||||
|
||||
apiPod *rktapi.Pod
|
||||
|
||||
|
@ -59,7 +59,7 @@ type rktContainerHandler struct {
|
|||
libcontainerHandler *libcontainer.Handler
|
||||
}
|
||||
|
||||
func newRktContainerHandler(name string, rktClient rktapi.PublicAPIClient, rktPath string, cgroupSubsystems *libcontainer.CgroupSubsystems, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, rootFs string, ignoreMetrics container.MetricSet) (container.ContainerHandler, error) {
|
||||
func newRktContainerHandler(name string, rktClient rktapi.PublicAPIClient, rktPath string, cgroupSubsystems *libcontainer.CgroupSubsystems, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, rootFs string, includedMetrics container.MetricSet) (container.ContainerHandler, error) {
|
||||
aliases := make([]string, 1)
|
||||
isPod := false
|
||||
|
||||
|
@ -109,7 +109,7 @@ func newRktContainerHandler(name string, rktClient rktapi.PublicAPIClient, rktPa
|
|||
Paths: cgroupPaths,
|
||||
}
|
||||
|
||||
libcontainerHandler := libcontainer.NewHandler(cgroupManager, rootFs, pid, ignoreMetrics)
|
||||
libcontainerHandler := libcontainer.NewHandler(cgroupManager, rootFs, pid, includedMetrics)
|
||||
|
||||
rootfsStorageDir := getRootFs(rktPath, parsed)
|
||||
|
||||
|
@ -125,14 +125,14 @@ func newRktContainerHandler(name string, rktClient rktapi.PublicAPIClient, rktPa
|
|||
fsInfo: fsInfo,
|
||||
isPod: isPod,
|
||||
rootfsStorageDir: rootfsStorageDir,
|
||||
ignoreMetrics: ignoreMetrics,
|
||||
includedMetrics: includedMetrics,
|
||||
apiPod: apiPod,
|
||||
labels: labels,
|
||||
reference: containerReference,
|
||||
libcontainerHandler: libcontainerHandler,
|
||||
}
|
||||
|
||||
if !ignoreMetrics.Has(container.DiskUsageMetrics) {
|
||||
if includedMetrics.Has(container.DiskUsageMetrics) {
|
||||
handler.fsHandler = common.NewFsHandler(common.DefaultPeriod, rootfsStorageDir, "", fsInfo)
|
||||
}
|
||||
|
||||
|
@ -170,8 +170,8 @@ func (handler *rktContainerHandler) Cleanup() {
|
|||
}
|
||||
|
||||
func (handler *rktContainerHandler) GetSpec() (info.ContainerSpec, error) {
|
||||
hasNetwork := handler.isPod && !handler.ignoreMetrics.Has(container.NetworkUsageMetrics)
|
||||
hasFilesystem := !handler.ignoreMetrics.Has(container.DiskUsageMetrics)
|
||||
hasNetwork := handler.isPod && handler.includedMetrics.Has(container.NetworkUsageMetrics)
|
||||
hasFilesystem := handler.includedMetrics.Has(container.DiskUsageMetrics)
|
||||
|
||||
spec, err := common.GetSpec(handler.cgroupPaths, handler.machineInfoFactory, hasNetwork, hasFilesystem)
|
||||
|
||||
|
@ -186,11 +186,11 @@ func (handler *rktContainerHandler) getFsStats(stats *info.ContainerStats) error
|
|||
return err
|
||||
}
|
||||
|
||||
if !handler.ignoreMetrics.Has(container.DiskIOMetrics) {
|
||||
if handler.includedMetrics.Has(container.DiskIOMetrics) {
|
||||
common.AssignDeviceNamesToDiskStats((*common.MachineInfoNamer)(mi), &stats.DiskIo)
|
||||
}
|
||||
|
||||
if handler.ignoreMetrics.Has(container.DiskUsageMetrics) {
|
||||
if !handler.includedMetrics.Has(container.DiskUsageMetrics) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ func (f *systemdFactory) DebugInfo() map[string][]string {
|
|||
}
|
||||
|
||||
// Register registers the systemd container factory.
|
||||
func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics container.MetricSet) error {
|
||||
func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) error {
|
||||
glog.V(1).Infof("Registering systemd factory")
|
||||
factory := &systemdFactory{}
|
||||
container.RegisterContainerHandlerFactory(factory, []watcher.ContainerWatchSource{watcher.Raw})
|
||||
|
|
|
@ -422,7 +422,7 @@ func (self *RealFsInfo) GetFsInfoForPath(mountSet map[string]struct{}) ([]Fs, er
|
|||
}
|
||||
}
|
||||
if err != nil {
|
||||
glog.Errorf("Stat fs failed. Error: %v", err)
|
||||
glog.V(4).Infof("Stat fs failed. Error: %v", err)
|
||||
} else {
|
||||
deviceSet[device] = struct{}{}
|
||||
fs.DeviceInfo = DeviceInfo{
|
||||
|
@ -533,6 +533,21 @@ func (self *RealFsInfo) GetDirFsDevice(dir string) (*DeviceInfo, error) {
|
|||
}
|
||||
|
||||
mount, found := self.mounts[dir]
|
||||
// try the parent dir if not found until we reach the root dir
|
||||
// this is an issue on btrfs systems where the directory is not
|
||||
// the subvolume
|
||||
for !found {
|
||||
pathdir, _ := filepath.Split(dir)
|
||||
// break when we reach root
|
||||
if pathdir == "/" {
|
||||
break
|
||||
}
|
||||
// trim "/" from the new parent path otherwise the next possible
|
||||
// filepath.Split in the loop will not split the string any further
|
||||
dir = strings.TrimSuffix(pathdir, "/")
|
||||
mount, found = self.mounts[dir]
|
||||
}
|
||||
|
||||
if found && mount.Fstype == "btrfs" && mount.Major == 0 && strings.HasPrefix(mount.Source, "/dev/") {
|
||||
major, minor, err := getBtrfsMajorMinorIds(mount)
|
||||
if err != nil {
|
||||
|
|
|
@ -358,6 +358,9 @@ type MemoryStats struct {
|
|||
// Units: Bytes.
|
||||
Swap uint64 `json:"swap"`
|
||||
|
||||
// The amount of memory used for mapped files (includes tmpfs/shmem)
|
||||
MappedFile uint64 `json:"mapped_file"`
|
||||
|
||||
// The amount of working set memory, this includes recently accessed memory,
|
||||
// dirty memory, and kernel memory. Working set is <= "usage".
|
||||
// Units: Bytes.
|
||||
|
|
|
@ -19,6 +19,7 @@ go_library(
|
|||
"//vendor/github.com/google/cadvisor/container/containerd:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/container/crio:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/container/docker:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/container/mesos:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/container/raw:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/container/rkt:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/container/systemd:go_default_library",
|
||||
|
|
|
@ -33,6 +33,7 @@ import (
|
|||
"github.com/google/cadvisor/container/containerd"
|
||||
"github.com/google/cadvisor/container/crio"
|
||||
"github.com/google/cadvisor/container/docker"
|
||||
"github.com/google/cadvisor/container/mesos"
|
||||
"github.com/google/cadvisor/container/raw"
|
||||
"github.com/google/cadvisor/container/rkt"
|
||||
"github.com/google/cadvisor/container/systemd"
|
||||
|
@ -141,7 +142,7 @@ type Manager interface {
|
|||
}
|
||||
|
||||
// New takes a memory storage and returns a new manager.
|
||||
func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs, maxHousekeepingInterval time.Duration, allowDynamicHousekeeping bool, ignoreMetricsSet container.MetricSet, collectorHttpClient *http.Client) (Manager, error) {
|
||||
func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs, maxHousekeepingInterval time.Duration, allowDynamicHousekeeping bool, includedMetricsSet container.MetricSet, collectorHttpClient *http.Client, rawContainerCgroupPathPrefixWhiteList []string) (Manager, error) {
|
||||
if memoryCache == nil {
|
||||
return nil, fmt.Errorf("manager requires memory storage")
|
||||
}
|
||||
|
@ -203,20 +204,21 @@ func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs, maxHousekeepingIn
|
|||
eventsChannel := make(chan watcher.ContainerEvent, 16)
|
||||
|
||||
newManager := &manager{
|
||||
containers: make(map[namespacedContainerName]*containerData),
|
||||
quitChannels: make([]chan error, 0, 2),
|
||||
memoryCache: memoryCache,
|
||||
fsInfo: fsInfo,
|
||||
cadvisorContainer: selfContainer,
|
||||
inHostNamespace: inHostNamespace,
|
||||
startupTime: time.Now(),
|
||||
maxHousekeepingInterval: maxHousekeepingInterval,
|
||||
allowDynamicHousekeeping: allowDynamicHousekeeping,
|
||||
ignoreMetrics: ignoreMetricsSet,
|
||||
containerWatchers: []watcher.ContainerWatcher{},
|
||||
eventsChannel: eventsChannel,
|
||||
collectorHttpClient: collectorHttpClient,
|
||||
nvidiaManager: &accelerators.NvidiaManager{},
|
||||
containers: make(map[namespacedContainerName]*containerData),
|
||||
quitChannels: make([]chan error, 0, 2),
|
||||
memoryCache: memoryCache,
|
||||
fsInfo: fsInfo,
|
||||
cadvisorContainer: selfContainer,
|
||||
inHostNamespace: inHostNamespace,
|
||||
startupTime: time.Now(),
|
||||
maxHousekeepingInterval: maxHousekeepingInterval,
|
||||
allowDynamicHousekeeping: allowDynamicHousekeeping,
|
||||
includedMetrics: includedMetricsSet,
|
||||
containerWatchers: []watcher.ContainerWatcher{},
|
||||
eventsChannel: eventsChannel,
|
||||
collectorHttpClient: collectorHttpClient,
|
||||
nvidiaManager: &accelerators.NvidiaManager{},
|
||||
rawContainerCgroupPathPrefixWhiteList: rawContainerCgroupPathPrefixWhiteList,
|
||||
}
|
||||
|
||||
machineInfo, err := machine.Info(sysfs, fsInfo, inHostNamespace)
|
||||
|
@ -283,21 +285,23 @@ type manager struct {
|
|||
startupTime time.Time
|
||||
maxHousekeepingInterval time.Duration
|
||||
allowDynamicHousekeeping bool
|
||||
ignoreMetrics container.MetricSet
|
||||
includedMetrics container.MetricSet
|
||||
containerWatchers []watcher.ContainerWatcher
|
||||
eventsChannel chan watcher.ContainerEvent
|
||||
collectorHttpClient *http.Client
|
||||
nvidiaManager accelerators.AcceleratorManager
|
||||
// List of raw container cgroup path prefix whitelist.
|
||||
rawContainerCgroupPathPrefixWhiteList []string
|
||||
}
|
||||
|
||||
// Start the container manager.
|
||||
func (self *manager) Start() error {
|
||||
err := docker.Register(self, self.fsInfo, self.ignoreMetrics)
|
||||
err := docker.Register(self, self.fsInfo, self.includedMetrics)
|
||||
if err != nil {
|
||||
glog.V(5).Infof("Registration of the Docker container factory failed: %v.", err)
|
||||
}
|
||||
|
||||
err = rkt.Register(self, self.fsInfo, self.ignoreMetrics)
|
||||
err = rkt.Register(self, self.fsInfo, self.includedMetrics)
|
||||
if err != nil {
|
||||
glog.V(5).Infof("Registration of the rkt container factory failed: %v", err)
|
||||
} else {
|
||||
|
@ -308,22 +312,27 @@ func (self *manager) Start() error {
|
|||
self.containerWatchers = append(self.containerWatchers, watcher)
|
||||
}
|
||||
|
||||
err = containerd.Register(self, self.fsInfo, self.ignoreMetrics)
|
||||
err = containerd.Register(self, self.fsInfo, self.includedMetrics)
|
||||
if err != nil {
|
||||
glog.V(5).Infof("Registration of the containerd container factory failed: %v", err)
|
||||
}
|
||||
|
||||
err = crio.Register(self, self.fsInfo, self.ignoreMetrics)
|
||||
err = crio.Register(self, self.fsInfo, self.includedMetrics)
|
||||
if err != nil {
|
||||
glog.V(5).Infof("Registration of the crio container factory failed: %v", err)
|
||||
}
|
||||
|
||||
err = systemd.Register(self, self.fsInfo, self.ignoreMetrics)
|
||||
err = mesos.Register(self, self.fsInfo, self.includedMetrics)
|
||||
if err != nil {
|
||||
glog.V(5).Infof("Registration of the mesos container factory failed: %v", err)
|
||||
}
|
||||
|
||||
err = systemd.Register(self, self.fsInfo, self.includedMetrics)
|
||||
if err != nil {
|
||||
glog.V(5).Infof("Registration of the systemd container factory failed: %v", err)
|
||||
}
|
||||
|
||||
err = raw.Register(self, self.fsInfo, self.ignoreMetrics)
|
||||
err = raw.Register(self, self.fsInfo, self.includedMetrics, self.rawContainerCgroupPathPrefixWhiteList)
|
||||
if err != nil {
|
||||
glog.Errorf("Registration of the raw container factory failed: %v", err)
|
||||
}
|
||||
|
@ -619,6 +628,11 @@ func (self *manager) AllDockerContainers(query *info.ContainerInfoRequest) (map[
|
|||
for name, cont := range containers {
|
||||
inf, err := self.containerDataToContainerInfo(cont, query)
|
||||
if err != nil {
|
||||
// Ignore the error because of race condition and return best-effort result.
|
||||
if err == memory.ErrDataNotFound {
|
||||
glog.Warningf("Error getting data for container %s because of race condition", name)
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
output[name] = *inf
|
||||
|
@ -1072,22 +1086,25 @@ func (m *manager) destroyContainerLocked(containerName string) error {
|
|||
|
||||
// Detect all containers that have been added or deleted from the specified container.
|
||||
func (m *manager) getContainersDiff(containerName string) (added []info.ContainerReference, removed []info.ContainerReference, err error) {
|
||||
m.containersLock.RLock()
|
||||
defer m.containersLock.RUnlock()
|
||||
|
||||
// Get all subcontainers recursively.
|
||||
m.containersLock.RLock()
|
||||
cont, ok := m.containers[namespacedContainerName{
|
||||
Name: containerName,
|
||||
}]
|
||||
m.containersLock.RUnlock()
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("failed to find container %q while checking for new containers", containerName)
|
||||
}
|
||||
allContainers, err := cont.handler.ListContainers(container.ListRecursive)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
allContainers = append(allContainers, info.ContainerReference{Name: containerName})
|
||||
|
||||
m.containersLock.RLock()
|
||||
defer m.containersLock.RUnlock()
|
||||
|
||||
// Determine which were added and which were removed.
|
||||
allContainersSet := make(map[string]*containerData)
|
||||
for name, d := range m.containers {
|
||||
|
|
|
@ -8,6 +8,7 @@ go_library(
|
|||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/container:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/info/v1:go_default_library",
|
||||
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
|
||||
],
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/google/cadvisor/container"
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
@ -114,7 +115,7 @@ type PrometheusCollector struct {
|
|||
// ContainerLabelsFunc specifies which base labels will be attached to all
|
||||
// exported metrics. If left to nil, the DefaultContainerLabels function
|
||||
// will be used instead.
|
||||
func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCollector {
|
||||
func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetrics container.MetricSet) *PrometheusCollector {
|
||||
if f == nil {
|
||||
f = DefaultContainerLabels
|
||||
}
|
||||
|
@ -134,7 +135,12 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCo
|
|||
getValues: func(s *info.ContainerStats) metricValues {
|
||||
return metricValues{{value: float64(time.Now().Unix())}}
|
||||
},
|
||||
}, {
|
||||
},
|
||||
},
|
||||
}
|
||||
if includedMetrics.Has(container.CpuUsageMetrics) {
|
||||
c.containerMetrics = append(c.containerMetrics, []containerMetric{
|
||||
{
|
||||
name: "container_cpu_user_seconds_total",
|
||||
help: "Cumulative user cpu time consumed in seconds.",
|
||||
valueType: prometheus.CounterValue,
|
||||
|
@ -197,7 +203,12 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCo
|
|||
getValues: func(s *info.ContainerStats) metricValues {
|
||||
return metricValues{{value: float64(s.Cpu.CFS.ThrottledTime) / float64(time.Second)}}
|
||||
},
|
||||
}, {
|
||||
},
|
||||
}...)
|
||||
}
|
||||
if includedMetrics.Has(container.ProcessSchedulerMetrics) {
|
||||
c.containerMetrics = append(c.containerMetrics, []containerMetric{
|
||||
{
|
||||
name: "container_cpu_schedstat_run_seconds_total",
|
||||
help: "Time duration the processes of the container have run on the CPU.",
|
||||
valueType: prometheus.CounterValue,
|
||||
|
@ -218,7 +229,12 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCo
|
|||
getValues: func(s *info.ContainerStats) metricValues {
|
||||
return metricValues{{value: float64(s.Cpu.Schedstat.RunPeriods)}}
|
||||
},
|
||||
}, {
|
||||
},
|
||||
}...)
|
||||
}
|
||||
if includedMetrics.Has(container.CpuLoadMetrics) {
|
||||
c.containerMetrics = append(c.containerMetrics, []containerMetric{
|
||||
{
|
||||
name: "container_cpu_load_average_10s",
|
||||
help: "Value of container cpu load average over the last 10 seconds.",
|
||||
valueType: prometheus.GaugeValue,
|
||||
|
@ -226,6 +242,40 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCo
|
|||
return metricValues{{value: float64(s.Cpu.LoadAverage)}}
|
||||
},
|
||||
}, {
|
||||
name: "container_tasks_state",
|
||||
help: "Number of tasks in given state",
|
||||
extraLabels: []string{"state"},
|
||||
valueType: prometheus.GaugeValue,
|
||||
getValues: func(s *info.ContainerStats) metricValues {
|
||||
return metricValues{
|
||||
{
|
||||
value: float64(s.TaskStats.NrSleeping),
|
||||
labels: []string{"sleeping"},
|
||||
},
|
||||
{
|
||||
value: float64(s.TaskStats.NrRunning),
|
||||
labels: []string{"running"},
|
||||
},
|
||||
{
|
||||
value: float64(s.TaskStats.NrStopped),
|
||||
labels: []string{"stopped"},
|
||||
},
|
||||
{
|
||||
value: float64(s.TaskStats.NrUninterruptible),
|
||||
labels: []string{"uninterruptible"},
|
||||
},
|
||||
{
|
||||
value: float64(s.TaskStats.NrIoWait),
|
||||
labels: []string{"iowaiting"},
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
}...)
|
||||
}
|
||||
if includedMetrics.Has(container.MemoryUsageMetrics) {
|
||||
c.containerMetrics = append(c.containerMetrics, []containerMetric{
|
||||
{
|
||||
name: "container_memory_cache",
|
||||
help: "Number of bytes of page cache memory.",
|
||||
valueType: prometheus.GaugeValue,
|
||||
|
@ -239,6 +289,13 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCo
|
|||
getValues: func(s *info.ContainerStats) metricValues {
|
||||
return metricValues{{value: float64(s.Memory.RSS)}}
|
||||
},
|
||||
}, {
|
||||
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)}}
|
||||
},
|
||||
}, {
|
||||
name: "container_memory_swap",
|
||||
help: "Container swap usage in bytes.",
|
||||
|
@ -300,7 +357,12 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCo
|
|||
},
|
||||
}
|
||||
},
|
||||
}, {
|
||||
},
|
||||
}...)
|
||||
}
|
||||
if includedMetrics.Has(container.AcceleratorUsageMetrics) {
|
||||
c.containerMetrics = append(c.containerMetrics, []containerMetric{
|
||||
{
|
||||
name: "container_accelerator_memory_total_bytes",
|
||||
help: "Total accelerator memory.",
|
||||
valueType: prometheus.GaugeValue,
|
||||
|
@ -345,7 +407,12 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCo
|
|||
}
|
||||
return values
|
||||
},
|
||||
}, {
|
||||
},
|
||||
}...)
|
||||
}
|
||||
if includedMetrics.Has(container.DiskUsageMetrics) {
|
||||
c.containerMetrics = append(c.containerMetrics, []containerMetric{
|
||||
{
|
||||
name: "container_fs_inodes_free",
|
||||
help: "Number of available Inodes",
|
||||
valueType: prometheus.GaugeValue,
|
||||
|
@ -385,7 +452,12 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCo
|
|||
return float64(fs.Usage)
|
||||
})
|
||||
},
|
||||
}, {
|
||||
},
|
||||
}...)
|
||||
}
|
||||
if includedMetrics.Has(container.DiskIOMetrics) {
|
||||
c.containerMetrics = append(c.containerMetrics, []containerMetric{
|
||||
{
|
||||
name: "container_fs_reads_bytes_total",
|
||||
help: "Cumulative count of bytes read",
|
||||
valueType: prometheus.CounterValue,
|
||||
|
@ -547,7 +619,12 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCo
|
|||
return float64(fs.WeightedIoTime) / float64(time.Second)
|
||||
})
|
||||
},
|
||||
}, {
|
||||
},
|
||||
}...)
|
||||
}
|
||||
if includedMetrics.Has(container.NetworkUsageMetrics) {
|
||||
c.containerMetrics = append(c.containerMetrics, []containerMetric{
|
||||
{
|
||||
name: "container_network_receive_bytes_total",
|
||||
help: "Cumulative count of bytes received",
|
||||
valueType: prometheus.CounterValue,
|
||||
|
@ -667,7 +744,12 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCo
|
|||
}
|
||||
return values
|
||||
},
|
||||
}, {
|
||||
},
|
||||
}...)
|
||||
}
|
||||
if includedMetrics.Has(container.NetworkTcpUsageMetrics) {
|
||||
c.containerMetrics = append(c.containerMetrics, []containerMetric{
|
||||
{
|
||||
name: "container_network_tcp_usage_total",
|
||||
help: "tcp connection usage statistic for container",
|
||||
valueType: prometheus.GaugeValue,
|
||||
|
@ -720,7 +802,12 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCo
|
|||
},
|
||||
}
|
||||
},
|
||||
}, {
|
||||
},
|
||||
}...)
|
||||
}
|
||||
if includedMetrics.Has(container.NetworkUdpUsageMetrics) {
|
||||
c.containerMetrics = append(c.containerMetrics, []containerMetric{
|
||||
{
|
||||
name: "container_network_udp_usage_total",
|
||||
help: "udp connection usage statistic for container",
|
||||
valueType: prometheus.GaugeValue,
|
||||
|
@ -745,37 +832,8 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCo
|
|||
},
|
||||
}
|
||||
},
|
||||
}, {
|
||||
name: "container_tasks_state",
|
||||
help: "Number of tasks in given state",
|
||||
extraLabels: []string{"state"},
|
||||
valueType: prometheus.GaugeValue,
|
||||
getValues: func(s *info.ContainerStats) metricValues {
|
||||
return metricValues{
|
||||
{
|
||||
value: float64(s.TaskStats.NrSleeping),
|
||||
labels: []string{"sleeping"},
|
||||
},
|
||||
{
|
||||
value: float64(s.TaskStats.NrRunning),
|
||||
labels: []string{"running"},
|
||||
},
|
||||
{
|
||||
value: float64(s.TaskStats.NrStopped),
|
||||
labels: []string{"stopped"},
|
||||
},
|
||||
{
|
||||
value: float64(s.TaskStats.NrUninterruptible),
|
||||
labels: []string{"uninterruptible"},
|
||||
},
|
||||
{
|
||||
value: float64(s.TaskStats.NrIoWait),
|
||||
labels: []string{"iowaiting"},
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}...)
|
||||
}
|
||||
|
||||
return c
|
||||
|
@ -842,6 +900,19 @@ 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]
|
||||
}
|
||||
if image := container.Spec.Image; len(image) > 0 {
|
||||
set[LabelImage] = image
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
func (c *PrometheusCollector) collectContainersInfo(ch chan<- prometheus.Metric) {
|
||||
containers, err := c.infoProvider.SubcontainersInfo("/", &info.ContainerInfoRequest{NumStats: 1})
|
||||
if err != nil {
|
||||
|
@ -889,6 +960,9 @@ func (c *PrometheusCollector) collectContainersInfo(ch chan<- prometheus.Metric)
|
|||
}
|
||||
|
||||
// Now for the actual metrics
|
||||
if len(container.Stats) == 0 {
|
||||
continue
|
||||
}
|
||||
stats := container.Stats[0]
|
||||
for _, cm := range c.containerMetrics {
|
||||
if cm.condition != nil && !cm.condition(container.Spec) {
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,13 @@
|
|||
Copyright 2013-2015, Mesosphere, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
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.
|
|
@ -0,0 +1,50 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"client.go",
|
||||
"doc.go",
|
||||
"filters.go",
|
||||
"fixedpoint.go",
|
||||
"labels.go",
|
||||
"mesos.pb.go",
|
||||
"mesos.pb_ffjson.go",
|
||||
"ranges.go",
|
||||
"resources.go",
|
||||
"values.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib",
|
||||
importpath = "github.com/mesos/mesos-go/api/v1/lib",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/gogo/protobuf/gogoproto:go_default_library",
|
||||
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/roles:go_default_library",
|
||||
"//vendor/github.com/pquerna/ffjson/fflib/v1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/agent:all-srcs",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/client:all-srcs",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/debug:all-srcs",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:all-srcs",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli:all-srcs",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/recordio:all-srcs",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/roles:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,35 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"agent.pb.go",
|
||||
"agent.pb_ffjson.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/agent",
|
||||
importpath = "github.com/mesos/mesos-go/api/v1/lib/agent",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/gogo/protobuf/gogoproto:go_default_library",
|
||||
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib:go_default_library",
|
||||
"//vendor/github.com/pquerna/ffjson/fflib/v1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/agent/calls:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
File diff suppressed because it is too large
Load Diff
15157
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/agent.pb_ffjson.go
generated
vendored
Normal file
15157
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/agent.pb_ffjson.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,706 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package mesos.agent;
|
||||
|
||||
import "github.com/mesos/mesos-go/api/v1/lib/mesos.proto";
|
||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
option go_package = "agent";
|
||||
option (gogoproto.benchgen_all) = true;
|
||||
option (gogoproto.enum_stringer_all) = true;
|
||||
option (gogoproto.equal_all) = true;
|
||||
option (gogoproto.goproto_enum_prefix_all) = false;
|
||||
option (gogoproto.goproto_enum_stringer_all) = false;
|
||||
option (gogoproto.goproto_stringer_all) = false;
|
||||
option (gogoproto.goproto_unrecognized_all) = false;
|
||||
option (gogoproto.gostring_all) = true;
|
||||
option (gogoproto.marshaler_all) = true;
|
||||
option (gogoproto.populate_all) = true;
|
||||
option (gogoproto.protosizer_all) = true;
|
||||
option (gogoproto.stringer_all) = true;
|
||||
option (gogoproto.testgen_all) = true;
|
||||
option (gogoproto.unmarshaler_all) = true;
|
||||
option (gogoproto.verbose_equal_all) = true;
|
||||
|
||||
/**
|
||||
* Calls that can be sent to the v1 agent API.
|
||||
*
|
||||
* A call is described using the standard protocol buffer "union"
|
||||
* trick, see
|
||||
* https://developers.google.com/protocol-buffers/docs/techniques#union.
|
||||
*/
|
||||
message Call {
|
||||
// If a call of type `Call::FOO` requires additional parameters they can be
|
||||
// included in the corresponding `Call::Foo` message. Similarly, if a call
|
||||
// receives a synchronous response it will be returned as a `Response`
|
||||
// message of type `Response::FOO`; see `Call::LaunchNestedContainerSession`
|
||||
// and `Call::AttachContainerOutput` for exceptions.
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
|
||||
GET_HEALTH = 1; // Retrieves the agent's health status.
|
||||
GET_FLAGS = 2; // Retrieves the agent's flag configuration.
|
||||
GET_VERSION = 3; // Retrieves the agent's version information.
|
||||
GET_METRICS = 4; // See 'GetMetrics' below.
|
||||
|
||||
GET_LOGGING_LEVEL = 5; // Retrieves the agent's logging level.
|
||||
SET_LOGGING_LEVEL = 6; // See 'SetLoggingLevel' below.
|
||||
|
||||
LIST_FILES = 7;
|
||||
READ_FILE = 8; // See 'ReadFile' below.
|
||||
|
||||
GET_STATE = 9;
|
||||
|
||||
GET_CONTAINERS = 10;
|
||||
|
||||
// Retrieves the information about known frameworks.
|
||||
GET_FRAMEWORKS = 11;
|
||||
|
||||
// Retrieves the information about known executors.
|
||||
GET_EXECUTORS = 12;
|
||||
|
||||
// Retrieves the information about known operations.
|
||||
GET_OPERATIONS = 31;
|
||||
|
||||
// Retrieves the information about known tasks.
|
||||
GET_TASKS = 13;
|
||||
|
||||
// Retrieves the agent information.
|
||||
GET_AGENT = 20;
|
||||
|
||||
// Retrieves the information about known resource providers.
|
||||
GET_RESOURCE_PROVIDERS = 26;
|
||||
|
||||
// Calls for managing nested containers underneath an executor's container.
|
||||
// Some of these calls are deprecated in favor of the calls
|
||||
// for both standalone or nested containers further below.
|
||||
LAUNCH_NESTED_CONTAINER = 14 [deprecated = true];
|
||||
WAIT_NESTED_CONTAINER = 15 [deprecated = true];
|
||||
KILL_NESTED_CONTAINER = 16 [deprecated = true];
|
||||
REMOVE_NESTED_CONTAINER = 21 [deprecated = true];
|
||||
|
||||
// See 'LaunchNestedContainerSession' below.
|
||||
LAUNCH_NESTED_CONTAINER_SESSION = 17;
|
||||
|
||||
ATTACH_CONTAINER_INPUT = 18; // See 'AttachContainerInput' below.
|
||||
ATTACH_CONTAINER_OUTPUT = 19; // see 'AttachContainerOutput' below.
|
||||
|
||||
// Calls for managing standalone containers
|
||||
// or containers nested underneath another container.
|
||||
LAUNCH_CONTAINER = 22; // See 'LaunchContainer' below.
|
||||
WAIT_CONTAINER = 23; // See 'WaitContainer' below.
|
||||
KILL_CONTAINER = 24; // See 'KillContainer' below.
|
||||
REMOVE_CONTAINER = 25; // See 'RemoveContainer' below.
|
||||
|
||||
ADD_RESOURCE_PROVIDER_CONFIG = 27; // See 'AddResourceProviderConfig' below. // NOLINT
|
||||
UPDATE_RESOURCE_PROVIDER_CONFIG = 28; // See 'UpdateResourceProviderConfig' below. // NOLINT
|
||||
REMOVE_RESOURCE_PROVIDER_CONFIG = 29; // See 'RemoveResourceProviderConfig' below. // NOLINT
|
||||
|
||||
// Prune unused container images.
|
||||
PRUNE_IMAGES = 30;
|
||||
|
||||
option (gogoproto.goproto_enum_prefix) = true;
|
||||
}
|
||||
|
||||
// Provides a snapshot of the current metrics tracked by the agent.
|
||||
message GetMetrics {
|
||||
// If set, `timeout` would be used to determines the maximum amount of time
|
||||
// the API will take to respond. If the timeout is exceeded, some metrics
|
||||
// may not be included in the response.
|
||||
optional DurationInfo timeout = 1;
|
||||
}
|
||||
|
||||
// Sets the logging verbosity level for a specified duration. Mesos uses
|
||||
// [glog](https://github.com/google/glog) for logging. The library only uses
|
||||
// verbose logging which means nothing will be output unless the verbosity
|
||||
// level is set (by default it's 0, libprocess uses levels 1, 2, and 3).
|
||||
message SetLoggingLevel {
|
||||
// The verbosity level.
|
||||
required uint32 level = 1 [(gogoproto.nullable) = false];
|
||||
// The duration to keep verbosity level toggled. After this duration, the
|
||||
// verbosity level of log would revert to the original level.
|
||||
required DurationInfo duration = 2 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Provides the file listing for a directory.
|
||||
message ListFiles {
|
||||
required string path = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Reads data from a file.
|
||||
message ReadFile {
|
||||
// The path of file.
|
||||
required string path = 1 [(gogoproto.nullable) = false];
|
||||
|
||||
// Initial offset in file to start reading from.
|
||||
required uint64 offset = 2 [(gogoproto.nullable) = false];
|
||||
|
||||
// The maximum number of bytes to read. The read length is capped at 16
|
||||
// memory pages.
|
||||
optional uint64 length = 3;
|
||||
}
|
||||
|
||||
// Lists active containers on the agent.
|
||||
message GetContainers {
|
||||
optional bool show_nested = 1;
|
||||
optional bool show_standalone = 2;
|
||||
}
|
||||
|
||||
// Deprecated in favor of `LaunchContainer`.
|
||||
message LaunchNestedContainer {
|
||||
required ContainerID container_id = 1 [(gogoproto.customname) = "ContainerID", (gogoproto.nullable) = false];
|
||||
optional CommandInfo command = 2;
|
||||
optional ContainerInfo container = 3;
|
||||
}
|
||||
|
||||
// Deprecated in favor of `WaitContainer`.
|
||||
message WaitNestedContainer {
|
||||
required ContainerID container_id = 1 [(gogoproto.customname) = "ContainerID", (gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Deprecated in favor of `KillContainer`.
|
||||
message KillNestedContainer {
|
||||
required ContainerID container_id = 1 [(gogoproto.customname) = "ContainerID", (gogoproto.nullable) = false];
|
||||
optional int32 signal = 2;
|
||||
}
|
||||
|
||||
// Deprecated in favor of `RemoveContainer`.
|
||||
message RemoveNestedContainer {
|
||||
required ContainerID container_id = 1 [(gogoproto.customname) = "ContainerID", (gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Launches a nested container within an executor's tree of containers.
|
||||
// The differences between this call and `LaunchNestedContainer` are:
|
||||
// 1) The container's life-cycle is tied to the lifetime of the
|
||||
// connection used to make this call, i.e., if the connection ever
|
||||
// breaks, the container will be destroyed.
|
||||
// 2) The nested container shares the same namespaces and cgroups as
|
||||
// its parent container.
|
||||
// 3) Results in a streaming response of type `ProcessIO`. So the call
|
||||
// needs to be made on a persistent connection.
|
||||
message LaunchNestedContainerSession {
|
||||
required ContainerID container_id = 1 [(gogoproto.customname) = "ContainerID", (gogoproto.nullable) = false];
|
||||
optional CommandInfo command = 2;
|
||||
optional ContainerInfo container = 3;
|
||||
}
|
||||
|
||||
// Attaches the caller to the STDIN of the entry point of the container.
|
||||
// Clients can use this to stream input data to a container.
|
||||
// Note that this call needs to be made on a persistent connection by
|
||||
// streaming a CONTAINER_ID message followed by one or more PROCESS_IO
|
||||
// messages.
|
||||
message AttachContainerInput {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
CONTAINER_ID = 1;
|
||||
PROCESS_IO = 2;
|
||||
|
||||
option (gogoproto.goproto_enum_prefix) = true;
|
||||
}
|
||||
|
||||
optional Type type = 1 [(gogoproto.nullable) = false];
|
||||
optional ContainerID container_id = 2 [(gogoproto.customname) = "ContainerID"];
|
||||
optional ProcessIO process_io = 3 [(gogoproto.customname) = "ProcessIO"];
|
||||
}
|
||||
|
||||
// Attaches the caller to the STDOUT and STDERR of the entrypoint of
|
||||
// the container. Clients can use this to stream output/error from the
|
||||
// container. This call will result in a streaming response of `ProcessIO`;
|
||||
// so this call needs to be made on a persistent connection.
|
||||
message AttachContainerOutput {
|
||||
required ContainerID container_id = 1 [(gogoproto.customname) = "ContainerID", (gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Launches a either a "standalone" container on this agent
|
||||
// or a nested container within another tree of containers.
|
||||
//
|
||||
// A standalone container is launched by specifying a ContainerID
|
||||
// with no parent. Standalone containers bypass the normal offer cycle
|
||||
// between the master and agent. Unlike other containers, a standalone
|
||||
// container does not have an executor or any tasks. This means the
|
||||
// standalone container does not report back to Mesos or any framework
|
||||
// and must be supervised separately.
|
||||
//
|
||||
// A nested container is launched by specifying a ContainerID with
|
||||
// another existing container (including standalone containers)
|
||||
// as the parent.
|
||||
//
|
||||
// Returns 200 OK if the new container launch succeeds.
|
||||
// Returns 202 Accepted if the requested ContainerID is already in use
|
||||
// by a standalone or nested container.
|
||||
// Returns 400 Bad Request if the container launch fails.
|
||||
message LaunchContainer {
|
||||
// NOTE: Some characters cannot be used in the ID. All characters
|
||||
// must be valid filesystem path characters. In addition, '/' and '.'
|
||||
// are reserved.
|
||||
required ContainerID container_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "ContainerID"];
|
||||
|
||||
optional CommandInfo command = 2;
|
||||
|
||||
// NOTE: Nested containers may not specify resources and instead
|
||||
// share resources with its parent container.
|
||||
//
|
||||
// TODO(josephw): These resources are purely used for isolation
|
||||
// and are not accounted for by the Mesos master (if connected).
|
||||
// It is the caller's responsibility to ensure that resources are
|
||||
// not overcommitted (e.g. CPU and memory) or conflicting (e.g. ports
|
||||
// and volumes). Once there is support for preempting tasks and a
|
||||
// way to update the resources advertised by the agent, these standalone
|
||||
// container resources should be accounted for by the master.
|
||||
repeated Resource resources = 3 [(gogoproto.nullable) = false];
|
||||
|
||||
optional ContainerInfo container = 4;
|
||||
}
|
||||
|
||||
// Waits for the standalone or nested container to terminate
|
||||
// and returns the exit status.
|
||||
//
|
||||
// Returns 200 OK if and when the container exits.
|
||||
// Returns 404 Not Found if the container does not exist.
|
||||
message WaitContainer {
|
||||
required ContainerID container_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "ContainerID"];
|
||||
}
|
||||
|
||||
// Kills the standalone or nested container. The signal to be sent
|
||||
// to the container can be specified in the 'signal' field.
|
||||
//
|
||||
// Returns 200 OK if the signal is sent successfully.
|
||||
// Returns 404 Not Found if the container does not exist.
|
||||
message KillContainer {
|
||||
required ContainerID container_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "ContainerID"];
|
||||
|
||||
// Defaults to SIGKILL.
|
||||
optional int32 signal = 2;
|
||||
}
|
||||
|
||||
// Removes a container's artifacts (runtime and sandbox directories).
|
||||
//
|
||||
// For nested containers, it is important to use this call if multiple
|
||||
// nested containers are launched under the same parent container, because
|
||||
// garbage collection only takes place at the parent container. Artifacts
|
||||
// belonging to nested containers will not be garbage collected while
|
||||
// the parent container is running.
|
||||
//
|
||||
// TODO(josephw): A standalone container's runtime directory is currently
|
||||
// garbage collected as soon as the container exits. To allow the user to
|
||||
// retrieve the exit status reliably, the runtime directory cannot be
|
||||
// garbage collected immediately. Instead, the user will eventually be
|
||||
// required to make this call after the standalone container has exited.
|
||||
// Also, a standalone container's sandbox directory is currently not
|
||||
// garbage collected and is only deleted via this call.
|
||||
//
|
||||
// Returns 200 OK if the removal is successful or if the parent container
|
||||
// (for nested containers) does not exist.
|
||||
// Returns 500 Internal Server Error if anything goes wrong, including
|
||||
// if the container is still running or does not exist.
|
||||
//
|
||||
// TODO(josephw): Consider returning a 400 Bad Request instead of 500
|
||||
// Internal Server Error when the user tries to remove a running or
|
||||
// nonexistent nested container.
|
||||
message RemoveContainer {
|
||||
required ContainerID container_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "ContainerID"];
|
||||
}
|
||||
|
||||
// Adds a new resource provider config file.
|
||||
//
|
||||
// The content of the `info` field will be written into a new config file in
|
||||
// the resource provider config directory, and a new resource provider will be
|
||||
// launched asynchronously based on the config. Callers must not set the
|
||||
// `info.id` field. This call is idempotent, so if a config file identical to
|
||||
// the content of the `info` field already exists, this call will return
|
||||
// without launching a resource provider. Note that if a config file is
|
||||
// placed into the resource provider config directory out-of-band after the
|
||||
// agent starts up, it will not be checked against this call.
|
||||
//
|
||||
// Returns 200 OK if a new config file is created, or an identical config file
|
||||
// exists.
|
||||
// Returns 400 Bad Request if `info` is not well-formed.
|
||||
// Returns 403 Forbidden if the call is not authorized.
|
||||
// Returns 409 Conflict if another config file that describes a
|
||||
// resource provider of the same type and name exists, but the content is
|
||||
// not identical.
|
||||
// Returns 500 Internal Server Error if anything goes wrong.
|
||||
message AddResourceProviderConfig {
|
||||
required ResourceProviderInfo info = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Updates an existing resource provider config file.
|
||||
//
|
||||
// The content of the `info` field will be written into an existing config
|
||||
// file that describes a resource provider of the specified type and name in
|
||||
// the resource provider config directory, and the corresponding resource
|
||||
// provider will be relaunched asynchronously to reflect the changes in the
|
||||
// config. Callers must not set the `info.id` field. This call is idempotent,
|
||||
// so if there is no change in the config, this call will return without
|
||||
// relaunching the resource provider. Note that if a config file is placed
|
||||
// into the resource provider config directory out-of-band after the agent
|
||||
// starts up, it will not be checked against this call.
|
||||
//
|
||||
// Returns 200 OK if an existing config file is updated, or there is no change
|
||||
// in the config file.
|
||||
// Returns 400 Bad Request if `info` is not well-formed.
|
||||
// Returns 403 Forbidden if the call is not authorized.
|
||||
// Returns 404 Not Found if no config file describes a resource
|
||||
// provider of the same type and name exists.
|
||||
// Returns 500 Internal Server Error if anything goes wrong.
|
||||
message UpdateResourceProviderConfig {
|
||||
required ResourceProviderInfo info = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Removes a config file from the resource provider config directory.
|
||||
//
|
||||
// The config file that describes the resource provider of the specified type
|
||||
// and name will be removed, and the corresponding resource provider will be
|
||||
// terminated asynchronously. This call is idempotent, so if no matching
|
||||
// config file exists, this call will return without terminating any resource
|
||||
// provider. Note that if a config file is placed into the resource provider
|
||||
// config directory out-of-band after the agent starts up, it will not be
|
||||
// checked against this call.
|
||||
//
|
||||
// Returns 200 OK if the config file is removed, or no matching config file
|
||||
// exists.
|
||||
// Returns 403 Forbidden if the call is not authorized.
|
||||
// Returns 500 Internal Server Error if anything goes wrong.
|
||||
message RemoveResourceProviderConfig {
|
||||
required string type = 1 [(gogoproto.nullable) = false];
|
||||
required string name = 2 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Prune unused container images from image store.
|
||||
//
|
||||
// Images and layers referenced by active containers as well as
|
||||
// image references specified in `excluded_images` will not be pruned.
|
||||
message PruneImages {
|
||||
repeated Image excluded_images = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
optional Type type = 1 [(gogoproto.nullable) = false];
|
||||
|
||||
optional GetMetrics get_metrics = 2;
|
||||
optional SetLoggingLevel set_logging_level = 3;
|
||||
optional ListFiles list_files = 4;
|
||||
optional ReadFile read_file = 5;
|
||||
|
||||
optional GetContainers get_containers = 20;
|
||||
|
||||
optional LaunchNestedContainer launch_nested_container = 6
|
||||
[deprecated = true];
|
||||
|
||||
optional WaitNestedContainer wait_nested_container = 7 [deprecated = true];
|
||||
optional KillNestedContainer kill_nested_container = 8 [deprecated = true];
|
||||
optional RemoveNestedContainer remove_nested_container = 12
|
||||
[deprecated = true];
|
||||
|
||||
optional LaunchNestedContainerSession launch_nested_container_session = 9;
|
||||
optional AttachContainerInput attach_container_input = 10;
|
||||
optional AttachContainerOutput attach_container_output = 11;
|
||||
optional LaunchContainer launch_container = 13;
|
||||
optional WaitContainer wait_container = 14;
|
||||
optional KillContainer kill_container = 15;
|
||||
optional RemoveContainer remove_container = 16;
|
||||
|
||||
optional AddResourceProviderConfig add_resource_provider_config = 17;
|
||||
optional UpdateResourceProviderConfig update_resource_provider_config = 18;
|
||||
optional RemoveResourceProviderConfig remove_resource_provider_config = 19;
|
||||
|
||||
optional PruneImages prune_images = 21;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Synchronous responses for all calls made to the v1 agent API.
|
||||
*/
|
||||
message Response {
|
||||
// Each of the responses of type `FOO` corresponds to `Foo` message below.
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
|
||||
GET_HEALTH = 1; // See 'GetHealth' below.
|
||||
GET_FLAGS = 2; // See 'GetFlags' below.
|
||||
GET_VERSION = 3; // See 'GetVersion' below.
|
||||
GET_METRICS = 4; // See 'GetMetrics' below.
|
||||
|
||||
GET_LOGGING_LEVEL = 5; // See 'GetLoggingLevel' below.
|
||||
|
||||
LIST_FILES = 6;
|
||||
READ_FILE = 7; // See 'ReadFile' below.
|
||||
|
||||
GET_STATE = 8;
|
||||
|
||||
GET_CONTAINERS = 9;
|
||||
GET_FRAMEWORKS = 10; // See 'GetFrameworks' below.
|
||||
GET_EXECUTORS = 11; // See 'GetExecutors' below.
|
||||
GET_OPERATIONS = 17; // See 'GetOperations' below.
|
||||
GET_TASKS = 12; // See 'GetTasks' below.
|
||||
GET_AGENT = 14; // See 'GetAgent' below.
|
||||
GET_RESOURCE_PROVIDERS = 16; // See 'GetResourceProviders' below.
|
||||
|
||||
WAIT_NESTED_CONTAINER = 13 [deprecated = true];
|
||||
WAIT_CONTAINER = 15; // See 'WaitContainer' below.
|
||||
|
||||
option (gogoproto.goproto_enum_prefix) = true;
|
||||
}
|
||||
|
||||
// `healthy` would be true if the agent is healthy. Delayed responses are also
|
||||
// indicative of the poor health of the agent.
|
||||
message GetHealth {
|
||||
required bool healthy = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Contains the flag configuration of the agent.
|
||||
message GetFlags {
|
||||
repeated Flag flags = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Contains the version information of the agent.
|
||||
message GetVersion {
|
||||
required VersionInfo version_info = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Contains a snapshot of the current metrics.
|
||||
message GetMetrics {
|
||||
repeated Metric metrics = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Contains the logging level of the agent.
|
||||
message GetLoggingLevel {
|
||||
required uint32 level = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Contains the file listing(similar to `ls -l`) for a directory.
|
||||
message ListFiles {
|
||||
repeated FileInfo file_infos = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Contains the file data.
|
||||
message ReadFile {
|
||||
// The size of file (in bytes).
|
||||
required uint64 size = 1 [(gogoproto.nullable) = false];
|
||||
|
||||
required bytes data = 2;
|
||||
}
|
||||
|
||||
// Contains full state of the agent i.e. information about the tasks,
|
||||
// frameworks and executors running in the cluster.
|
||||
message GetState {
|
||||
optional GetTasks get_tasks = 1;
|
||||
optional GetExecutors get_executors = 2;
|
||||
optional GetFrameworks get_frameworks = 3;
|
||||
}
|
||||
|
||||
// Information about containers running on this agent. It contains
|
||||
// ContainerStatus and ResourceStatistics along with some metadata
|
||||
// of the containers.
|
||||
message GetContainers {
|
||||
message Container {
|
||||
optional FrameworkID framework_id = 1 [(gogoproto.customname) = "FrameworkID"];
|
||||
optional ExecutorID executor_id = 2 [(gogoproto.customname) = "ExecutorID"];
|
||||
optional string executor_name = 3;
|
||||
required ContainerID container_id = 4 [(gogoproto.customname) = "ContainerID", (gogoproto.nullable) = false];
|
||||
optional ContainerStatus container_status = 5;
|
||||
optional ResourceStatistics resource_statistics = 6;
|
||||
}
|
||||
|
||||
repeated Container containers = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Information about all the frameworks known to the agent at the current
|
||||
// time.
|
||||
message GetFrameworks {
|
||||
message Framework {
|
||||
required FrameworkInfo framework_info = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
repeated Framework frameworks = 1 [(gogoproto.nullable) = false];
|
||||
repeated Framework completed_frameworks = 2 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Lists information about all the executors known to the agent at the
|
||||
// current time.
|
||||
message GetExecutors {
|
||||
message Executor {
|
||||
required ExecutorInfo executor_info = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
repeated Executor executors = 1 [(gogoproto.nullable) = false];
|
||||
repeated Executor completed_executors = 2 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Lists information about all operations known to the agent at the
|
||||
// current time.
|
||||
message GetOperations {
|
||||
repeated Operation operations = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Lists information about all the tasks known to the agent at the current
|
||||
// time.
|
||||
message GetTasks {
|
||||
// Tasks that are pending in the agent's queue before an executor is
|
||||
// launched.
|
||||
repeated Task pending_tasks = 1 [(gogoproto.nullable) = false];
|
||||
|
||||
// Tasks that are enqueued for a launched executor that has not yet
|
||||
// registered.
|
||||
repeated Task queued_tasks = 2 [(gogoproto.nullable) = false];
|
||||
|
||||
// Tasks that are running.
|
||||
repeated Task launched_tasks = 3 [(gogoproto.nullable) = false];
|
||||
|
||||
// Tasks that are terminated but pending updates.
|
||||
repeated Task terminated_tasks = 4 [(gogoproto.nullable) = false];
|
||||
|
||||
// Tasks that are terminated and updates acked.
|
||||
repeated Task completed_tasks = 5 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Contains the agent's information.
|
||||
message GetAgent {
|
||||
optional AgentInfo agent_info = 1;
|
||||
}
|
||||
|
||||
// Lists information about all resource providers known to the agent
|
||||
// at the current time.
|
||||
message GetResourceProviders {
|
||||
message ResourceProvider {
|
||||
required ResourceProviderInfo resource_provider_info = 1 [(gogoproto.nullable) = false];
|
||||
repeated Resource total_resources = 2 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
repeated ResourceProvider resource_providers = 1 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// Returns termination information about the nested container.
|
||||
message WaitNestedContainer {
|
||||
// Wait status of the lead process in the container. Note that this
|
||||
// is the return value of `wait(2)`, so callers must use the `wait(2)`
|
||||
// family of macros to extract whether the process exited cleanly and
|
||||
// what the exit code was.
|
||||
optional int32 exit_status = 1;
|
||||
|
||||
// The `state` and `reason` fields may be populated if the Mesos agent
|
||||
// terminates the container. In the absence of any special knowledge,
|
||||
// executors should propagate this information via the `status` field
|
||||
// of an `Update` call for the corresponding TaskID.
|
||||
optional TaskState state = 2;
|
||||
optional TaskStatus.Reason reason = 3;
|
||||
|
||||
// This field will be populated if the task was terminated due to
|
||||
// a resource limitation.
|
||||
optional TaskResourceLimitation limitation = 4;
|
||||
|
||||
optional string message = 5;
|
||||
}
|
||||
|
||||
// Returns termination information about the standalone or nested container.
|
||||
message WaitContainer {
|
||||
// Wait status of the lead process in the container. Note that this
|
||||
// is the return value of `wait(2)`, so callers must use the `wait(2)`
|
||||
// family of macros to extract whether the process exited cleanly and
|
||||
// what the exit code was.
|
||||
optional int32 exit_status = 1;
|
||||
|
||||
// The `state` and `reason` fields may be populated if the Mesos agent
|
||||
// terminates the container. In the absence of any special knowledge,
|
||||
// executors should propagate this information via the `status` field
|
||||
// of an `Update` call for the corresponding TaskID.
|
||||
optional TaskState state = 2;
|
||||
optional TaskStatus.Reason reason = 3;
|
||||
|
||||
// This field will be populated if the task was terminated due to
|
||||
// a resource limitation.
|
||||
optional TaskResourceLimitation limitation = 4;
|
||||
|
||||
optional string message = 5;
|
||||
}
|
||||
|
||||
optional Type type = 1 [(gogoproto.nullable) = false];
|
||||
|
||||
optional GetHealth get_health = 2;
|
||||
optional GetFlags get_flags = 3;
|
||||
optional GetVersion get_version = 4;
|
||||
optional GetMetrics get_metrics = 5;
|
||||
optional GetLoggingLevel get_logging_level = 6;
|
||||
optional ListFiles list_files = 7;
|
||||
optional ReadFile read_file = 8;
|
||||
optional GetState get_state = 9;
|
||||
optional GetContainers get_containers = 10;
|
||||
optional GetFrameworks get_frameworks = 11;
|
||||
optional GetExecutors get_executors = 12;
|
||||
optional GetOperations get_operations = 18;
|
||||
optional GetTasks get_tasks = 13;
|
||||
optional GetAgent get_agent = 15;
|
||||
optional GetResourceProviders get_resource_providers = 17;
|
||||
optional WaitNestedContainer wait_nested_container = 14;
|
||||
optional WaitContainer wait_container = 16;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Streaming response to `Call::LAUNCH_NESTED_CONTAINER_SESSION` and
|
||||
* `Call::ATTACH_CONTAINER_OUTPUT`.
|
||||
*
|
||||
* This message is also used to stream request data for
|
||||
* `Call::ATTACH_CONTAINER_INPUT`.
|
||||
*/
|
||||
message ProcessIO {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
DATA = 1;
|
||||
CONTROL = 2;
|
||||
|
||||
option (gogoproto.goproto_enum_prefix) = true;
|
||||
}
|
||||
|
||||
message Data {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
STDIN = 1;
|
||||
STDOUT = 2;
|
||||
STDERR = 3;
|
||||
|
||||
option (gogoproto.goproto_enum_prefix) = true;
|
||||
}
|
||||
|
||||
optional Type type = 1 [(gogoproto.nullable) = false];
|
||||
optional bytes data = 2;
|
||||
}
|
||||
|
||||
|
||||
message Control {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
TTY_INFO = 1;
|
||||
HEARTBEAT = 2;
|
||||
|
||||
option (gogoproto.goproto_enum_prefix) = true;
|
||||
}
|
||||
|
||||
message Heartbeat {
|
||||
optional DurationInfo interval = 1;
|
||||
}
|
||||
|
||||
optional Type type = 1 [(gogoproto.nullable) = false];
|
||||
optional TTYInfo tty_info = 2 [(gogoproto.customname) = "TTYInfo"];
|
||||
optional Heartbeat heartbeat = 3;
|
||||
}
|
||||
|
||||
optional Type type = 1 [(gogoproto.nullable) = false];
|
||||
optional Data data = 2;
|
||||
optional Control control = 3;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"calls.go",
|
||||
"calls_generated.go",
|
||||
"gen.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/agent/calls",
|
||||
importpath = "github.com/mesos/mesos-go/api/v1/lib/agent/calls",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/agent:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,258 @@
|
|||
package calls
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/mesos/mesos-go/api/v1/lib"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/agent"
|
||||
)
|
||||
|
||||
func GetHealth() *agent.Call { return &agent.Call{Type: agent.Call_GET_HEALTH} }
|
||||
|
||||
func GetFlags() *agent.Call { return &agent.Call{Type: agent.Call_GET_FLAGS} }
|
||||
|
||||
func GetVersion() *agent.Call { return &agent.Call{Type: agent.Call_GET_VERSION} }
|
||||
|
||||
func GetMetrics(d *time.Duration) (call *agent.Call) {
|
||||
call = &agent.Call{
|
||||
Type: agent.Call_GET_METRICS,
|
||||
GetMetrics: &agent.Call_GetMetrics{},
|
||||
}
|
||||
if d != nil {
|
||||
call.GetMetrics.Timeout = &mesos.DurationInfo{
|
||||
Nanoseconds: d.Nanoseconds(),
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetLoggingLevel() *agent.Call { return &agent.Call{Type: agent.Call_GET_LOGGING_LEVEL} }
|
||||
|
||||
func SetLoggingLevel(level uint32, d time.Duration) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_SET_LOGGING_LEVEL,
|
||||
SetLoggingLevel: &agent.Call_SetLoggingLevel{
|
||||
Duration: mesos.DurationInfo{Nanoseconds: d.Nanoseconds()},
|
||||
Level: level,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ListFiles(path string) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_LIST_FILES,
|
||||
ListFiles: &agent.Call_ListFiles{
|
||||
Path: path,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ReadFile(path string, offset uint64) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_READ_FILE,
|
||||
ReadFile: &agent.Call_ReadFile{
|
||||
Path: path,
|
||||
Offset: offset,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ReadFileWithLength(path string, offset, length uint64) (call *agent.Call) {
|
||||
call = ReadFile(path, offset)
|
||||
call.ReadFile.Length = &length
|
||||
return
|
||||
}
|
||||
|
||||
func GetState() *agent.Call { return &agent.Call{Type: agent.Call_GET_STATE} }
|
||||
|
||||
func GetContainers() *agent.Call { return &agent.Call{Type: agent.Call_GET_CONTAINERS} }
|
||||
|
||||
func GetFrameworks() *agent.Call { return &agent.Call{Type: agent.Call_GET_FRAMEWORKS} }
|
||||
|
||||
func GetExecutors() *agent.Call { return &agent.Call{Type: agent.Call_GET_EXECUTORS} }
|
||||
|
||||
func GetOperations() *agent.Call { return &agent.Call{Type: agent.Call_GET_OPERATIONS} }
|
||||
|
||||
func GetTasks() *agent.Call { return &agent.Call{Type: agent.Call_GET_TASKS} }
|
||||
|
||||
func GetAgent() *agent.Call { return &agent.Call{Type: agent.Call_GET_AGENT} }
|
||||
|
||||
func GetResourceProviders() *agent.Call { return &agent.Call{Type: agent.Call_GET_RESOURCE_PROVIDERS} }
|
||||
|
||||
func LaunchNestedContainer(cid mesos.ContainerID, cmd *mesos.CommandInfo, ci *mesos.ContainerInfo) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_LAUNCH_NESTED_CONTAINER,
|
||||
LaunchNestedContainer: &agent.Call_LaunchNestedContainer{
|
||||
ContainerID: cid,
|
||||
Command: cmd,
|
||||
Container: ci,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func LaunchContainer(cid mesos.ContainerID, cmd *mesos.CommandInfo, ci *mesos.ContainerInfo, r []mesos.Resource) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_LAUNCH_CONTAINER,
|
||||
LaunchContainer: &agent.Call_LaunchContainer{
|
||||
ContainerID: cid,
|
||||
Command: cmd,
|
||||
Container: ci,
|
||||
Resources: r,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func WaitNestedContainer(cid mesos.ContainerID) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_WAIT_NESTED_CONTAINER,
|
||||
WaitNestedContainer: &agent.Call_WaitNestedContainer{
|
||||
ContainerID: cid,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func WaitContainer(cid mesos.ContainerID) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_WAIT_CONTAINER,
|
||||
WaitContainer: &agent.Call_WaitContainer{
|
||||
ContainerID: cid,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func KillNestedContainer(cid mesos.ContainerID) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_KILL_NESTED_CONTAINER,
|
||||
KillNestedContainer: &agent.Call_KillNestedContainer{
|
||||
ContainerID: cid,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func KillContainer(cid mesos.ContainerID) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_KILL_CONTAINER,
|
||||
KillContainer: &agent.Call_KillContainer{
|
||||
ContainerID: cid,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveNestedContainer(cid mesos.ContainerID) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_REMOVE_NESTED_CONTAINER,
|
||||
RemoveNestedContainer: &agent.Call_RemoveNestedContainer{
|
||||
ContainerID: cid,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveContainer(cid mesos.ContainerID) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_REMOVE_CONTAINER,
|
||||
RemoveContainer: &agent.Call_RemoveContainer{
|
||||
ContainerID: cid,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func LaunchNestedContainerSession(cid mesos.ContainerID, cmd *mesos.CommandInfo, ci *mesos.ContainerInfo) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_LAUNCH_NESTED_CONTAINER_SESSION,
|
||||
LaunchNestedContainerSession: &agent.Call_LaunchNestedContainerSession{
|
||||
ContainerID: cid,
|
||||
Command: cmd,
|
||||
Container: ci,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func AttachContainerOutput(cid mesos.ContainerID) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_ATTACH_CONTAINER_OUTPUT,
|
||||
AttachContainerOutput: &agent.Call_AttachContainerOutput{
|
||||
ContainerID: cid,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// AttachContainerInput returns a Call that is used to initiate attachment to a container's stdin.
|
||||
// Callers should first send this Call followed by one or more AttachContainerInputXxx calls.
|
||||
func AttachContainerInput(cid mesos.ContainerID) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_ATTACH_CONTAINER_INPUT,
|
||||
AttachContainerInput: &agent.Call_AttachContainerInput{
|
||||
Type: agent.Call_AttachContainerInput_CONTAINER_ID,
|
||||
ContainerID: &cid,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func AttachContainerInputData(data []byte) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_ATTACH_CONTAINER_INPUT,
|
||||
AttachContainerInput: &agent.Call_AttachContainerInput{
|
||||
Type: agent.Call_AttachContainerInput_PROCESS_IO,
|
||||
ProcessIO: &agent.ProcessIO{
|
||||
Type: agent.ProcessIO_DATA,
|
||||
Data: &agent.ProcessIO_Data{
|
||||
Type: agent.ProcessIO_Data_STDIN,
|
||||
Data: data,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func AttachContainerInputTTY(t *mesos.TTYInfo) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_ATTACH_CONTAINER_INPUT,
|
||||
AttachContainerInput: &agent.Call_AttachContainerInput{
|
||||
Type: agent.Call_AttachContainerInput_PROCESS_IO,
|
||||
ProcessIO: &agent.ProcessIO{
|
||||
Type: agent.ProcessIO_CONTROL,
|
||||
Control: &agent.ProcessIO_Control{
|
||||
Type: agent.ProcessIO_Control_TTY_INFO,
|
||||
TTYInfo: t,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func AddResourceProviderConfig(rpi mesos.ResourceProviderInfo) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_ADD_RESOURCE_PROVIDER_CONFIG,
|
||||
AddResourceProviderConfig: &agent.Call_AddResourceProviderConfig{
|
||||
Info: rpi,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateResourceProviderConfig(rpi mesos.ResourceProviderInfo) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_UPDATE_RESOURCE_PROVIDER_CONFIG,
|
||||
UpdateResourceProviderConfig: &agent.Call_UpdateResourceProviderConfig{
|
||||
Info: rpi,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveResourceProviderConfig(typ, name string) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_REMOVE_RESOURCE_PROVIDER_CONFIG,
|
||||
RemoveResourceProviderConfig: &agent.Call_RemoveResourceProviderConfig{
|
||||
Type: typ,
|
||||
Name: name,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func PruneImages(excluded []mesos.Image) *agent.Call {
|
||||
return &agent.Call{
|
||||
Type: agent.Call_PRUNE_IMAGES,
|
||||
PruneImages: &agent.Call_PruneImages{
|
||||
ExcludedImages: excluded,
|
||||
},
|
||||
}
|
||||
}
|
129
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/calls/calls_generated.go
generated
vendored
Normal file
129
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/calls/calls_generated.go
generated
vendored
Normal file
|
@ -0,0 +1,129 @@
|
|||
package calls
|
||||
|
||||
// go generate -import github.com/mesos/mesos-go/api/v1/lib/agent -type C:agent.Call
|
||||
// GENERATED CODE FOLLOWS; DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/mesos/mesos-go/api/v1/lib"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding"
|
||||
|
||||
"github.com/mesos/mesos-go/api/v1/lib/agent"
|
||||
)
|
||||
|
||||
type (
|
||||
// Request generates a Call that's sent to a Mesos agent. Subsequent invocations are expected to
|
||||
// yield equivalent calls. Intended for use w/ non-streaming requests to an agent.
|
||||
Request interface {
|
||||
Call() *agent.Call
|
||||
}
|
||||
|
||||
// RequestFunc is the functional adaptation of Request.
|
||||
RequestFunc func() *agent.Call
|
||||
|
||||
// RequestStreaming generates a Call that's send to a Mesos agent. Subsequent invocations MAY generate
|
||||
// different Call objects. No more Call objects are expected once a nil is returned to signal the end of
|
||||
// of the request stream.
|
||||
RequestStreaming interface {
|
||||
Request
|
||||
IsStreaming()
|
||||
}
|
||||
|
||||
// RequestStreamingFunc is the functional adaptation of RequestStreaming.
|
||||
RequestStreamingFunc func() *agent.Call
|
||||
|
||||
// Send issues a Request to a Mesos agent and properly manages Call-specific mechanics.
|
||||
Sender interface {
|
||||
Send(context.Context, Request) (mesos.Response, error)
|
||||
}
|
||||
|
||||
// SenderFunc is the functional adaptation of the Sender interface
|
||||
SenderFunc func(context.Context, Request) (mesos.Response, error)
|
||||
)
|
||||
|
||||
func (f RequestFunc) Call() *agent.Call { return f() }
|
||||
|
||||
func (f RequestFunc) Marshaler() encoding.Marshaler {
|
||||
// avoid returning (*agent.Call)(nil) for interface type
|
||||
if call := f(); call != nil {
|
||||
return call
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f RequestStreamingFunc) Push(c ...*agent.Call) RequestStreamingFunc { return Push(f, c...) }
|
||||
|
||||
func (f RequestStreamingFunc) Marshaler() encoding.Marshaler {
|
||||
// avoid returning (*agent.Call)(nil) for interface type
|
||||
if call := f(); call != nil {
|
||||
return call
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f RequestStreamingFunc) IsStreaming() {}
|
||||
|
||||
func (f RequestStreamingFunc) Call() *agent.Call { return f() }
|
||||
|
||||
// Push prepends one or more calls onto a request stream. If no calls are given then the original stream is returned.
|
||||
func Push(r RequestStreaming, c ...*agent.Call) RequestStreamingFunc {
|
||||
return func() *agent.Call {
|
||||
if len(c) == 0 {
|
||||
return r.Call()
|
||||
}
|
||||
head := c[0]
|
||||
c = c[1:]
|
||||
return head
|
||||
}
|
||||
}
|
||||
|
||||
// Empty generates a stream that always returns nil.
|
||||
func Empty() RequestStreamingFunc { return func() *agent.Call { return nil } }
|
||||
|
||||
var (
|
||||
_ = Request(RequestFunc(nil))
|
||||
_ = RequestStreaming(RequestStreamingFunc(nil))
|
||||
_ = Sender(SenderFunc(nil))
|
||||
)
|
||||
|
||||
// NonStreaming returns a RequestFunc that always generates the same Call.
|
||||
func NonStreaming(c *agent.Call) RequestFunc { return func() *agent.Call { return c } }
|
||||
|
||||
// FromChan returns a streaming request that fetches calls from the given channel until it closes.
|
||||
// If a nil chan is specified then the returned func will always generate nil.
|
||||
func FromChan(ch <-chan *agent.Call) RequestStreamingFunc {
|
||||
if ch == nil {
|
||||
// avoid blocking forever if we're handed a nil chan
|
||||
return func() *agent.Call { return nil }
|
||||
}
|
||||
return func() *agent.Call {
|
||||
if m, ok := <-ch; ok {
|
||||
return m
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Send implements the Sender interface for SenderFunc
|
||||
func (f SenderFunc) Send(ctx context.Context, r Request) (mesos.Response, error) {
|
||||
return f(ctx, r)
|
||||
}
|
||||
|
||||
// IgnoreResponse generates a sender that closes any non-nil response received by Mesos.
|
||||
func IgnoreResponse(s Sender) SenderFunc {
|
||||
return func(ctx context.Context, r Request) (mesos.Response, error) {
|
||||
resp, err := s.Send(ctx, r)
|
||||
if resp != nil {
|
||||
resp.Close()
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// SendNoData is a convenience func that executes the given Call using the provided Sender
|
||||
// and always drops the response data.
|
||||
func SendNoData(ctx context.Context, sender Sender, r Request) (err error) {
|
||||
_, err = IgnoreResponse(sender).Send(ctx, r)
|
||||
return
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package calls
|
||||
|
||||
//go:generate go run ../../extras/gen/sender.go ../../extras/gen/gen.go -import github.com/mesos/mesos-go/api/v1/lib/agent -type C:agent.Call
|
|
@ -0,0 +1,71 @@
|
|||
package mesos
|
||||
|
||||
// DEPRECATED in favor of github.com/mesos/mesos-go/api/v1/lib/client
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding"
|
||||
)
|
||||
|
||||
// A Client represents a Mesos API client which can send Calls and return
|
||||
// a streaming Decoder from which callers can read Events from, an io.Closer to
|
||||
// close the event stream on graceful termination and an error in case of failure.
|
||||
type Client interface {
|
||||
Do(encoding.Marshaler) (Response, error)
|
||||
}
|
||||
|
||||
// ClientFunc is a functional adapter of the Client interface
|
||||
type ClientFunc func(encoding.Marshaler) (Response, error)
|
||||
|
||||
// Do implements Client
|
||||
func (cf ClientFunc) Do(m encoding.Marshaler) (Response, error) { return cf(m) }
|
||||
|
||||
// Response captures the output of a Mesos API operation. Callers are responsible for invoking
|
||||
// Close when they're finished processing the response otherwise there may be connection leaks.
|
||||
type Response interface {
|
||||
io.Closer
|
||||
encoding.Decoder
|
||||
}
|
||||
|
||||
// ResponseDecorator optionally modifies the behavior of a Response
|
||||
type ResponseDecorator interface {
|
||||
Decorate(Response) Response
|
||||
}
|
||||
|
||||
// ResponseDecoratorFunc is the functional adapter for ResponseDecorator
|
||||
type ResponseDecoratorFunc func(Response) Response
|
||||
|
||||
func (f ResponseDecoratorFunc) Decorate(r Response) Response { return f(r) }
|
||||
|
||||
// CloseFunc is the functional adapter for io.Closer
|
||||
type CloseFunc func() error
|
||||
|
||||
// Close implements io.Closer
|
||||
func (f CloseFunc) Close() error { return f() }
|
||||
|
||||
// ResponseWrapper delegates to optional overrides for invocations of Response methods.
|
||||
type ResponseWrapper struct {
|
||||
Response Response
|
||||
Closer io.Closer
|
||||
Decoder encoding.Decoder
|
||||
}
|
||||
|
||||
func (wrapper *ResponseWrapper) Close() error {
|
||||
if wrapper.Closer != nil {
|
||||
return wrapper.Closer.Close()
|
||||
}
|
||||
if wrapper.Response != nil {
|
||||
return wrapper.Response.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (wrapper *ResponseWrapper) Decode(u encoding.Unmarshaler) error {
|
||||
if wrapper.Decoder != nil {
|
||||
return wrapper.Decoder.Decode(u)
|
||||
}
|
||||
return wrapper.Response.Decode(u)
|
||||
}
|
||||
|
||||
var _ = Response(&ResponseWrapper{})
|
|
@ -0,0 +1,24 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["client.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/client",
|
||||
importpath = "github.com/mesos/mesos-go/api/v1/lib/client",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,54 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding"
|
||||
)
|
||||
|
||||
type (
|
||||
// ResponseClass indicates the kind of response that a caller is expecting from Mesos.
|
||||
ResponseClass int
|
||||
|
||||
// Request is a non-streaming request from the client to the server.
|
||||
// Marshaler always returns the same object; the object is sent once to the server and then
|
||||
// a response is expected.
|
||||
Request interface {
|
||||
Marshaler() encoding.Marshaler
|
||||
}
|
||||
|
||||
// RequestStreaming is a streaming request from the client to the server.
|
||||
// Marshaler returns a new object for upon each invocation, nil when there are no more objects to send.
|
||||
// Client implementations are expected to differentiate between Request and RequestStreaming either by
|
||||
// type-switching or by attempting interface conversion.
|
||||
RequestStreaming interface {
|
||||
Request
|
||||
IsStreaming()
|
||||
}
|
||||
|
||||
RequestFunc func() encoding.Marshaler
|
||||
RequestStreamingFunc func() encoding.Marshaler
|
||||
)
|
||||
|
||||
var (
|
||||
_ = Request(RequestFunc(nil))
|
||||
_ = RequestStreaming(RequestStreamingFunc(nil))
|
||||
)
|
||||
|
||||
func (f RequestFunc) Marshaler() encoding.Marshaler { return f() }
|
||||
func (f RequestStreamingFunc) Marshaler() encoding.Marshaler { return f() }
|
||||
func (f RequestStreamingFunc) IsStreaming() {}
|
||||
|
||||
// RequestSingleton generates a non-streaming Request that always returns the same marshaler
|
||||
func RequestSingleton(m encoding.Marshaler) Request {
|
||||
return RequestFunc(func() encoding.Marshaler { return m })
|
||||
}
|
||||
|
||||
const (
|
||||
ResponseClassSingleton ResponseClass = iota
|
||||
ResponseClassStreaming
|
||||
ResponseClassNoData
|
||||
|
||||
// ResponseClassAuto should be used with versions of Mesos prior to 1.2.x.
|
||||
// Otherwise, this type is deprecated and callers should use ResponseClassSingleton
|
||||
// or ResponseClassStreaming instead.
|
||||
ResponseClassAuto
|
||||
)
|
|
@ -0,0 +1,23 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["logger.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/debug",
|
||||
importpath = "github.com/mesos/mesos-go/api/v1/lib/debug",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,17 @@
|
|||
package debug
|
||||
|
||||
import "log"
|
||||
|
||||
type Logger bool
|
||||
|
||||
func (d Logger) Log(v ...interface{}) {
|
||||
if d {
|
||||
log.Print(v...)
|
||||
}
|
||||
}
|
||||
|
||||
func (d Logger) Logf(s string, v ...interface{}) {
|
||||
if d {
|
||||
log.Printf(s, v...)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
// Package mesos presents common v1 HTTP API message types in addition to extension APIs that
|
||||
// aim to simplify use of the machine-generated code.
|
||||
package mesos
|
|
@ -0,0 +1,33 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["types.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/encoding",
|
||||
importpath = "github.com/mesos/mesos-go/api/v1/lib/encoding",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/codecs:all-srcs",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing:all-srcs",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/json:all-srcs",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/proto:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,28 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["codecs.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/codecs",
|
||||
importpath = "github.com/mesos/mesos-go/api/v1/lib/encoding/codecs",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/json:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/proto:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
33
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/codecs/codecs.go
generated
vendored
Normal file
33
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/codecs/codecs.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package codecs
|
||||
|
||||
import (
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding/json"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding/proto"
|
||||
)
|
||||
|
||||
const (
|
||||
// MediaTypeProtobuf is the Protobuf serialization format media type.
|
||||
MediaTypeProtobuf = encoding.MediaType("application/x-protobuf")
|
||||
// MediaTypeJSON is the JSON serialiation format media type.
|
||||
MediaTypeJSON = encoding.MediaType("application/json")
|
||||
|
||||
NameProtobuf = "protobuf"
|
||||
NameJSON = "json"
|
||||
)
|
||||
|
||||
// ByMediaType are pre-configured default Codecs, ready to use OOTB
|
||||
var ByMediaType = map[encoding.MediaType]encoding.Codec{
|
||||
MediaTypeProtobuf: encoding.Codec{
|
||||
Name: NameProtobuf,
|
||||
Type: MediaTypeProtobuf,
|
||||
NewEncoder: proto.NewEncoder,
|
||||
NewDecoder: proto.NewDecoder,
|
||||
},
|
||||
MediaTypeJSON: encoding.Codec{
|
||||
Name: NameJSON,
|
||||
Type: MediaTypeJSON,
|
||||
NewEncoder: json.NewEncoder,
|
||||
NewDecoder: json.NewDecoder,
|
||||
},
|
||||
}
|
26
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing/BUILD
generated
vendored
Normal file
26
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing/BUILD
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"decoder.go",
|
||||
"framing.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing",
|
||||
importpath = "github.com/mesos/mesos-go/api/v1/lib/encoding/framing",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
34
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing/decoder.go
generated
vendored
Normal file
34
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing/decoder.go
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
package framing
|
||||
|
||||
type (
|
||||
// UnmarshalFunc translates bytes to objects
|
||||
UnmarshalFunc func([]byte, interface{}) error
|
||||
|
||||
// Decoder reads and decodes Protobuf messages from an io.Reader.
|
||||
Decoder interface {
|
||||
// Decode reads the next encoded message from its input and stores it
|
||||
// in the value pointed to by m. If m isn't a proto.Message, Decode will panic.
|
||||
Decode(interface{}) error
|
||||
}
|
||||
|
||||
// DecoderFunc is the functional adaptation of Decoder
|
||||
DecoderFunc func(interface{}) error
|
||||
)
|
||||
|
||||
func (f DecoderFunc) Decode(m interface{}) error { return f(m) }
|
||||
|
||||
var _ = Decoder(DecoderFunc(nil))
|
||||
|
||||
// NewDecoder returns a new Decoder that reads from the given frame Reader.
|
||||
func NewDecoder(r Reader, uf UnmarshalFunc) DecoderFunc {
|
||||
return func(m interface{}) error {
|
||||
// Note: the buf returned by ReadFrame will change over time, it can't be sub-sliced
|
||||
// and then those sub-slices retained. Examination of generated proto code seems to indicate
|
||||
// that byte buffers are copied vs. referenced by sub-slice (gogo protoc).
|
||||
frame, err := r.ReadFrame()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return uf(frame, m)
|
||||
}
|
||||
}
|
70
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing/framing.go
generated
vendored
Normal file
70
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing/framing.go
generated
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
package framing
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type Error string
|
||||
|
||||
func (err Error) Error() string { return string(err) }
|
||||
|
||||
const (
|
||||
ErrorUnderrun = Error("frame underrun, unexpected EOF")
|
||||
ErrorBadSize = Error("bad frame size")
|
||||
ErrorOversizedFrame = Error("oversized frame, max size exceeded")
|
||||
)
|
||||
|
||||
type (
|
||||
// Reader generates data frames from some source, returning io.EOF when the end of the input stream is
|
||||
// detected.
|
||||
Reader interface {
|
||||
ReadFrame() (frame []byte, err error)
|
||||
}
|
||||
|
||||
// ReaderFunc is the functional adaptation of Reader.
|
||||
ReaderFunc func() ([]byte, error)
|
||||
|
||||
// Writer sends whole frames to some endpoint; returns io.ErrShortWrite if the frame is only partially written.
|
||||
Writer interface {
|
||||
WriteFrame(frame []byte) error
|
||||
}
|
||||
|
||||
// WriterFunc is the functional adaptation of Writer.
|
||||
WriterFunc func([]byte) error
|
||||
)
|
||||
|
||||
func (f ReaderFunc) ReadFrame() ([]byte, error) { return f() }
|
||||
func (f WriterFunc) WriteFrame(b []byte) error { return f(b) }
|
||||
|
||||
var _ = Reader(ReaderFunc(nil))
|
||||
var _ = Writer(WriterFunc(nil))
|
||||
|
||||
// EOFReaderFunc always returns nil, io.EOF; it implements the ReaderFunc API.
|
||||
func EOFReaderFunc() ([]byte, error) { return nil, io.EOF }
|
||||
|
||||
var _ = ReaderFunc(EOFReaderFunc) // sanity check
|
||||
|
||||
// ReadAll returns a reader func that returns the complete contents of `r` in a single frame.
|
||||
// A zero length frame is treated as an "end of stream" condition, returning io.EOF.
|
||||
func ReadAll(r io.Reader) ReaderFunc {
|
||||
return func() (b []byte, err error) {
|
||||
b, err = ioutil.ReadAll(r)
|
||||
if len(b) == 0 && err == nil {
|
||||
err = io.EOF
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// WriterFor adapts an io.Writer to the Writer interface. All buffers are written to `w` without decoration or
|
||||
// modification.
|
||||
func WriterFor(w io.Writer) WriterFunc {
|
||||
return func(b []byte) error {
|
||||
n, err := w.Write(b)
|
||||
if err == nil && n != len(b) {
|
||||
return io.ErrShortWrite
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["json.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/json",
|
||||
importpath = "github.com/mesos/mesos-go/api/v1/lib/encoding/json",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,28 @@
|
|||
package json
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding/framing"
|
||||
)
|
||||
|
||||
// NewEncoder returns a new Encoder of Calls to JSON messages written to
|
||||
// the given io.Writer.
|
||||
func NewEncoder(s encoding.Sink) encoding.Encoder {
|
||||
w := s()
|
||||
return encoding.EncoderFunc(func(m encoding.Marshaler) error {
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return w.WriteFrame(b)
|
||||
})
|
||||
}
|
||||
|
||||
// NewDecoder returns a new Decoder of JSON messages read from the given source.
|
||||
func NewDecoder(s encoding.Source) encoding.Decoder {
|
||||
r := s()
|
||||
dec := framing.NewDecoder(r, json.Unmarshal)
|
||||
return encoding.DecoderFunc(func(u encoding.Unmarshaler) error { return dec.Decode(u) })
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"encoding.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/proto",
|
||||
importpath = "github.com/mesos/mesos-go/api/v1/lib/encoding/proto",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,4 @@
|
|||
// Package proto implements protobuf utilities such as functional options to
|
||||
// construct complex structs and encoders and decoders composable with
|
||||
// io.ReadWriters.
|
||||
package proto
|
30
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/proto/encoding.go
generated
vendored
Normal file
30
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/proto/encoding.go
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
package proto
|
||||
|
||||
import (
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding/framing"
|
||||
)
|
||||
|
||||
// NewEncoder returns a new Encoder of Calls to Protobuf messages written to
|
||||
// the given io.Writer.
|
||||
func NewEncoder(s encoding.Sink) encoding.Encoder {
|
||||
w := s()
|
||||
return encoding.EncoderFunc(func(m encoding.Marshaler) error {
|
||||
b, err := proto.Marshal(m.(proto.Message))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return w.WriteFrame(b)
|
||||
})
|
||||
}
|
||||
|
||||
// NewDecoder returns a new Decoder of Protobuf messages read from the given Source.
|
||||
func NewDecoder(s encoding.Source) encoding.Decoder {
|
||||
r := s()
|
||||
var (
|
||||
uf = func(b []byte, m interface{}) error { return proto.Unmarshal(b, m.(proto.Message)) }
|
||||
dec = framing.NewDecoder(r, uf)
|
||||
)
|
||||
return encoding.DecoderFunc(func(u encoding.Unmarshaler) error { return dec.Decode(u) })
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
package encoding
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
pb "github.com/gogo/protobuf/proto"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding/framing"
|
||||
)
|
||||
|
||||
type MediaType string
|
||||
|
||||
// ContentType returns the HTTP Content-Type associated with the MediaType
|
||||
func (m MediaType) ContentType() string { return string(m) }
|
||||
|
||||
type (
|
||||
Source func() framing.Reader
|
||||
Sink func() framing.Writer
|
||||
|
||||
// A Codec composes encoding and decoding of a serialization format.
|
||||
Codec struct {
|
||||
Name string
|
||||
Type MediaType
|
||||
NewEncoder func(Sink) Encoder
|
||||
NewDecoder func(Source) Decoder
|
||||
}
|
||||
|
||||
SourceFactory interface {
|
||||
NewSource(r io.Reader) Source
|
||||
}
|
||||
SourceFactoryFunc func(r io.Reader) Source
|
||||
|
||||
SinkFactory interface {
|
||||
NewSink(w io.Writer) Sink
|
||||
}
|
||||
SinkFactoryFunc func(w io.Writer) Sink
|
||||
)
|
||||
|
||||
func (f SourceFactoryFunc) NewSource(r io.Reader) Source { return f(r) }
|
||||
|
||||
func (f SinkFactoryFunc) NewSink(w io.Writer) Sink { return f(w) }
|
||||
|
||||
var (
|
||||
_ = SourceFactory(SourceFactoryFunc(nil))
|
||||
_ = SinkFactory(SinkFactoryFunc(nil))
|
||||
)
|
||||
|
||||
// SourceReader returns a Source that buffers all input from the given io.Reader
|
||||
// and returns the contents in a single frame.
|
||||
func SourceReader(r io.Reader) Source {
|
||||
ch := make(chan framing.ReaderFunc, 1)
|
||||
ch <- framing.ReadAll(r)
|
||||
return func() framing.Reader {
|
||||
select {
|
||||
case f := <-ch:
|
||||
return f
|
||||
default:
|
||||
return framing.ReaderFunc(framing.EOFReaderFunc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SinkWriter returns a Sink that sends a frame to an io.Writer with no decoration.
|
||||
func SinkWriter(w io.Writer) Sink { return func() framing.Writer { return framing.WriterFor(w) } }
|
||||
|
||||
// String implements the fmt.Stringer interface.
|
||||
func (c *Codec) String() string {
|
||||
if c == nil {
|
||||
return ""
|
||||
}
|
||||
return c.Name
|
||||
}
|
||||
|
||||
type (
|
||||
// Marshaler composes the supported marshaling formats.
|
||||
Marshaler interface {
|
||||
pb.Marshaler
|
||||
json.Marshaler
|
||||
}
|
||||
// Unmarshaler composes the supporter unmarshaling formats.
|
||||
Unmarshaler interface {
|
||||
pb.Unmarshaler
|
||||
json.Unmarshaler
|
||||
}
|
||||
// An Encoder encodes a given Marshaler or returns an error in case of failure.
|
||||
Encoder interface {
|
||||
Encode(Marshaler) error
|
||||
}
|
||||
|
||||
// EncoderFunc is the functional adapter for Encoder
|
||||
EncoderFunc func(Marshaler) error
|
||||
|
||||
// A Decoder decodes a given Unmarshaler or returns an error in case of failure.
|
||||
Decoder interface {
|
||||
Decode(Unmarshaler) error
|
||||
}
|
||||
|
||||
// DecoderFunc is the functional adapter for Decoder
|
||||
DecoderFunc func(Unmarshaler) error
|
||||
)
|
||||
|
||||
// Decode implements the Decoder interface
|
||||
func (f DecoderFunc) Decode(u Unmarshaler) error { return f(u) }
|
||||
|
||||
// Encode implements the Encoder interface
|
||||
func (f EncoderFunc) Encode(m Marshaler) error { return f(m) }
|
||||
|
||||
var (
|
||||
_ = Encoder(EncoderFunc(nil))
|
||||
_ = Decoder(DecoderFunc(nil))
|
||||
)
|
|
@ -0,0 +1,26 @@
|
|||
package mesos
|
||||
|
||||
import "time"
|
||||
|
||||
type FilterOpt func(*Filters)
|
||||
|
||||
func (f *Filters) With(opts ...FilterOpt) *Filters {
|
||||
for _, o := range opts {
|
||||
o(f)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func RefuseSeconds(d time.Duration) FilterOpt {
|
||||
return func(f *Filters) {
|
||||
s := d.Seconds()
|
||||
f.RefuseSeconds = &s
|
||||
}
|
||||
}
|
||||
|
||||
func OptionalFilters(fo ...FilterOpt) *Filters {
|
||||
if len(fo) == 0 {
|
||||
return nil
|
||||
}
|
||||
return (&Filters{}).With(fo...)
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package mesos
|
||||
|
||||
// fixed point scalar math from mesos:src/common/values.cpp
|
||||
// --
|
||||
// We manipulate scalar values by converting them from floating point to a
|
||||
// fixed point representation, doing a calculation, and then converting
|
||||
// the result back to floating point. We deliberately only preserve three
|
||||
// decimal digits of precision in the fixed point representation. This
|
||||
// ensures that client applications see predictable numerical behavior, at
|
||||
// the expense of sacrificing some precision.
|
||||
|
||||
import "math"
|
||||
|
||||
func convertToFloat64(f int64) float64 {
|
||||
// NOTE: We do the conversion from fixed point via integer division
|
||||
// and then modulus, rather than a single floating point division.
|
||||
// This ensures that we only apply floating point division to inputs
|
||||
// in the range [0,999], which is easier to check for correctness.
|
||||
var (
|
||||
quotient = float64(f / 1000)
|
||||
remainder = float64(f%1000) / 1000.0
|
||||
)
|
||||
return quotient + remainder
|
||||
}
|
||||
|
||||
func convertToFixed64(f float64) int64 {
|
||||
return round64(f * 1000)
|
||||
}
|
||||
|
||||
func round64(f float64) int64 {
|
||||
if math.Abs(f) < 0.5 {
|
||||
return 0
|
||||
}
|
||||
return int64(f + math.Copysign(0.5, f))
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"auth_basic.go",
|
||||
"http.go",
|
||||
"opts.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli",
|
||||
importpath = "github.com/mesos/mesos-go/api/v1/lib/httpcli",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/client:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/debug:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/codecs:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/recordio:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
23
vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors/BUILD
generated
vendored
Normal file
23
vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors/BUILD
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["apierrors.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors",
|
||||
importpath = "github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
161
vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors/apierrors.go
generated
vendored
Normal file
161
vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors/apierrors.go
generated
vendored
Normal file
|
@ -0,0 +1,161 @@
|
|||
package apierrors
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Code is a Mesos HTTP v1 API response status code
|
||||
type Code int
|
||||
|
||||
const (
|
||||
// MsgNotLeader is returned by Do calls that are sent to a non leading Mesos master.
|
||||
MsgNotLeader = "call sent to a non-leading master"
|
||||
// MsgAuth is returned by Do calls that are not successfully authenticated.
|
||||
MsgAuth = "call not authenticated"
|
||||
// MsgUnsubscribed is returned by Do calls that are sent before a subscription is established.
|
||||
MsgUnsubscribed = "no subscription established"
|
||||
// MsgVersion is returned by Do calls that are sent to an incompatible API version.
|
||||
MsgVersion = "incompatible API version"
|
||||
// MsgMalformed is returned by Do calls that are malformed.
|
||||
MsgMalformed = "malformed request"
|
||||
// MsgMediaType is returned by Do calls that are sent with an unsupported media type.
|
||||
MsgMediaType = "unsupported media type"
|
||||
// MsgRateLimit is returned by Do calls that are rate limited. This is a temporary condition
|
||||
// that should clear.
|
||||
MsgRateLimit = "rate limited"
|
||||
// MsgUnavailable is returned by Do calls that are sent to a master or agent that's in recovery, or
|
||||
// does not yet realize that it's the leader. This is a temporary condition that should clear.
|
||||
MsgUnavailable = "mesos server unavailable"
|
||||
// MsgNotFound could happen if the master or agent libprocess has not yet set up http routes.
|
||||
MsgNotFound = "mesos http endpoint not found"
|
||||
|
||||
CodeNotLeader = Code(http.StatusTemporaryRedirect)
|
||||
CodeNotAuthenticated = Code(http.StatusUnauthorized)
|
||||
CodeUnsubscribed = Code(http.StatusForbidden)
|
||||
CodeIncompatibleVersion = Code(http.StatusConflict)
|
||||
CodeMalformedRequest = Code(http.StatusBadRequest)
|
||||
CodeUnsupportedMediaType = Code(http.StatusNotAcceptable)
|
||||
CodeRateLimitExceeded = Code(http.StatusTooManyRequests)
|
||||
CodeMesosUnavailable = Code(http.StatusServiceUnavailable)
|
||||
CodeNotFound = Code(http.StatusNotFound)
|
||||
|
||||
MaxSizeDetails = 4 * 1024 // MaxSizeDetails limits the length of the details message read from a response body
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrorTable maps HTTP response codes to their respective Mesos v1 API error messages.
|
||||
ErrorTable = map[Code]string{
|
||||
CodeNotLeader: MsgNotLeader,
|
||||
CodeMalformedRequest: MsgMalformed,
|
||||
CodeIncompatibleVersion: MsgVersion,
|
||||
CodeUnsubscribed: MsgUnsubscribed,
|
||||
CodeNotAuthenticated: MsgAuth,
|
||||
CodeUnsupportedMediaType: MsgMediaType,
|
||||
CodeNotFound: MsgNotFound,
|
||||
CodeMesosUnavailable: MsgUnavailable,
|
||||
CodeRateLimitExceeded: MsgRateLimit,
|
||||
}
|
||||
)
|
||||
|
||||
// Error captures HTTP v1 API error codes and messages generated by Mesos.
|
||||
type Error struct {
|
||||
code Code // code is the HTTP response status code generated by Mesos
|
||||
message string // message briefly summarizes the nature of the error, possibly includes details from Mesos
|
||||
}
|
||||
|
||||
// IsError returns true for all HTTP status codes that are not considered informational or successful.
|
||||
func (code Code) IsError() bool {
|
||||
return code >= 300
|
||||
}
|
||||
|
||||
// FromResponse returns an `*Error` for a response containing a status code that indicates an error condition.
|
||||
// The response body (if any) is captured in the Error.Details field.
|
||||
// Returns nil for nil responses and responses with non-error status codes.
|
||||
// See IsErrorCode.
|
||||
func FromResponse(res *http.Response) error {
|
||||
if res == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
code := Code(res.StatusCode)
|
||||
if !code.IsError() {
|
||||
// non-error HTTP response codes don't generate errors
|
||||
return nil
|
||||
}
|
||||
|
||||
var details string
|
||||
|
||||
if res.Body != nil {
|
||||
defer res.Body.Close()
|
||||
buf, _ := ioutil.ReadAll(io.LimitReader(res.Body, MaxSizeDetails))
|
||||
details = string(buf)
|
||||
}
|
||||
|
||||
return code.Error(details)
|
||||
}
|
||||
|
||||
// Error generates an error from the given status code and detail string.
|
||||
func (code Code) Error(details string) error {
|
||||
if !code.IsError() {
|
||||
return nil
|
||||
}
|
||||
err := &Error{
|
||||
code: code,
|
||||
message: ErrorTable[code],
|
||||
}
|
||||
if details != "" {
|
||||
err.message = err.message + ": " + details
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Error implements error interface
|
||||
func (e *Error) Error() string { return e.message }
|
||||
|
||||
// Temporary returns true if the error is a temporary condition that should eventually clear.
|
||||
func (e *Error) Temporary() bool {
|
||||
switch e.code {
|
||||
// TODO(jdef): NotFound **could** be a temporary error because there's a race at mesos startup in which the
|
||||
// HTTP server responds before the internal listeners have been initialized. But it could also be reported
|
||||
// because the client is accessing an invalid endpoint; as of right now, a client cannot distinguish between
|
||||
// these cases.
|
||||
// https://issues.apache.org/jira/browse/MESOS-7697
|
||||
case CodeRateLimitExceeded, CodeMesosUnavailable:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// CodesIndicatingSubscriptionLoss is a set of apierror.Code entries which each indicate that
|
||||
// the event subscription stream has been severed between the scheduler and mesos. It's respresented
|
||||
// as a public map variable so that clients can program additional error codes (if such are discovered)
|
||||
// without hacking the code of the mesos-go library directly.
|
||||
var CodesIndicatingSubscriptionLoss = func(codes ...Code) map[Code]struct{} {
|
||||
result := make(map[Code]struct{}, len(codes))
|
||||
for _, code := range codes {
|
||||
result[code] = struct{}{}
|
||||
}
|
||||
return result
|
||||
}(
|
||||
// expand this list as we discover other errors that guarantee we've lost our event subscription.
|
||||
CodeUnsubscribed,
|
||||
)
|
||||
|
||||
// SubscriptionLoss returns true if the error indicates that the event subscription stream has been severed
|
||||
// between mesos and a mesos client.
|
||||
func (e *Error) SubscriptionLoss() (result bool) {
|
||||
_, result = CodesIndicatingSubscriptionLoss[e.code]
|
||||
return
|
||||
}
|
||||
|
||||
// Matches returns true if the given error is an API error with a matching error code
|
||||
func (code Code) Matches(err error) bool {
|
||||
if err == nil {
|
||||
return !code.IsError()
|
||||
}
|
||||
apiErr, ok := err.(*Error)
|
||||
return ok && apiErr.code == code
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package httpcli
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// roundTripperFunc is the functional adaptation of http.RoundTripper
|
||||
type roundTripperFunc func(*http.Request) (*http.Response, error)
|
||||
|
||||
// RoundTrip implements RoundTripper for roundTripperFunc
|
||||
func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { return f(req) }
|
||||
|
||||
// BasicAuth generates a functional config option that sets HTTP Basic authentication for a Client
|
||||
func BasicAuth(username, passwd string) ConfigOpt {
|
||||
// TODO(jdef) this could be more efficient. according to the stdlib we're not supposed to
|
||||
// mutate the original Request, so we copy here (including headers). another approach would
|
||||
// be to generate a functional RequestOpt that adds the right header.
|
||||
return WrapRoundTripper(func(rt http.RoundTripper) http.RoundTripper {
|
||||
return roundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
||||
var h http.Header
|
||||
if req.Header != nil {
|
||||
h = make(http.Header, len(req.Header))
|
||||
for k, v := range req.Header {
|
||||
h[k] = append(make([]string, 0, len(v)), v...)
|
||||
}
|
||||
}
|
||||
clonedReq := *req
|
||||
clonedReq.Header = h
|
||||
clonedReq.SetBasicAuth(username, passwd)
|
||||
return rt.RoundTrip(&clonedReq)
|
||||
})
|
||||
})
|
||||
}
|
|
@ -0,0 +1,614 @@
|
|||
package httpcli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/mesos/mesos-go/api/v1/lib"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/client"
|
||||
logger "github.com/mesos/mesos-go/api/v1/lib/debug"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding/codecs"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding/framing"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/recordio"
|
||||
)
|
||||
|
||||
func noRedirect(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }
|
||||
|
||||
// ProtocolError is returned when we receive a response from Mesos that is outside of the HTTP API specification.
|
||||
// Receipt of the following will yield protocol errors:
|
||||
// - any unexpected non-error HTTP response codes (e.g. 199)
|
||||
// - any unexpected Content-Type
|
||||
type ProtocolError string
|
||||
|
||||
// Error implements error interface
|
||||
func (pe ProtocolError) Error() string { return string(pe) }
|
||||
|
||||
const (
|
||||
debug = logger.Logger(false)
|
||||
mediaTypeRecordIO = encoding.MediaType("application/recordio")
|
||||
)
|
||||
|
||||
// DoFunc sends an HTTP request and returns an HTTP response.
|
||||
//
|
||||
// An error is returned if caused by client policy (such as
|
||||
// http.Client.CheckRedirect), or if there was an HTTP protocol error. A
|
||||
// non-2xx response doesn't cause an error.
|
||||
//
|
||||
// When err is nil, resp always contains a non-nil resp.Body.
|
||||
//
|
||||
// Callers should close resp.Body when done reading from it. If resp.Body is
|
||||
// not closed, an underlying RoundTripper (typically Transport) may not be able
|
||||
// to re-use a persistent TCP connection to the server for a subsequent
|
||||
// "keep-alive" request.
|
||||
//
|
||||
// The request Body, if non-nil, will be closed by an underlying Transport,
|
||||
// even on errors.
|
||||
type DoFunc func(*http.Request) (*http.Response, error)
|
||||
|
||||
// Response captures the output of a Mesos HTTP API operation. Callers are responsible for invoking
|
||||
// Close when they're finished processing the response otherwise there may be connection leaks.
|
||||
type Response struct {
|
||||
io.Closer
|
||||
encoding.Decoder
|
||||
Header http.Header
|
||||
}
|
||||
|
||||
// ErrorMapperFunc generates an error for the given response.
|
||||
type ErrorMapperFunc func(*http.Response) error
|
||||
|
||||
// ResponseHandler is invoked to process an HTTP response. Callers SHALL invoke Close for
|
||||
// a non-nil Response, even when errors are returned.
|
||||
type ResponseHandler func(*http.Response, client.ResponseClass, error) (mesos.Response, error)
|
||||
|
||||
// A Client is a Mesos HTTP APIs client.
|
||||
type Client struct {
|
||||
url string
|
||||
do DoFunc
|
||||
header http.Header
|
||||
codec encoding.Codec
|
||||
errorMapper ErrorMapperFunc
|
||||
requestOpts []RequestOpt
|
||||
buildRequestFunc func(client.Request, client.ResponseClass, ...RequestOpt) (*http.Request, error)
|
||||
handleResponse ResponseHandler
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultCodec = codecs.ByMediaType[codecs.MediaTypeProtobuf]
|
||||
DefaultHeaders = http.Header{}
|
||||
|
||||
// DefaultConfigOpt represents the default client config options.
|
||||
DefaultConfigOpt = []ConfigOpt{
|
||||
Transport(func(t *http.Transport) {
|
||||
// all calls should be ack'd by the server within this interval.
|
||||
t.ResponseHeaderTimeout = 15 * time.Second
|
||||
t.MaxIdleConnsPerHost = 2 // don't depend on go's default
|
||||
}),
|
||||
}
|
||||
|
||||
DefaultErrorMapper = ErrorMapperFunc(apierrors.FromResponse)
|
||||
)
|
||||
|
||||
// New returns a new Client with the given Opts applied.
|
||||
// Callers are expected to configure the URL, Do, and Codec options prior to
|
||||
// invoking Do.
|
||||
func New(opts ...Opt) *Client {
|
||||
c := &Client{
|
||||
codec: DefaultCodec,
|
||||
do: With(DefaultConfigOpt...),
|
||||
header: cloneHeaders(DefaultHeaders),
|
||||
errorMapper: DefaultErrorMapper,
|
||||
}
|
||||
c.buildRequestFunc = c.buildRequest
|
||||
c.handleResponse = c.HandleResponse
|
||||
c.With(opts...)
|
||||
return c
|
||||
}
|
||||
|
||||
func cloneHeaders(hs http.Header) http.Header {
|
||||
result := make(http.Header)
|
||||
for k, v := range hs {
|
||||
cloned := make([]string, len(v))
|
||||
copy(cloned, v)
|
||||
result[k] = cloned
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Endpoint returns the current Mesos API endpoint URL that the caller is set to invoke
|
||||
func (c *Client) Endpoint() string {
|
||||
return c.url
|
||||
}
|
||||
|
||||
// RequestOpt defines a functional option for an http.Request.
|
||||
type RequestOpt func(*http.Request)
|
||||
|
||||
// RequestOpts is a convenience type
|
||||
type RequestOpts []RequestOpt
|
||||
|
||||
// Apply this set of request options to the given HTTP request.
|
||||
func (opts RequestOpts) Apply(req *http.Request) {
|
||||
// apply per-request options
|
||||
for _, o := range opts {
|
||||
if o != nil {
|
||||
o(req)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// With applies the given Opts to a Client and returns itself.
|
||||
func (c *Client) With(opts ...Opt) Opt {
|
||||
return Opts(opts).Merged().Apply(c)
|
||||
}
|
||||
|
||||
// WithTemporary configures the Client with the temporary option and returns the results of
|
||||
// invoking f(). Changes made to the Client by the temporary option are reverted before this
|
||||
// func returns.
|
||||
func (c *Client) WithTemporary(opt Opt, f func() error) error {
|
||||
if opt != nil {
|
||||
undo := c.With(opt)
|
||||
defer c.With(undo)
|
||||
}
|
||||
return f()
|
||||
}
|
||||
|
||||
// Mesos returns a mesos.Client variant backed by this implementation.
|
||||
// Deprecated.
|
||||
func (c *Client) Mesos(opts ...RequestOpt) mesos.Client {
|
||||
return mesos.ClientFunc(func(m encoding.Marshaler) (mesos.Response, error) {
|
||||
return c.Do(m, opts...)
|
||||
})
|
||||
}
|
||||
|
||||
func prepareForResponse(rc client.ResponseClass, codec encoding.Codec) (RequestOpts, error) {
|
||||
// We need to tell Mesos both the content-type and message-content-type that we're expecting, otherwise
|
||||
// the server may give us validation problems, or else send back a vague content-type (w/o a
|
||||
// message-content-type). In order to communicate these things we need to understand the desired response
|
||||
// type from the perspective of the caller --> client.ResponseClass.
|
||||
var accept RequestOpts
|
||||
switch rc {
|
||||
case client.ResponseClassSingleton, client.ResponseClassAuto, client.ResponseClassNoData:
|
||||
accept = append(accept, Header("Accept", codec.Type.ContentType()))
|
||||
case client.ResponseClassStreaming:
|
||||
accept = append(accept, Header("Accept", mediaTypeRecordIO.ContentType()))
|
||||
accept = append(accept, Header("Message-Accept", codec.Type.ContentType()))
|
||||
default:
|
||||
return nil, ProtocolError(fmt.Sprintf("illegal response class requested: %v", rc))
|
||||
}
|
||||
return accept, nil
|
||||
}
|
||||
|
||||
// buildRequest is a factory func that generates and returns an http.Request for the
|
||||
// given marshaler and request options.
|
||||
func (c *Client) buildRequest(cr client.Request, rc client.ResponseClass, opt ...RequestOpt) (*http.Request, error) {
|
||||
if crs, ok := cr.(client.RequestStreaming); ok {
|
||||
return c.buildRequestStream(crs.Marshaler, rc, opt...)
|
||||
}
|
||||
accept, err := prepareForResponse(rc, c.codec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//TODO(jdef): use a pool to allocate these (and reduce garbage)?
|
||||
// .. or else, use a pipe (like streaming does) to avoid the intermediate buffer?
|
||||
var body bytes.Buffer
|
||||
if err := c.codec.NewEncoder(encoding.SinkWriter(&body)).Encode(cr.Marshaler()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", c.url, &body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
helper := HTTPRequestHelper{req}
|
||||
return helper.
|
||||
withOptions(c.requestOpts, opt).
|
||||
withHeaders(c.header).
|
||||
withHeader("Content-Type", c.codec.Type.ContentType()).
|
||||
withHeader("Accept", c.codec.Type.ContentType()).
|
||||
withOptions(accept).
|
||||
Request, nil
|
||||
}
|
||||
|
||||
func (c *Client) buildRequestStream(f func() encoding.Marshaler, rc client.ResponseClass, opt ...RequestOpt) (*http.Request, error) {
|
||||
accept, err := prepareForResponse(rc, c.codec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
pr, pw = io.Pipe()
|
||||
enc = c.codec.NewEncoder(func() framing.Writer { return recordio.NewWriter(pw) })
|
||||
)
|
||||
req, err := http.NewRequest("POST", c.url, pr)
|
||||
if err != nil {
|
||||
pw.Close() // ignore error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go func() {
|
||||
var closeOnce sync.Once
|
||||
defer closeOnce.Do(func() {
|
||||
pw.Close()
|
||||
})
|
||||
for {
|
||||
m := f()
|
||||
if m == nil {
|
||||
// no more messages to send; end of the stream
|
||||
break
|
||||
}
|
||||
err := enc.Encode(m)
|
||||
if err != nil {
|
||||
closeOnce.Do(func() {
|
||||
pw.CloseWithError(err)
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
helper := HTTPRequestHelper{req}
|
||||
return helper.
|
||||
withOptions(c.requestOpts, opt).
|
||||
withHeaders(c.header).
|
||||
withHeader("Content-Type", mediaTypeRecordIO.ContentType()).
|
||||
withHeader("Message-Content-Type", c.codec.Type.ContentType()).
|
||||
withOptions(accept).
|
||||
Request, nil
|
||||
}
|
||||
|
||||
func validateSuccessfulResponse(codec encoding.Codec, res *http.Response, rc client.ResponseClass) error {
|
||||
switch res.StatusCode {
|
||||
case http.StatusOK:
|
||||
ct := res.Header.Get("Content-Type")
|
||||
switch rc {
|
||||
case client.ResponseClassNoData:
|
||||
if ct != "" {
|
||||
return ProtocolError(fmt.Sprintf("unexpected content type: %q", ct))
|
||||
}
|
||||
case client.ResponseClassSingleton, client.ResponseClassAuto:
|
||||
if ct != codec.Type.ContentType() {
|
||||
return ProtocolError(fmt.Sprintf("unexpected content type: %q", ct))
|
||||
}
|
||||
case client.ResponseClassStreaming:
|
||||
if ct != mediaTypeRecordIO.ContentType() {
|
||||
return ProtocolError(fmt.Sprintf("unexpected content type: %q", ct))
|
||||
}
|
||||
ct = res.Header.Get("Message-Content-Type")
|
||||
if ct != codec.Type.ContentType() {
|
||||
return ProtocolError(fmt.Sprintf("unexpected message content type: %q", ct))
|
||||
}
|
||||
default:
|
||||
return ProtocolError(fmt.Sprintf("unsupported response-class: %q", rc))
|
||||
}
|
||||
|
||||
case http.StatusAccepted:
|
||||
// nothing to validate, we're not expecting any response entity in this case.
|
||||
// TODO(jdef) perhaps check Content-Length == 0 here?
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newSourceFactory(rc client.ResponseClass) encoding.SourceFactoryFunc {
|
||||
switch rc {
|
||||
case client.ResponseClassNoData:
|
||||
return nil
|
||||
case client.ResponseClassSingleton:
|
||||
return encoding.SourceReader
|
||||
case client.ResponseClassStreaming, client.ResponseClassAuto:
|
||||
return recordIOSourceFactory
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported response-class: %q", rc))
|
||||
}
|
||||
}
|
||||
|
||||
func recordIOSourceFactory(r io.Reader) encoding.Source {
|
||||
return func() framing.Reader { return recordio.NewReader(r) }
|
||||
}
|
||||
|
||||
// HandleResponse parses an HTTP response from a Mesos service endpoint, transforming the
|
||||
// raw HTTP response into a mesos.Response.
|
||||
func (c *Client) HandleResponse(res *http.Response, rc client.ResponseClass, err error) (mesos.Response, error) {
|
||||
if err != nil {
|
||||
if res != nil && res.Body != nil {
|
||||
res.Body.Close()
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &Response{
|
||||
Closer: res.Body,
|
||||
Header: res.Header,
|
||||
}
|
||||
if err = c.errorMapper(res); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
err = validateSuccessfulResponse(c.codec, res, rc)
|
||||
if err != nil {
|
||||
res.Body.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch res.StatusCode {
|
||||
case http.StatusOK:
|
||||
debug.Log("request OK, decoding response")
|
||||
|
||||
sf := newSourceFactory(rc)
|
||||
if sf == nil {
|
||||
if rc != client.ResponseClassNoData {
|
||||
panic("nil Source for response that expected data")
|
||||
}
|
||||
// we don't expect any data. drain the response body and close it (compliant with golang's expectations
|
||||
// for http/1.1 keepalive support.
|
||||
defer res.Body.Close()
|
||||
_, err = io.Copy(ioutil.Discard, res.Body)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.Decoder = c.codec.NewDecoder(sf.NewSource(res.Body))
|
||||
|
||||
case http.StatusAccepted:
|
||||
debug.Log("request Accepted")
|
||||
|
||||
// noop; no decoder for these types of calls
|
||||
defer res.Body.Close()
|
||||
_, err = io.Copy(ioutil.Discard, res.Body)
|
||||
return nil, err
|
||||
|
||||
default:
|
||||
debug.Log("unexpected HTTP status", res.StatusCode)
|
||||
|
||||
defer res.Body.Close()
|
||||
io.Copy(ioutil.Discard, res.Body) // intentionally discard any error here
|
||||
return nil, ProtocolError(fmt.Sprintf("unexpected mesos HTTP response code: %d", res.StatusCode))
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Do is deprecated in favor of Send.
|
||||
func (c *Client) Do(m encoding.Marshaler, opt ...RequestOpt) (res mesos.Response, err error) {
|
||||
return c.Send(client.RequestSingleton(m), client.ResponseClassAuto, opt...)
|
||||
}
|
||||
|
||||
// Send sends a Call and returns (a) a Response (should be closed when finished) that
|
||||
// contains a either a streaming or non-streaming Decoder from which callers can read
|
||||
// objects from, and; (b) an error in case of failure. Callers are expected to *always*
|
||||
// close a non-nil Response if one is returned. For operations which are successful but
|
||||
// also for which there are no expected result objects the embedded Decoder will be nil.
|
||||
// The provided ResponseClass determines whether the client implementation will attempt
|
||||
// to decode a result as a single obeject or as an object stream. When working with
|
||||
// versions of Mesos prior to v1.2.x callers MUST use ResponseClassAuto.
|
||||
func (c *Client) Send(cr client.Request, rc client.ResponseClass, opt ...RequestOpt) (res mesos.Response, err error) {
|
||||
var (
|
||||
hreq *http.Request
|
||||
hres *http.Response
|
||||
)
|
||||
hreq, err = c.buildRequestFunc(cr, rc, opt...)
|
||||
if err == nil {
|
||||
hres, err = c.do(hreq)
|
||||
res, err = c.handleResponse(hres, rc, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ErrorMapper returns am Opt that overrides the existing error mapping behavior of the client.
|
||||
func ErrorMapper(em ErrorMapperFunc) Opt {
|
||||
return func(c *Client) Opt {
|
||||
old := c.errorMapper
|
||||
c.errorMapper = em
|
||||
return ErrorMapper(old)
|
||||
}
|
||||
}
|
||||
|
||||
// Endpoint returns an Opt that sets a Client's URL.
|
||||
func Endpoint(rawurl string) Opt {
|
||||
return func(c *Client) Opt {
|
||||
old := c.url
|
||||
c.url = rawurl
|
||||
return Endpoint(old)
|
||||
}
|
||||
}
|
||||
|
||||
// WrapDoer returns an Opt that decorates a Client's DoFunc
|
||||
func WrapDoer(f func(DoFunc) DoFunc) Opt {
|
||||
return func(c *Client) Opt {
|
||||
old := c.do
|
||||
c.do = f(c.do)
|
||||
return Do(old)
|
||||
}
|
||||
}
|
||||
|
||||
// Do returns an Opt that sets a Client's DoFunc
|
||||
func Do(do DoFunc) Opt {
|
||||
return func(c *Client) Opt {
|
||||
old := c.do
|
||||
c.do = do
|
||||
return Do(old)
|
||||
}
|
||||
}
|
||||
|
||||
// Codec returns an Opt that sets a Client's Codec.
|
||||
func Codec(codec encoding.Codec) Opt {
|
||||
return func(c *Client) Opt {
|
||||
old := c.codec
|
||||
c.codec = codec
|
||||
return Codec(old)
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultHeader returns an Opt that adds a header to an Client's headers.
|
||||
func DefaultHeader(k, v string) Opt {
|
||||
return func(c *Client) Opt {
|
||||
old, found := c.header[k]
|
||||
old = append([]string{}, old...) // clone
|
||||
c.header.Add(k, v)
|
||||
return func(c *Client) Opt {
|
||||
if found {
|
||||
c.header[k] = old
|
||||
} else {
|
||||
c.header.Del(k)
|
||||
}
|
||||
return DefaultHeader(k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HandleResponse returns a functional config option to set the HTTP response handler of the client.
|
||||
func HandleResponse(f ResponseHandler) Opt {
|
||||
return func(c *Client) Opt {
|
||||
old := c.handleResponse
|
||||
c.handleResponse = f
|
||||
return HandleResponse(old)
|
||||
}
|
||||
}
|
||||
|
||||
// RequestOptions returns an Opt that applies the given set of options to every Client request.
|
||||
func RequestOptions(opts ...RequestOpt) Opt {
|
||||
if len(opts) == 0 {
|
||||
return nil
|
||||
}
|
||||
return func(c *Client) Opt {
|
||||
old := append([]RequestOpt{}, c.requestOpts...)
|
||||
c.requestOpts = opts
|
||||
return RequestOptions(old...)
|
||||
}
|
||||
}
|
||||
|
||||
// Header returns an RequestOpt that adds a header value to an HTTP requests's header.
|
||||
func Header(k, v string) RequestOpt { return func(r *http.Request) { r.Header.Add(k, v) } }
|
||||
|
||||
// Close returns a RequestOpt that determines whether to close the underlying connection after sending the request.
|
||||
func Close(b bool) RequestOpt { return func(r *http.Request) { r.Close = b } }
|
||||
|
||||
// Context returns a RequestOpt that sets the request's Context (ctx must be non-nil)
|
||||
func Context(ctx context.Context) RequestOpt {
|
||||
return func(r *http.Request) {
|
||||
r2 := r.WithContext(ctx)
|
||||
*r = *r2
|
||||
}
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
client *http.Client
|
||||
dialer *net.Dialer
|
||||
transport *http.Transport
|
||||
}
|
||||
|
||||
type ConfigOpt func(*Config)
|
||||
|
||||
// With returns a DoFunc that executes HTTP round-trips.
|
||||
// The default implementation provides reasonable defaults for timeouts:
|
||||
// keep-alive, connection, request/response read/write, and TLS handshake.
|
||||
// Callers can customize configuration by specifying one or more ConfigOpt's.
|
||||
func With(opt ...ConfigOpt) DoFunc {
|
||||
var (
|
||||
dialer = &net.Dialer{
|
||||
LocalAddr: &net.TCPAddr{IP: net.IPv4zero},
|
||||
KeepAlive: 30 * time.Second,
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
transport = &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
Dial: dialer.Dial,
|
||||
ResponseHeaderTimeout: 5 * time.Second,
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: false},
|
||||
TLSHandshakeTimeout: 5 * time.Second,
|
||||
}
|
||||
config = &Config{
|
||||
dialer: dialer,
|
||||
transport: transport,
|
||||
client: &http.Client{
|
||||
Transport: transport,
|
||||
CheckRedirect: noRedirect, // so we can actually see the 307 redirects
|
||||
},
|
||||
}
|
||||
)
|
||||
for _, o := range opt {
|
||||
if o != nil {
|
||||
o(config)
|
||||
}
|
||||
}
|
||||
return config.client.Do
|
||||
}
|
||||
|
||||
// Timeout returns an ConfigOpt that sets a Config's response header timeout, tls handshake timeout,
|
||||
// and dialer timeout.
|
||||
func Timeout(d time.Duration) ConfigOpt {
|
||||
return func(c *Config) {
|
||||
c.transport.ResponseHeaderTimeout = d
|
||||
c.transport.TLSHandshakeTimeout = d
|
||||
c.dialer.Timeout = d
|
||||
}
|
||||
}
|
||||
|
||||
// RoundTripper returns a ConfigOpt that sets a Config's round-tripper.
|
||||
func RoundTripper(rt http.RoundTripper) ConfigOpt {
|
||||
return func(c *Config) {
|
||||
c.client.Transport = rt
|
||||
}
|
||||
}
|
||||
|
||||
// TLSConfig returns a ConfigOpt that sets a Config's TLS configuration.
|
||||
func TLSConfig(tc *tls.Config) ConfigOpt {
|
||||
return func(c *Config) {
|
||||
c.transport.TLSClientConfig = tc
|
||||
}
|
||||
}
|
||||
|
||||
// Transport returns a ConfigOpt that allows tweaks of the default Config's http.Transport
|
||||
func Transport(modifyTransport func(*http.Transport)) ConfigOpt {
|
||||
return func(c *Config) {
|
||||
if modifyTransport != nil {
|
||||
modifyTransport(c.transport)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WrapRoundTripper allows a caller to customize a configuration's HTTP exchanger. Useful
|
||||
// for authentication protocols that operate over stock HTTP.
|
||||
func WrapRoundTripper(f func(http.RoundTripper) http.RoundTripper) ConfigOpt {
|
||||
return func(c *Config) {
|
||||
if f != nil {
|
||||
if rt := f(c.client.Transport); rt != nil {
|
||||
c.client.Transport = rt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HTTPRequestHelper wraps an http.Request and provides utility funcs to simplify code elsewhere
|
||||
type HTTPRequestHelper struct {
|
||||
*http.Request
|
||||
}
|
||||
|
||||
func (r *HTTPRequestHelper) withOptions(optsets ...RequestOpts) *HTTPRequestHelper {
|
||||
for _, opts := range optsets {
|
||||
opts.Apply(r.Request)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *HTTPRequestHelper) withHeaders(hh http.Header) *HTTPRequestHelper {
|
||||
for k, v := range hh {
|
||||
r.Header[k] = v
|
||||
debug.Log("request header " + k + ": " + v[0])
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *HTTPRequestHelper) withHeader(key, value string) *HTTPRequestHelper {
|
||||
r.Header.Set(key, value)
|
||||
return r
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package httpcli
|
||||
|
||||
type (
|
||||
// Opt defines a functional option for the HTTP client type. A functional option
|
||||
// must return an Opt that acts as an "undo" if applied to the same Client.
|
||||
Opt func(*Client) Opt
|
||||
// Opts represents a series of functional options
|
||||
Opts []Opt
|
||||
)
|
||||
|
||||
// Apply is a nil-safe application of an Opt: if the receiver is nil then this func
|
||||
// simply returns nil, otherwise it returns the result invoking the receiving Opt
|
||||
// with the given Client.
|
||||
func (o Opt) Apply(c *Client) (result Opt) {
|
||||
if o != nil {
|
||||
result = o(c)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Merged generates a single Opt that applies all the functional options, in-order
|
||||
func (opts Opts) Merged() Opt {
|
||||
if len(opts) == 0 {
|
||||
return nil
|
||||
}
|
||||
return func(c *Client) Opt {
|
||||
var (
|
||||
size = len(opts)
|
||||
undo = make(Opts, size)
|
||||
)
|
||||
size-- // make this a zero-based offset
|
||||
for i, opt := range opts {
|
||||
if opt != nil {
|
||||
undo[size-i] = opt(c)
|
||||
}
|
||||
}
|
||||
return undo.Merged()
|
||||
}
|
||||
}
|
||||
|
||||
// And combines two functional options into a single Opt
|
||||
func (o Opt) And(other Opt) Opt {
|
||||
if o == nil {
|
||||
if other == nil {
|
||||
return nil
|
||||
}
|
||||
return other
|
||||
}
|
||||
if other == nil {
|
||||
return o
|
||||
}
|
||||
return Opts{o, other}.Merged()
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package mesos
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
type labelList []Label // convenience type, for working with unwrapped Label slices
|
||||
|
||||
// Equivalent returns true if left and right have the same labels. Order is not important.
|
||||
func (left *Labels) Equivalent(right *Labels) bool {
|
||||
return labelList(left.GetLabels()).Equivalent(labelList(right.GetLabels()))
|
||||
}
|
||||
|
||||
// Equivalent returns true if left and right have the same labels. Order is not important.
|
||||
func (left labelList) Equivalent(right labelList) bool {
|
||||
if len(left) != len(right) {
|
||||
return false
|
||||
} else {
|
||||
for i := range left {
|
||||
found := false
|
||||
for j := range right {
|
||||
if left[i].Equivalent(right[j]) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Equivalent returns true if left and right represent the same Label.
|
||||
func (left Label) Equivalent(right Label) bool {
|
||||
if left.Key != right.Key {
|
||||
return false
|
||||
}
|
||||
if left.Value == nil {
|
||||
return right.Value == nil
|
||||
} else {
|
||||
return right.Value != nil && *left.Value == *right.Value
|
||||
}
|
||||
}
|
||||
|
||||
func (left Label) writeTo(w io.Writer) (n int64, err error) {
|
||||
write := func(s string) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var n2 int
|
||||
n2, err = io.WriteString(w, s)
|
||||
n += int64(n2)
|
||||
}
|
||||
write(left.Key)
|
||||
if s := left.GetValue(); s != "" {
|
||||
write("=")
|
||||
write(s)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (left *Labels) writeTo(w io.Writer) (n int64, err error) {
|
||||
var (
|
||||
lab = left.GetLabels()
|
||||
n2 int
|
||||
n3 int64
|
||||
)
|
||||
for i := range lab {
|
||||
if i > 0 {
|
||||
n2, err = io.WriteString(w, ",")
|
||||
n += int64(n2)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
n3, err = lab[i].writeTo(w)
|
||||
n += n3
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (left *Labels) Format() string {
|
||||
if left == nil {
|
||||
return ""
|
||||
}
|
||||
var b bytes.Buffer
|
||||
left.writeTo(&b)
|
||||
return b.String()
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,253 @@
|
|||
package mesos
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Ranges represents a list of Ranges.
|
||||
type Ranges []Value_Range
|
||||
|
||||
// NewRanges returns squashed Ranges from the given numbers.
|
||||
func NewRanges(ns ...uint64) Ranges {
|
||||
xs := append(uint64s{}, ns...)
|
||||
sort.Sort(xs)
|
||||
rs := make(Ranges, len(xs))
|
||||
for i := range xs {
|
||||
rs[i].Begin, rs[i].End = xs[i], xs[i]
|
||||
}
|
||||
return rs.Squash()
|
||||
}
|
||||
|
||||
// NewPortRanges returns Ranges from the "ports" resource in the
|
||||
// given *Offer. If that resource isn't provided, nil will be returned.
|
||||
//
|
||||
// The returned Ranges are sorted and have all overlapping ranges merged from
|
||||
// left to right. e.g. [[0, 5], [4, 3], [10, 7]] -> [[0, 5], [7, 10]]
|
||||
func NewPortRanges(o *Offer) Ranges {
|
||||
if o == nil {
|
||||
return Ranges{}
|
||||
}
|
||||
|
||||
var (
|
||||
r Resource
|
||||
found bool
|
||||
)
|
||||
for i := range o.Resources {
|
||||
if o.Resources[i].GetName() == "ports" {
|
||||
r = o.Resources[i]
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return Ranges{}
|
||||
}
|
||||
|
||||
offered := r.GetRanges().GetRange()
|
||||
rs := make(Ranges, len(offered))
|
||||
for i, r := range offered {
|
||||
if lo, hi := r.GetBegin(), r.GetEnd(); lo <= hi {
|
||||
rs[i].Begin, rs[i].End = lo, hi
|
||||
} else {
|
||||
rs[i].Begin, rs[i].End = hi, lo
|
||||
}
|
||||
}
|
||||
return rs.Sort().Squash()
|
||||
}
|
||||
|
||||
// These three methods implement sort.Interface
|
||||
func (rs Ranges) Len() int { return len(rs) }
|
||||
func (rs Ranges) Swap(i, j int) { rs[i], rs[j] = rs[j], rs[i] }
|
||||
func (rs Ranges) Less(i, j int) bool {
|
||||
return rs[i].Begin < rs[j].Begin || (rs[i].Begin == rs[j].Begin && rs[i].End < rs[j].End)
|
||||
}
|
||||
|
||||
// Size returns the sum of the Size of all Ranges.
|
||||
func (rs Ranges) Size() uint64 {
|
||||
var sz uint64
|
||||
for i := range rs {
|
||||
sz += 1 + (rs[i].End - rs[i].Begin)
|
||||
}
|
||||
return sz
|
||||
}
|
||||
|
||||
// Sort sorts the receiving Ranges and returns the result; convenience
|
||||
func (rs Ranges) Sort() Ranges {
|
||||
sort.Sort(rs)
|
||||
return rs
|
||||
}
|
||||
|
||||
// Squash merges overlapping and continuous Ranges. It assumes they're pre-sorted.
|
||||
func (rs Ranges) Squash() Ranges {
|
||||
if len(rs) < 2 {
|
||||
return rs
|
||||
}
|
||||
squashed := Ranges{rs[0]}
|
||||
for i := 1; i < len(rs); i++ {
|
||||
switch max := squashed[len(squashed)-1].End; {
|
||||
case 1+max < rs[i].Begin: // no overlap nor continuity: push
|
||||
squashed = append(squashed, rs[i])
|
||||
case max <= rs[i].End: // overlap or continuity: squash
|
||||
squashed[len(squashed)-1].End = rs[i].End
|
||||
}
|
||||
}
|
||||
return squashed
|
||||
}
|
||||
|
||||
// Search performs a binary search for n returning the index of the Range it was
|
||||
// found at or -1 if not found.
|
||||
func (rs Ranges) Search(n uint64) int {
|
||||
for lo, hi := 0, len(rs)-1; lo <= hi; {
|
||||
switch m := lo + (hi-lo)/2; {
|
||||
case n < rs[m].Begin:
|
||||
hi = m - 1
|
||||
case n > rs[m].End:
|
||||
lo = m + 1
|
||||
default:
|
||||
return m
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Partition partitions Ranges around n. It returns the partitioned Ranges
|
||||
// and a boolean indicating if n was found.
|
||||
func (rs Ranges) Partition(n uint64) (Ranges, bool) {
|
||||
i := rs.Search(n)
|
||||
if i < 0 {
|
||||
return rs, false
|
||||
}
|
||||
|
||||
pn := make(Ranges, 0, len(rs)+1)
|
||||
switch pn = append(pn, rs[:i]...); {
|
||||
case rs[i].Begin == rs[i].End: // delete
|
||||
case rs[i].Begin == n: // increment lower bound
|
||||
pn = append(pn, Value_Range{rs[i].Begin + 1, rs[i].End})
|
||||
case rs[i].End == n: // decrement upper bound
|
||||
pn = append(pn, Value_Range{rs[i].Begin, rs[i].End - 1})
|
||||
default: // split
|
||||
pn = append(pn, Value_Range{rs[i].Begin, n - 1}, Value_Range{n + 1, rs[i].End})
|
||||
}
|
||||
return append(pn, rs[i+1:]...), true
|
||||
}
|
||||
|
||||
// Remove removes a range from already coalesced ranges.
|
||||
// The algorithms constructs a new vector of ranges which is then
|
||||
// Squash'ed into a Ranges instance.
|
||||
func (rs Ranges) Remove(removal Value_Range) Ranges {
|
||||
ranges := make([]Value_Range, 0, len(rs))
|
||||
for _, r := range rs {
|
||||
// skip if the entire range is subsumed by removal
|
||||
if r.Begin >= removal.Begin && r.End <= removal.End {
|
||||
continue
|
||||
}
|
||||
// divide if the range subsumes the removal
|
||||
if r.Begin < removal.Begin && r.End > removal.End {
|
||||
ranges = append(ranges,
|
||||
Value_Range{r.Begin, removal.Begin - 1},
|
||||
Value_Range{removal.End + 1, r.End},
|
||||
)
|
||||
continue
|
||||
}
|
||||
// add the full range if there's no intersection
|
||||
if r.End < removal.Begin || r.Begin > removal.End {
|
||||
ranges = append(ranges, r)
|
||||
continue
|
||||
}
|
||||
// trim if the range does intersect
|
||||
if r.End > removal.End {
|
||||
ranges = append(ranges, Value_Range{removal.End + 1, r.End})
|
||||
} else {
|
||||
if r.Begin >= removal.Begin {
|
||||
// should never happen
|
||||
panic("r.Begin >= removal.Begin")
|
||||
}
|
||||
ranges = append(ranges, Value_Range{r.Begin, removal.Begin - 1})
|
||||
}
|
||||
}
|
||||
return Ranges(ranges).Squash()
|
||||
}
|
||||
|
||||
// Compare assumes that both Ranges are already in sort-order.
|
||||
// Returns 0 if rs and right are equivalent, -1 if rs is a subset of right, or else 1
|
||||
func (rs Ranges) Compare(right Ranges) int {
|
||||
x, y, result := rs.equiv(right)
|
||||
if result {
|
||||
return 0
|
||||
}
|
||||
for _, a := range x {
|
||||
// make sure that this range is a subset of a range in y
|
||||
matched := false
|
||||
for _, b := range y {
|
||||
if a.Begin >= b.Begin && a.End <= b.End {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Equivalent assumes that both Ranges are already in sort-order.
|
||||
func (rs Ranges) Equivalent(right Ranges) (result bool) {
|
||||
_, _, result = rs.equiv(right)
|
||||
return
|
||||
}
|
||||
|
||||
// Equivalent assumes that both Ranges are already in sort-order.
|
||||
func (rs Ranges) equiv(right Ranges) (_, _ Ranges, _ bool) {
|
||||
// we need to squash rs and right but don't want to change the originals
|
||||
switch len(rs) {
|
||||
case 0:
|
||||
case 1:
|
||||
rs = Ranges{rs[0]}
|
||||
default:
|
||||
rs = Ranges(append([]Value_Range{rs[0], rs[1]}, rs[2:]...)).Sort().Squash()
|
||||
}
|
||||
switch len(right) {
|
||||
case 0:
|
||||
case 1:
|
||||
right = Ranges{right[0]}
|
||||
default:
|
||||
right = Ranges(append([]Value_Range{right[0], right[1]}, right[2:]...)).Sort().Squash()
|
||||
}
|
||||
return rs, right, (&Value_Ranges{Range: rs}).Equal(&Value_Ranges{Range: right})
|
||||
}
|
||||
|
||||
func (rs Ranges) Clone() Ranges {
|
||||
if len(rs) == 0 {
|
||||
return nil
|
||||
}
|
||||
x := make(Ranges, len(rs))
|
||||
copy(x, rs)
|
||||
return x
|
||||
}
|
||||
|
||||
// Min returns the minimum number in Ranges. It will panic on empty Ranges.
|
||||
func (rs Ranges) Min() uint64 { return rs[0].Begin }
|
||||
|
||||
// Max returns the maximum number in Ranges. It will panic on empty Ranges.
|
||||
func (rs Ranges) Max() uint64 { return rs[len(rs)-1].End }
|
||||
|
||||
// resource returns a *Resource with the given name and Ranges.
|
||||
func (rs Ranges) resource(name string) Resource {
|
||||
vr := make([]Value_Range, len(rs))
|
||||
copy(vr, rs)
|
||||
return Resource{
|
||||
Name: name,
|
||||
Type: RANGES.Enum(),
|
||||
Ranges: &Value_Ranges{Range: vr},
|
||||
}
|
||||
}
|
||||
|
||||
// uint64s is an utility used to sort a slice of uint64s
|
||||
type uint64s []uint64
|
||||
|
||||
// These three methods implement sort.Interface
|
||||
func (ns uint64s) Len() int { return len(ns) }
|
||||
func (ns uint64s) Less(i, j int) bool { return ns[i] < ns[j] }
|
||||
func (ns uint64s) Swap(i, j int) { ns[i], ns[j] = ns[j], ns[i] }
|
|
@ -0,0 +1,32 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"reader.go",
|
||||
"strconv.go",
|
||||
"writer.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/recordio",
|
||||
importpath = "github.com/mesos/mesos-go/api/v1/lib/recordio",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/debug:go_default_library",
|
||||
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,5 @@
|
|||
// Package recordio implements the Mesos variant of RecordIO framing, whereby
|
||||
// each record is prefixed by a line that indicates the length of the record in
|
||||
// decimal ASCII. The bytes of the record immediately follow the length-line.
|
||||
// Zero-length records are allowed.
|
||||
package recordio
|
|
@ -0,0 +1,145 @@
|
|||
package recordio
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
logger "github.com/mesos/mesos-go/api/v1/lib/debug"
|
||||
"github.com/mesos/mesos-go/api/v1/lib/encoding/framing"
|
||||
)
|
||||
|
||||
const debug = logger.Logger(false)
|
||||
|
||||
type (
|
||||
Opt func(*reader)
|
||||
|
||||
reader struct {
|
||||
*bufio.Scanner
|
||||
pend int
|
||||
splitf func(data []byte, atEOF bool) (int, []byte, error)
|
||||
maxf int // max frame size
|
||||
}
|
||||
)
|
||||
|
||||
// NewReader returns a reader that parses frames from a recordio stream.
|
||||
func NewReader(read io.Reader, opt ...Opt) framing.Reader {
|
||||
debug.Log("new frame reader")
|
||||
r := &reader{Scanner: bufio.NewScanner(read)}
|
||||
r.Split(func(data []byte, atEOF bool) (int, []byte, error) {
|
||||
// Scanner panics if we invoke Split after scanning has started,
|
||||
// use this proxy func as a work-around.
|
||||
return r.splitf(data, atEOF)
|
||||
})
|
||||
buf := make([]byte, 16*1024)
|
||||
r.Buffer(buf, 1<<22) // 1<<22 == max protobuf size
|
||||
r.splitf = r.splitSize
|
||||
// apply options
|
||||
for _, f := range opt {
|
||||
if f != nil {
|
||||
f(r)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// MaxMessageSize returns a functional option that configures the internal Scanner's buffer and max token (message)
|
||||
// length, in bytes.
|
||||
func MaxMessageSize(max int) Opt {
|
||||
return func(r *reader) {
|
||||
buf := make([]byte, max>>1)
|
||||
r.Buffer(buf, max)
|
||||
r.maxf = max
|
||||
}
|
||||
}
|
||||
|
||||
func (r *reader) splitSize(data []byte, atEOF bool) (int, []byte, error) {
|
||||
const maxTokenLength = 20 // textual length of largest uint64 number
|
||||
if atEOF {
|
||||
x := len(data)
|
||||
switch {
|
||||
case x == 0:
|
||||
debug.Log("EOF and empty frame, returning io.EOF")
|
||||
return 0, nil, io.EOF
|
||||
case x < 2: // min frame size
|
||||
debug.Log("remaining data less than min total frame length")
|
||||
return 0, nil, framing.ErrorUnderrun
|
||||
}
|
||||
// otherwise, we may have a valid frame...
|
||||
}
|
||||
debug.Log("len(data)=", len(data))
|
||||
adv := 0
|
||||
for {
|
||||
i := 0
|
||||
for ; i < maxTokenLength && i < len(data) && data[i] != '\n'; i++ {
|
||||
}
|
||||
debug.Log("i=", i)
|
||||
if i == len(data) {
|
||||
debug.Log("need more input")
|
||||
return 0, nil, nil // need more input
|
||||
}
|
||||
if i == maxTokenLength && data[i] != '\n' {
|
||||
debug.Log("frame size: max token length exceeded")
|
||||
return 0, nil, framing.ErrorBadSize
|
||||
}
|
||||
n, err := ParseUintBytes(bytes.TrimSpace(data[:i]), 10, 64)
|
||||
if err != nil {
|
||||
debug.Log("failed to parse frame size field:", err)
|
||||
return 0, nil, framing.ErrorBadSize
|
||||
}
|
||||
if r.maxf != 0 && int(n) > r.maxf {
|
||||
debug.Log("frame size max length exceeded:", n)
|
||||
return 0, nil, framing.ErrorOversizedFrame
|
||||
}
|
||||
if n == 0 {
|
||||
// special case... don't invoke splitData, just parse the next size header
|
||||
adv += i + 1
|
||||
data = data[i+1:]
|
||||
continue
|
||||
}
|
||||
r.pend = int(n)
|
||||
r.splitf = r.splitFrame
|
||||
debug.Logf("split next frame: %d, %d", n, adv+i+1)
|
||||
return adv + i + 1, data[:0], nil // returning a nil token screws up the Scanner, so return empty
|
||||
}
|
||||
}
|
||||
|
||||
func (r *reader) splitFrame(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||
x := len(data)
|
||||
debug.Log("splitFrame:x=", x, ",eof=", atEOF)
|
||||
if atEOF {
|
||||
if x < r.pend {
|
||||
return 0, nil, framing.ErrorUnderrun
|
||||
}
|
||||
}
|
||||
if r.pend == 0 {
|
||||
panic("asked to read frame data, but no data left in frame")
|
||||
}
|
||||
if x < int(r.pend) {
|
||||
// need more data
|
||||
return 0, nil, nil
|
||||
}
|
||||
r.splitf = r.splitSize
|
||||
adv := int(r.pend)
|
||||
r.pend = 0
|
||||
return adv, data[:adv], nil
|
||||
}
|
||||
|
||||
// ReadFrame implements framing.Reader
|
||||
func (r *reader) ReadFrame() (tok []byte, err error) {
|
||||
for r.Scan() {
|
||||
b := r.Bytes()
|
||||
if len(b) == 0 {
|
||||
continue
|
||||
}
|
||||
tok = b
|
||||
debug.Log("len(tok)", len(tok))
|
||||
break
|
||||
}
|
||||
// either scan failed, or it succeeded and we have a token...
|
||||
err = r.Err()
|
||||
if err == nil && len(tok) == 0 {
|
||||
err = io.EOF
|
||||
}
|
||||
return
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
Copyright 2013 The Camlistore 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 recordio
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// ParseUintBytes is like strconv.ParseUint, but using a []byte.
|
||||
func ParseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {
|
||||
var cutoff, maxVal uint64
|
||||
|
||||
if bitSize == 0 {
|
||||
bitSize = int(strconv.IntSize)
|
||||
}
|
||||
|
||||
s0 := s
|
||||
switch {
|
||||
case len(s) < 1:
|
||||
err = strconv.ErrSyntax
|
||||
goto Error
|
||||
|
||||
case 2 <= base && base <= 36:
|
||||
// valid base; nothing to do
|
||||
|
||||
case base == 0:
|
||||
// Look for octal, hex prefix.
|
||||
switch {
|
||||
case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
|
||||
base = 16
|
||||
s = s[2:]
|
||||
if len(s) < 1 {
|
||||
err = strconv.ErrSyntax
|
||||
goto Error
|
||||
}
|
||||
case s[0] == '0':
|
||||
base = 8
|
||||
default:
|
||||
base = 10
|
||||
}
|
||||
|
||||
default:
|
||||
err = errors.New("invalid base " + strconv.Itoa(base))
|
||||
goto Error
|
||||
}
|
||||
|
||||
n = 0
|
||||
cutoff = cutoff64(base)
|
||||
maxVal = 1<<uint(bitSize) - 1
|
||||
|
||||
for i := 0; i < len(s); i++ {
|
||||
var v byte
|
||||
d := s[i]
|
||||
switch {
|
||||
case '0' <= d && d <= '9':
|
||||
v = d - '0'
|
||||
case 'a' <= d && d <= 'z':
|
||||
v = d - 'a' + 10
|
||||
case 'A' <= d && d <= 'Z':
|
||||
v = d - 'A' + 10
|
||||
default:
|
||||
n = 0
|
||||
err = strconv.ErrSyntax
|
||||
goto Error
|
||||
}
|
||||
if int(v) >= base {
|
||||
n = 0
|
||||
err = strconv.ErrSyntax
|
||||
goto Error
|
||||
}
|
||||
|
||||
if n >= cutoff {
|
||||
// n*base overflows
|
||||
n = 1<<64 - 1
|
||||
err = strconv.ErrRange
|
||||
goto Error
|
||||
}
|
||||
n *= uint64(base)
|
||||
|
||||
n1 := n + uint64(v)
|
||||
if n1 < n || n1 > maxVal {
|
||||
// n+v overflows
|
||||
n = 1<<64 - 1
|
||||
err = strconv.ErrRange
|
||||
goto Error
|
||||
}
|
||||
n = n1
|
||||
}
|
||||
|
||||
return n, nil
|
||||
|
||||
Error:
|
||||
return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err}
|
||||
}
|
||||
|
||||
// Return the first number n such that n*base >= 1<<64.
|
||||
func cutoff64(base int) uint64 {
|
||||
if base < 2 {
|
||||
return 0
|
||||
}
|
||||
return (1<<64-1)/uint64(base) + 1
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package recordio
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var lf = []byte{'\n'}
|
||||
|
||||
type Writer struct {
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
func NewWriter(out io.Writer) *Writer {
|
||||
return &Writer{out}
|
||||
}
|
||||
|
||||
func (w *Writer) writeBuffer(b []byte, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := w.out.Write(b)
|
||||
if err == nil && n != len(b) {
|
||||
return io.ErrShortWrite
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *Writer) WriteFrame(b []byte) (err error) {
|
||||
err = w.writeBuffer(([]byte)(strconv.Itoa(len(b))), err)
|
||||
err = w.writeBuffer(lf, err)
|
||||
err = w.writeBuffer(b, err)
|
||||
return
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,23 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["role.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/roles",
|
||||
importpath = "github.com/mesos/mesos-go/api/v1/lib/roles",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,82 @@
|
|||
package roles
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Role is a deprecated type.
|
||||
type Role string
|
||||
|
||||
const defaultRole = Role("*")
|
||||
|
||||
func (r Role) IsDefault() bool {
|
||||
return r == defaultRole
|
||||
}
|
||||
|
||||
func (r Role) Assign() func(interface{}) {
|
||||
return func(v interface{}) {
|
||||
type roler interface {
|
||||
WithRole(string)
|
||||
}
|
||||
if ri, ok := v.(roler); ok {
|
||||
ri.WithRole(string(r))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r Role) Proto() *string {
|
||||
s := string(r)
|
||||
return &s
|
||||
}
|
||||
|
||||
// IsStrictSubroleOf returns true if left is a strict subrole of right.
|
||||
func IsStrictSubroleOf(left, right string) bool {
|
||||
return len(left) > len(right) && left[len(right)] == '/' && strings.HasPrefix(left, right)
|
||||
}
|
||||
|
||||
var illegalComponents = map[string]struct{}{
|
||||
".": struct{}{},
|
||||
"..": struct{}{},
|
||||
"*": struct{}{},
|
||||
}
|
||||
|
||||
func Parse(s string) (string, error) {
|
||||
if s == string(defaultRole) {
|
||||
return s, nil
|
||||
}
|
||||
if strings.HasPrefix(s, "/") {
|
||||
return "", fmt.Errorf("role %q cannot start with a slash", s)
|
||||
}
|
||||
if strings.HasSuffix(s, "/") {
|
||||
return "", fmt.Errorf("role %q cannot end with a slash", s)
|
||||
}
|
||||
|
||||
// validate each component in the role path
|
||||
for _, part := range strings.Split(s, "/") {
|
||||
if part == "" {
|
||||
return "", fmt.Errorf("role %q cannot contain two adjacent slashes", s)
|
||||
}
|
||||
if bad, found := illegalComponents[part]; found {
|
||||
return "", fmt.Errorf("role %q cannot contain %q as a component", s, bad)
|
||||
}
|
||||
if strings.HasPrefix(part, "-") {
|
||||
return "", fmt.Errorf("role component %q is invalid because it begins with a dash", part)
|
||||
}
|
||||
if strings.IndexFunc(part, func(r rune) bool { return unicode.IsSpace(r) || unicode.IsControl(r) }) > -1 {
|
||||
return "", fmt.Errorf("role component %q is invalid because it contains backspace or whitespace", part)
|
||||
}
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func Validate(roles ...string) error {
|
||||
for i := range roles {
|
||||
_, err := Parse(roles[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
package mesos
|
||||
|
||||
func (left *Value_Scalar) Compare(right *Value_Scalar) int {
|
||||
var (
|
||||
a = convertToFixed64(left.GetValue())
|
||||
b = convertToFixed64(right.GetValue())
|
||||
)
|
||||
if a < b {
|
||||
return -1
|
||||
}
|
||||
if a > b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (left *Value_Ranges) Compare(right *Value_Ranges) int {
|
||||
return Ranges(left.GetRange()).Compare(right.GetRange())
|
||||
}
|
||||
|
||||
func (left *Value_Set) Compare(right *Value_Set) int {
|
||||
i, j := left.GetItem(), right.GetItem()
|
||||
if len(i) <= len(j) {
|
||||
b := make(map[string]struct{}, len(j))
|
||||
for _, x := range j {
|
||||
b[x] = struct{}{}
|
||||
}
|
||||
// make sure that each item on the left exists on the right,
|
||||
// otherwise left is not a subset of right.
|
||||
a := make(map[string]struct{}, len(i))
|
||||
for _, x := range i {
|
||||
if _, ok := b[x]; !ok {
|
||||
return 1
|
||||
}
|
||||
a[x] = struct{}{}
|
||||
}
|
||||
// if every item on the right also exists on the left, then
|
||||
// the sets are equal, otherwise left < right
|
||||
for x := range b {
|
||||
if _, ok := a[x]; !ok {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func (left *Value_Set) Add(right *Value_Set) *Value_Set {
|
||||
lefty := left.GetItem()
|
||||
righty := right.GetItem()
|
||||
c := len(lefty) + len(righty)
|
||||
if c == 0 {
|
||||
return nil
|
||||
}
|
||||
m := make(map[string]struct{}, c)
|
||||
for _, v := range lefty {
|
||||
m[v] = struct{}{}
|
||||
}
|
||||
for _, v := range righty {
|
||||
m[v] = struct{}{}
|
||||
}
|
||||
x := make([]string, 0, len(m))
|
||||
for v := range m {
|
||||
x = append(x, v)
|
||||
}
|
||||
return &Value_Set{Item: x}
|
||||
}
|
||||
|
||||
func (left *Value_Set) Subtract(right *Value_Set) *Value_Set {
|
||||
// for each item in right, remove it from left
|
||||
lefty := left.GetItem()
|
||||
righty := right.GetItem()
|
||||
if c := len(lefty); c == 0 {
|
||||
return nil
|
||||
} else if len(righty) == 0 {
|
||||
x := make([]string, c)
|
||||
copy(x, lefty)
|
||||
return &Value_Set{Item: x}
|
||||
}
|
||||
|
||||
a := make(map[string]struct{}, len(lefty))
|
||||
for _, x := range lefty {
|
||||
a[x] = struct{}{}
|
||||
}
|
||||
for _, x := range righty {
|
||||
delete(a, x)
|
||||
}
|
||||
if len(a) == 0 {
|
||||
return nil
|
||||
}
|
||||
i := 0
|
||||
for k := range a {
|
||||
lefty[i] = k
|
||||
i++
|
||||
}
|
||||
return &Value_Set{Item: lefty[:len(a)]}
|
||||
}
|
||||
|
||||
func (left *Value_Ranges) Add(right *Value_Ranges) *Value_Ranges {
|
||||
a, b := Ranges(left.GetRange()), Ranges(right.GetRange())
|
||||
c := len(a) + len(b)
|
||||
if c == 0 {
|
||||
return nil
|
||||
}
|
||||
x := make(Ranges, c)
|
||||
if len(a) > 0 {
|
||||
copy(x, a)
|
||||
}
|
||||
if len(b) > 0 {
|
||||
copy(x[len(a):], b)
|
||||
}
|
||||
return &Value_Ranges{
|
||||
Range: x.Sort().Squash(),
|
||||
}
|
||||
}
|
||||
|
||||
func (left *Value_Ranges) Subtract(right *Value_Ranges) *Value_Ranges {
|
||||
a, b := Ranges(left.GetRange()), Ranges(right.GetRange())
|
||||
if len(a) > 1 {
|
||||
x := make(Ranges, len(a))
|
||||
copy(x, a)
|
||||
a = x.Sort().Squash()
|
||||
}
|
||||
for _, r := range b {
|
||||
a = a.Remove(r)
|
||||
}
|
||||
if len(a) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &Value_Ranges{Range: a}
|
||||
}
|
||||
|
||||
func (left *Value_Scalar) Add(right *Value_Scalar) *Value_Scalar {
|
||||
sum := convertToFixed64(left.GetValue()) + convertToFixed64(right.GetValue())
|
||||
return &Value_Scalar{Value: convertToFloat64(sum)}
|
||||
}
|
||||
|
||||
func (left *Value_Scalar) Subtract(right *Value_Scalar) *Value_Scalar {
|
||||
diff := convertToFixed64(left.GetValue()) - convertToFixed64(right.GetValue())
|
||||
return &Value_Scalar{Value: convertToFloat64(diff)}
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,8 @@
|
|||
ffjson
|
||||
Copyright (c) 2014, Paul Querna
|
||||
|
||||
This product includes software developed by
|
||||
Paul Querna (http://paul.querna.org/).
|
||||
|
||||
Portions of this software were developed as
|
||||
part of Go, Copyright (c) 2012 The Go Authors.
|
|
@ -0,0 +1,41 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"buffer.go",
|
||||
"buffer_nopool.go",
|
||||
"buffer_pool.go",
|
||||
"bytenum.go",
|
||||
"decimal.go",
|
||||
"extfloat.go",
|
||||
"fold.go",
|
||||
"ftoa.go",
|
||||
"iota.go",
|
||||
"jsonstring.go",
|
||||
"lexer.go",
|
||||
"reader.go",
|
||||
"reader_scan_generic.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/pquerna/ffjson/fflib/v1",
|
||||
importpath = "github.com/pquerna/ffjson/fflib/v1",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//vendor/github.com/pquerna/ffjson/fflib/v1/internal:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//vendor/github.com/pquerna/ffjson/fflib/v1/internal:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue