mirror of
https://github.com/kubernetes/node-problem-detector.git
synced 2026-03-02 09:40:29 +00:00
Merge pull request #773 from MartinForReal/shafan/boskos
Replace boskos client with the one in sigs.k8s.io/boskos
This commit is contained in:
21
go.mod
21
go.mod
@@ -5,7 +5,7 @@ go 1.20
|
||||
require (
|
||||
cloud.google.com/go/compute/metadata v0.2.3
|
||||
code.cloudfoundry.org/clock v1.1.0
|
||||
contrib.go.opencensus.io/exporter/prometheus v0.0.0-20190427222117-f6cda26f80a3
|
||||
contrib.go.opencensus.io/exporter/prometheus v0.1.0
|
||||
contrib.go.opencensus.io/exporter/stackdriver v0.13.4
|
||||
github.com/acobaugh/osrelease v0.1.0
|
||||
github.com/avast/retry-go v3.0.0+incompatible
|
||||
@@ -28,12 +28,12 @@ require (
|
||||
golang.org/x/oauth2 v0.9.0
|
||||
golang.org/x/sys v0.9.0
|
||||
google.golang.org/api v0.114.0
|
||||
k8s.io/api v0.17.2
|
||||
k8s.io/apimachinery v0.17.2
|
||||
k8s.io/api v0.17.3
|
||||
k8s.io/apimachinery v0.17.3
|
||||
k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible
|
||||
k8s.io/component-base v0.17.2
|
||||
k8s.io/klog v1.0.0
|
||||
k8s.io/test-infra v0.0.0-20190914015041-e1cbc3ccd91c
|
||||
sigs.k8s.io/boskos v0.0.0-20200515170311-7d36bde8cdf6
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -54,14 +54,14 @@ require (
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/gofuzz v1.0.0 // indirect
|
||||
github.com/google/gofuzz v1.1.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.8.0 // indirect
|
||||
github.com/googleapis/gnostic v0.3.1 // indirect
|
||||
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce // indirect
|
||||
github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874 // indirect
|
||||
github.com/imdario/mergo v0.3.7 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.0.0 // indirect
|
||||
github.com/imdario/mergo v0.3.8 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
|
||||
@@ -94,8 +94,9 @@ require (
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a // indirect
|
||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect
|
||||
sigs.k8s.io/yaml v1.1.0 // indirect
|
||||
k8s.io/test-infra v0.0.0-20200514184223-ba32c8aae783 // indirect
|
||||
k8s.io/utils v0.0.0-20200122174043-1e243dd1a584 // indirect
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
|
||||
"k8s.io/node-problem-detector/pkg/util/tomb"
|
||||
"k8s.io/node-problem-detector/test/e2e/lib/gce"
|
||||
"k8s.io/test-infra/boskos/client"
|
||||
"sigs.k8s.io/boskos/client"
|
||||
|
||||
"github.com/onsi/ginkgo"
|
||||
"github.com/onsi/ginkgo/config"
|
||||
@@ -101,7 +101,9 @@ func rentBoskosProjectIfNeededOnNode1() []byte {
|
||||
}
|
||||
|
||||
fmt.Printf("Renting project from Boskos\n")
|
||||
boskosClient = client.NewClient(*jobName, *boskosServerURL)
|
||||
var err error
|
||||
boskosClient, err = client.NewClient(*jobName, *boskosServerURL, "", "")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
boskosRenewingTomb = tomb.NewTomb()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), *boskosWaitDuration)
|
||||
|
||||
2
vendor/github.com/google/gofuzz/README.md
generated
vendored
2
vendor/github.com/google/gofuzz/README.md
generated
vendored
@@ -3,7 +3,7 @@ gofuzz
|
||||
|
||||
gofuzz is a library for populating go objects with random values.
|
||||
|
||||
[](https://godoc.org/github.com/google/gofuzz)
|
||||
[](https://godoc.org/github.com/google/gofuzz)
|
||||
[](https://travis-ci.org/google/gofuzz)
|
||||
|
||||
This is useful for testing:
|
||||
|
||||
35
vendor/github.com/google/gofuzz/fuzz.go
generated
vendored
35
vendor/github.com/google/gofuzz/fuzz.go
generated
vendored
@@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -28,13 +29,14 @@ type fuzzFuncMap map[reflect.Type]reflect.Value
|
||||
|
||||
// Fuzzer knows how to fill any object with random fields.
|
||||
type Fuzzer struct {
|
||||
fuzzFuncs fuzzFuncMap
|
||||
defaultFuzzFuncs fuzzFuncMap
|
||||
r *rand.Rand
|
||||
nilChance float64
|
||||
minElements int
|
||||
maxElements int
|
||||
maxDepth int
|
||||
fuzzFuncs fuzzFuncMap
|
||||
defaultFuzzFuncs fuzzFuncMap
|
||||
r *rand.Rand
|
||||
nilChance float64
|
||||
minElements int
|
||||
maxElements int
|
||||
maxDepth int
|
||||
skipFieldPatterns []*regexp.Regexp
|
||||
}
|
||||
|
||||
// New returns a new Fuzzer. Customize your Fuzzer further by calling Funcs,
|
||||
@@ -150,6 +152,13 @@ func (f *Fuzzer) MaxDepth(d int) *Fuzzer {
|
||||
return f
|
||||
}
|
||||
|
||||
// Skip fields which match the supplied pattern. Call this multiple times if needed
|
||||
// This is useful to skip XXX_ fields generated by protobuf
|
||||
func (f *Fuzzer) SkipFieldsWithPattern(pattern *regexp.Regexp) *Fuzzer {
|
||||
f.skipFieldPatterns = append(f.skipFieldPatterns, pattern)
|
||||
return f
|
||||
}
|
||||
|
||||
// Fuzz recursively fills all of obj's fields with something random. First
|
||||
// this tries to find a custom fuzz function (see Funcs). If there is no
|
||||
// custom function this tests whether the object implements fuzz.Interface and,
|
||||
@@ -274,7 +283,17 @@ func (fc *fuzzerContext) doFuzz(v reflect.Value, flags uint64) {
|
||||
v.Set(reflect.Zero(v.Type()))
|
||||
case reflect.Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
fc.doFuzz(v.Field(i), 0)
|
||||
skipField := false
|
||||
fieldName := v.Type().Field(i).Name
|
||||
for _, pattern := range fc.fuzzer.skipFieldPatterns {
|
||||
if pattern.MatchString(fieldName) {
|
||||
skipField = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !skipField {
|
||||
fc.doFuzz(v.Field(i), 0)
|
||||
}
|
||||
}
|
||||
case reflect.Chan:
|
||||
fallthrough
|
||||
|
||||
2
vendor/github.com/hashicorp/errwrap/README.md
generated
vendored
2
vendor/github.com/hashicorp/errwrap/README.md
generated
vendored
@@ -48,7 +48,7 @@ func main() {
|
||||
// We can use the Contains helpers to check if an error contains
|
||||
// another error. It is safe to do this with a nil error, or with
|
||||
// an error that doesn't even use the errwrap package.
|
||||
if errwrap.Contains(err, ErrNotExist) {
|
||||
if errwrap.Contains(err, "does not exist") {
|
||||
// Do something
|
||||
}
|
||||
if errwrap.ContainsType(err, new(os.PathError)) {
|
||||
|
||||
6
vendor/github.com/hashicorp/go-multierror/format.go
generated
vendored
6
vendor/github.com/hashicorp/go-multierror/format.go
generated
vendored
@@ -13,7 +13,7 @@ type ErrorFormatFunc func([]error) string
|
||||
// that occurred along with a bullet point list of the errors.
|
||||
func ListFormatFunc(es []error) string {
|
||||
if len(es) == 1 {
|
||||
return fmt.Sprintf("1 error occurred:\n\n* %s", es[0])
|
||||
return fmt.Sprintf("1 error occurred:\n\t* %s\n\n", es[0])
|
||||
}
|
||||
|
||||
points := make([]string, len(es))
|
||||
@@ -22,6 +22,6 @@ func ListFormatFunc(es []error) string {
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"%d errors occurred:\n\n%s",
|
||||
len(es), strings.Join(points, "\n"))
|
||||
"%d errors occurred:\n\t%s\n\n",
|
||||
len(es), strings.Join(points, "\n\t"))
|
||||
}
|
||||
|
||||
16
vendor/github.com/hashicorp/go-multierror/sort.go
generated
vendored
Normal file
16
vendor/github.com/hashicorp/go-multierror/sort.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package multierror
|
||||
|
||||
// Len implements sort.Interface function for length
|
||||
func (err Error) Len() int {
|
||||
return len(err.Errors)
|
||||
}
|
||||
|
||||
// Swap implements sort.Interface function for swapping elements
|
||||
func (err Error) Swap(i, j int) {
|
||||
err.Errors[i], err.Errors[j] = err.Errors[j], err.Errors[i]
|
||||
}
|
||||
|
||||
// Less implements sort.Interface function for determining order
|
||||
func (err Error) Less(i, j int) bool {
|
||||
return err.Errors[i].Error() < err.Errors[j].Error()
|
||||
}
|
||||
2
vendor/github.com/imdario/mergo/.travis.yml
generated
vendored
2
vendor/github.com/imdario/mergo/.travis.yml
generated
vendored
@@ -4,4 +4,6 @@ install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
script:
|
||||
- go test -race -v ./...
|
||||
after_script:
|
||||
- $HOME/gopath/bin/goveralls -service=travis-ci -repotoken $COVERALLS_TOKEN
|
||||
|
||||
50
vendor/github.com/imdario/mergo/merge.go
generated
vendored
50
vendor/github.com/imdario/mergo/merge.go
generated
vendored
@@ -26,10 +26,12 @@ func hasExportedField(dst reflect.Value) (exported bool) {
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Overwrite bool
|
||||
AppendSlice bool
|
||||
Transformers Transformers
|
||||
overwriteWithEmptyValue bool
|
||||
Overwrite bool
|
||||
AppendSlice bool
|
||||
TypeCheck bool
|
||||
Transformers Transformers
|
||||
overwriteWithEmptyValue bool
|
||||
overwriteSliceWithEmptyValue bool
|
||||
}
|
||||
|
||||
type Transformers interface {
|
||||
@@ -41,7 +43,9 @@ type Transformers interface {
|
||||
// short circuiting on recursive types.
|
||||
func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
|
||||
overwrite := config.Overwrite
|
||||
typeCheck := config.TypeCheck
|
||||
overwriteWithEmptySrc := config.overwriteWithEmptyValue
|
||||
overwriteSliceWithEmptySrc := config.overwriteSliceWithEmptyValue
|
||||
config.overwriteWithEmptyValue = false
|
||||
|
||||
if !src.IsValid() {
|
||||
@@ -128,11 +132,14 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
|
||||
dstSlice = reflect.ValueOf(dstElement.Interface())
|
||||
}
|
||||
|
||||
if (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
|
||||
if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
|
||||
if typeCheck && srcSlice.Type() != dstSlice.Type() {
|
||||
return fmt.Errorf("cannot override two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
|
||||
}
|
||||
dstSlice = srcSlice
|
||||
} else if config.AppendSlice {
|
||||
if srcSlice.Type() != dstSlice.Type() {
|
||||
return fmt.Errorf("cannot append two slice with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
|
||||
return fmt.Errorf("cannot append two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
|
||||
}
|
||||
dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
|
||||
}
|
||||
@@ -143,7 +150,7 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
|
||||
continue
|
||||
}
|
||||
|
||||
if srcElement.IsValid() && (overwrite || (!dstElement.IsValid() || isEmptyValue(dstElement))) {
|
||||
if srcElement.IsValid() && ((srcElement.Kind() != reflect.Ptr && overwrite) || !dstElement.IsValid() || isEmptyValue(dstElement)) {
|
||||
if dst.IsNil() {
|
||||
dst.Set(reflect.MakeMap(dst.Type()))
|
||||
}
|
||||
@@ -154,7 +161,7 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
|
||||
if !dst.CanSet() {
|
||||
break
|
||||
}
|
||||
if (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
|
||||
if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
|
||||
dst.Set(src)
|
||||
} else if config.AppendSlice {
|
||||
if src.Type() != dst.Type() {
|
||||
@@ -168,11 +175,21 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
|
||||
if src.IsNil() {
|
||||
break
|
||||
}
|
||||
if src.Kind() != reflect.Interface {
|
||||
|
||||
if dst.Kind() != reflect.Ptr && src.Type().AssignableTo(dst.Type()) {
|
||||
if dst.IsNil() || overwrite {
|
||||
if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
|
||||
dst.Set(src)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if src.Kind() != reflect.Interface {
|
||||
if dst.IsNil() || (src.Kind() != reflect.Ptr && overwrite) {
|
||||
if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
|
||||
dst.Set(src)
|
||||
}
|
||||
} else if src.Kind() == reflect.Ptr {
|
||||
if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
|
||||
return
|
||||
@@ -198,6 +215,7 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
|
||||
dst.Set(src)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -209,7 +227,7 @@ func Merge(dst, src interface{}, opts ...func(*Config)) error {
|
||||
return merge(dst, src, opts...)
|
||||
}
|
||||
|
||||
// MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overriden by
|
||||
// MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overridden by
|
||||
// non-empty src attribute values.
|
||||
// Deprecated: use Merge(…) with WithOverride
|
||||
func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
|
||||
@@ -228,11 +246,21 @@ func WithOverride(config *Config) {
|
||||
config.Overwrite = true
|
||||
}
|
||||
|
||||
// WithAppendSlice will make merge append slices instead of overwriting it
|
||||
// WithOverride will make merge override empty dst slice with empty src slice.
|
||||
func WithOverrideEmptySlice(config *Config) {
|
||||
config.overwriteSliceWithEmptyValue = true
|
||||
}
|
||||
|
||||
// WithAppendSlice will make merge append slices instead of overwriting it.
|
||||
func WithAppendSlice(config *Config) {
|
||||
config.AppendSlice = true
|
||||
}
|
||||
|
||||
// WithTypeCheck will make merge check types while overwriting it (must be used with WithOverride).
|
||||
func WithTypeCheck(config *Config) {
|
||||
config.TypeCheck = true
|
||||
}
|
||||
|
||||
func merge(dst, src interface{}, opts ...func(*Config)) error {
|
||||
var (
|
||||
vDst, vSrc reflect.Value
|
||||
|
||||
42
vendor/k8s.io/test-infra/prow/config/secret/BUILD.bazel
generated
vendored
Normal file
42
vendor/k8s.io/test-infra/prow/config/secret/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"agent.go",
|
||||
"secret.go",
|
||||
],
|
||||
importpath = "k8s.io/test-infra/prow/config/secret",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//prow/logrusutil:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/util/sets: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"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["agent_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//prow/logrusutil:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
],
|
||||
)
|
||||
152
vendor/k8s.io/test-infra/prow/config/secret/agent.go
generated
vendored
Normal file
152
vendor/k8s.io/test-infra/prow/config/secret/agent.go
generated
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes 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 secret implements an agent to read and reload the secrets.
|
||||
package secret
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
|
||||
"k8s.io/test-infra/prow/logrusutil"
|
||||
)
|
||||
|
||||
// Agent watches a path and automatically loads the secrets stored.
|
||||
type Agent struct {
|
||||
sync.RWMutex
|
||||
secretsMap map[string][]byte
|
||||
}
|
||||
|
||||
// Start creates goroutines to monitor the files that contain the secret value.
|
||||
// Additionally, Start wraps the current standard logger formatter with a
|
||||
// censoring formatter that removes secret occurrences from the logs.
|
||||
func (a *Agent) Start(paths []string) error {
|
||||
secretsMap, err := LoadSecrets(paths)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.secretsMap = secretsMap
|
||||
|
||||
// Start one goroutine for each file to monitor and update the secret's values.
|
||||
for secretPath := range secretsMap {
|
||||
go a.reloadSecret(secretPath)
|
||||
}
|
||||
|
||||
logrus.SetFormatter(logrusutil.NewCensoringFormatter(logrus.StandardLogger().Formatter, a.getSecrets))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add registers a new path to the agent.
|
||||
func (a *Agent) Add(path string) error {
|
||||
secret, err := LoadSingleSecret(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.setSecret(path, secret)
|
||||
|
||||
// Start one goroutine for each file to monitor and update the secret's values.
|
||||
go a.reloadSecret(path)
|
||||
return nil
|
||||
}
|
||||
|
||||
// reloadSecret will begin polling the secret file at the path. If the first load
|
||||
// fails, Start with return the error and abort. Future load failures will log
|
||||
// the failure message but continue attempting to load.
|
||||
func (a *Agent) reloadSecret(secretPath string) {
|
||||
var lastModTime time.Time
|
||||
logger := logrus.NewEntry(logrus.StandardLogger())
|
||||
|
||||
skips := 0
|
||||
for range time.Tick(1 * time.Second) {
|
||||
if skips < 600 {
|
||||
// Check if the file changed to see if it needs to be re-read.
|
||||
secretStat, err := os.Stat(secretPath)
|
||||
if err != nil {
|
||||
logger.WithField("secret-path", secretPath).
|
||||
WithError(err).Error("Error loading secret file.")
|
||||
continue
|
||||
}
|
||||
|
||||
recentModTime := secretStat.ModTime()
|
||||
if !recentModTime.After(lastModTime) {
|
||||
skips++
|
||||
continue // file hasn't been modified
|
||||
}
|
||||
lastModTime = recentModTime
|
||||
}
|
||||
|
||||
if secretValue, err := LoadSingleSecret(secretPath); err != nil {
|
||||
logger.WithField("secret-path: ", secretPath).
|
||||
WithError(err).Error("Error loading secret.")
|
||||
} else {
|
||||
a.setSecret(secretPath, secretValue)
|
||||
skips = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetSecret returns the value of a secret stored in a map.
|
||||
func (a *Agent) GetSecret(secretPath string) []byte {
|
||||
a.RLock()
|
||||
defer a.RUnlock()
|
||||
return a.secretsMap[secretPath]
|
||||
}
|
||||
|
||||
// setSecret sets a value in a map of secrets.
|
||||
func (a *Agent) setSecret(secretPath string, secretValue []byte) {
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
a.secretsMap[secretPath] = secretValue
|
||||
}
|
||||
|
||||
// GetTokenGenerator returns a function that gets the value of a given secret.
|
||||
func (a *Agent) GetTokenGenerator(secretPath string) func() []byte {
|
||||
return func() []byte {
|
||||
return a.GetSecret(secretPath)
|
||||
}
|
||||
}
|
||||
|
||||
const censored = "CENSORED"
|
||||
|
||||
var censoredBytes = []byte(censored)
|
||||
|
||||
// Censor replaces sensitive parts of the content with a placeholder.
|
||||
func (a *Agent) Censor(content []byte) []byte {
|
||||
for sKey := range a.secretsMap {
|
||||
secret := a.GetSecret(sKey)
|
||||
content = bytes.ReplaceAll(content, secret, censoredBytes)
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
func (a *Agent) getSecrets() sets.String {
|
||||
a.RLock()
|
||||
defer a.RUnlock()
|
||||
secrets := sets.NewString()
|
||||
for _, v := range a.secretsMap {
|
||||
secrets.Insert(string(v))
|
||||
}
|
||||
return secrets
|
||||
}
|
||||
46
vendor/k8s.io/test-infra/prow/config/secret/secret.go
generated
vendored
Normal file
46
vendor/k8s.io/test-infra/prow/config/secret/secret.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes 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 secret
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// LoadSecrets loads multiple paths of secrets and add them in a map.
|
||||
func LoadSecrets(paths []string) (map[string][]byte, error) {
|
||||
secretsMap := make(map[string][]byte, len(paths))
|
||||
|
||||
for _, path := range paths {
|
||||
secretValue, err := LoadSingleSecret(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secretsMap[path] = secretValue
|
||||
}
|
||||
return secretsMap, nil
|
||||
}
|
||||
|
||||
// LoadSingleSecret reads and returns the value of a single file.
|
||||
func LoadSingleSecret(path string) ([]byte, error) {
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading %s: %v", path, err)
|
||||
}
|
||||
return bytes.TrimSpace(b), nil
|
||||
}
|
||||
37
vendor/k8s.io/test-infra/prow/logrusutil/BUILD.bazel
generated
vendored
Normal file
37
vendor/k8s.io/test-infra/prow/logrusutil/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["logrusutil.go"],
|
||||
importpath = "k8s.io/test-infra/prow/logrusutil",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//prow/version:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/util/sets: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"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["logrusutil_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/util/sets:go_default_library",
|
||||
],
|
||||
)
|
||||
129
vendor/k8s.io/test-infra/prow/logrusutil/logrusutil.go
generated
vendored
Normal file
129
vendor/k8s.io/test-infra/prow/logrusutil/logrusutil.go
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes 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 logrusutil implements some helpers for using logrus
|
||||
package logrusutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
|
||||
"k8s.io/test-infra/prow/version"
|
||||
)
|
||||
|
||||
// DefaultFieldsFormatter wraps another logrus.Formatter, injecting
|
||||
// DefaultFields into each Format() call, existing fields are preserved
|
||||
// if they have the same key
|
||||
type DefaultFieldsFormatter struct {
|
||||
WrappedFormatter logrus.Formatter
|
||||
DefaultFields logrus.Fields
|
||||
PrintLineNumber bool
|
||||
}
|
||||
|
||||
// Init set Logrus formatter
|
||||
// if DefaultFieldsFormatter.wrappedFormatter is nil &logrus.JSONFormatter{} will be used instead
|
||||
func Init(formatter *DefaultFieldsFormatter) {
|
||||
if formatter == nil {
|
||||
return
|
||||
}
|
||||
if formatter.WrappedFormatter == nil {
|
||||
formatter.WrappedFormatter = &logrus.JSONFormatter{}
|
||||
}
|
||||
logrus.SetFormatter(formatter)
|
||||
logrus.SetReportCaller(formatter.PrintLineNumber)
|
||||
}
|
||||
|
||||
// ComponentInit is a syntax sugar for easier Init
|
||||
func ComponentInit() {
|
||||
Init(
|
||||
&DefaultFieldsFormatter{
|
||||
PrintLineNumber: true,
|
||||
DefaultFields: logrus.Fields{"component": version.Name},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// Format implements logrus.Formatter's Format. We allocate a new Fields
|
||||
// map in order to not modify the caller's Entry, as that is not a thread
|
||||
// safe operation.
|
||||
func (f *DefaultFieldsFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||
data := make(logrus.Fields, len(entry.Data)+len(f.DefaultFields))
|
||||
for k, v := range f.DefaultFields {
|
||||
data[k] = v
|
||||
}
|
||||
for k, v := range entry.Data {
|
||||
data[k] = v
|
||||
}
|
||||
return f.WrappedFormatter.Format(&logrus.Entry{
|
||||
Logger: entry.Logger,
|
||||
Data: data,
|
||||
Time: entry.Time,
|
||||
Level: entry.Level,
|
||||
Message: entry.Message,
|
||||
Caller: entry.Caller,
|
||||
})
|
||||
}
|
||||
|
||||
// CensoringFormatter represents a logrus formatter that
|
||||
// can be used to censor sensitive information
|
||||
type CensoringFormatter struct {
|
||||
delegate logrus.Formatter
|
||||
getSecrets func() sets.String
|
||||
}
|
||||
|
||||
func (f CensoringFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||
raw, err := f.delegate.Format(entry)
|
||||
if err != nil {
|
||||
return raw, err
|
||||
}
|
||||
return f.censor(raw), nil
|
||||
}
|
||||
|
||||
const censored = "CENSORED"
|
||||
|
||||
var (
|
||||
censoredBytes = []byte(censored)
|
||||
standardLog = logrus.NewEntry(logrus.StandardLogger())
|
||||
)
|
||||
|
||||
// Censor replaces sensitive parts of the content with a placeholder.
|
||||
func (f CensoringFormatter) censor(content []byte) []byte {
|
||||
for _, secret := range f.getSecrets().List() {
|
||||
trimmedSecret := strings.TrimSpace(secret)
|
||||
if trimmedSecret != secret {
|
||||
standardLog.Warning("Secret is not trimmed")
|
||||
secret = trimmedSecret
|
||||
}
|
||||
if secret == "" {
|
||||
standardLog.Warning("Secret is an empty string, ignoring")
|
||||
continue
|
||||
}
|
||||
content = bytes.ReplaceAll(content, []byte(secret), censoredBytes)
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
// NewCensoringFormatter generates a `CensoringFormatter` with
|
||||
// a formatter as delegate and a set of strings to censor
|
||||
func NewCensoringFormatter(f logrus.Formatter, getSecrets func() sets.String) CensoringFormatter {
|
||||
return CensoringFormatter{
|
||||
getSecrets: getSecrets,
|
||||
delegate: f,
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,10 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["storage.go"],
|
||||
importpath = "k8s.io/test-infra/boskos/storage",
|
||||
srcs = ["doc.go"],
|
||||
importpath = "k8s.io/test-infra/prow/version",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//boskos/common:go_default_library"],
|
||||
x_defs = {"Version": "{DOCKER_TAG}"},
|
||||
)
|
||||
|
||||
filegroup(
|
||||
36
vendor/k8s.io/test-infra/prow/version/doc.go
generated
vendored
Normal file
36
vendor/k8s.io/test-infra/prow/version/doc.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Copyright 2020 The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// version holds variables that identify a Prow binary's name and version
|
||||
package version
|
||||
|
||||
var (
|
||||
// Name is the colloquial identifier for the compiled component
|
||||
Name = "unset"
|
||||
// Version is a concatenation of the commit SHA and date for the build
|
||||
Version = "0"
|
||||
)
|
||||
|
||||
// UserAgent exposes the component's name and version for user-agent header
|
||||
func UserAgent() string {
|
||||
return Name + "/" + Version
|
||||
}
|
||||
|
||||
// UserAgentFor exposes the component's name and version for user-agent header
|
||||
// while embedding the additional identifier
|
||||
func UserAgentWithIdentifier(identifier string) string {
|
||||
return Name + "." + identifier + "/" + Version
|
||||
}
|
||||
45
vendor/k8s.io/utils/inotify/inotify.go
generated
vendored
45
vendor/k8s.io/utils/inotify/inotify.go
generated
vendored
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Kubernetes 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 inotify // import "k8s.io/utils/inotify"
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Event represents a notification
|
||||
type Event struct {
|
||||
Mask uint32 // Mask of events
|
||||
Cookie uint32 // Unique cookie associating related events (for rename(2))
|
||||
Name string // File name (optional)
|
||||
}
|
||||
|
||||
type watch struct {
|
||||
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
|
||||
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
|
||||
}
|
||||
|
||||
// Watcher represents an inotify instance
|
||||
type Watcher struct {
|
||||
mu sync.Mutex
|
||||
fd int // File descriptor (as returned by the inotify_init() syscall)
|
||||
watches map[string]*watch // Map of inotify watches (key: path)
|
||||
paths map[int]string // Map of watched paths (key: watch descriptor)
|
||||
Error chan error // Errors are sent on this channel
|
||||
Event chan *Event // Events are returned on this channel
|
||||
done chan bool // Channel for sending a "quit message" to the reader goroutine
|
||||
isClosed bool // Set to true when Close() is first called
|
||||
}
|
||||
33
vendor/k8s.io/utils/inotify/inotify_linux.go
generated
vendored
33
vendor/k8s.io/utils/inotify/inotify_linux.go
generated
vendored
@@ -1,5 +1,3 @@
|
||||
// +build linux
|
||||
|
||||
// Copyright 2010 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.
|
||||
@@ -33,10 +31,35 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Event represents a notification
|
||||
type Event struct {
|
||||
Mask uint32 // Mask of events
|
||||
Cookie uint32 // Unique cookie associating related events (for rename(2))
|
||||
Name string // File name (optional)
|
||||
}
|
||||
|
||||
type watch struct {
|
||||
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
|
||||
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
|
||||
}
|
||||
|
||||
// Watcher represents an inotify instance
|
||||
type Watcher struct {
|
||||
mu sync.Mutex
|
||||
fd int // File descriptor (as returned by the inotify_init() syscall)
|
||||
watches map[string]*watch // Map of inotify watches (key: path)
|
||||
paths map[int]string // Map of watched paths (key: watch descriptor)
|
||||
Error chan error // Errors are sent on this channel
|
||||
Event chan *Event // Events are returned on this channel
|
||||
done chan bool // Channel for sending a "quit message" to the reader goroutine
|
||||
isClosed bool // Set to true when Close() is first called
|
||||
}
|
||||
|
||||
// NewWatcher creates and returns a new inotify instance using inotify_init(2)
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
fd, errno := syscall.InotifyInit1(syscall.IN_CLOEXEC)
|
||||
@@ -120,11 +143,7 @@ func (w *Watcher) RemoveWatch(path string) error {
|
||||
}
|
||||
success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
|
||||
if success == -1 {
|
||||
// when file descriptor or watch descriptor not found, InotifyRmWatch syscall return EINVAL error
|
||||
// if return error, it may lead this path remain in watches and paths map, and no other event can trigger remove action.
|
||||
if errno != syscall.EINVAL {
|
||||
return os.NewSyscallError("inotify_rm_watch", errno)
|
||||
}
|
||||
return os.NewSyscallError("inotify_rm_watch", errno)
|
||||
}
|
||||
delete(w.watches, path)
|
||||
// Locking here to protect the read from paths in readEvents.
|
||||
|
||||
54
vendor/k8s.io/utils/inotify/inotify_others.go
generated
vendored
54
vendor/k8s.io/utils/inotify/inotify_others.go
generated
vendored
@@ -1,54 +0,0 @@
|
||||
// +build !linux
|
||||
|
||||
/*
|
||||
Copyright 2020 The Kubernetes 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 inotify // import "k8s.io/utils/inotify"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var errNotSupported = fmt.Errorf("watch not supported on %s", runtime.GOOS)
|
||||
|
||||
// NewWatcher creates and returns a new inotify instance using inotify_init(2)
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
return nil, errNotSupported
|
||||
}
|
||||
|
||||
// Close closes an inotify watcher instance
|
||||
// It sends a message to the reader goroutine to quit and removes all watches
|
||||
// associated with the inotify instance
|
||||
func (w *Watcher) Close() error {
|
||||
return errNotSupported
|
||||
}
|
||||
|
||||
// AddWatch adds path to the watched file set.
|
||||
// The flags are interpreted as described in inotify_add_watch(2).
|
||||
func (w *Watcher) AddWatch(path string, flags uint32) error {
|
||||
return errNotSupported
|
||||
}
|
||||
|
||||
// Watch adds path to the watched file set, watching all events.
|
||||
func (w *Watcher) Watch(path string) error {
|
||||
return errNotSupported
|
||||
}
|
||||
|
||||
// RemoveWatch removes path from the watched file set.
|
||||
func (w *Watcher) RemoveWatch(path string) error {
|
||||
return errNotSupported
|
||||
}
|
||||
33
vendor/modules.txt
vendored
33
vendor/modules.txt
vendored
@@ -23,7 +23,7 @@ cloud.google.com/go/trace/internal
|
||||
## explicit; go 1.20
|
||||
code.cloudfoundry.org/clock
|
||||
code.cloudfoundry.org/clock/fakeclock
|
||||
# contrib.go.opencensus.io/exporter/prometheus v0.0.0-20190427222117-f6cda26f80a3
|
||||
# contrib.go.opencensus.io/exporter/prometheus v0.1.0
|
||||
## explicit
|
||||
contrib.go.opencensus.io/exporter/prometheus
|
||||
# contrib.go.opencensus.io/exporter/stackdriver v0.13.4
|
||||
@@ -140,7 +140,7 @@ github.com/google/go-cmp/cmp/internal/diff
|
||||
github.com/google/go-cmp/cmp/internal/flags
|
||||
github.com/google/go-cmp/cmp/internal/function
|
||||
github.com/google/go-cmp/cmp/internal/value
|
||||
# github.com/google/gofuzz v1.0.0
|
||||
# github.com/google/gofuzz v1.1.0
|
||||
## explicit; go 1.12
|
||||
github.com/google/gofuzz
|
||||
# github.com/google/uuid v1.3.0
|
||||
@@ -161,10 +161,10 @@ github.com/googleapis/gax-go/v2/internal
|
||||
github.com/googleapis/gnostic/OpenAPIv2
|
||||
github.com/googleapis/gnostic/compiler
|
||||
github.com/googleapis/gnostic/extensions
|
||||
# github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce
|
||||
# github.com/hashicorp/errwrap v1.0.0
|
||||
## explicit
|
||||
github.com/hashicorp/errwrap
|
||||
# github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874
|
||||
# github.com/hashicorp/go-multierror v1.0.0
|
||||
## explicit
|
||||
github.com/hashicorp/go-multierror
|
||||
# github.com/hpcloud/tail v1.0.0
|
||||
@@ -174,7 +174,7 @@ github.com/hpcloud/tail/ratelimiter
|
||||
github.com/hpcloud/tail/util
|
||||
github.com/hpcloud/tail/watch
|
||||
github.com/hpcloud/tail/winfile
|
||||
# github.com/imdario/mergo v0.3.7
|
||||
# github.com/imdario/mergo v0.3.8
|
||||
## explicit
|
||||
github.com/imdario/mergo
|
||||
# github.com/jmespath/go-jmespath v0.4.0
|
||||
@@ -564,7 +564,7 @@ gopkg.in/yaml.v2
|
||||
# gopkg.in/yaml.v3 v3.0.1
|
||||
## explicit
|
||||
gopkg.in/yaml.v3
|
||||
# k8s.io/api v0.17.2 => k8s.io/api v0.17.2
|
||||
# k8s.io/api v0.17.3 => k8s.io/api v0.17.2
|
||||
## explicit; go 1.12
|
||||
k8s.io/api/admissionregistration/v1
|
||||
k8s.io/api/admissionregistration/v1beta1
|
||||
@@ -606,7 +606,7 @@ k8s.io/api/settings/v1alpha1
|
||||
k8s.io/api/storage/v1
|
||||
k8s.io/api/storage/v1alpha1
|
||||
k8s.io/api/storage/v1beta1
|
||||
# k8s.io/apimachinery v0.17.2 => k8s.io/apimachinery v0.17.2
|
||||
# k8s.io/apimachinery v0.17.3 => k8s.io/apimachinery v0.17.2
|
||||
## explicit; go 1.12
|
||||
k8s.io/apimachinery/pkg/api/errors
|
||||
k8s.io/apimachinery/pkg/api/meta
|
||||
@@ -724,17 +724,22 @@ k8s.io/klog
|
||||
# k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
|
||||
## explicit; go 1.12
|
||||
k8s.io/kube-openapi/pkg/util/proto
|
||||
# k8s.io/test-infra v0.0.0-20190914015041-e1cbc3ccd91c
|
||||
# k8s.io/test-infra v0.0.0-20200514184223-ba32c8aae783
|
||||
## explicit; go 1.13
|
||||
k8s.io/test-infra/boskos/client
|
||||
k8s.io/test-infra/boskos/common
|
||||
k8s.io/test-infra/boskos/storage
|
||||
# k8s.io/utils v0.0.0-20211116205334-6203023598ed
|
||||
k8s.io/test-infra/prow/config/secret
|
||||
k8s.io/test-infra/prow/logrusutil
|
||||
k8s.io/test-infra/prow/version
|
||||
# k8s.io/utils v0.0.0-20200122174043-1e243dd1a584
|
||||
## explicit; go 1.12
|
||||
k8s.io/utils/inotify
|
||||
k8s.io/utils/integer
|
||||
# sigs.k8s.io/yaml v1.1.0
|
||||
## explicit
|
||||
# sigs.k8s.io/boskos v0.0.0-20200515170311-7d36bde8cdf6
|
||||
## explicit; go 1.14
|
||||
sigs.k8s.io/boskos/client
|
||||
sigs.k8s.io/boskos/common
|
||||
sigs.k8s.io/boskos/storage
|
||||
# sigs.k8s.io/yaml v1.2.0
|
||||
## explicit; go 1.12
|
||||
sigs.k8s.io/yaml
|
||||
# k8s.io/api => k8s.io/api v0.17.2
|
||||
# k8s.io/apimachinery => k8s.io/apimachinery v0.17.2
|
||||
|
||||
201
vendor/sigs.k8s.io/boskos/LICENSE
generated
vendored
Normal file
201
vendor/sigs.k8s.io/boskos/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.
|
||||
@@ -20,9 +20,11 @@ go_library(
|
||||
deps = [
|
||||
"//boskos/common:go_default_library",
|
||||
"//boskos/storage:go_default_library",
|
||||
"//prow/config/secret:go_default_library",
|
||||
"@com_github_google_uuid//:go_default_library",
|
||||
"@com_github_hashicorp_go_multierror//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/util/errors:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -33,12 +33,14 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/test-infra/boskos/common"
|
||||
"k8s.io/test-infra/boskos/storage"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
|
||||
"k8s.io/test-infra/prow/config/secret"
|
||||
"sigs.k8s.io/boskos/common"
|
||||
"sigs.k8s.io/boskos/storage"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -60,9 +62,11 @@ type Client struct {
|
||||
// http is the http.Client used to interact with the boskos REST API
|
||||
http http.Client
|
||||
|
||||
owner string
|
||||
url string
|
||||
lock sync.Mutex
|
||||
owner string
|
||||
url string
|
||||
username string
|
||||
getPassword func() []byte
|
||||
lock sync.Mutex
|
||||
|
||||
storage storage.PersistenceLayer
|
||||
}
|
||||
@@ -71,12 +75,37 @@ type Client struct {
|
||||
//
|
||||
// Clients created with this function default to retrying failed connection
|
||||
// attempts three times with a ten second pause between each attempt.
|
||||
func NewClient(owner string, url string) *Client {
|
||||
func NewClient(owner string, urlString, username, passwordFile string) (*Client, error) {
|
||||
|
||||
if (username == "") != (passwordFile == "") {
|
||||
return nil, fmt.Errorf("username and passwordFile must be specified together")
|
||||
}
|
||||
|
||||
var getPassword func() []byte
|
||||
if passwordFile != "" {
|
||||
u, err := url.Parse(urlString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if u.Scheme != "https" {
|
||||
// returning error here would make the tests hard
|
||||
// we print out a warning message here instead
|
||||
fmt.Printf("[WARNING] should NOT use password without enabling TLS: '%s'\n", urlString)
|
||||
}
|
||||
|
||||
sa := &secret.Agent{}
|
||||
if err := sa.Start([]string{passwordFile}); err != nil {
|
||||
logrus.WithError(err).Fatal("Failed to start secrets agent")
|
||||
}
|
||||
getPassword = sa.GetTokenGenerator(passwordFile)
|
||||
}
|
||||
|
||||
client := &Client{
|
||||
url: url,
|
||||
owner: owner,
|
||||
storage: storage.NewMemoryStorage(),
|
||||
url: urlString,
|
||||
username: username,
|
||||
getPassword: getPassword,
|
||||
owner: owner,
|
||||
storage: storage.NewMemoryStorage(),
|
||||
}
|
||||
|
||||
// Configure the dialer to attempt three additional times to establish
|
||||
@@ -104,7 +133,7 @@ func NewClient(owner string, url string) *Client {
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
}
|
||||
|
||||
return client
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// public method
|
||||
@@ -220,8 +249,8 @@ func (c *Client) ReleaseAll(dest string) error {
|
||||
}
|
||||
var allErrors error
|
||||
for _, r := range resources {
|
||||
c.storage.Delete(r.GetName())
|
||||
err := c.Release(r.GetName(), dest)
|
||||
c.storage.Delete(r.Name)
|
||||
err := c.Release(r.Name, dest)
|
||||
if err != nil {
|
||||
allErrors = multierror.Append(allErrors, err)
|
||||
}
|
||||
@@ -258,7 +287,7 @@ func (c *Client) UpdateAll(state string) error {
|
||||
}
|
||||
var allErrors error
|
||||
for _, r := range resources {
|
||||
if err := c.Update(r.GetName(), state, nil); err != nil {
|
||||
if err := c.Update(r.Name, state, nil); err != nil {
|
||||
allErrors = multierror.Append(allErrors, err)
|
||||
continue
|
||||
}
|
||||
@@ -283,12 +312,7 @@ func (c *Client) SyncAll() error {
|
||||
return nil
|
||||
}
|
||||
var allErrors error
|
||||
for _, i := range resources {
|
||||
r, err := common.ItemToResource(i)
|
||||
if err != nil {
|
||||
allErrors = multierror.Append(allErrors, err)
|
||||
continue
|
||||
}
|
||||
for _, r := range resources {
|
||||
if err := c.Update(r.Name, r.State, nil); err != nil {
|
||||
allErrors = multierror.Append(allErrors, err)
|
||||
continue
|
||||
@@ -309,7 +333,7 @@ func (c *Client) UpdateOne(name, state string, userData *common.UserData) error
|
||||
if err != nil {
|
||||
return fmt.Errorf("no resource name %v", name)
|
||||
}
|
||||
if err := c.Update(r.GetName(), state, userData); err != nil {
|
||||
if err := c.Update(r.Name, state, userData); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.updateLocalResource(r, state, userData)
|
||||
@@ -335,18 +359,14 @@ func (c *Client) HasResource() bool {
|
||||
|
||||
// private methods
|
||||
|
||||
func (c *Client) updateLocalResource(i common.Item, state string, data *common.UserData) error {
|
||||
res, err := common.ItemToResource(i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func (c *Client) updateLocalResource(res common.Resource, state string, data *common.UserData) error {
|
||||
res.State = state
|
||||
if res.UserData == nil {
|
||||
res.UserData = data
|
||||
} else {
|
||||
res.UserData.Update(data)
|
||||
}
|
||||
_, err = c.storage.Update(res)
|
||||
_, err := c.storage.Update(res)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -359,34 +379,45 @@ func (c *Client) acquire(rtype, state, dest, requestID string) (*common.Resource
|
||||
if requestID != "" {
|
||||
values.Set("request_id", requestID)
|
||||
}
|
||||
resp, err := c.httpPost("/acquire", values, "", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
switch resp.StatusCode {
|
||||
case http.StatusOK:
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := common.Resource{}
|
||||
|
||||
res := common.Resource{}
|
||||
err = json.Unmarshal(body, &res)
|
||||
work := func(retriedErrs *[]error) (bool, error) {
|
||||
resp, err := c.httpPost("/acquire", values, "", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Swallow the error so we can retry
|
||||
*retriedErrs = append(*retriedErrs, err)
|
||||
return false, nil
|
||||
}
|
||||
if res.Name == "" {
|
||||
return nil, fmt.Errorf("unable to parse resource")
|
||||
defer resp.Body.Close()
|
||||
|
||||
switch resp.StatusCode {
|
||||
case http.StatusOK:
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(body, &res)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if res.Name == "" {
|
||||
return false, fmt.Errorf("unable to parse resource")
|
||||
}
|
||||
return true, nil
|
||||
case http.StatusUnauthorized:
|
||||
return false, ErrAlreadyInUse
|
||||
case http.StatusNotFound:
|
||||
return false, ErrNotFound
|
||||
default:
|
||||
*retriedErrs = append(*retriedErrs, fmt.Errorf("status %s, status code %v", resp.Status, resp.StatusCode))
|
||||
// Swallow it so we can retry
|
||||
return false, nil
|
||||
}
|
||||
return &res, nil
|
||||
case http.StatusUnauthorized:
|
||||
return nil, ErrAlreadyInUse
|
||||
case http.StatusNotFound:
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
return nil, fmt.Errorf("status %s, status code %v", resp.Status, resp.StatusCode)
|
||||
|
||||
return &res, retry(work)
|
||||
}
|
||||
|
||||
func (c *Client) acquireByState(state, dest string, names []string) ([]common.Resource, error) {
|
||||
@@ -395,25 +426,33 @@ func (c *Client) acquireByState(state, dest string, names []string) ([]common.Re
|
||||
values.Set("dest", dest)
|
||||
values.Set("names", strings.Join(names, ","))
|
||||
values.Set("owner", c.owner)
|
||||
resp, err := c.httpPost("/acquirebystate", values, "", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var resources []common.Resource
|
||||
|
||||
switch resp.StatusCode {
|
||||
case http.StatusOK:
|
||||
var resources []common.Resource
|
||||
if err := json.NewDecoder(resp.Body).Decode(&resources); err != nil {
|
||||
return nil, err
|
||||
work := func(retriedErrs *[]error) (bool, error) {
|
||||
resp, err := c.httpPost("/acquirebystate", values, "", nil)
|
||||
if err != nil {
|
||||
*retriedErrs = append(*retriedErrs, err)
|
||||
return false, nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
switch resp.StatusCode {
|
||||
case http.StatusOK:
|
||||
if err := json.NewDecoder(resp.Body).Decode(&resources); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
case http.StatusUnauthorized:
|
||||
return false, ErrAlreadyInUse
|
||||
case http.StatusNotFound:
|
||||
return false, ErrNotFound
|
||||
default:
|
||||
*retriedErrs = append(*retriedErrs, fmt.Errorf("status %s, status code %v", resp.Status, resp.StatusCode))
|
||||
return false, nil
|
||||
}
|
||||
return resources, nil
|
||||
case http.StatusUnauthorized:
|
||||
return nil, ErrAlreadyInUse
|
||||
case http.StatusNotFound:
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
return nil, fmt.Errorf("status %s, status code %v", resp.Status, resp.StatusCode)
|
||||
|
||||
return resources, retry(work)
|
||||
}
|
||||
|
||||
// Release a lease for a resource and set its state to the destination state
|
||||
@@ -422,43 +461,62 @@ func (c *Client) Release(name, dest string) error {
|
||||
values.Set("name", name)
|
||||
values.Set("dest", dest)
|
||||
values.Set("owner", c.owner)
|
||||
resp, err := c.httpPost("/release", values, "", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("status %s, statusCode %v releasing %s", resp.Status, resp.StatusCode, name)
|
||||
work := func(retriedErrs *[]error) (bool, error) {
|
||||
resp, err := c.httpPost("/release", values, "", nil)
|
||||
if err != nil {
|
||||
*retriedErrs = append(*retriedErrs, err)
|
||||
return false, nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
*retriedErrs = append(*retriedErrs, fmt.Errorf("status %s, statusCode %v releasing %s", resp.Status, resp.StatusCode, name))
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
return nil
|
||||
|
||||
return retry(work)
|
||||
}
|
||||
|
||||
// Update a resource on the server, setting the state and user data
|
||||
func (c *Client) Update(name, state string, userData *common.UserData) error {
|
||||
var body io.Reader
|
||||
var bodyData *bytes.Buffer
|
||||
if userData != nil {
|
||||
b := new(bytes.Buffer)
|
||||
err := json.NewEncoder(b).Encode(userData)
|
||||
bodyData = new(bytes.Buffer)
|
||||
err := json.NewEncoder(bodyData).Encode(userData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
body = b
|
||||
}
|
||||
values := url.Values{}
|
||||
values.Set("name", name)
|
||||
values.Set("owner", c.owner)
|
||||
values.Set("state", state)
|
||||
resp, err := c.httpPost("/update", values, "application/json", body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("status %s, status code %v updating %s", resp.Status, resp.StatusCode, name)
|
||||
work := func(retriedErrs *[]error) (bool, error) {
|
||||
// As the body is an io.Reader and hence its content
|
||||
// can only be read once, we have to copy it for every request we make
|
||||
var body io.Reader
|
||||
if bodyData != nil {
|
||||
body = bytes.NewReader(bodyData.Bytes())
|
||||
}
|
||||
resp, err := c.httpPost("/update", values, "application/json", body)
|
||||
if err != nil {
|
||||
*retriedErrs = append(*retriedErrs, err)
|
||||
return false, nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
*retriedErrs = append(*retriedErrs, fmt.Errorf("status %s, status code %v updating %s", resp.Status, resp.StatusCode, name))
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
return nil
|
||||
|
||||
return retry(work)
|
||||
}
|
||||
|
||||
func (c *Client) reset(rtype, state string, expire time.Duration, dest string) (map[string]string, error) {
|
||||
@@ -468,46 +526,59 @@ func (c *Client) reset(rtype, state string, expire time.Duration, dest string) (
|
||||
values.Set("state", state)
|
||||
values.Set("expire", expire.String())
|
||||
values.Set("dest", dest)
|
||||
resp, err := c.httpPost("/reset", values, "", nil)
|
||||
if err != nil {
|
||||
return rmap, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
work := func(retriedErrs *[]error) (bool, error) {
|
||||
resp, err := c.httpPost("/reset", values, "", nil)
|
||||
if err != nil {
|
||||
return rmap, err
|
||||
*retriedErrs = append(*retriedErrs, err)
|
||||
return false, nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(body, &rmap)
|
||||
return true, err
|
||||
}
|
||||
*retriedErrs = append(*retriedErrs, fmt.Errorf("status %s, status code %v", resp.Status, resp.StatusCode))
|
||||
return false, nil
|
||||
|
||||
err = json.Unmarshal(body, &rmap)
|
||||
return rmap, err
|
||||
}
|
||||
|
||||
return rmap, fmt.Errorf("status %s, status code %v", resp.Status, resp.StatusCode)
|
||||
return rmap, retry(work)
|
||||
}
|
||||
|
||||
func (c *Client) metric(rtype string) (common.Metric, error) {
|
||||
var metric common.Metric
|
||||
values := url.Values{}
|
||||
values.Set("type", rtype)
|
||||
resp, err := c.httpGet("/metric", values)
|
||||
if err != nil {
|
||||
return metric, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return metric, fmt.Errorf("status %s, status code %v", resp.Status, resp.StatusCode)
|
||||
work := func(retriedErrs *[]error) (bool, error) {
|
||||
resp, err := c.httpGet("/metric", values)
|
||||
if err != nil {
|
||||
*retriedErrs = append(*retriedErrs, err)
|
||||
return false, nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
*retriedErrs = append(*retriedErrs, fmt.Errorf("status %s, status code %v", resp.Status, resp.StatusCode))
|
||||
return false, nil
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, json.Unmarshal(body, &metric)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return metric, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(body, &metric)
|
||||
return metric, err
|
||||
return metric, retry(work)
|
||||
}
|
||||
|
||||
func (c *Client) httpGet(action string, values url.Values) (*http.Response, error) {
|
||||
@@ -518,6 +589,9 @@ func (c *Client) httpGet(action string, values url.Values) (*http.Response, erro
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c.username != "" && c.getPassword != nil {
|
||||
req.SetBasicAuth(c.username, string(c.getPassword()))
|
||||
}
|
||||
return c.http.Do(req)
|
||||
}
|
||||
|
||||
@@ -529,6 +603,9 @@ func (c *Client) httpPost(action string, values url.Values, contentType string,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c.username != "" && c.getPassword != nil {
|
||||
req.SetBasicAuth(c.username, string(c.getPassword()))
|
||||
}
|
||||
if contentType != "" {
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
}
|
||||
@@ -606,3 +683,34 @@ func isDialErrorRetriable(err error) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// workFunc describes retrieable work. It should
|
||||
// * Return an error for non-recoverable errors
|
||||
// * Write retriable errors into `retriedErrs` and return with false, nil
|
||||
// * Return with true, nil on success
|
||||
type workFunc func(retriedErrs *[]error) (bool, error)
|
||||
|
||||
// SleepFunc is called when requests are retried. This may be replaced in tests.
|
||||
var SleepFunc = time.Sleep
|
||||
|
||||
func retry(work workFunc) error {
|
||||
var retriedErrs []error
|
||||
|
||||
maxAttempts := 4
|
||||
for i := 1; i <= maxAttempts; i++ {
|
||||
success, err := work(&retriedErrs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if success {
|
||||
return nil
|
||||
}
|
||||
if i == maxAttempts {
|
||||
break
|
||||
}
|
||||
|
||||
SleepFunc(time.Duration(i*i) * time.Second)
|
||||
}
|
||||
|
||||
return utilerrors.NewAggregate(retriedErrs)
|
||||
}
|
||||
@@ -41,6 +41,5 @@ filegroup(
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["common_test.go"],
|
||||
data = ["//boskos:testdata"],
|
||||
embed = [":go_default_library"],
|
||||
)
|
||||
@@ -30,12 +30,12 @@ import (
|
||||
const (
|
||||
// Busy state defines a resource being used.
|
||||
Busy = "busy"
|
||||
// Cleaning state defines a resource being cleaned
|
||||
Cleaning = "cleaning"
|
||||
// Dirty state defines a resource that needs cleaning
|
||||
Dirty = "dirty"
|
||||
// Free state defines a resource that is usable
|
||||
Free = "free"
|
||||
// Cleaning state defines a resource being cleaned
|
||||
Cleaning = "cleaning"
|
||||
// Leased state defines a resource being leased in order to make a new resource
|
||||
Leased = "leased"
|
||||
// ToBeDeleted is used for resources about to be deleted, they will be verified by a cleaner which mark them as tombstone
|
||||
@@ -46,6 +46,19 @@ const (
|
||||
Other = "other"
|
||||
)
|
||||
|
||||
var (
|
||||
// KnownStates is the set of all known states, excluding "other".
|
||||
KnownStates = []string{
|
||||
Busy,
|
||||
Cleaning,
|
||||
Dirty,
|
||||
Free,
|
||||
Leased,
|
||||
ToBeDeleted,
|
||||
Tombstone,
|
||||
}
|
||||
)
|
||||
|
||||
// UserData is a map of Name to user defined interface, serialized into a string
|
||||
type UserData struct {
|
||||
sync.Map
|
||||
@@ -57,11 +70,6 @@ type UserDataMap map[string]string
|
||||
// LeasedResources is a list of resources name that used in order to create another resource by Mason
|
||||
type LeasedResources []string
|
||||
|
||||
// Item interfaces for resources and configs
|
||||
type Item interface {
|
||||
GetName() string
|
||||
}
|
||||
|
||||
// Duration is a wrapper around time.Duration that parses times in either
|
||||
// 'integer number of nanoseconds' or 'duration string' formats and serializes
|
||||
// to 'duration string' format.
|
||||
@@ -133,9 +141,13 @@ type Metric struct {
|
||||
// TODO: implements state transition metrics
|
||||
}
|
||||
|
||||
// IsInUse reports if the resource is owned by anything else than Boskos.
|
||||
func (r *Resource) IsInUse() bool {
|
||||
return r.Owner != ""
|
||||
// NewMetric returns a new Metric struct.
|
||||
func NewMetric(rtype string) Metric {
|
||||
return Metric{
|
||||
Type: rtype,
|
||||
Current: map[string]int{},
|
||||
Owners: map[string]int{},
|
||||
}
|
||||
}
|
||||
|
||||
// NewResource creates a new Boskos Resource.
|
||||
@@ -150,7 +162,6 @@ func NewResource(name, rtype, state, owner string, t time.Time) Resource {
|
||||
State: state,
|
||||
Owner: owner,
|
||||
LastUpdate: t,
|
||||
UserData: &UserData{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,42 +192,12 @@ func (ud *UserDataNotFound) Error() string {
|
||||
return fmt.Sprintf("user data ID %s does not exist", ud.ID)
|
||||
}
|
||||
|
||||
// ResourceByUpdateTime helps sorting resources by update time
|
||||
type ResourceByUpdateTime []Resource
|
||||
|
||||
func (ut ResourceByUpdateTime) Len() int { return len(ut) }
|
||||
func (ut ResourceByUpdateTime) Swap(i, j int) { ut[i], ut[j] = ut[j], ut[i] }
|
||||
func (ut ResourceByUpdateTime) Less(i, j int) bool { return ut[i].LastUpdate.Before(ut[j].LastUpdate) }
|
||||
|
||||
// ResourceByName helps sorting resources by name
|
||||
type ResourceByName []Resource
|
||||
|
||||
func (ut ResourceByName) Len() int { return len(ut) }
|
||||
func (ut ResourceByName) Swap(i, j int) { ut[i], ut[j] = ut[j], ut[i] }
|
||||
func (ut ResourceByName) Less(i, j int) bool { return ut[i].GetName() < ut[j].GetName() }
|
||||
|
||||
// ResourceByDeleteState helps sorting resources by state, putting Tombstone first, then ToBeDeleted,
|
||||
// and sorting alphabetacally by resource name
|
||||
type ResourceByDeleteState []Resource
|
||||
|
||||
func (ut ResourceByDeleteState) Len() int { return len(ut) }
|
||||
func (ut ResourceByDeleteState) Swap(i, j int) { ut[i], ut[j] = ut[j], ut[i] }
|
||||
func (ut ResourceByDeleteState) Less(i, j int) bool {
|
||||
order := map[string]int{Tombstone: 0, ToBeDeleted: 1}
|
||||
stateIndex := func(s string) int {
|
||||
i, ok := order[s]
|
||||
if ok {
|
||||
return i
|
||||
}
|
||||
return 2
|
||||
}
|
||||
indexI := stateIndex(ut[i].State)
|
||||
indexJ := stateIndex(ut[i].State)
|
||||
if indexI == indexJ {
|
||||
return ut[i].GetName() < ut[j].GetName()
|
||||
}
|
||||
return indexI < indexJ
|
||||
}
|
||||
func (ut ResourceByName) Less(i, j int) bool { return ut[i].Name < ut[j].Name }
|
||||
|
||||
// CommaSeparatedStrings is used to parse comma separated string flag into a list of strings
|
||||
type CommaSeparatedStrings []string
|
||||
@@ -240,9 +221,6 @@ func (r *CommaSeparatedStrings) Type() string {
|
||||
return "commaSeparatedStrings"
|
||||
}
|
||||
|
||||
// GetName implements the Item interface used for storage
|
||||
func (res Resource) GetName() string { return res.Name }
|
||||
|
||||
// UnmarshalJSON implements JSON Unmarshaler interface
|
||||
func (ud *UserData) UnmarshalJSON(data []byte) error {
|
||||
tmpMap := UserDataMap{}
|
||||
@@ -313,12 +291,3 @@ func (ud *UserData) FromMap(m UserDataMap) {
|
||||
ud.Store(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// ItemToResource casts a Item back to a Resource
|
||||
func ItemToResource(i Item) (Resource, error) {
|
||||
res, ok := i.(Resource)
|
||||
if !ok {
|
||||
return Resource{}, fmt.Errorf("cannot construct Resource from received object %v", i)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
@@ -17,7 +17,6 @@ limitations under the License.
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
@@ -43,9 +42,12 @@ type DynamicResourceLifeCycle struct {
|
||||
Type string `json:"type"`
|
||||
// Initial state to be created as
|
||||
InitialState string `json:"state"`
|
||||
// Minimum Number of resources to be use a buffer
|
||||
// Minimum number of resources to be use as a buffer.
|
||||
// Resources in the process of being deleted and cleaned up are included in this count.
|
||||
MinCount int `json:"min-count"`
|
||||
// Maximum resources expected
|
||||
// Maximum number of resources expected. This maximum may be temporarily
|
||||
// exceeded while resources are in the process of being deleted, though this
|
||||
// is only expected when MaxCount is lowered.
|
||||
MaxCount int `json:"max-count"`
|
||||
// Lifespan of a resource, time after which the resource should be reset.
|
||||
LifeSpan *time.Duration `json:"lifespan,omitempty"`
|
||||
@@ -60,10 +62,7 @@ type DRLCByName []DynamicResourceLifeCycle
|
||||
|
||||
func (ut DRLCByName) Len() int { return len(ut) }
|
||||
func (ut DRLCByName) Swap(i, j int) { ut[i], ut[j] = ut[j], ut[i] }
|
||||
func (ut DRLCByName) Less(i, j int) bool { return ut[i].GetName() < ut[j].GetName() }
|
||||
|
||||
// GetName implements the Item interface used for storage
|
||||
func (res DynamicResourceLifeCycle) GetName() string { return res.Type }
|
||||
func (ut DRLCByName) Less(i, j int) bool { return ut[i].Type < ut[j].Type }
|
||||
|
||||
// NewDynamicResourceLifeCycleFromConfig parse the a ResourceEntry into a DynamicResourceLifeCycle
|
||||
func NewDynamicResourceLifeCycleFromConfig(e ResourceEntry) DynamicResourceLifeCycle {
|
||||
@@ -82,12 +81,6 @@ func NewDynamicResourceLifeCycleFromConfig(e ResourceEntry) DynamicResourceLifeC
|
||||
}
|
||||
}
|
||||
|
||||
// NewResourceFromNewDynamicResourceLifeCycle creates a resource from DynamicResourceLifeCycle given a name and a time.
|
||||
// Using this method helps make sure all the resources are created the same way.
|
||||
func NewResourceFromNewDynamicResourceLifeCycle(name string, dlrc *DynamicResourceLifeCycle, now time.Time) Resource {
|
||||
return NewResource(name, dlrc.Type, dlrc.InitialState, "", now)
|
||||
}
|
||||
|
||||
// Copy returns a copy of the TypeToResources
|
||||
func (t TypeToResources) Copy() TypeToResources {
|
||||
n := TypeToResources{}
|
||||
@@ -97,15 +90,6 @@ func (t TypeToResources) Copy() TypeToResources {
|
||||
return n
|
||||
}
|
||||
|
||||
// ItemToDynamicResourceLifeCycle casts a Item back to a Resource
|
||||
func ItemToDynamicResourceLifeCycle(i Item) (DynamicResourceLifeCycle, error) {
|
||||
res, ok := i.(DynamicResourceLifeCycle)
|
||||
if !ok {
|
||||
return DynamicResourceLifeCycle{}, fmt.Errorf("cannot construct Resource from received object %v", i)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GenerateDynamicResourceName generates a unique name for dynamic resources
|
||||
func GenerateDynamicResourceName() string {
|
||||
return uuid.New().String()
|
||||
30
vendor/sigs.k8s.io/boskos/storage/BUILD.bazel
generated
vendored
Normal file
30
vendor/sigs.k8s.io/boskos/storage/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["storage.go"],
|
||||
importpath = "k8s.io/test-infra/boskos/storage",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//boskos/common:go_default_library"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["storage_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = ["//boskos/common: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"],
|
||||
)
|
||||
@@ -21,79 +21,79 @@ import (
|
||||
|
||||
"fmt"
|
||||
|
||||
"k8s.io/test-infra/boskos/common"
|
||||
"sigs.k8s.io/boskos/common"
|
||||
)
|
||||
|
||||
// PersistenceLayer defines a simple interface to persists Boskos Information
|
||||
type PersistenceLayer interface {
|
||||
Add(i common.Item) error
|
||||
Add(r common.Resource) error
|
||||
Delete(name string) error
|
||||
Update(i common.Item) (common.Item, error)
|
||||
Get(name string) (common.Item, error)
|
||||
List() ([]common.Item, error)
|
||||
Update(r common.Resource) (common.Resource, error)
|
||||
Get(name string) (common.Resource, error)
|
||||
List() ([]common.Resource, error)
|
||||
}
|
||||
|
||||
type inMemoryStore struct {
|
||||
items map[string]common.Item
|
||||
lock sync.RWMutex
|
||||
resources map[string]common.Resource
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// NewMemoryStorage creates an in memory persistence layer
|
||||
func NewMemoryStorage() PersistenceLayer {
|
||||
return &inMemoryStore{
|
||||
items: map[string]common.Item{},
|
||||
resources: map[string]common.Resource{},
|
||||
}
|
||||
}
|
||||
|
||||
func (im *inMemoryStore) Add(i common.Item) error {
|
||||
func (im *inMemoryStore) Add(r common.Resource) error {
|
||||
im.lock.Lock()
|
||||
defer im.lock.Unlock()
|
||||
_, ok := im.items[i.GetName()]
|
||||
_, ok := im.resources[r.Name]
|
||||
if ok {
|
||||
return fmt.Errorf("item %s already exists", i.GetName())
|
||||
return fmt.Errorf("resource %s already exists", r.Name)
|
||||
}
|
||||
im.items[i.GetName()] = i
|
||||
im.resources[r.Name] = r
|
||||
return nil
|
||||
}
|
||||
|
||||
func (im *inMemoryStore) Delete(name string) error {
|
||||
im.lock.Lock()
|
||||
defer im.lock.Unlock()
|
||||
_, ok := im.items[name]
|
||||
_, ok := im.resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("cannot find item %s", name)
|
||||
}
|
||||
delete(im.items, name)
|
||||
delete(im.resources, name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (im *inMemoryStore) Update(i common.Item) (common.Item, error) {
|
||||
func (im *inMemoryStore) Update(r common.Resource) (common.Resource, error) {
|
||||
im.lock.Lock()
|
||||
defer im.lock.Unlock()
|
||||
_, ok := im.items[i.GetName()]
|
||||
_, ok := im.resources[r.Name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot find item %s", i.GetName())
|
||||
return common.Resource{}, fmt.Errorf("cannot find item %s", r.Name)
|
||||
}
|
||||
im.items[i.GetName()] = i
|
||||
return i, nil
|
||||
im.resources[r.Name] = r
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (im *inMemoryStore) Get(name string) (common.Item, error) {
|
||||
func (im *inMemoryStore) Get(name string) (common.Resource, error) {
|
||||
im.lock.RLock()
|
||||
defer im.lock.RUnlock()
|
||||
i, ok := im.items[name]
|
||||
r, ok := im.resources[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot find item %s", name)
|
||||
return common.Resource{}, fmt.Errorf("cannot find item %s", name)
|
||||
}
|
||||
return i, nil
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (im *inMemoryStore) List() ([]common.Item, error) {
|
||||
func (im *inMemoryStore) List() ([]common.Resource, error) {
|
||||
im.lock.RLock()
|
||||
defer im.lock.RUnlock()
|
||||
var items []common.Item
|
||||
for _, i := range im.items {
|
||||
items = append(items, i)
|
||||
var resources []common.Resource
|
||||
for _, r := range im.resources {
|
||||
resources = append(resources, r)
|
||||
}
|
||||
return items, nil
|
||||
return resources, nil
|
||||
}
|
||||
15
vendor/sigs.k8s.io/yaml/.travis.yml
generated
vendored
15
vendor/sigs.k8s.io/yaml/.travis.yml
generated
vendored
@@ -1,14 +1,13 @@
|
||||
language: go
|
||||
dist: xenial
|
||||
go:
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
script:
|
||||
- go get -t -v ./...
|
||||
- diff -u <(echo -n) <(gofmt -d .)
|
||||
- diff -u <(echo -n) <(gofmt -d *.go)
|
||||
- diff -u <(echo -n) <(golint $(go list -e ./...) | grep -v YAMLToJSON)
|
||||
- go tool vet .
|
||||
- go test -v -race ./...
|
||||
- GO111MODULE=on go vet .
|
||||
- GO111MODULE=on go test -v -race ./...
|
||||
- git diff --exit-code
|
||||
install:
|
||||
- go get golang.org/x/lint/golint
|
||||
- GO111MODULE=off go get golang.org/x/lint/golint
|
||||
|
||||
2
vendor/sigs.k8s.io/yaml/OWNERS
generated
vendored
2
vendor/sigs.k8s.io/yaml/OWNERS
generated
vendored
@@ -1,3 +1,5 @@
|
||||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
approvers:
|
||||
- dims
|
||||
- lavalamp
|
||||
|
||||
14
vendor/sigs.k8s.io/yaml/README.md
generated
vendored
14
vendor/sigs.k8s.io/yaml/README.md
generated
vendored
@@ -1,12 +1,14 @@
|
||||
# YAML marshaling and unmarshaling support for Go
|
||||
|
||||
[](https://travis-ci.org/ghodss/yaml)
|
||||
[](https://travis-ci.org/kubernetes-sigs/yaml)
|
||||
|
||||
kubernetes-sigs/yaml is a permanent fork of [ghodss/yaml](https://github.com/ghodss/yaml).
|
||||
|
||||
## Introduction
|
||||
|
||||
A wrapper around [go-yaml](https://github.com/go-yaml/yaml) designed to enable a better way of handling YAML when marshaling to and from structs.
|
||||
|
||||
In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/).
|
||||
In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://web.archive.org/web/20190603050330/http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/).
|
||||
|
||||
## Compatibility
|
||||
|
||||
@@ -32,13 +34,13 @@ GOOD:
|
||||
To install, run:
|
||||
|
||||
```
|
||||
$ go get github.com/ghodss/yaml
|
||||
$ go get sigs.k8s.io/yaml
|
||||
```
|
||||
|
||||
And import using:
|
||||
|
||||
```
|
||||
import "github.com/ghodss/yaml"
|
||||
import "sigs.k8s.io/yaml"
|
||||
```
|
||||
|
||||
Usage is very similar to the JSON library:
|
||||
@@ -49,7 +51,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type Person struct {
|
||||
@@ -93,7 +95,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
61
vendor/sigs.k8s.io/yaml/yaml.go
generated
vendored
61
vendor/sigs.k8s.io/yaml/yaml.go
generated
vendored
@@ -317,3 +317,64 @@ func convertToJSONableObject(yamlObj interface{}, jsonTarget *reflect.Value) (in
|
||||
return yamlObj, nil
|
||||
}
|
||||
}
|
||||
|
||||
// JSONObjectToYAMLObject converts an in-memory JSON object into a YAML in-memory MapSlice,
|
||||
// without going through a byte representation. A nil or empty map[string]interface{} input is
|
||||
// converted to an empty map, i.e. yaml.MapSlice(nil).
|
||||
//
|
||||
// interface{} slices stay interface{} slices. map[string]interface{} becomes yaml.MapSlice.
|
||||
//
|
||||
// int64 and float64 are down casted following the logic of github.com/go-yaml/yaml:
|
||||
// - float64s are down-casted as far as possible without data-loss to int, int64, uint64.
|
||||
// - int64s are down-casted to int if possible without data-loss.
|
||||
//
|
||||
// Big int/int64/uint64 do not lose precision as in the json-yaml roundtripping case.
|
||||
//
|
||||
// string, bool and any other types are unchanged.
|
||||
func JSONObjectToYAMLObject(j map[string]interface{}) yaml.MapSlice {
|
||||
if len(j) == 0 {
|
||||
return nil
|
||||
}
|
||||
ret := make(yaml.MapSlice, 0, len(j))
|
||||
for k, v := range j {
|
||||
ret = append(ret, yaml.MapItem{Key: k, Value: jsonToYAMLValue(v)})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func jsonToYAMLValue(j interface{}) interface{} {
|
||||
switch j := j.(type) {
|
||||
case map[string]interface{}:
|
||||
if j == nil {
|
||||
return interface{}(nil)
|
||||
}
|
||||
return JSONObjectToYAMLObject(j)
|
||||
case []interface{}:
|
||||
if j == nil {
|
||||
return interface{}(nil)
|
||||
}
|
||||
ret := make([]interface{}, len(j))
|
||||
for i := range j {
|
||||
ret[i] = jsonToYAMLValue(j[i])
|
||||
}
|
||||
return ret
|
||||
case float64:
|
||||
// replicate the logic in https://github.com/go-yaml/yaml/blob/51d6538a90f86fe93ac480b35f37b2be17fef232/resolve.go#L151
|
||||
if i64 := int64(j); j == float64(i64) {
|
||||
if i := int(i64); i64 == int64(i) {
|
||||
return i
|
||||
}
|
||||
return i64
|
||||
}
|
||||
if ui64 := uint64(j); j == float64(ui64) {
|
||||
return ui64
|
||||
}
|
||||
return j
|
||||
case int64:
|
||||
if i := int(j); j == int64(i) {
|
||||
return i
|
||||
}
|
||||
return j
|
||||
}
|
||||
return j
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user