update cadvisor to v0.31.0
This commit is contained in:
39
vendor/github.com/Rican7/retry/.travis.yml
generated
vendored
Normal file
39
vendor/github.com/Rican7/retry/.travis.yml
generated
vendored
Normal file
@@ -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
|
||||
29
vendor/github.com/Rican7/retry/BUILD
generated
vendored
Normal file
29
vendor/github.com/Rican7/retry/BUILD
generated
vendored
Normal file
@@ -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"],
|
||||
)
|
||||
19
vendor/github.com/Rican7/retry/LICENSE
generated
vendored
Normal file
19
vendor/github.com/Rican7/retry/LICENSE
generated
vendored
Normal file
@@ -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.
|
||||
83
vendor/github.com/Rican7/retry/Makefile
generated
vendored
Normal file
83
vendor/github.com/Rican7/retry/Makefile
generated
vendored
Normal file
@@ -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
|
||||
101
vendor/github.com/Rican7/retry/README.md
generated
vendored
Normal file
101
vendor/github.com/Rican7/retry/README.md
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
# retry
|
||||
|
||||
[](https://travis-ci.org/Rican7/retry)
|
||||
[](https://coveralls.io/github/Rican7/retry)
|
||||
[](http://goreportcard.com/report/Rican7/retry)
|
||||
[](https://godoc.org/github.com/Rican7/retry)
|
||||
[](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),
|
||||
),
|
||||
)
|
||||
```
|
||||
23
vendor/github.com/Rican7/retry/backoff/BUILD
generated
vendored
Normal file
23
vendor/github.com/Rican7/retry/backoff/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 = ["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"],
|
||||
)
|
||||
67
vendor/github.com/Rican7/retry/backoff/backoff.go
generated
vendored
Normal file
67
vendor/github.com/Rican7/retry/backoff/backoff.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
23
vendor/github.com/Rican7/retry/jitter/BUILD
generated
vendored
Normal file
23
vendor/github.com/Rican7/retry/jitter/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 = ["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"],
|
||||
)
|
||||
89
vendor/github.com/Rican7/retry/jitter/jitter.go
generated
vendored
Normal file
89
vendor/github.com/Rican7/retry/jitter/jitter.go
generated
vendored
Normal file
@@ -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))
|
||||
}
|
||||
36
vendor/github.com/Rican7/retry/retry.go
generated
vendored
Normal file
36
vendor/github.com/Rican7/retry/retry.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
27
vendor/github.com/Rican7/retry/strategy/BUILD
generated
vendored
Normal file
27
vendor/github.com/Rican7/retry/strategy/BUILD
generated
vendored
Normal file
@@ -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"],
|
||||
)
|
||||
85
vendor/github.com/Rican7/retry/strategy/strategy.go
generated
vendored
Normal file
85
vendor/github.com/Rican7/retry/strategy/strategy.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
51
vendor/github.com/google/cadvisor/accelerators/nvidia.go
generated
vendored
51
vendor/github.com/google/cadvisor/accelerators/nvidia.go
generated
vendored
@@ -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
|
||||
|
||||
7
vendor/github.com/google/cadvisor/cache/memory/memory.go
generated
vendored
7
vendor/github.com/google/cadvisor/cache/memory/memory.go
generated
vendored
@@ -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
|
||||
}()
|
||||
|
||||
1
vendor/github.com/google/cadvisor/container/BUILD
generated
vendored
1
vendor/github.com/google/cadvisor/container/BUILD
generated
vendored
@@ -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",
|
||||
|
||||
1
vendor/github.com/google/cadvisor/container/container.go
generated
vendored
1
vendor/github.com/google/cadvisor/container/container.go
generated
vendored
@@ -36,6 +36,7 @@ const (
|
||||
ContainerTypeSystemd
|
||||
ContainerTypeCrio
|
||||
ContainerTypeContainerd
|
||||
ContainerTypeMesos
|
||||
)
|
||||
|
||||
// Interface for container operation handlers.
|
||||
|
||||
10
vendor/github.com/google/cadvisor/container/containerd/factory.go
generated
vendored
10
vendor/github.com/google/cadvisor/container/containerd/factory.go
generated
vendored
@@ -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})
|
||||
|
||||
14
vendor/github.com/google/cadvisor/container/containerd/handler.go
generated
vendored
14
vendor/github.com/google/cadvisor/container/containerd/handler.go
generated
vendored
@@ -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
|
||||
|
||||
8
vendor/github.com/google/cadvisor/container/crio/factory.go
generated
vendored
8
vendor/github.com/google/cadvisor/container/crio/factory.go
generated
vendored
@@ -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})
|
||||
|
||||
18
vendor/github.com/google/cadvisor/container/crio/handler.go
generated
vendored
18
vendor/github.com/google/cadvisor/container/crio/handler.go
generated
vendored
@@ -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
|
||||
|
||||
8
vendor/github.com/google/cadvisor/container/docker/factory.go
generated
vendored
8
vendor/github.com/google/cadvisor/container/docker/factory.go
generated
vendored
@@ -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,
|
||||
|
||||
18
vendor/github.com/google/cadvisor/container/docker/handler.go
generated
vendored
18
vendor/github.com/google/cadvisor/container/docker/handler.go
generated
vendored
@@ -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
|
||||
|
||||
1
vendor/github.com/google/cadvisor/container/factory.go
generated
vendored
1
vendor/github.com/google/cadvisor/container/factory.go
generated
vendored
@@ -51,6 +51,7 @@ const (
|
||||
NetworkUsageMetrics MetricKind = "network"
|
||||
NetworkTcpUsageMetrics MetricKind = "tcp"
|
||||
NetworkUdpUsageMetrics MetricKind = "udp"
|
||||
AcceleratorUsageMetrics MetricKind = "accelerator"
|
||||
AppMetrics MetricKind = "app"
|
||||
)
|
||||
|
||||
|
||||
21
vendor/github.com/google/cadvisor/container/libcontainer/handler.go
generated
vendored
21
vendor/github.com/google/cadvisor/container/libcontainer/handler.go
generated
vendored
@@ -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
|
||||
|
||||
47
vendor/github.com/google/cadvisor/container/mesos/BUILD
generated
vendored
Normal file
47
vendor/github.com/google/cadvisor/container/mesos/BUILD
generated
vendored
Normal file
@@ -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"],
|
||||
)
|
||||
190
vendor/github.com/google/cadvisor/container/mesos/client.go
generated
vendored
Normal file
190
vendor/github.com/google/cadvisor/container/mesos/client.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
148
vendor/github.com/google/cadvisor/container/mesos/factory.go
generated
vendored
Normal file
148
vendor/github.com/google/cadvisor/container/mesos/factory.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
213
vendor/github.com/google/cadvisor/container/mesos/handler.go
generated
vendored
Normal file
213
vendor/github.com/google/cadvisor/container/mesos/handler.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
147
vendor/github.com/google/cadvisor/container/mesos/mesos_agent.go
generated
vendored
Normal file
147
vendor/github.com/google/cadvisor/container/mesos/mesos_agent.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
22
vendor/github.com/google/cadvisor/container/raw/factory.go
generated
vendored
22
vendor/github.com/google/cadvisor/container/raw/factory.go
generated
vendored
@@ -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
|
||||
|
||||
4
vendor/github.com/google/cadvisor/container/raw/handler.go
generated
vendored
4
vendor/github.com/google/cadvisor/container/raw/handler.go
generated
vendored
@@ -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,
|
||||
|
||||
8
vendor/github.com/google/cadvisor/container/rkt/factory.go
generated
vendored
8
vendor/github.com/google/cadvisor/container/rkt/factory.go
generated
vendored
@@ -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})
|
||||
|
||||
18
vendor/github.com/google/cadvisor/container/rkt/handler.go
generated
vendored
18
vendor/github.com/google/cadvisor/container/rkt/handler.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
|
||||
2
vendor/github.com/google/cadvisor/container/systemd/factory.go
generated
vendored
2
vendor/github.com/google/cadvisor/container/systemd/factory.go
generated
vendored
@@ -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})
|
||||
|
||||
17
vendor/github.com/google/cadvisor/fs/fs.go
generated
vendored
17
vendor/github.com/google/cadvisor/fs/fs.go
generated
vendored
@@ -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 {
|
||||
|
||||
3
vendor/github.com/google/cadvisor/info/v1/container.go
generated
vendored
3
vendor/github.com/google/cadvisor/info/v1/container.go
generated
vendored
@@ -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.
|
||||
|
||||
1
vendor/github.com/google/cadvisor/manager/BUILD
generated
vendored
1
vendor/github.com/google/cadvisor/manager/BUILD
generated
vendored
@@ -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",
|
||||
|
||||
67
vendor/github.com/google/cadvisor/manager/manager.go
generated
vendored
67
vendor/github.com/google/cadvisor/manager/manager.go
generated
vendored
@@ -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 {
|
||||
|
||||
1
vendor/github.com/google/cadvisor/metrics/BUILD
generated
vendored
1
vendor/github.com/google/cadvisor/metrics/BUILD
generated
vendored
@@ -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",
|
||||
],
|
||||
|
||||
154
vendor/github.com/google/cadvisor/metrics/prometheus.go
generated
vendored
154
vendor/github.com/google/cadvisor/metrics/prometheus.go
generated
vendored
@@ -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) {
|
||||
|
||||
201
vendor/github.com/mesos/mesos-go/LICENSE
generated
vendored
Normal file
201
vendor/github.com/mesos/mesos-go/LICENSE
generated
vendored
Normal file
@@ -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.
|
||||
13
vendor/github.com/mesos/mesos-go/NOTICE
generated
vendored
Normal file
13
vendor/github.com/mesos/mesos-go/NOTICE
generated
vendored
Normal file
@@ -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.
|
||||
50
vendor/github.com/mesos/mesos-go/api/v1/lib/BUILD
generated
vendored
Normal file
50
vendor/github.com/mesos/mesos-go/api/v1/lib/BUILD
generated
vendored
Normal file
@@ -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"],
|
||||
)
|
||||
35
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/BUILD
generated
vendored
Normal file
35
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/BUILD
generated
vendored
Normal file
@@ -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"],
|
||||
)
|
||||
17324
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/agent.pb.go
generated
vendored
Normal file
17324
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/agent.pb.go
generated
vendored
Normal file
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
706
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/agent.proto
generated
vendored
Normal file
706
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/agent.proto
generated
vendored
Normal file
@@ -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;
|
||||
}
|
||||
32
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/calls/BUILD
generated
vendored
Normal file
32
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/calls/BUILD
generated
vendored
Normal file
@@ -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"],
|
||||
)
|
||||
258
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/calls/calls.go
generated
vendored
Normal file
258
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/calls/calls.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
3
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/calls/gen.go
generated
vendored
Normal file
3
vendor/github.com/mesos/mesos-go/api/v1/lib/agent/calls/gen.go
generated
vendored
Normal file
@@ -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
|
||||
71
vendor/github.com/mesos/mesos-go/api/v1/lib/client.go
generated
vendored
Normal file
71
vendor/github.com/mesos/mesos-go/api/v1/lib/client.go
generated
vendored
Normal file
@@ -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{})
|
||||
24
vendor/github.com/mesos/mesos-go/api/v1/lib/client/BUILD
generated
vendored
Normal file
24
vendor/github.com/mesos/mesos-go/api/v1/lib/client/BUILD
generated
vendored
Normal file
@@ -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"],
|
||||
)
|
||||
54
vendor/github.com/mesos/mesos-go/api/v1/lib/client/client.go
generated
vendored
Normal file
54
vendor/github.com/mesos/mesos-go/api/v1/lib/client/client.go
generated
vendored
Normal file
@@ -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
|
||||
)
|
||||
23
vendor/github.com/mesos/mesos-go/api/v1/lib/debug/BUILD
generated
vendored
Normal file
23
vendor/github.com/mesos/mesos-go/api/v1/lib/debug/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 = ["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"],
|
||||
)
|
||||
17
vendor/github.com/mesos/mesos-go/api/v1/lib/debug/logger.go
generated
vendored
Normal file
17
vendor/github.com/mesos/mesos-go/api/v1/lib/debug/logger.go
generated
vendored
Normal file
@@ -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...)
|
||||
}
|
||||
}
|
||||
3
vendor/github.com/mesos/mesos-go/api/v1/lib/doc.go
generated
vendored
Normal file
3
vendor/github.com/mesos/mesos-go/api/v1/lib/doc.go
generated
vendored
Normal file
@@ -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
|
||||
33
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/BUILD
generated
vendored
Normal file
33
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/BUILD
generated
vendored
Normal file
@@ -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"],
|
||||
)
|
||||
28
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/codecs/BUILD
generated
vendored
Normal file
28
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/codecs/BUILD
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
27
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/json/BUILD
generated
vendored
Normal file
27
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/json/BUILD
generated
vendored
Normal file
@@ -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"],
|
||||
)
|
||||
28
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/json/json.go
generated
vendored
Normal file
28
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/json/json.go
generated
vendored
Normal file
@@ -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) })
|
||||
}
|
||||
31
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/proto/BUILD
generated
vendored
Normal file
31
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/proto/BUILD
generated
vendored
Normal file
@@ -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"],
|
||||
)
|
||||
4
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/proto/doc.go
generated
vendored
Normal file
4
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/proto/doc.go
generated
vendored
Normal file
@@ -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) })
|
||||
}
|
||||
111
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/types.go
generated
vendored
Normal file
111
vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/types.go
generated
vendored
Normal file
@@ -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))
|
||||
)
|
||||
26
vendor/github.com/mesos/mesos-go/api/v1/lib/filters.go
generated
vendored
Normal file
26
vendor/github.com/mesos/mesos-go/api/v1/lib/filters.go
generated
vendored
Normal file
@@ -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...)
|
||||
}
|
||||
35
vendor/github.com/mesos/mesos-go/api/v1/lib/fixedpoint.go
generated
vendored
Normal file
35
vendor/github.com/mesos/mesos-go/api/v1/lib/fixedpoint.go
generated
vendored
Normal file
@@ -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))
|
||||
}
|
||||
40
vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/BUILD
generated
vendored
Normal file
40
vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/BUILD
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
33
vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/auth_basic.go
generated
vendored
Normal file
33
vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/auth_basic.go
generated
vendored
Normal file
@@ -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)
|
||||
})
|
||||
})
|
||||
}
|
||||
614
vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/http.go
generated
vendored
Normal file
614
vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/http.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
53
vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/opts.go
generated
vendored
Normal file
53
vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/opts.go
generated
vendored
Normal file
@@ -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()
|
||||
}
|
||||
95
vendor/github.com/mesos/mesos-go/api/v1/lib/labels.go
generated
vendored
Normal file
95
vendor/github.com/mesos/mesos-go/api/v1/lib/labels.go
generated
vendored
Normal file
@@ -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()
|
||||
}
|
||||
72498
vendor/github.com/mesos/mesos-go/api/v1/lib/mesos.pb.go
generated
vendored
Normal file
72498
vendor/github.com/mesos/mesos-go/api/v1/lib/mesos.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
63680
vendor/github.com/mesos/mesos-go/api/v1/lib/mesos.pb_ffjson.go
generated
vendored
Normal file
63680
vendor/github.com/mesos/mesos-go/api/v1/lib/mesos.pb_ffjson.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3600
vendor/github.com/mesos/mesos-go/api/v1/lib/mesos.proto
generated
vendored
Normal file
3600
vendor/github.com/mesos/mesos-go/api/v1/lib/mesos.proto
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
253
vendor/github.com/mesos/mesos-go/api/v1/lib/ranges.go
generated
vendored
Normal file
253
vendor/github.com/mesos/mesos-go/api/v1/lib/ranges.go
generated
vendored
Normal file
@@ -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] }
|
||||
32
vendor/github.com/mesos/mesos-go/api/v1/lib/recordio/BUILD
generated
vendored
Normal file
32
vendor/github.com/mesos/mesos-go/api/v1/lib/recordio/BUILD
generated
vendored
Normal file
@@ -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"],
|
||||
)
|
||||
5
vendor/github.com/mesos/mesos-go/api/v1/lib/recordio/doc.go
generated
vendored
Normal file
5
vendor/github.com/mesos/mesos-go/api/v1/lib/recordio/doc.go
generated
vendored
Normal file
@@ -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
|
||||
145
vendor/github.com/mesos/mesos-go/api/v1/lib/recordio/reader.go
generated
vendored
Normal file
145
vendor/github.com/mesos/mesos-go/api/v1/lib/recordio/reader.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
117
vendor/github.com/mesos/mesos-go/api/v1/lib/recordio/strconv.go
generated
vendored
Normal file
117
vendor/github.com/mesos/mesos-go/api/v1/lib/recordio/strconv.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
34
vendor/github.com/mesos/mesos-go/api/v1/lib/recordio/writer.go
generated
vendored
Normal file
34
vendor/github.com/mesos/mesos-go/api/v1/lib/recordio/writer.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
1145
vendor/github.com/mesos/mesos-go/api/v1/lib/resources.go
generated
vendored
Normal file
1145
vendor/github.com/mesos/mesos-go/api/v1/lib/resources.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
23
vendor/github.com/mesos/mesos-go/api/v1/lib/roles/BUILD
generated
vendored
Normal file
23
vendor/github.com/mesos/mesos-go/api/v1/lib/roles/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 = ["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"],
|
||||
)
|
||||
82
vendor/github.com/mesos/mesos-go/api/v1/lib/roles/role.go
generated
vendored
Normal file
82
vendor/github.com/mesos/mesos-go/api/v1/lib/roles/role.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
142
vendor/github.com/mesos/mesos-go/api/v1/lib/values.go
generated
vendored
Normal file
142
vendor/github.com/mesos/mesos-go/api/v1/lib/values.go
generated
vendored
Normal file
@@ -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)}
|
||||
}
|
||||
202
vendor/github.com/pquerna/ffjson/LICENSE
generated
vendored
Normal file
202
vendor/github.com/pquerna/ffjson/LICENSE
generated
vendored
Normal file
@@ -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.
|
||||
8
vendor/github.com/pquerna/ffjson/NOTICE
generated
vendored
Normal file
8
vendor/github.com/pquerna/ffjson/NOTICE
generated
vendored
Normal file
@@ -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.
|
||||
41
vendor/github.com/pquerna/ffjson/fflib/v1/BUILD
generated
vendored
Normal file
41
vendor/github.com/pquerna/ffjson/fflib/v1/BUILD
generated
vendored
Normal file
@@ -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"],
|
||||
)
|
||||
421
vendor/github.com/pquerna/ffjson/fflib/v1/buffer.go
generated
vendored
Normal file
421
vendor/github.com/pquerna/ffjson/fflib/v1/buffer.go
generated
vendored
Normal file
@@ -0,0 +1,421 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package v1
|
||||
|
||||
// Simple byte buffer for marshaling data.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type grower interface {
|
||||
Grow(n int)
|
||||
}
|
||||
|
||||
type truncater interface {
|
||||
Truncate(n int)
|
||||
Reset()
|
||||
}
|
||||
|
||||
type bytesReader interface {
|
||||
Bytes() []byte
|
||||
String() string
|
||||
}
|
||||
|
||||
type runeWriter interface {
|
||||
WriteRune(r rune) (n int, err error)
|
||||
}
|
||||
|
||||
type stringWriter interface {
|
||||
WriteString(s string) (n int, err error)
|
||||
}
|
||||
|
||||
type lener interface {
|
||||
Len() int
|
||||
}
|
||||
|
||||
type rewinder interface {
|
||||
Rewind(n int) (err error)
|
||||
}
|
||||
|
||||
type encoder interface {
|
||||
Encode(interface{}) error
|
||||
}
|
||||
|
||||
// TODO(pquerna): continue to reduce these interfaces
|
||||
|
||||
type EncodingBuffer interface {
|
||||
io.Writer
|
||||
io.WriterTo
|
||||
io.ByteWriter
|
||||
stringWriter
|
||||
truncater
|
||||
grower
|
||||
rewinder
|
||||
encoder
|
||||
}
|
||||
|
||||
type DecodingBuffer interface {
|
||||
io.ReadWriter
|
||||
io.ByteWriter
|
||||
stringWriter
|
||||
runeWriter
|
||||
truncater
|
||||
grower
|
||||
bytesReader
|
||||
lener
|
||||
}
|
||||
|
||||
// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
|
||||
// The zero value for Buffer is an empty buffer ready to use.
|
||||
type Buffer struct {
|
||||
buf []byte // contents are the bytes buf[off : len(buf)]
|
||||
off int // read at &buf[off], write at &buf[len(buf)]
|
||||
runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune
|
||||
encoder *json.Encoder
|
||||
skipTrailingByte bool
|
||||
}
|
||||
|
||||
// ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer.
|
||||
var ErrTooLarge = errors.New("fflib.v1.Buffer: too large")
|
||||
|
||||
// Bytes returns a slice of the contents of the unread portion of the buffer;
|
||||
// len(b.Bytes()) == b.Len(). If the caller changes the contents of the
|
||||
// returned slice, the contents of the buffer will change provided there
|
||||
// are no intervening method calls on the Buffer.
|
||||
func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }
|
||||
|
||||
// String returns the contents of the unread portion of the buffer
|
||||
// as a string. If the Buffer is a nil pointer, it returns "<nil>".
|
||||
func (b *Buffer) String() string {
|
||||
if b == nil {
|
||||
// Special case, useful in debugging.
|
||||
return "<nil>"
|
||||
}
|
||||
return string(b.buf[b.off:])
|
||||
}
|
||||
|
||||
// Len returns the number of bytes of the unread portion of the buffer;
|
||||
// b.Len() == len(b.Bytes()).
|
||||
func (b *Buffer) Len() int { return len(b.buf) - b.off }
|
||||
|
||||
// Truncate discards all but the first n unread bytes from the buffer.
|
||||
// It panics if n is negative or greater than the length of the buffer.
|
||||
func (b *Buffer) Truncate(n int) {
|
||||
if n == 0 {
|
||||
b.off = 0
|
||||
b.buf = b.buf[0:0]
|
||||
} else {
|
||||
b.buf = b.buf[0 : b.off+n]
|
||||
}
|
||||
}
|
||||
|
||||
// Reset resets the buffer so it has no content.
|
||||
// b.Reset() is the same as b.Truncate(0).
|
||||
func (b *Buffer) Reset() { b.Truncate(0) }
|
||||
|
||||
// grow grows the buffer to guarantee space for n more bytes.
|
||||
// It returns the index where bytes should be written.
|
||||
// If the buffer can't grow it will panic with ErrTooLarge.
|
||||
func (b *Buffer) grow(n int) int {
|
||||
// If we have no buffer, get one from the pool
|
||||
m := b.Len()
|
||||
if m == 0 {
|
||||
if b.buf == nil {
|
||||
b.buf = makeSlice(2 * n)
|
||||
b.off = 0
|
||||
} else if b.off != 0 {
|
||||
// If buffer is empty, reset to recover space.
|
||||
b.Truncate(0)
|
||||
}
|
||||
}
|
||||
if len(b.buf)+n > cap(b.buf) {
|
||||
var buf []byte
|
||||
if m+n <= cap(b.buf)/2 {
|
||||
// We can slide things down instead of allocating a new
|
||||
// slice. We only need m+n <= cap(b.buf) to slide, but
|
||||
// we instead let capacity get twice as large so we
|
||||
// don't spend all our time copying.
|
||||
copy(b.buf[:], b.buf[b.off:])
|
||||
buf = b.buf[:m]
|
||||
} else {
|
||||
// not enough space anywhere
|
||||
buf = makeSlice(2*cap(b.buf) + n)
|
||||
copy(buf, b.buf[b.off:])
|
||||
Pool(b.buf)
|
||||
b.buf = buf
|
||||
}
|
||||
b.off = 0
|
||||
}
|
||||
b.buf = b.buf[0 : b.off+m+n]
|
||||
return b.off + m
|
||||
}
|
||||
|
||||
// Grow grows the buffer's capacity, if necessary, to guarantee space for
|
||||
// another n bytes. After Grow(n), at least n bytes can be written to the
|
||||
// buffer without another allocation.
|
||||
// If n is negative, Grow will panic.
|
||||
// If the buffer can't grow it will panic with ErrTooLarge.
|
||||
func (b *Buffer) Grow(n int) {
|
||||
if n < 0 {
|
||||
panic("bytes.Buffer.Grow: negative count")
|
||||
}
|
||||
m := b.grow(n)
|
||||
b.buf = b.buf[0:m]
|
||||
}
|
||||
|
||||
// Write appends the contents of p to the buffer, growing the buffer as
|
||||
// needed. The return value n is the length of p; err is always nil. If the
|
||||
// buffer becomes too large, Write will panic with ErrTooLarge.
|
||||
func (b *Buffer) Write(p []byte) (n int, err error) {
|
||||
if b.skipTrailingByte {
|
||||
p = p[:len(p)-1]
|
||||
}
|
||||
m := b.grow(len(p))
|
||||
return copy(b.buf[m:], p), nil
|
||||
}
|
||||
|
||||
// WriteString appends the contents of s to the buffer, growing the buffer as
|
||||
// needed. The return value n is the length of s; err is always nil. If the
|
||||
// buffer becomes too large, WriteString will panic with ErrTooLarge.
|
||||
func (b *Buffer) WriteString(s string) (n int, err error) {
|
||||
m := b.grow(len(s))
|
||||
return copy(b.buf[m:], s), nil
|
||||
}
|
||||
|
||||
// MinRead is the minimum slice size passed to a Read call by
|
||||
// Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond
|
||||
// what is required to hold the contents of r, ReadFrom will not grow the
|
||||
// underlying buffer.
|
||||
const minRead = 512
|
||||
|
||||
// ReadFrom reads data from r until EOF and appends it to the buffer, growing
|
||||
// the buffer as needed. The return value n is the number of bytes read. Any
|
||||
// error except io.EOF encountered during the read is also returned. If the
|
||||
// buffer becomes too large, ReadFrom will panic with ErrTooLarge.
|
||||
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
// If buffer is empty, reset to recover space.
|
||||
if b.off >= len(b.buf) {
|
||||
b.Truncate(0)
|
||||
}
|
||||
for {
|
||||
if free := cap(b.buf) - len(b.buf); free < minRead {
|
||||
// not enough space at end
|
||||
newBuf := b.buf
|
||||
if b.off+free < minRead {
|
||||
// not enough space using beginning of buffer;
|
||||
// double buffer capacity
|
||||
newBuf = makeSlice(2*cap(b.buf) + minRead)
|
||||
}
|
||||
copy(newBuf, b.buf[b.off:])
|
||||
Pool(b.buf)
|
||||
b.buf = newBuf[:len(b.buf)-b.off]
|
||||
b.off = 0
|
||||
}
|
||||
m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
|
||||
b.buf = b.buf[0 : len(b.buf)+m]
|
||||
n += int64(m)
|
||||
if e == io.EOF {
|
||||
break
|
||||
}
|
||||
if e != nil {
|
||||
return n, e
|
||||
}
|
||||
}
|
||||
return n, nil // err is EOF, so return nil explicitly
|
||||
}
|
||||
|
||||
// WriteTo writes data to w until the buffer is drained or an error occurs.
|
||||
// The return value n is the number of bytes written; it always fits into an
|
||||
// int, but it is int64 to match the io.WriterTo interface. Any error
|
||||
// encountered during the write is also returned.
|
||||
func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
|
||||
if b.off < len(b.buf) {
|
||||
nBytes := b.Len()
|
||||
m, e := w.Write(b.buf[b.off:])
|
||||
if m > nBytes {
|
||||
panic("bytes.Buffer.WriteTo: invalid Write count")
|
||||
}
|
||||
b.off += m
|
||||
n = int64(m)
|
||||
if e != nil {
|
||||
return n, e
|
||||
}
|
||||
// all bytes should have been written, by definition of
|
||||
// Write method in io.Writer
|
||||
if m != nBytes {
|
||||
return n, io.ErrShortWrite
|
||||
}
|
||||
}
|
||||
// Buffer is now empty; reset.
|
||||
b.Truncate(0)
|
||||
return
|
||||
}
|
||||
|
||||
// WriteByte appends the byte c to the buffer, growing the buffer as needed.
|
||||
// The returned error is always nil, but is included to match bufio.Writer's
|
||||
// WriteByte. If the buffer becomes too large, WriteByte will panic with
|
||||
// ErrTooLarge.
|
||||
func (b *Buffer) WriteByte(c byte) error {
|
||||
m := b.grow(1)
|
||||
b.buf[m] = c
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Buffer) Rewind(n int) error {
|
||||
b.buf = b.buf[:len(b.buf)-n]
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Buffer) Encode(v interface{}) error {
|
||||
if b.encoder == nil {
|
||||
b.encoder = json.NewEncoder(b)
|
||||
}
|
||||
b.skipTrailingByte = true
|
||||
err := b.encoder.Encode(v)
|
||||
b.skipTrailingByte = false
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteRune appends the UTF-8 encoding of Unicode code point r to the
|
||||
// buffer, returning its length and an error, which is always nil but is
|
||||
// included to match bufio.Writer's WriteRune. The buffer is grown as needed;
|
||||
// if it becomes too large, WriteRune will panic with ErrTooLarge.
|
||||
func (b *Buffer) WriteRune(r rune) (n int, err error) {
|
||||
if r < utf8.RuneSelf {
|
||||
b.WriteByte(byte(r))
|
||||
return 1, nil
|
||||
}
|
||||
n = utf8.EncodeRune(b.runeBytes[0:], r)
|
||||
b.Write(b.runeBytes[0:n])
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Read reads the next len(p) bytes from the buffer or until the buffer
|
||||
// is drained. The return value n is the number of bytes read. If the
|
||||
// buffer has no data to return, err is io.EOF (unless len(p) is zero);
|
||||
// otherwise it is nil.
|
||||
func (b *Buffer) Read(p []byte) (n int, err error) {
|
||||
if b.off >= len(b.buf) {
|
||||
// Buffer is empty, reset to recover space.
|
||||
b.Truncate(0)
|
||||
if len(p) == 0 {
|
||||
return
|
||||
}
|
||||
return 0, io.EOF
|
||||
}
|
||||
n = copy(p, b.buf[b.off:])
|
||||
b.off += n
|
||||
return
|
||||
}
|
||||
|
||||
// Next returns a slice containing the next n bytes from the buffer,
|
||||
// advancing the buffer as if the bytes had been returned by Read.
|
||||
// If there are fewer than n bytes in the buffer, Next returns the entire buffer.
|
||||
// The slice is only valid until the next call to a read or write method.
|
||||
func (b *Buffer) Next(n int) []byte {
|
||||
m := b.Len()
|
||||
if n > m {
|
||||
n = m
|
||||
}
|
||||
data := b.buf[b.off : b.off+n]
|
||||
b.off += n
|
||||
return data
|
||||
}
|
||||
|
||||
// ReadByte reads and returns the next byte from the buffer.
|
||||
// If no byte is available, it returns error io.EOF.
|
||||
func (b *Buffer) ReadByte() (c byte, err error) {
|
||||
if b.off >= len(b.buf) {
|
||||
// Buffer is empty, reset to recover space.
|
||||
b.Truncate(0)
|
||||
return 0, io.EOF
|
||||
}
|
||||
c = b.buf[b.off]
|
||||
b.off++
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// ReadRune reads and returns the next UTF-8-encoded
|
||||
// Unicode code point from the buffer.
|
||||
// If no bytes are available, the error returned is io.EOF.
|
||||
// If the bytes are an erroneous UTF-8 encoding, it
|
||||
// consumes one byte and returns U+FFFD, 1.
|
||||
func (b *Buffer) ReadRune() (r rune, size int, err error) {
|
||||
if b.off >= len(b.buf) {
|
||||
// Buffer is empty, reset to recover space.
|
||||
b.Truncate(0)
|
||||
return 0, 0, io.EOF
|
||||
}
|
||||
c := b.buf[b.off]
|
||||
if c < utf8.RuneSelf {
|
||||
b.off++
|
||||
return rune(c), 1, nil
|
||||
}
|
||||
r, n := utf8.DecodeRune(b.buf[b.off:])
|
||||
b.off += n
|
||||
return r, n, nil
|
||||
}
|
||||
|
||||
// ReadBytes reads until the first occurrence of delim in the input,
|
||||
// returning a slice containing the data up to and including the delimiter.
|
||||
// If ReadBytes encounters an error before finding a delimiter,
|
||||
// it returns the data read before the error and the error itself (often io.EOF).
|
||||
// ReadBytes returns err != nil if and only if the returned data does not end in
|
||||
// delim.
|
||||
func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) {
|
||||
slice, err := b.readSlice(delim)
|
||||
// return a copy of slice. The buffer's backing array may
|
||||
// be overwritten by later calls.
|
||||
line = append(line, slice...)
|
||||
return
|
||||
}
|
||||
|
||||
// readSlice is like ReadBytes but returns a reference to internal buffer data.
|
||||
func (b *Buffer) readSlice(delim byte) (line []byte, err error) {
|
||||
i := bytes.IndexByte(b.buf[b.off:], delim)
|
||||
end := b.off + i + 1
|
||||
if i < 0 {
|
||||
end = len(b.buf)
|
||||
err = io.EOF
|
||||
}
|
||||
line = b.buf[b.off:end]
|
||||
b.off = end
|
||||
return line, err
|
||||
}
|
||||
|
||||
// ReadString reads until the first occurrence of delim in the input,
|
||||
// returning a string containing the data up to and including the delimiter.
|
||||
// If ReadString encounters an error before finding a delimiter,
|
||||
// it returns the data read before the error and the error itself (often io.EOF).
|
||||
// ReadString returns err != nil if and only if the returned data does not end
|
||||
// in delim.
|
||||
func (b *Buffer) ReadString(delim byte) (line string, err error) {
|
||||
slice, err := b.readSlice(delim)
|
||||
return string(slice), err
|
||||
}
|
||||
|
||||
// NewBuffer creates and initializes a new Buffer using buf as its initial
|
||||
// contents. It is intended to prepare a Buffer to read existing data. It
|
||||
// can also be used to size the internal buffer for writing. To do that,
|
||||
// buf should have the desired capacity but a length of zero.
|
||||
//
|
||||
// In most cases, new(Buffer) (or just declaring a Buffer variable) is
|
||||
// sufficient to initialize a Buffer.
|
||||
func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }
|
||||
|
||||
// NewBufferString creates and initializes a new Buffer using string s as its
|
||||
// initial contents. It is intended to prepare a buffer to read an existing
|
||||
// string.
|
||||
//
|
||||
// In most cases, new(Buffer) (or just declaring a Buffer variable) is
|
||||
// sufficient to initialize a Buffer.
|
||||
func NewBufferString(s string) *Buffer {
|
||||
return &Buffer{buf: []byte(s)}
|
||||
}
|
||||
11
vendor/github.com/pquerna/ffjson/fflib/v1/buffer_nopool.go
generated
vendored
Normal file
11
vendor/github.com/pquerna/ffjson/fflib/v1/buffer_nopool.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// +build !go1.3
|
||||
|
||||
package v1
|
||||
|
||||
// Stub version of buffer_pool.go for Go 1.2, which doesn't have sync.Pool.
|
||||
|
||||
func Pool(b []byte) {}
|
||||
|
||||
func makeSlice(n int) []byte {
|
||||
return make([]byte, n)
|
||||
}
|
||||
105
vendor/github.com/pquerna/ffjson/fflib/v1/buffer_pool.go
generated
vendored
Normal file
105
vendor/github.com/pquerna/ffjson/fflib/v1/buffer_pool.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.3
|
||||
|
||||
package v1
|
||||
|
||||
// Allocation pools for Buffers.
|
||||
|
||||
import "sync"
|
||||
|
||||
var pools [14]sync.Pool
|
||||
var pool64 *sync.Pool
|
||||
|
||||
func init() {
|
||||
var i uint
|
||||
// TODO(pquerna): add science here around actual pool sizes.
|
||||
for i = 6; i < 20; i++ {
|
||||
n := 1 << i
|
||||
pools[poolNum(n)].New = func() interface{} { return make([]byte, 0, n) }
|
||||
}
|
||||
pool64 = &pools[0]
|
||||
}
|
||||
|
||||
// This returns the pool number that will give a buffer of
|
||||
// at least 'i' bytes.
|
||||
func poolNum(i int) int {
|
||||
// TODO(pquerna): convert to log2 w/ bsr asm instruction:
|
||||
// <https://groups.google.com/forum/#!topic/golang-nuts/uAb5J1_y7ns>
|
||||
if i <= 64 {
|
||||
return 0
|
||||
} else if i <= 128 {
|
||||
return 1
|
||||
} else if i <= 256 {
|
||||
return 2
|
||||
} else if i <= 512 {
|
||||
return 3
|
||||
} else if i <= 1024 {
|
||||
return 4
|
||||
} else if i <= 2048 {
|
||||
return 5
|
||||
} else if i <= 4096 {
|
||||
return 6
|
||||
} else if i <= 8192 {
|
||||
return 7
|
||||
} else if i <= 16384 {
|
||||
return 8
|
||||
} else if i <= 32768 {
|
||||
return 9
|
||||
} else if i <= 65536 {
|
||||
return 10
|
||||
} else if i <= 131072 {
|
||||
return 11
|
||||
} else if i <= 262144 {
|
||||
return 12
|
||||
} else if i <= 524288 {
|
||||
return 13
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
// Send a buffer to the Pool to reuse for other instances.
|
||||
// You may no longer utilize the content of the buffer, since it may be used
|
||||
// by other goroutines.
|
||||
func Pool(b []byte) {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
c := cap(b)
|
||||
|
||||
// Our smallest buffer is 64 bytes, so we discard smaller buffers.
|
||||
if c < 64 {
|
||||
return
|
||||
}
|
||||
|
||||
// We need to put the incoming buffer into the NEXT buffer,
|
||||
// since a buffer guarantees AT LEAST the number of bytes available
|
||||
// that is the top of this buffer.
|
||||
// That is the reason for dividing the cap by 2, so it gets into the NEXT bucket.
|
||||
// We add 2 to avoid rounding down if size is exactly power of 2.
|
||||
pn := poolNum((c + 2) >> 1)
|
||||
if pn != -1 {
|
||||
pools[pn].Put(b[0:0])
|
||||
}
|
||||
// if we didn't have a slot for this []byte, we just drop it and let the GC
|
||||
// take care of it.
|
||||
}
|
||||
|
||||
// makeSlice allocates a slice of size n -- it will attempt to use a pool'ed
|
||||
// instance whenever possible.
|
||||
func makeSlice(n int) []byte {
|
||||
if n <= 64 {
|
||||
return pool64.Get().([]byte)[0:n]
|
||||
}
|
||||
|
||||
pn := poolNum(n)
|
||||
|
||||
if pn != -1 {
|
||||
return pools[pn].Get().([]byte)[0:n]
|
||||
} else {
|
||||
return make([]byte, n)
|
||||
}
|
||||
}
|
||||
88
vendor/github.com/pquerna/ffjson/fflib/v1/bytenum.go
generated
vendored
Normal file
88
vendor/github.com/pquerna/ffjson/fflib/v1/bytenum.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright 2014 Paul Querna
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Portions of this file are on Go stdlib's strconv/iota.go */
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/pquerna/ffjson/fflib/v1/internal"
|
||||
)
|
||||
|
||||
func ParseFloat(s []byte, bitSize int) (f float64, err error) {
|
||||
return internal.ParseFloat(s, bitSize)
|
||||
}
|
||||
|
||||
// ParseUint is like ParseInt but for unsigned numbers, and oeprating on []byte
|
||||
func ParseUint(s []byte, base int, bitSize int) (n uint64, err error) {
|
||||
if len(s) == 1 {
|
||||
switch s[0] {
|
||||
case '0':
|
||||
return 0, nil
|
||||
case '1':
|
||||
return 1, nil
|
||||
case '2':
|
||||
return 2, nil
|
||||
case '3':
|
||||
return 3, nil
|
||||
case '4':
|
||||
return 4, nil
|
||||
case '5':
|
||||
return 5, nil
|
||||
case '6':
|
||||
return 6, nil
|
||||
case '7':
|
||||
return 7, nil
|
||||
case '8':
|
||||
return 8, nil
|
||||
case '9':
|
||||
return 9, nil
|
||||
}
|
||||
}
|
||||
return internal.ParseUint(s, base, bitSize)
|
||||
}
|
||||
|
||||
func ParseInt(s []byte, base int, bitSize int) (i int64, err error) {
|
||||
if len(s) == 1 {
|
||||
switch s[0] {
|
||||
case '0':
|
||||
return 0, nil
|
||||
case '1':
|
||||
return 1, nil
|
||||
case '2':
|
||||
return 2, nil
|
||||
case '3':
|
||||
return 3, nil
|
||||
case '4':
|
||||
return 4, nil
|
||||
case '5':
|
||||
return 5, nil
|
||||
case '6':
|
||||
return 6, nil
|
||||
case '7':
|
||||
return 7, nil
|
||||
case '8':
|
||||
return 8, nil
|
||||
case '9':
|
||||
return 9, nil
|
||||
}
|
||||
}
|
||||
return internal.ParseInt(s, base, bitSize)
|
||||
}
|
||||
378
vendor/github.com/pquerna/ffjson/fflib/v1/decimal.go
generated
vendored
Normal file
378
vendor/github.com/pquerna/ffjson/fflib/v1/decimal.go
generated
vendored
Normal file
@@ -0,0 +1,378 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Multiprecision decimal numbers.
|
||||
// For floating-point formatting only; not general purpose.
|
||||
// Only operations are assign and (binary) left/right shift.
|
||||
// Can do binary floating point in multiprecision decimal precisely
|
||||
// because 2 divides 10; cannot do decimal floating point
|
||||
// in multiprecision binary precisely.
|
||||
|
||||
package v1
|
||||
|
||||
type decimal struct {
|
||||
d [800]byte // digits
|
||||
nd int // number of digits used
|
||||
dp int // decimal point
|
||||
neg bool
|
||||
trunc bool // discarded nonzero digits beyond d[:nd]
|
||||
}
|
||||
|
||||
func (a *decimal) String() string {
|
||||
n := 10 + a.nd
|
||||
if a.dp > 0 {
|
||||
n += a.dp
|
||||
}
|
||||
if a.dp < 0 {
|
||||
n += -a.dp
|
||||
}
|
||||
|
||||
buf := make([]byte, n)
|
||||
w := 0
|
||||
switch {
|
||||
case a.nd == 0:
|
||||
return "0"
|
||||
|
||||
case a.dp <= 0:
|
||||
// zeros fill space between decimal point and digits
|
||||
buf[w] = '0'
|
||||
w++
|
||||
buf[w] = '.'
|
||||
w++
|
||||
w += digitZero(buf[w : w+-a.dp])
|
||||
w += copy(buf[w:], a.d[0:a.nd])
|
||||
|
||||
case a.dp < a.nd:
|
||||
// decimal point in middle of digits
|
||||
w += copy(buf[w:], a.d[0:a.dp])
|
||||
buf[w] = '.'
|
||||
w++
|
||||
w += copy(buf[w:], a.d[a.dp:a.nd])
|
||||
|
||||
default:
|
||||
// zeros fill space between digits and decimal point
|
||||
w += copy(buf[w:], a.d[0:a.nd])
|
||||
w += digitZero(buf[w : w+a.dp-a.nd])
|
||||
}
|
||||
return string(buf[0:w])
|
||||
}
|
||||
|
||||
func digitZero(dst []byte) int {
|
||||
for i := range dst {
|
||||
dst[i] = '0'
|
||||
}
|
||||
return len(dst)
|
||||
}
|
||||
|
||||
// trim trailing zeros from number.
|
||||
// (They are meaningless; the decimal point is tracked
|
||||
// independent of the number of digits.)
|
||||
func trim(a *decimal) {
|
||||
for a.nd > 0 && a.d[a.nd-1] == '0' {
|
||||
a.nd--
|
||||
}
|
||||
if a.nd == 0 {
|
||||
a.dp = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Assign v to a.
|
||||
func (a *decimal) Assign(v uint64) {
|
||||
var buf [24]byte
|
||||
|
||||
// Write reversed decimal in buf.
|
||||
n := 0
|
||||
for v > 0 {
|
||||
v1 := v / 10
|
||||
v -= 10 * v1
|
||||
buf[n] = byte(v + '0')
|
||||
n++
|
||||
v = v1
|
||||
}
|
||||
|
||||
// Reverse again to produce forward decimal in a.d.
|
||||
a.nd = 0
|
||||
for n--; n >= 0; n-- {
|
||||
a.d[a.nd] = buf[n]
|
||||
a.nd++
|
||||
}
|
||||
a.dp = a.nd
|
||||
trim(a)
|
||||
}
|
||||
|
||||
// Maximum shift that we can do in one pass without overflow.
|
||||
// Signed int has 31 bits, and we have to be able to accommodate 9<<k.
|
||||
const maxShift = 27
|
||||
|
||||
// Binary shift right (* 2) by k bits. k <= maxShift to avoid overflow.
|
||||
func rightShift(a *decimal, k uint) {
|
||||
r := 0 // read pointer
|
||||
w := 0 // write pointer
|
||||
|
||||
// Pick up enough leading digits to cover first shift.
|
||||
n := 0
|
||||
for ; n>>k == 0; r++ {
|
||||
if r >= a.nd {
|
||||
if n == 0 {
|
||||
// a == 0; shouldn't get here, but handle anyway.
|
||||
a.nd = 0
|
||||
return
|
||||
}
|
||||
for n>>k == 0 {
|
||||
n = n * 10
|
||||
r++
|
||||
}
|
||||
break
|
||||
}
|
||||
c := int(a.d[r])
|
||||
n = n*10 + c - '0'
|
||||
}
|
||||
a.dp -= r - 1
|
||||
|
||||
// Pick up a digit, put down a digit.
|
||||
for ; r < a.nd; r++ {
|
||||
c := int(a.d[r])
|
||||
dig := n >> k
|
||||
n -= dig << k
|
||||
a.d[w] = byte(dig + '0')
|
||||
w++
|
||||
n = n*10 + c - '0'
|
||||
}
|
||||
|
||||
// Put down extra digits.
|
||||
for n > 0 {
|
||||
dig := n >> k
|
||||
n -= dig << k
|
||||
if w < len(a.d) {
|
||||
a.d[w] = byte(dig + '0')
|
||||
w++
|
||||
} else if dig > 0 {
|
||||
a.trunc = true
|
||||
}
|
||||
n = n * 10
|
||||
}
|
||||
|
||||
a.nd = w
|
||||
trim(a)
|
||||
}
|
||||
|
||||
// Cheat sheet for left shift: table indexed by shift count giving
|
||||
// number of new digits that will be introduced by that shift.
|
||||
//
|
||||
// For example, leftcheats[4] = {2, "625"}. That means that
|
||||
// if we are shifting by 4 (multiplying by 16), it will add 2 digits
|
||||
// when the string prefix is "625" through "999", and one fewer digit
|
||||
// if the string prefix is "000" through "624".
|
||||
//
|
||||
// Credit for this trick goes to Ken.
|
||||
|
||||
type leftCheat struct {
|
||||
delta int // number of new digits
|
||||
cutoff string // minus one digit if original < a.
|
||||
}
|
||||
|
||||
var leftcheats = []leftCheat{
|
||||
// Leading digits of 1/2^i = 5^i.
|
||||
// 5^23 is not an exact 64-bit floating point number,
|
||||
// so have to use bc for the math.
|
||||
/*
|
||||
seq 27 | sed 's/^/5^/' | bc |
|
||||
awk 'BEGIN{ print "\tleftCheat{ 0, \"\" }," }
|
||||
{
|
||||
log2 = log(2)/log(10)
|
||||
printf("\tleftCheat{ %d, \"%s\" },\t// * %d\n",
|
||||
int(log2*NR+1), $0, 2**NR)
|
||||
}'
|
||||
*/
|
||||
{0, ""},
|
||||
{1, "5"}, // * 2
|
||||
{1, "25"}, // * 4
|
||||
{1, "125"}, // * 8
|
||||
{2, "625"}, // * 16
|
||||
{2, "3125"}, // * 32
|
||||
{2, "15625"}, // * 64
|
||||
{3, "78125"}, // * 128
|
||||
{3, "390625"}, // * 256
|
||||
{3, "1953125"}, // * 512
|
||||
{4, "9765625"}, // * 1024
|
||||
{4, "48828125"}, // * 2048
|
||||
{4, "244140625"}, // * 4096
|
||||
{4, "1220703125"}, // * 8192
|
||||
{5, "6103515625"}, // * 16384
|
||||
{5, "30517578125"}, // * 32768
|
||||
{5, "152587890625"}, // * 65536
|
||||
{6, "762939453125"}, // * 131072
|
||||
{6, "3814697265625"}, // * 262144
|
||||
{6, "19073486328125"}, // * 524288
|
||||
{7, "95367431640625"}, // * 1048576
|
||||
{7, "476837158203125"}, // * 2097152
|
||||
{7, "2384185791015625"}, // * 4194304
|
||||
{7, "11920928955078125"}, // * 8388608
|
||||
{8, "59604644775390625"}, // * 16777216
|
||||
{8, "298023223876953125"}, // * 33554432
|
||||
{8, "1490116119384765625"}, // * 67108864
|
||||
{9, "7450580596923828125"}, // * 134217728
|
||||
}
|
||||
|
||||
// Is the leading prefix of b lexicographically less than s?
|
||||
func prefixIsLessThan(b []byte, s string) bool {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if i >= len(b) {
|
||||
return true
|
||||
}
|
||||
if b[i] != s[i] {
|
||||
return b[i] < s[i]
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Binary shift left (/ 2) by k bits. k <= maxShift to avoid overflow.
|
||||
func leftShift(a *decimal, k uint) {
|
||||
delta := leftcheats[k].delta
|
||||
if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) {
|
||||
delta--
|
||||
}
|
||||
|
||||
r := a.nd // read index
|
||||
w := a.nd + delta // write index
|
||||
n := 0
|
||||
|
||||
// Pick up a digit, put down a digit.
|
||||
for r--; r >= 0; r-- {
|
||||
n += (int(a.d[r]) - '0') << k
|
||||
quo := n / 10
|
||||
rem := n - 10*quo
|
||||
w--
|
||||
if w < len(a.d) {
|
||||
a.d[w] = byte(rem + '0')
|
||||
} else if rem != 0 {
|
||||
a.trunc = true
|
||||
}
|
||||
n = quo
|
||||
}
|
||||
|
||||
// Put down extra digits.
|
||||
for n > 0 {
|
||||
quo := n / 10
|
||||
rem := n - 10*quo
|
||||
w--
|
||||
if w < len(a.d) {
|
||||
a.d[w] = byte(rem + '0')
|
||||
} else if rem != 0 {
|
||||
a.trunc = true
|
||||
}
|
||||
n = quo
|
||||
}
|
||||
|
||||
a.nd += delta
|
||||
if a.nd >= len(a.d) {
|
||||
a.nd = len(a.d)
|
||||
}
|
||||
a.dp += delta
|
||||
trim(a)
|
||||
}
|
||||
|
||||
// Binary shift left (k > 0) or right (k < 0).
|
||||
func (a *decimal) Shift(k int) {
|
||||
switch {
|
||||
case a.nd == 0:
|
||||
// nothing to do: a == 0
|
||||
case k > 0:
|
||||
for k > maxShift {
|
||||
leftShift(a, maxShift)
|
||||
k -= maxShift
|
||||
}
|
||||
leftShift(a, uint(k))
|
||||
case k < 0:
|
||||
for k < -maxShift {
|
||||
rightShift(a, maxShift)
|
||||
k += maxShift
|
||||
}
|
||||
rightShift(a, uint(-k))
|
||||
}
|
||||
}
|
||||
|
||||
// If we chop a at nd digits, should we round up?
|
||||
func shouldRoundUp(a *decimal, nd int) bool {
|
||||
if nd < 0 || nd >= a.nd {
|
||||
return false
|
||||
}
|
||||
if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even
|
||||
// if we truncated, a little higher than what's recorded - always round up
|
||||
if a.trunc {
|
||||
return true
|
||||
}
|
||||
return nd > 0 && (a.d[nd-1]-'0')%2 != 0
|
||||
}
|
||||
// not halfway - digit tells all
|
||||
return a.d[nd] >= '5'
|
||||
}
|
||||
|
||||
// Round a to nd digits (or fewer).
|
||||
// If nd is zero, it means we're rounding
|
||||
// just to the left of the digits, as in
|
||||
// 0.09 -> 0.1.
|
||||
func (a *decimal) Round(nd int) {
|
||||
if nd < 0 || nd >= a.nd {
|
||||
return
|
||||
}
|
||||
if shouldRoundUp(a, nd) {
|
||||
a.RoundUp(nd)
|
||||
} else {
|
||||
a.RoundDown(nd)
|
||||
}
|
||||
}
|
||||
|
||||
// Round a down to nd digits (or fewer).
|
||||
func (a *decimal) RoundDown(nd int) {
|
||||
if nd < 0 || nd >= a.nd {
|
||||
return
|
||||
}
|
||||
a.nd = nd
|
||||
trim(a)
|
||||
}
|
||||
|
||||
// Round a up to nd digits (or fewer).
|
||||
func (a *decimal) RoundUp(nd int) {
|
||||
if nd < 0 || nd >= a.nd {
|
||||
return
|
||||
}
|
||||
|
||||
// round up
|
||||
for i := nd - 1; i >= 0; i-- {
|
||||
c := a.d[i]
|
||||
if c < '9' { // can stop after this digit
|
||||
a.d[i]++
|
||||
a.nd = i + 1
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Number is all 9s.
|
||||
// Change to single 1 with adjusted decimal point.
|
||||
a.d[0] = '1'
|
||||
a.nd = 1
|
||||
a.dp++
|
||||
}
|
||||
|
||||
// Extract integer part, rounded appropriately.
|
||||
// No guarantees about overflow.
|
||||
func (a *decimal) RoundedInteger() uint64 {
|
||||
if a.dp > 20 {
|
||||
return 0xFFFFFFFFFFFFFFFF
|
||||
}
|
||||
var i int
|
||||
n := uint64(0)
|
||||
for i = 0; i < a.dp && i < a.nd; i++ {
|
||||
n = n*10 + uint64(a.d[i]-'0')
|
||||
}
|
||||
for ; i < a.dp; i++ {
|
||||
n *= 10
|
||||
}
|
||||
if shouldRoundUp(a, a.dp) {
|
||||
n++
|
||||
}
|
||||
return n
|
||||
}
|
||||
668
vendor/github.com/pquerna/ffjson/fflib/v1/extfloat.go
generated
vendored
Normal file
668
vendor/github.com/pquerna/ffjson/fflib/v1/extfloat.go
generated
vendored
Normal file
@@ -0,0 +1,668 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package v1
|
||||
|
||||
// An extFloat represents an extended floating-point number, with more
|
||||
// precision than a float64. It does not try to save bits: the
|
||||
// number represented by the structure is mant*(2^exp), with a negative
|
||||
// sign if neg is true.
|
||||
type extFloat struct {
|
||||
mant uint64
|
||||
exp int
|
||||
neg bool
|
||||
}
|
||||
|
||||
// Powers of ten taken from double-conversion library.
|
||||
// http://code.google.com/p/double-conversion/
|
||||
const (
|
||||
firstPowerOfTen = -348
|
||||
stepPowerOfTen = 8
|
||||
)
|
||||
|
||||
var smallPowersOfTen = [...]extFloat{
|
||||
{1 << 63, -63, false}, // 1
|
||||
{0xa << 60, -60, false}, // 1e1
|
||||
{0x64 << 57, -57, false}, // 1e2
|
||||
{0x3e8 << 54, -54, false}, // 1e3
|
||||
{0x2710 << 50, -50, false}, // 1e4
|
||||
{0x186a0 << 47, -47, false}, // 1e5
|
||||
{0xf4240 << 44, -44, false}, // 1e6
|
||||
{0x989680 << 40, -40, false}, // 1e7
|
||||
}
|
||||
|
||||
var powersOfTen = [...]extFloat{
|
||||
{0xfa8fd5a0081c0288, -1220, false}, // 10^-348
|
||||
{0xbaaee17fa23ebf76, -1193, false}, // 10^-340
|
||||
{0x8b16fb203055ac76, -1166, false}, // 10^-332
|
||||
{0xcf42894a5dce35ea, -1140, false}, // 10^-324
|
||||
{0x9a6bb0aa55653b2d, -1113, false}, // 10^-316
|
||||
{0xe61acf033d1a45df, -1087, false}, // 10^-308
|
||||
{0xab70fe17c79ac6ca, -1060, false}, // 10^-300
|
||||
{0xff77b1fcbebcdc4f, -1034, false}, // 10^-292
|
||||
{0xbe5691ef416bd60c, -1007, false}, // 10^-284
|
||||
{0x8dd01fad907ffc3c, -980, false}, // 10^-276
|
||||
{0xd3515c2831559a83, -954, false}, // 10^-268
|
||||
{0x9d71ac8fada6c9b5, -927, false}, // 10^-260
|
||||
{0xea9c227723ee8bcb, -901, false}, // 10^-252
|
||||
{0xaecc49914078536d, -874, false}, // 10^-244
|
||||
{0x823c12795db6ce57, -847, false}, // 10^-236
|
||||
{0xc21094364dfb5637, -821, false}, // 10^-228
|
||||
{0x9096ea6f3848984f, -794, false}, // 10^-220
|
||||
{0xd77485cb25823ac7, -768, false}, // 10^-212
|
||||
{0xa086cfcd97bf97f4, -741, false}, // 10^-204
|
||||
{0xef340a98172aace5, -715, false}, // 10^-196
|
||||
{0xb23867fb2a35b28e, -688, false}, // 10^-188
|
||||
{0x84c8d4dfd2c63f3b, -661, false}, // 10^-180
|
||||
{0xc5dd44271ad3cdba, -635, false}, // 10^-172
|
||||
{0x936b9fcebb25c996, -608, false}, // 10^-164
|
||||
{0xdbac6c247d62a584, -582, false}, // 10^-156
|
||||
{0xa3ab66580d5fdaf6, -555, false}, // 10^-148
|
||||
{0xf3e2f893dec3f126, -529, false}, // 10^-140
|
||||
{0xb5b5ada8aaff80b8, -502, false}, // 10^-132
|
||||
{0x87625f056c7c4a8b, -475, false}, // 10^-124
|
||||
{0xc9bcff6034c13053, -449, false}, // 10^-116
|
||||
{0x964e858c91ba2655, -422, false}, // 10^-108
|
||||
{0xdff9772470297ebd, -396, false}, // 10^-100
|
||||
{0xa6dfbd9fb8e5b88f, -369, false}, // 10^-92
|
||||
{0xf8a95fcf88747d94, -343, false}, // 10^-84
|
||||
{0xb94470938fa89bcf, -316, false}, // 10^-76
|
||||
{0x8a08f0f8bf0f156b, -289, false}, // 10^-68
|
||||
{0xcdb02555653131b6, -263, false}, // 10^-60
|
||||
{0x993fe2c6d07b7fac, -236, false}, // 10^-52
|
||||
{0xe45c10c42a2b3b06, -210, false}, // 10^-44
|
||||
{0xaa242499697392d3, -183, false}, // 10^-36
|
||||
{0xfd87b5f28300ca0e, -157, false}, // 10^-28
|
||||
{0xbce5086492111aeb, -130, false}, // 10^-20
|
||||
{0x8cbccc096f5088cc, -103, false}, // 10^-12
|
||||
{0xd1b71758e219652c, -77, false}, // 10^-4
|
||||
{0x9c40000000000000, -50, false}, // 10^4
|
||||
{0xe8d4a51000000000, -24, false}, // 10^12
|
||||
{0xad78ebc5ac620000, 3, false}, // 10^20
|
||||
{0x813f3978f8940984, 30, false}, // 10^28
|
||||
{0xc097ce7bc90715b3, 56, false}, // 10^36
|
||||
{0x8f7e32ce7bea5c70, 83, false}, // 10^44
|
||||
{0xd5d238a4abe98068, 109, false}, // 10^52
|
||||
{0x9f4f2726179a2245, 136, false}, // 10^60
|
||||
{0xed63a231d4c4fb27, 162, false}, // 10^68
|
||||
{0xb0de65388cc8ada8, 189, false}, // 10^76
|
||||
{0x83c7088e1aab65db, 216, false}, // 10^84
|
||||
{0xc45d1df942711d9a, 242, false}, // 10^92
|
||||
{0x924d692ca61be758, 269, false}, // 10^100
|
||||
{0xda01ee641a708dea, 295, false}, // 10^108
|
||||
{0xa26da3999aef774a, 322, false}, // 10^116
|
||||
{0xf209787bb47d6b85, 348, false}, // 10^124
|
||||
{0xb454e4a179dd1877, 375, false}, // 10^132
|
||||
{0x865b86925b9bc5c2, 402, false}, // 10^140
|
||||
{0xc83553c5c8965d3d, 428, false}, // 10^148
|
||||
{0x952ab45cfa97a0b3, 455, false}, // 10^156
|
||||
{0xde469fbd99a05fe3, 481, false}, // 10^164
|
||||
{0xa59bc234db398c25, 508, false}, // 10^172
|
||||
{0xf6c69a72a3989f5c, 534, false}, // 10^180
|
||||
{0xb7dcbf5354e9bece, 561, false}, // 10^188
|
||||
{0x88fcf317f22241e2, 588, false}, // 10^196
|
||||
{0xcc20ce9bd35c78a5, 614, false}, // 10^204
|
||||
{0x98165af37b2153df, 641, false}, // 10^212
|
||||
{0xe2a0b5dc971f303a, 667, false}, // 10^220
|
||||
{0xa8d9d1535ce3b396, 694, false}, // 10^228
|
||||
{0xfb9b7cd9a4a7443c, 720, false}, // 10^236
|
||||
{0xbb764c4ca7a44410, 747, false}, // 10^244
|
||||
{0x8bab8eefb6409c1a, 774, false}, // 10^252
|
||||
{0xd01fef10a657842c, 800, false}, // 10^260
|
||||
{0x9b10a4e5e9913129, 827, false}, // 10^268
|
||||
{0xe7109bfba19c0c9d, 853, false}, // 10^276
|
||||
{0xac2820d9623bf429, 880, false}, // 10^284
|
||||
{0x80444b5e7aa7cf85, 907, false}, // 10^292
|
||||
{0xbf21e44003acdd2d, 933, false}, // 10^300
|
||||
{0x8e679c2f5e44ff8f, 960, false}, // 10^308
|
||||
{0xd433179d9c8cb841, 986, false}, // 10^316
|
||||
{0x9e19db92b4e31ba9, 1013, false}, // 10^324
|
||||
{0xeb96bf6ebadf77d9, 1039, false}, // 10^332
|
||||
{0xaf87023b9bf0ee6b, 1066, false}, // 10^340
|
||||
}
|
||||
|
||||
// floatBits returns the bits of the float64 that best approximates
|
||||
// the extFloat passed as receiver. Overflow is set to true if
|
||||
// the resulting float64 is ±Inf.
|
||||
func (f *extFloat) floatBits(flt *floatInfo) (bits uint64, overflow bool) {
|
||||
f.Normalize()
|
||||
|
||||
exp := f.exp + 63
|
||||
|
||||
// Exponent too small.
|
||||
if exp < flt.bias+1 {
|
||||
n := flt.bias + 1 - exp
|
||||
f.mant >>= uint(n)
|
||||
exp += n
|
||||
}
|
||||
|
||||
// Extract 1+flt.mantbits bits from the 64-bit mantissa.
|
||||
mant := f.mant >> (63 - flt.mantbits)
|
||||
if f.mant&(1<<(62-flt.mantbits)) != 0 {
|
||||
// Round up.
|
||||
mant += 1
|
||||
}
|
||||
|
||||
// Rounding might have added a bit; shift down.
|
||||
if mant == 2<<flt.mantbits {
|
||||
mant >>= 1
|
||||
exp++
|
||||
}
|
||||
|
||||
// Infinities.
|
||||
if exp-flt.bias >= 1<<flt.expbits-1 {
|
||||
// ±Inf
|
||||
mant = 0
|
||||
exp = 1<<flt.expbits - 1 + flt.bias
|
||||
overflow = true
|
||||
} else if mant&(1<<flt.mantbits) == 0 {
|
||||
// Denormalized?
|
||||
exp = flt.bias
|
||||
}
|
||||
// Assemble bits.
|
||||
bits = mant & (uint64(1)<<flt.mantbits - 1)
|
||||
bits |= uint64((exp-flt.bias)&(1<<flt.expbits-1)) << flt.mantbits
|
||||
if f.neg {
|
||||
bits |= 1 << (flt.mantbits + flt.expbits)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AssignComputeBounds sets f to the floating point value
|
||||
// defined by mant, exp and precision given by flt. It returns
|
||||
// lower, upper such that any number in the closed interval
|
||||
// [lower, upper] is converted back to the same floating point number.
|
||||
func (f *extFloat) AssignComputeBounds(mant uint64, exp int, neg bool, flt *floatInfo) (lower, upper extFloat) {
|
||||
f.mant = mant
|
||||
f.exp = exp - int(flt.mantbits)
|
||||
f.neg = neg
|
||||
if f.exp <= 0 && mant == (mant>>uint(-f.exp))<<uint(-f.exp) {
|
||||
// An exact integer
|
||||
f.mant >>= uint(-f.exp)
|
||||
f.exp = 0
|
||||
return *f, *f
|
||||
}
|
||||
expBiased := exp - flt.bias
|
||||
|
||||
upper = extFloat{mant: 2*f.mant + 1, exp: f.exp - 1, neg: f.neg}
|
||||
if mant != 1<<flt.mantbits || expBiased == 1 {
|
||||
lower = extFloat{mant: 2*f.mant - 1, exp: f.exp - 1, neg: f.neg}
|
||||
} else {
|
||||
lower = extFloat{mant: 4*f.mant - 1, exp: f.exp - 2, neg: f.neg}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Normalize normalizes f so that the highest bit of the mantissa is
|
||||
// set, and returns the number by which the mantissa was left-shifted.
|
||||
func (f *extFloat) Normalize() (shift uint) {
|
||||
mant, exp := f.mant, f.exp
|
||||
if mant == 0 {
|
||||
return 0
|
||||
}
|
||||
if mant>>(64-32) == 0 {
|
||||
mant <<= 32
|
||||
exp -= 32
|
||||
}
|
||||
if mant>>(64-16) == 0 {
|
||||
mant <<= 16
|
||||
exp -= 16
|
||||
}
|
||||
if mant>>(64-8) == 0 {
|
||||
mant <<= 8
|
||||
exp -= 8
|
||||
}
|
||||
if mant>>(64-4) == 0 {
|
||||
mant <<= 4
|
||||
exp -= 4
|
||||
}
|
||||
if mant>>(64-2) == 0 {
|
||||
mant <<= 2
|
||||
exp -= 2
|
||||
}
|
||||
if mant>>(64-1) == 0 {
|
||||
mant <<= 1
|
||||
exp -= 1
|
||||
}
|
||||
shift = uint(f.exp - exp)
|
||||
f.mant, f.exp = mant, exp
|
||||
return
|
||||
}
|
||||
|
||||
// Multiply sets f to the product f*g: the result is correctly rounded,
|
||||
// but not normalized.
|
||||
func (f *extFloat) Multiply(g extFloat) {
|
||||
fhi, flo := f.mant>>32, uint64(uint32(f.mant))
|
||||
ghi, glo := g.mant>>32, uint64(uint32(g.mant))
|
||||
|
||||
// Cross products.
|
||||
cross1 := fhi * glo
|
||||
cross2 := flo * ghi
|
||||
|
||||
// f.mant*g.mant is fhi*ghi << 64 + (cross1+cross2) << 32 + flo*glo
|
||||
f.mant = fhi*ghi + (cross1 >> 32) + (cross2 >> 32)
|
||||
rem := uint64(uint32(cross1)) + uint64(uint32(cross2)) + ((flo * glo) >> 32)
|
||||
// Round up.
|
||||
rem += (1 << 31)
|
||||
|
||||
f.mant += (rem >> 32)
|
||||
f.exp = f.exp + g.exp + 64
|
||||
}
|
||||
|
||||
var uint64pow10 = [...]uint64{
|
||||
1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
|
||||
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
|
||||
}
|
||||
|
||||
// AssignDecimal sets f to an approximate value mantissa*10^exp. It
|
||||
// returns true if the value represented by f is guaranteed to be the
|
||||
// best approximation of d after being rounded to a float64 or
|
||||
// float32 depending on flt.
|
||||
func (f *extFloat) AssignDecimal(mantissa uint64, exp10 int, neg bool, trunc bool, flt *floatInfo) (ok bool) {
|
||||
const uint64digits = 19
|
||||
const errorscale = 8
|
||||
errors := 0 // An upper bound for error, computed in errorscale*ulp.
|
||||
if trunc {
|
||||
// the decimal number was truncated.
|
||||
errors += errorscale / 2
|
||||
}
|
||||
|
||||
f.mant = mantissa
|
||||
f.exp = 0
|
||||
f.neg = neg
|
||||
|
||||
// Multiply by powers of ten.
|
||||
i := (exp10 - firstPowerOfTen) / stepPowerOfTen
|
||||
if exp10 < firstPowerOfTen || i >= len(powersOfTen) {
|
||||
return false
|
||||
}
|
||||
adjExp := (exp10 - firstPowerOfTen) % stepPowerOfTen
|
||||
|
||||
// We multiply by exp%step
|
||||
if adjExp < uint64digits && mantissa < uint64pow10[uint64digits-adjExp] {
|
||||
// We can multiply the mantissa exactly.
|
||||
f.mant *= uint64pow10[adjExp]
|
||||
f.Normalize()
|
||||
} else {
|
||||
f.Normalize()
|
||||
f.Multiply(smallPowersOfTen[adjExp])
|
||||
errors += errorscale / 2
|
||||
}
|
||||
|
||||
// We multiply by 10 to the exp - exp%step.
|
||||
f.Multiply(powersOfTen[i])
|
||||
if errors > 0 {
|
||||
errors += 1
|
||||
}
|
||||
errors += errorscale / 2
|
||||
|
||||
// Normalize
|
||||
shift := f.Normalize()
|
||||
errors <<= shift
|
||||
|
||||
// Now f is a good approximation of the decimal.
|
||||
// Check whether the error is too large: that is, if the mantissa
|
||||
// is perturbated by the error, the resulting float64 will change.
|
||||
// The 64 bits mantissa is 1 + 52 bits for float64 + 11 extra bits.
|
||||
//
|
||||
// In many cases the approximation will be good enough.
|
||||
denormalExp := flt.bias - 63
|
||||
var extrabits uint
|
||||
if f.exp <= denormalExp {
|
||||
// f.mant * 2^f.exp is smaller than 2^(flt.bias+1).
|
||||
extrabits = uint(63 - flt.mantbits + 1 + uint(denormalExp-f.exp))
|
||||
} else {
|
||||
extrabits = uint(63 - flt.mantbits)
|
||||
}
|
||||
|
||||
halfway := uint64(1) << (extrabits - 1)
|
||||
mant_extra := f.mant & (1<<extrabits - 1)
|
||||
|
||||
// Do a signed comparison here! If the error estimate could make
|
||||
// the mantissa round differently for the conversion to double,
|
||||
// then we can't give a definite answer.
|
||||
if int64(halfway)-int64(errors) < int64(mant_extra) &&
|
||||
int64(mant_extra) < int64(halfway)+int64(errors) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Frexp10 is an analogue of math.Frexp for decimal powers. It scales
|
||||
// f by an approximate power of ten 10^-exp, and returns exp10, so
|
||||
// that f*10^exp10 has the same value as the old f, up to an ulp,
|
||||
// as well as the index of 10^-exp in the powersOfTen table.
|
||||
func (f *extFloat) frexp10() (exp10, index int) {
|
||||
// The constants expMin and expMax constrain the final value of the
|
||||
// binary exponent of f. We want a small integral part in the result
|
||||
// because finding digits of an integer requires divisions, whereas
|
||||
// digits of the fractional part can be found by repeatedly multiplying
|
||||
// by 10.
|
||||
const expMin = -60
|
||||
const expMax = -32
|
||||
// Find power of ten such that x * 10^n has a binary exponent
|
||||
// between expMin and expMax.
|
||||
approxExp10 := ((expMin+expMax)/2 - f.exp) * 28 / 93 // log(10)/log(2) is close to 93/28.
|
||||
i := (approxExp10 - firstPowerOfTen) / stepPowerOfTen
|
||||
Loop:
|
||||
for {
|
||||
exp := f.exp + powersOfTen[i].exp + 64
|
||||
switch {
|
||||
case exp < expMin:
|
||||
i++
|
||||
case exp > expMax:
|
||||
i--
|
||||
default:
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
// Apply the desired decimal shift on f. It will have exponent
|
||||
// in the desired range. This is multiplication by 10^-exp10.
|
||||
f.Multiply(powersOfTen[i])
|
||||
|
||||
return -(firstPowerOfTen + i*stepPowerOfTen), i
|
||||
}
|
||||
|
||||
// frexp10Many applies a common shift by a power of ten to a, b, c.
|
||||
func frexp10Many(a, b, c *extFloat) (exp10 int) {
|
||||
exp10, i := c.frexp10()
|
||||
a.Multiply(powersOfTen[i])
|
||||
b.Multiply(powersOfTen[i])
|
||||
return
|
||||
}
|
||||
|
||||
// FixedDecimal stores in d the first n significant digits
|
||||
// of the decimal representation of f. It returns false
|
||||
// if it cannot be sure of the answer.
|
||||
func (f *extFloat) FixedDecimal(d *decimalSlice, n int) bool {
|
||||
if f.mant == 0 {
|
||||
d.nd = 0
|
||||
d.dp = 0
|
||||
d.neg = f.neg
|
||||
return true
|
||||
}
|
||||
if n == 0 {
|
||||
panic("strconv: internal error: extFloat.FixedDecimal called with n == 0")
|
||||
}
|
||||
// Multiply by an appropriate power of ten to have a reasonable
|
||||
// number to process.
|
||||
f.Normalize()
|
||||
exp10, _ := f.frexp10()
|
||||
|
||||
shift := uint(-f.exp)
|
||||
integer := uint32(f.mant >> shift)
|
||||
fraction := f.mant - (uint64(integer) << shift)
|
||||
ε := uint64(1) // ε is the uncertainty we have on the mantissa of f.
|
||||
|
||||
// Write exactly n digits to d.
|
||||
needed := n // how many digits are left to write.
|
||||
integerDigits := 0 // the number of decimal digits of integer.
|
||||
pow10 := uint64(1) // the power of ten by which f was scaled.
|
||||
for i, pow := 0, uint64(1); i < 20; i++ {
|
||||
if pow > uint64(integer) {
|
||||
integerDigits = i
|
||||
break
|
||||
}
|
||||
pow *= 10
|
||||
}
|
||||
rest := integer
|
||||
if integerDigits > needed {
|
||||
// the integral part is already large, trim the last digits.
|
||||
pow10 = uint64pow10[integerDigits-needed]
|
||||
integer /= uint32(pow10)
|
||||
rest -= integer * uint32(pow10)
|
||||
} else {
|
||||
rest = 0
|
||||
}
|
||||
|
||||
// Write the digits of integer: the digits of rest are omitted.
|
||||
var buf [32]byte
|
||||
pos := len(buf)
|
||||
for v := integer; v > 0; {
|
||||
v1 := v / 10
|
||||
v -= 10 * v1
|
||||
pos--
|
||||
buf[pos] = byte(v + '0')
|
||||
v = v1
|
||||
}
|
||||
for i := pos; i < len(buf); i++ {
|
||||
d.d[i-pos] = buf[i]
|
||||
}
|
||||
nd := len(buf) - pos
|
||||
d.nd = nd
|
||||
d.dp = integerDigits + exp10
|
||||
needed -= nd
|
||||
|
||||
if needed > 0 {
|
||||
if rest != 0 || pow10 != 1 {
|
||||
panic("strconv: internal error, rest != 0 but needed > 0")
|
||||
}
|
||||
// Emit digits for the fractional part. Each time, 10*fraction
|
||||
// fits in a uint64 without overflow.
|
||||
for needed > 0 {
|
||||
fraction *= 10
|
||||
ε *= 10 // the uncertainty scales as we multiply by ten.
|
||||
if 2*ε > 1<<shift {
|
||||
// the error is so large it could modify which digit to write, abort.
|
||||
return false
|
||||
}
|
||||
digit := fraction >> shift
|
||||
d.d[nd] = byte(digit + '0')
|
||||
fraction -= digit << shift
|
||||
nd++
|
||||
needed--
|
||||
}
|
||||
d.nd = nd
|
||||
}
|
||||
|
||||
// We have written a truncation of f (a numerator / 10^d.dp). The remaining part
|
||||
// can be interpreted as a small number (< 1) to be added to the last digit of the
|
||||
// numerator.
|
||||
//
|
||||
// If rest > 0, the amount is:
|
||||
// (rest<<shift | fraction) / (pow10 << shift)
|
||||
// fraction being known with a ±ε uncertainty.
|
||||
// The fact that n > 0 guarantees that pow10 << shift does not overflow a uint64.
|
||||
//
|
||||
// If rest = 0, pow10 == 1 and the amount is
|
||||
// fraction / (1 << shift)
|
||||
// fraction being known with a ±ε uncertainty.
|
||||
//
|
||||
// We pass this information to the rounding routine for adjustment.
|
||||
|
||||
ok := adjustLastDigitFixed(d, uint64(rest)<<shift|fraction, pow10, shift, ε)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
// Trim trailing zeros.
|
||||
for i := d.nd - 1; i >= 0; i-- {
|
||||
if d.d[i] != '0' {
|
||||
d.nd = i + 1
|
||||
break
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// adjustLastDigitFixed assumes d contains the representation of the integral part
|
||||
// of some number, whose fractional part is num / (den << shift). The numerator
|
||||
// num is only known up to an uncertainty of size ε, assumed to be less than
|
||||
// (den << shift)/2.
|
||||
//
|
||||
// It will increase the last digit by one to account for correct rounding, typically
|
||||
// when the fractional part is greater than 1/2, and will return false if ε is such
|
||||
// that no correct answer can be given.
|
||||
func adjustLastDigitFixed(d *decimalSlice, num, den uint64, shift uint, ε uint64) bool {
|
||||
if num > den<<shift {
|
||||
panic("strconv: num > den<<shift in adjustLastDigitFixed")
|
||||
}
|
||||
if 2*ε > den<<shift {
|
||||
panic("strconv: ε > (den<<shift)/2")
|
||||
}
|
||||
if 2*(num+ε) < den<<shift {
|
||||
return true
|
||||
}
|
||||
if 2*(num-ε) > den<<shift {
|
||||
// increment d by 1.
|
||||
i := d.nd - 1
|
||||
for ; i >= 0; i-- {
|
||||
if d.d[i] == '9' {
|
||||
d.nd--
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i < 0 {
|
||||
d.d[0] = '1'
|
||||
d.nd = 1
|
||||
d.dp++
|
||||
} else {
|
||||
d.d[i]++
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ShortestDecimal stores in d the shortest decimal representation of f
|
||||
// which belongs to the open interval (lower, upper), where f is supposed
|
||||
// to lie. It returns false whenever the result is unsure. The implementation
|
||||
// uses the Grisu3 algorithm.
|
||||
func (f *extFloat) ShortestDecimal(d *decimalSlice, lower, upper *extFloat) bool {
|
||||
if f.mant == 0 {
|
||||
d.nd = 0
|
||||
d.dp = 0
|
||||
d.neg = f.neg
|
||||
return true
|
||||
}
|
||||
if f.exp == 0 && *lower == *f && *lower == *upper {
|
||||
// an exact integer.
|
||||
var buf [24]byte
|
||||
n := len(buf) - 1
|
||||
for v := f.mant; v > 0; {
|
||||
v1 := v / 10
|
||||
v -= 10 * v1
|
||||
buf[n] = byte(v + '0')
|
||||
n--
|
||||
v = v1
|
||||
}
|
||||
nd := len(buf) - n - 1
|
||||
for i := 0; i < nd; i++ {
|
||||
d.d[i] = buf[n+1+i]
|
||||
}
|
||||
d.nd, d.dp = nd, nd
|
||||
for d.nd > 0 && d.d[d.nd-1] == '0' {
|
||||
d.nd--
|
||||
}
|
||||
if d.nd == 0 {
|
||||
d.dp = 0
|
||||
}
|
||||
d.neg = f.neg
|
||||
return true
|
||||
}
|
||||
upper.Normalize()
|
||||
// Uniformize exponents.
|
||||
if f.exp > upper.exp {
|
||||
f.mant <<= uint(f.exp - upper.exp)
|
||||
f.exp = upper.exp
|
||||
}
|
||||
if lower.exp > upper.exp {
|
||||
lower.mant <<= uint(lower.exp - upper.exp)
|
||||
lower.exp = upper.exp
|
||||
}
|
||||
|
||||
exp10 := frexp10Many(lower, f, upper)
|
||||
// Take a safety margin due to rounding in frexp10Many, but we lose precision.
|
||||
upper.mant++
|
||||
lower.mant--
|
||||
|
||||
// The shortest representation of f is either rounded up or down, but
|
||||
// in any case, it is a truncation of upper.
|
||||
shift := uint(-upper.exp)
|
||||
integer := uint32(upper.mant >> shift)
|
||||
fraction := upper.mant - (uint64(integer) << shift)
|
||||
|
||||
// How far we can go down from upper until the result is wrong.
|
||||
allowance := upper.mant - lower.mant
|
||||
// How far we should go to get a very precise result.
|
||||
targetDiff := upper.mant - f.mant
|
||||
|
||||
// Count integral digits: there are at most 10.
|
||||
var integerDigits int
|
||||
for i, pow := 0, uint64(1); i < 20; i++ {
|
||||
if pow > uint64(integer) {
|
||||
integerDigits = i
|
||||
break
|
||||
}
|
||||
pow *= 10
|
||||
}
|
||||
for i := 0; i < integerDigits; i++ {
|
||||
pow := uint64pow10[integerDigits-i-1]
|
||||
digit := integer / uint32(pow)
|
||||
d.d[i] = byte(digit + '0')
|
||||
integer -= digit * uint32(pow)
|
||||
// evaluate whether we should stop.
|
||||
if currentDiff := uint64(integer)<<shift + fraction; currentDiff < allowance {
|
||||
d.nd = i + 1
|
||||
d.dp = integerDigits + exp10
|
||||
d.neg = f.neg
|
||||
// Sometimes allowance is so large the last digit might need to be
|
||||
// decremented to get closer to f.
|
||||
return adjustLastDigit(d, currentDiff, targetDiff, allowance, pow<<shift, 2)
|
||||
}
|
||||
}
|
||||
d.nd = integerDigits
|
||||
d.dp = d.nd + exp10
|
||||
d.neg = f.neg
|
||||
|
||||
// Compute digits of the fractional part. At each step fraction does not
|
||||
// overflow. The choice of minExp implies that fraction is less than 2^60.
|
||||
var digit int
|
||||
multiplier := uint64(1)
|
||||
for {
|
||||
fraction *= 10
|
||||
multiplier *= 10
|
||||
digit = int(fraction >> shift)
|
||||
d.d[d.nd] = byte(digit + '0')
|
||||
d.nd++
|
||||
fraction -= uint64(digit) << shift
|
||||
if fraction < allowance*multiplier {
|
||||
// We are in the admissible range. Note that if allowance is about to
|
||||
// overflow, that is, allowance > 2^64/10, the condition is automatically
|
||||
// true due to the limited range of fraction.
|
||||
return adjustLastDigit(d,
|
||||
fraction, targetDiff*multiplier, allowance*multiplier,
|
||||
1<<shift, multiplier*2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adjustLastDigit modifies d = x-currentDiff*ε, to get closest to
|
||||
// d = x-targetDiff*ε, without becoming smaller than x-maxDiff*ε.
|
||||
// It assumes that a decimal digit is worth ulpDecimal*ε, and that
|
||||
// all data is known with a error estimate of ulpBinary*ε.
|
||||
func adjustLastDigit(d *decimalSlice, currentDiff, targetDiff, maxDiff, ulpDecimal, ulpBinary uint64) bool {
|
||||
if ulpDecimal < 2*ulpBinary {
|
||||
// Approximation is too wide.
|
||||
return false
|
||||
}
|
||||
for currentDiff+ulpDecimal/2+ulpBinary < targetDiff {
|
||||
d.d[d.nd-1]--
|
||||
currentDiff += ulpDecimal
|
||||
}
|
||||
if currentDiff+ulpDecimal <= targetDiff+ulpDecimal/2+ulpBinary {
|
||||
// we have two choices, and don't know what to do.
|
||||
return false
|
||||
}
|
||||
if currentDiff < ulpBinary || currentDiff > maxDiff-ulpBinary {
|
||||
// we went too far
|
||||
return false
|
||||
}
|
||||
if d.nd == 1 && d.d[0] == '0' {
|
||||
// the number has actually reached zero.
|
||||
d.nd = 0
|
||||
d.dp = 0
|
||||
}
|
||||
return true
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user