Add e2e tests

This commit is contained in:
Manuel de Brito Fontes 2017-10-17 19:50:27 -03:00
parent 99a355f25d
commit 601fb7dacf
1163 changed files with 289217 additions and 14195 deletions

View file

@ -9,6 +9,7 @@ load(
go_test(
name = "go_default_test",
srcs = ["feature_gate_test.go"],
importpath = "k8s.io/apiserver/pkg/util/feature",
library = ":go_default_library",
deps = ["//vendor/github.com/spf13/pflag:go_default_library"],
)
@ -16,6 +17,7 @@ go_test(
go_library(
name = "go_default_library",
srcs = ["feature_gate.go"],
importpath = "k8s.io/apiserver/pkg/util/feature",
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",

View file

@ -22,6 +22,7 @@ import (
"strconv"
"strings"
"sync"
"sync/atomic"
"github.com/golang/glog"
"github.com/spf13/pflag"
@ -46,7 +47,7 @@ var (
}
// Special handling for a few gates.
specialFeatures = map[Feature]func(f *featureGate, val bool){
specialFeatures = map[Feature]func(known map[Feature]FeatureSpec, enabled map[Feature]bool, val bool){
allAlphaGate: setUnsetAlphaGates,
}
@ -76,6 +77,8 @@ type FeatureGate interface {
// Set parses and stores flag gates for known features
// from a string like feature1=true,feature2=false,...
Set(value string) error
// SetFromMap stores flag gates for known features from a map[string]bool or returns an error
SetFromMap(m map[string]bool) error
// Enabled returns true if the key is enabled.
Enabled(key Feature) bool
// Add adds features to the featureGate.
@ -86,21 +89,23 @@ type FeatureGate interface {
// featureGate implements FeatureGate as well as pflag.Value for flag parsing.
type featureGate struct {
lock sync.RWMutex
special map[Feature]func(map[Feature]FeatureSpec, map[Feature]bool, bool)
known map[Feature]FeatureSpec
special map[Feature]func(*featureGate, bool)
enabled map[Feature]bool
// is set to true when AddFlag is called. Note: initialization is not go-routine safe, lookup is
// lock guards writes to known, enabled, and reads/writes of closed
lock sync.Mutex
// known holds a map[Feature]FeatureSpec
known *atomic.Value
// enabled holds a map[Feature]bool
enabled *atomic.Value
// closed is set to true when AddFlag is called, and prevents subsequent calls to Add
closed bool
}
func setUnsetAlphaGates(f *featureGate, val bool) {
for k, v := range f.known {
func setUnsetAlphaGates(known map[Feature]FeatureSpec, enabled map[Feature]bool, val bool) {
for k, v := range known {
if v.PreRelease == Alpha {
if _, found := f.enabled[k]; !found {
f.enabled[k] = val
if _, found := enabled[k]; !found {
enabled[k] = val
}
}
}
@ -110,30 +115,49 @@ func setUnsetAlphaGates(f *featureGate, val bool) {
var _ pflag.Value = &featureGate{}
func NewFeatureGate() *featureGate {
f := &featureGate{
known: map[Feature]FeatureSpec{},
special: specialFeatures,
enabled: map[Feature]bool{},
}
known := map[Feature]FeatureSpec{}
for k, v := range defaultFeatures {
f.known[k] = v
known[k] = v
}
knownValue := &atomic.Value{}
knownValue.Store(known)
enabled := map[Feature]bool{}
enabledValue := &atomic.Value{}
enabledValue.Store(enabled)
f := &featureGate{
known: knownValue,
special: specialFeatures,
enabled: enabledValue,
}
return f
}
// Set Parses a string of the form "key1=value1,key2=value2,..." into a
// Set parses a string of the form "key1=value1,key2=value2,..." into a
// map[string]bool of known keys or returns an error.
func (f *featureGate) Set(value string) error {
f.lock.Lock()
defer f.lock.Unlock()
// Copy existing state
known := map[Feature]FeatureSpec{}
for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
known[k] = v
}
enabled := map[Feature]bool{}
for k, v := range f.enabled.Load().(map[Feature]bool) {
enabled[k] = v
}
for _, s := range strings.Split(value, ",") {
if len(s) == 0 {
continue
}
arr := strings.SplitN(s, "=", 2)
k := Feature(strings.TrimSpace(arr[0]))
_, ok := f.known[Feature(k)]
_, ok := known[Feature(k)]
if !ok {
return fmt.Errorf("unrecognized key: %s", k)
}
@ -145,25 +169,62 @@ func (f *featureGate) Set(value string) error {
if err != nil {
return fmt.Errorf("invalid value of %s: %s, err: %v", k, v, err)
}
f.enabled[k] = boolValue
enabled[k] = boolValue
// Handle "special" features like "all alpha gates"
if fn, found := f.special[k]; found {
fn(f, boolValue)
fn(known, enabled, boolValue)
}
}
// Persist changes
f.known.Store(known)
f.enabled.Store(enabled)
glog.Infof("feature gates: %v", enabled)
return nil
}
// SetFromMap stores flag gates for known features from a map[string]bool or returns an error
func (f *featureGate) SetFromMap(m map[string]bool) error {
f.lock.Lock()
defer f.lock.Unlock()
// Copy existing state
known := map[Feature]FeatureSpec{}
for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
known[k] = v
}
enabled := map[Feature]bool{}
for k, v := range f.enabled.Load().(map[Feature]bool) {
enabled[k] = v
}
for k, v := range m {
k := Feature(k)
_, ok := known[k]
if !ok {
return fmt.Errorf("unrecognized key: %s", k)
}
enabled[k] = v
// Handle "special" features like "all alpha gates"
if fn, found := f.special[k]; found {
fn(known, enabled, v)
}
}
// Persist changes
f.known.Store(known)
f.enabled.Store(enabled)
glog.Infof("feature gates: %v", f.enabled)
return nil
}
// String returns a string containing all enabled feature gates, formatted as "key1=value1,key2=value2,...".
func (f *featureGate) String() string {
f.lock.RLock()
defer f.lock.RUnlock()
pairs := []string{}
for k, v := range f.enabled {
for k, v := range f.enabled.Load().(map[Feature]bool) {
pairs = append(pairs, fmt.Sprintf("%s=%t", k, v))
}
sort.Strings(pairs)
@ -183,31 +244,35 @@ func (f *featureGate) Add(features map[Feature]FeatureSpec) error {
return fmt.Errorf("cannot add a feature gate after adding it to the flag set")
}
// Copy existing state
known := map[Feature]FeatureSpec{}
for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
known[k] = v
}
for name, spec := range features {
if existingSpec, found := f.known[name]; found {
if existingSpec, found := known[name]; found {
if existingSpec == spec {
continue
}
return fmt.Errorf("feature gate %q with different spec already exists: %v", name, existingSpec)
}
f.known[name] = spec
known[name] = spec
}
// Persist updated state
f.known.Store(known)
return nil
}
// Enabled returns true if the key is enabled.
func (f *featureGate) Enabled(key Feature) bool {
f.lock.RLock()
defer f.lock.RUnlock()
defaultValue := f.known[key].Default
if f.enabled != nil {
if v, ok := f.enabled[key]; ok {
return v
}
if v, ok := f.enabled.Load().(map[Feature]bool)[key]; ok {
return v
}
return defaultValue
return f.known.Load().(map[Feature]FeatureSpec)[key].Default
}
// AddFlag adds a flag for setting global feature gates to the specified FlagSet.
@ -224,10 +289,8 @@ func (f *featureGate) AddFlag(fs *pflag.FlagSet) {
// KnownFeatures returns a slice of strings describing the FeatureGate's known features.
func (f *featureGate) KnownFeatures() []string {
f.lock.RLock()
defer f.lock.RUnlock()
var known []string
for k, v := range f.known {
for k, v := range f.known.Load().(map[Feature]FeatureSpec) {
pre := ""
if v.PreRelease != GA {
pre = fmt.Sprintf("%s - ", v.PreRelease)

View file

@ -135,8 +135,8 @@ func TestFeatureGateFlag(t *testing.T) {
t.Errorf("%d: Parse() Expected nil, Got %v", i, err)
}
for k, v := range test.expect {
if f.enabled[k] != v {
t.Errorf("%d: expected %s=%v, Got %v", i, k, v, f.enabled[k])
if actual := f.enabled.Load().(map[Feature]bool)[k]; actual != v {
t.Errorf("%d: expected %s=%v, Got %v", i, k, v, actual)
}
}
}

30
vendor/k8s.io/apiserver/pkg/util/logs/BUILD generated vendored Normal file
View file

@ -0,0 +1,30 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["logs.go"],
importpath = "k8s.io/apiserver/pkg/util/logs",
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

61
vendor/k8s.io/apiserver/pkg/util/logs/logs.go generated vendored Normal file
View file

@ -0,0 +1,61 @@
/*
Copyright 2014 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 logs
import (
"flag"
"log"
"time"
"github.com/golang/glog"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/util/wait"
)
var logFlushFreq = pflag.Duration("log-flush-frequency", 5*time.Second, "Maximum number of seconds between log flushes")
// TODO(thockin): This is temporary until we agree on log dirs and put those into each cmd.
func init() {
flag.Set("logtostderr", "true")
}
// GlogWriter serves as a bridge between the standard log package and the glog package.
type GlogWriter struct{}
// Write implements the io.Writer interface.
func (writer GlogWriter) Write(data []byte) (n int, err error) {
glog.Info(string(data))
return len(data), nil
}
// InitLogs initializes logs the way we want for kubernetes.
func InitLogs() {
log.SetOutput(GlogWriter{})
log.SetFlags(0)
// The default glog flush interval is 30 seconds, which is frighteningly long.
go wait.Until(glog.Flush, *logFlushFreq, wait.NeverStop)
}
// FlushLogs flushes logs immediately.
func FlushLogs() {
glog.Flush()
}
// NewLogger creates a new log.Logger which sends logs to glog.Info.
func NewLogger(prefix string) *log.Logger {
return log.New(GlogWriter{}, prefix, 0)
}