vendor: remove dep and use vndr
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
parent
16f44674a4
commit
148e72d81e
16131 changed files with 73815 additions and 4235138 deletions
112
vendor/k8s.io/kubernetes/pkg/util/BUILD
generated
vendored
112
vendor/k8s.io/kubernetes/pkg/util/BUILD
generated
vendored
|
@ -1,112 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"template.go",
|
||||
"trace.go",
|
||||
"trie.go",
|
||||
"umask.go",
|
||||
"util.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor:github.com/golang/glog"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"template_test.go",
|
||||
"util_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor:github.com/stretchr/testify/assert",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/diff",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/util/async:all-srcs",
|
||||
"//pkg/util/bandwidth:all-srcs",
|
||||
"//pkg/util/chmod:all-srcs",
|
||||
"//pkg/util/chown:all-srcs",
|
||||
"//pkg/util/config:all-srcs",
|
||||
"//pkg/util/configz:all-srcs",
|
||||
"//pkg/util/crlf:all-srcs",
|
||||
"//pkg/util/dbus:all-srcs",
|
||||
"//pkg/util/ebtables:all-srcs",
|
||||
"//pkg/util/env:all-srcs",
|
||||
"//pkg/util/errors:all-srcs",
|
||||
"//pkg/util/exec:all-srcs",
|
||||
"//pkg/util/flag:all-srcs",
|
||||
"//pkg/util/flock:all-srcs",
|
||||
"//pkg/util/framer:all-srcs",
|
||||
"//pkg/util/goroutinemap:all-srcs",
|
||||
"//pkg/util/hash:all-srcs",
|
||||
"//pkg/util/httpstream:all-srcs",
|
||||
"//pkg/util/i18n:all-srcs",
|
||||
"//pkg/util/initsystem:all-srcs",
|
||||
"//pkg/util/interrupt:all-srcs",
|
||||
"//pkg/util/intstr:all-srcs",
|
||||
"//pkg/util/io:all-srcs",
|
||||
"//pkg/util/iptables:all-srcs",
|
||||
"//pkg/util/json:all-srcs",
|
||||
"//pkg/util/keymutex:all-srcs",
|
||||
"//pkg/util/labels:all-srcs",
|
||||
"//pkg/util/limitwriter:all-srcs",
|
||||
"//pkg/util/logs:all-srcs",
|
||||
"//pkg/util/maps:all-srcs",
|
||||
"//pkg/util/metrics:all-srcs",
|
||||
"//pkg/util/mount:all-srcs",
|
||||
"//pkg/util/net:all-srcs",
|
||||
"//pkg/util/netsh:all-srcs",
|
||||
"//pkg/util/node:all-srcs",
|
||||
"//pkg/util/oom:all-srcs",
|
||||
"//pkg/util/parsers:all-srcs",
|
||||
"//pkg/util/procfs:all-srcs",
|
||||
"//pkg/util/proxy:all-srcs",
|
||||
"//pkg/util/rand:all-srcs",
|
||||
"//pkg/util/resourcecontainer:all-srcs",
|
||||
"//pkg/util/rlimit:all-srcs",
|
||||
"//pkg/util/runtime:all-srcs",
|
||||
"//pkg/util/selinux:all-srcs",
|
||||
"//pkg/util/sets:all-srcs",
|
||||
"//pkg/util/slice:all-srcs",
|
||||
"//pkg/util/strategicpatch:all-srcs",
|
||||
"//pkg/util/strings:all-srcs",
|
||||
"//pkg/util/sysctl:all-srcs",
|
||||
"//pkg/util/system:all-srcs",
|
||||
"//pkg/util/tail:all-srcs",
|
||||
"//pkg/util/taints:all-srcs",
|
||||
"//pkg/util/term:all-srcs",
|
||||
"//pkg/util/threading:all-srcs",
|
||||
"//pkg/util/uuid:all-srcs",
|
||||
"//pkg/util/validation:all-srcs",
|
||||
"//pkg/util/version:all-srcs",
|
||||
"//pkg/util/wait:all-srcs",
|
||||
"//pkg/util/workqueue:all-srcs",
|
||||
"//pkg/util/yaml:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
35
vendor/k8s.io/kubernetes/pkg/util/async/BUILD
generated
vendored
35
vendor/k8s.io/kubernetes/pkg/util/async/BUILD
generated
vendored
|
@ -1,35 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["runner.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["runner_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
58
vendor/k8s.io/kubernetes/pkg/util/async/runner.go
generated
vendored
58
vendor/k8s.io/kubernetes/pkg/util/async/runner.go
generated
vendored
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
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 async
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Runner is an abstraction to make it easy to start and stop groups of things that can be
|
||||
// described by a single function which waits on a channel close to exit.
|
||||
type Runner struct {
|
||||
lock sync.Mutex
|
||||
loopFuncs []func(stop chan struct{})
|
||||
stop *chan struct{}
|
||||
}
|
||||
|
||||
// NewRunner makes a runner for the given function(s). The function(s) should loop until
|
||||
// the channel is closed.
|
||||
func NewRunner(f ...func(stop chan struct{})) *Runner {
|
||||
return &Runner{loopFuncs: f}
|
||||
}
|
||||
|
||||
// Start begins running.
|
||||
func (r *Runner) Start() {
|
||||
r.lock.Lock()
|
||||
defer r.lock.Unlock()
|
||||
if r.stop == nil {
|
||||
c := make(chan struct{})
|
||||
r.stop = &c
|
||||
for i := range r.loopFuncs {
|
||||
go r.loopFuncs[i](*r.stop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stop stops running.
|
||||
func (r *Runner) Stop() {
|
||||
r.lock.Lock()
|
||||
defer r.lock.Unlock()
|
||||
if r.stop != nil {
|
||||
close(*r.stop)
|
||||
r.stop = nil
|
||||
}
|
||||
}
|
55
vendor/k8s.io/kubernetes/pkg/util/async/runner_test.go
generated
vendored
55
vendor/k8s.io/kubernetes/pkg/util/async/runner_test.go
generated
vendored
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 async
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRunner(t *testing.T) {
|
||||
var (
|
||||
lock sync.Mutex
|
||||
events []string
|
||||
funcs []func(chan struct{})
|
||||
)
|
||||
done := make(chan struct{}, 20)
|
||||
for i := 0; i < 10; i++ {
|
||||
iCopy := i
|
||||
funcs = append(funcs, func(c chan struct{}) {
|
||||
lock.Lock()
|
||||
events = append(events, fmt.Sprintf("%v starting\n", iCopy))
|
||||
lock.Unlock()
|
||||
<-c
|
||||
lock.Lock()
|
||||
events = append(events, fmt.Sprintf("%v stopping\n", iCopy))
|
||||
lock.Unlock()
|
||||
done <- struct{}{}
|
||||
})
|
||||
}
|
||||
|
||||
r := NewRunner(funcs...)
|
||||
r.Start()
|
||||
r.Stop()
|
||||
for i := 0; i < 10; i++ {
|
||||
<-done
|
||||
}
|
||||
if len(events) != 20 {
|
||||
t.Errorf("expected 20 events, but got:\n%v\n", events)
|
||||
}
|
||||
}
|
56
vendor/k8s.io/kubernetes/pkg/util/bandwidth/BUILD
generated
vendored
56
vendor/k8s.io/kubernetes/pkg/util/bandwidth/BUILD
generated
vendored
|
@ -1,56 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"fake_shaper.go",
|
||||
"interfaces.go",
|
||||
"linux.go",
|
||||
"utils.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api/resource:go_default_library",
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"linux_test.go",
|
||||
"utils_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/resource:go_default_library",
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
18
vendor/k8s.io/kubernetes/pkg/util/bandwidth/doc.go
generated
vendored
18
vendor/k8s.io/kubernetes/pkg/util/bandwidth/doc.go
generated
vendored
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 bandwidth provides utilities for bandwidth shaping
|
||||
package bandwidth // import "k8s.io/kubernetes/pkg/util/bandwidth"
|
49
vendor/k8s.io/kubernetes/pkg/util/bandwidth/fake_shaper.go
generated
vendored
49
vendor/k8s.io/kubernetes/pkg/util/bandwidth/fake_shaper.go
generated
vendored
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 bandwidth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
)
|
||||
|
||||
type FakeShaper struct {
|
||||
CIDRs []string
|
||||
ResetCIDRs []string
|
||||
}
|
||||
|
||||
func (f *FakeShaper) Limit(cidr string, egress, ingress *resource.Quantity) error {
|
||||
return errors.New("unimplemented")
|
||||
}
|
||||
|
||||
func (f *FakeShaper) Reset(cidr string) error {
|
||||
f.ResetCIDRs = append(f.ResetCIDRs, cidr)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FakeShaper) ReconcileInterface() error {
|
||||
return errors.New("unimplemented")
|
||||
}
|
||||
|
||||
func (f *FakeShaper) ReconcileCIDR(cidr string, egress, ingress *resource.Quantity) error {
|
||||
return errors.New("unimplemented")
|
||||
}
|
||||
|
||||
func (f *FakeShaper) GetCIDRs() ([]string, error) {
|
||||
return f.CIDRs, nil
|
||||
}
|
38
vendor/k8s.io/kubernetes/pkg/util/bandwidth/interfaces.go
generated
vendored
38
vendor/k8s.io/kubernetes/pkg/util/bandwidth/interfaces.go
generated
vendored
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 bandwidth
|
||||
|
||||
import "k8s.io/kubernetes/pkg/api/resource"
|
||||
|
||||
type BandwidthShaper interface {
|
||||
// Limit the bandwidth for a particular CIDR on a particular interface
|
||||
// * ingress and egress are in bits/second
|
||||
// * cidr is expected to be a valid network CIDR (e.g. '1.2.3.4/32' or '10.20.0.1/16')
|
||||
// 'egress' bandwidth limit applies to all packets on the interface whose source matches 'cidr'
|
||||
// 'ingress' bandwidth limit applies to all packets on the interface whose destination matches 'cidr'
|
||||
// Limits are aggregate limits for the CIDR, not per IP address. CIDRs must be unique, but can be overlapping, traffic
|
||||
// that matches multiple CIDRs counts against all limits.
|
||||
Limit(cidr string, egress, ingress *resource.Quantity) error
|
||||
// Remove a bandwidth limit for a particular CIDR on a particular network interface
|
||||
Reset(cidr string) error
|
||||
// Reconcile the interface managed by this shaper with the state on the ground.
|
||||
ReconcileInterface() error
|
||||
// Reconcile a CIDR managed by this shaper with the state on the ground
|
||||
ReconcileCIDR(cidr string, egress, ingress *resource.Quantity) error
|
||||
// GetCIDRs returns the set of CIDRs that are being managed by this shaper
|
||||
GetCIDRs() ([]string, error)
|
||||
}
|
322
vendor/k8s.io/kubernetes/pkg/util/bandwidth/linux.go
generated
vendored
322
vendor/k8s.io/kubernetes/pkg/util/bandwidth/linux.go
generated
vendored
|
@ -1,322 +0,0 @@
|
|||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2015 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 bandwidth
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
"k8s.io/kubernetes/pkg/util/exec"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// tcShaper provides an implementation of the BandwidthShaper interface on Linux using the 'tc' tool.
|
||||
// In general, using this requires that the caller posses the NET_CAP_ADMIN capability, though if you
|
||||
// do this within an container, it only requires the NS_CAPABLE capability for manipulations to that
|
||||
// container's network namespace.
|
||||
// Uses the hierarchical token bucket queuing discipline (htb), this requires Linux 2.4.20 or newer
|
||||
// or a custom kernel with that queuing discipline backported.
|
||||
type tcShaper struct {
|
||||
e exec.Interface
|
||||
iface string
|
||||
}
|
||||
|
||||
func NewTCShaper(iface string) BandwidthShaper {
|
||||
shaper := &tcShaper{
|
||||
e: exec.New(),
|
||||
iface: iface,
|
||||
}
|
||||
return shaper
|
||||
}
|
||||
|
||||
func (t *tcShaper) execAndLog(cmdStr string, args ...string) error {
|
||||
glog.V(6).Infof("Running: %s %s", cmdStr, strings.Join(args, " "))
|
||||
cmd := t.e.Command(cmdStr, args...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
glog.V(6).Infof("Output from tc: %s", string(out))
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *tcShaper) nextClassID() (int, error) {
|
||||
data, err := t.e.Command("tc", "class", "show", "dev", t.iface).CombinedOutput()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(bytes.NewBuffer(data))
|
||||
classes := sets.String{}
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
// skip empty lines
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
parts := strings.Split(line, " ")
|
||||
// expected tc line:
|
||||
// class htb 1:1 root prio 0 rate 1000Kbit ceil 1000Kbit burst 1600b cburst 1600b
|
||||
if len(parts) != 14 {
|
||||
return -1, fmt.Errorf("unexpected output from tc: %s (%v)", scanner.Text(), parts)
|
||||
}
|
||||
classes.Insert(parts[2])
|
||||
}
|
||||
|
||||
// Make sure it doesn't go forever
|
||||
for nextClass := 1; nextClass < 10000; nextClass++ {
|
||||
if !classes.Has(fmt.Sprintf("1:%d", nextClass)) {
|
||||
return nextClass, nil
|
||||
}
|
||||
}
|
||||
// This should really never happen
|
||||
return -1, fmt.Errorf("exhausted class space, please try again")
|
||||
}
|
||||
|
||||
// Convert a CIDR from text to a hex representation
|
||||
// Strips any masked parts of the IP, so 1.2.3.4/16 becomes hex(1.2.0.0)/ffffffff
|
||||
func hexCIDR(cidr string) (string, error) {
|
||||
ip, ipnet, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ip = ip.Mask(ipnet.Mask)
|
||||
hexIP := hex.EncodeToString([]byte(ip.To4()))
|
||||
hexMask := ipnet.Mask.String()
|
||||
return hexIP + "/" + hexMask, nil
|
||||
}
|
||||
|
||||
// Convert a CIDR from hex representation to text, opposite of the above.
|
||||
func asciiCIDR(cidr string) (string, error) {
|
||||
parts := strings.Split(cidr, "/")
|
||||
if len(parts) != 2 {
|
||||
return "", fmt.Errorf("unexpected CIDR format: %s", cidr)
|
||||
}
|
||||
ipData, err := hex.DecodeString(parts[0])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ip := net.IP(ipData)
|
||||
|
||||
maskData, err := hex.DecodeString(parts[1])
|
||||
mask := net.IPMask(maskData)
|
||||
size, _ := mask.Size()
|
||||
|
||||
return fmt.Sprintf("%s/%d", ip.String(), size), nil
|
||||
}
|
||||
|
||||
func (t *tcShaper) findCIDRClass(cidr string) (class, handle string, found bool, err error) {
|
||||
data, err := t.e.Command("tc", "filter", "show", "dev", t.iface).CombinedOutput()
|
||||
if err != nil {
|
||||
return "", "", false, err
|
||||
}
|
||||
|
||||
hex, err := hexCIDR(cidr)
|
||||
if err != nil {
|
||||
return "", "", false, err
|
||||
}
|
||||
spec := fmt.Sprintf("match %s", hex)
|
||||
|
||||
scanner := bufio.NewScanner(bytes.NewBuffer(data))
|
||||
filter := ""
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "filter") {
|
||||
filter = line
|
||||
continue
|
||||
}
|
||||
if strings.Contains(line, spec) {
|
||||
parts := strings.Split(filter, " ")
|
||||
// expected tc line:
|
||||
// filter parent 1: protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1
|
||||
if len(parts) != 19 {
|
||||
return "", "", false, fmt.Errorf("unexpected output from tc: %s %d (%v)", filter, len(parts), parts)
|
||||
}
|
||||
return parts[18], parts[9], true, nil
|
||||
}
|
||||
}
|
||||
return "", "", false, nil
|
||||
}
|
||||
|
||||
func makeKBitString(rsrc *resource.Quantity) string {
|
||||
return fmt.Sprintf("%dkbit", (rsrc.Value() / 1000))
|
||||
}
|
||||
|
||||
func (t *tcShaper) makeNewClass(rate string) (int, error) {
|
||||
class, err := t.nextClassID()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if err := t.execAndLog("tc", "class", "add",
|
||||
"dev", t.iface,
|
||||
"parent", "1:",
|
||||
"classid", fmt.Sprintf("1:%d", class),
|
||||
"htb", "rate", rate); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return class, nil
|
||||
}
|
||||
|
||||
func (t *tcShaper) Limit(cidr string, upload, download *resource.Quantity) (err error) {
|
||||
var downloadClass, uploadClass int
|
||||
if download != nil {
|
||||
if downloadClass, err = t.makeNewClass(makeKBitString(download)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := t.execAndLog("tc", "filter", "add",
|
||||
"dev", t.iface,
|
||||
"protocol", "ip",
|
||||
"parent", "1:0",
|
||||
"prio", "1", "u32",
|
||||
"match", "ip", "dst", cidr,
|
||||
"flowid", fmt.Sprintf("1:%d", downloadClass)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if upload != nil {
|
||||
if uploadClass, err = t.makeNewClass(makeKBitString(upload)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := t.execAndLog("tc", "filter", "add",
|
||||
"dev", t.iface,
|
||||
"protocol", "ip",
|
||||
"parent", "1:0",
|
||||
"prio", "1", "u32",
|
||||
"match", "ip", "src", cidr,
|
||||
"flowid", fmt.Sprintf("1:%d", uploadClass)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// tests to see if an interface exists, if it does, return true and the status line for the interface
|
||||
// returns false, "", <err> if an error occurs.
|
||||
func (t *tcShaper) interfaceExists() (bool, string, error) {
|
||||
data, err := t.e.Command("tc", "qdisc", "show", "dev", t.iface).CombinedOutput()
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
value := strings.TrimSpace(string(data))
|
||||
if len(value) == 0 {
|
||||
return false, "", nil
|
||||
}
|
||||
// Newer versions of tc and/or the kernel return the following instead of nothing:
|
||||
// qdisc noqueue 0: root refcnt 2
|
||||
fields := strings.Fields(value)
|
||||
if len(fields) > 1 && fields[1] == "noqueue" {
|
||||
return false, "", nil
|
||||
}
|
||||
return true, value, nil
|
||||
}
|
||||
|
||||
func (t *tcShaper) ReconcileCIDR(cidr string, upload, download *resource.Quantity) error {
|
||||
_, _, found, err := t.findCIDRClass(cidr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !found {
|
||||
return t.Limit(cidr, upload, download)
|
||||
}
|
||||
// TODO: actually check bandwidth limits here
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *tcShaper) ReconcileInterface() error {
|
||||
exists, output, err := t.interfaceExists()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
glog.V(4).Info("Didn't find bandwidth interface, creating")
|
||||
return t.initializeInterface()
|
||||
}
|
||||
fields := strings.Split(output, " ")
|
||||
if len(fields) < 12 || fields[1] != "htb" || fields[2] != "1:" {
|
||||
if err := t.deleteInterface(fields[2]); err != nil {
|
||||
return err
|
||||
}
|
||||
return t.initializeInterface()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *tcShaper) initializeInterface() error {
|
||||
return t.execAndLog("tc", "qdisc", "add", "dev", t.iface, "root", "handle", "1:", "htb", "default", "30")
|
||||
}
|
||||
|
||||
func (t *tcShaper) Reset(cidr string) error {
|
||||
class, handle, found, err := t.findCIDRClass(cidr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !found {
|
||||
return fmt.Errorf("Failed to find cidr: %s on interface: %s", cidr, t.iface)
|
||||
}
|
||||
if err := t.execAndLog("tc", "filter", "del",
|
||||
"dev", t.iface,
|
||||
"parent", "1:",
|
||||
"proto", "ip",
|
||||
"prio", "1",
|
||||
"handle", handle, "u32"); err != nil {
|
||||
return err
|
||||
}
|
||||
return t.execAndLog("tc", "class", "del", "dev", t.iface, "parent", "1:", "classid", class)
|
||||
}
|
||||
|
||||
func (t *tcShaper) deleteInterface(class string) error {
|
||||
return t.execAndLog("tc", "qdisc", "delete", "dev", t.iface, "root", "handle", class)
|
||||
}
|
||||
|
||||
func (t *tcShaper) GetCIDRs() ([]string, error) {
|
||||
data, err := t.e.Command("tc", "filter", "show", "dev", t.iface).CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := []string{}
|
||||
scanner := bufio.NewScanner(bytes.NewBuffer(data))
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(line, "match") {
|
||||
parts := strings.Split(line, " ")
|
||||
// expected tc line:
|
||||
// match <cidr> at <number>
|
||||
if len(parts) != 4 {
|
||||
return nil, fmt.Errorf("unexpected output: %v", parts)
|
||||
}
|
||||
cidr, err := asciiCIDR(parts[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, cidr)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
634
vendor/k8s.io/kubernetes/pkg/util/bandwidth/linux_test.go
generated
vendored
634
vendor/k8s.io/kubernetes/pkg/util/bandwidth/linux_test.go
generated
vendored
|
@ -1,634 +0,0 @@
|
|||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2015 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 bandwidth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
"k8s.io/kubernetes/pkg/util/exec"
|
||||
)
|
||||
|
||||
var tcClassOutput = `class htb 1:1 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
|
||||
class htb 1:2 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
|
||||
class htb 1:3 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
|
||||
class htb 1:4 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
|
||||
`
|
||||
|
||||
var tcClassOutput2 = `class htb 1:1 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
|
||||
class htb 1:2 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
|
||||
class htb 1:3 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
|
||||
class htb 1:4 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
|
||||
class htb 1:5 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
|
||||
`
|
||||
|
||||
func TestNextClassID(t *testing.T) {
|
||||
tests := []struct {
|
||||
output string
|
||||
expectErr bool
|
||||
expected int
|
||||
err error
|
||||
}{
|
||||
{
|
||||
output: tcClassOutput,
|
||||
expected: 5,
|
||||
},
|
||||
{
|
||||
output: "\n",
|
||||
expected: 1,
|
||||
},
|
||||
{
|
||||
expected: -1,
|
||||
expectErr: true,
|
||||
err: errors.New("test error"),
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return []byte(test.output), test.err },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd {
|
||||
return exec.InitFakeCmd(&fcmd, cmd, args...)
|
||||
},
|
||||
},
|
||||
}
|
||||
shaper := &tcShaper{e: &fexec}
|
||||
class, err := shaper.nextClassID()
|
||||
if test.expectErr {
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if class != test.expected {
|
||||
t.Errorf("expected: %d, found %d", test.expected, class)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHexCIDR(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
output string
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
input: "1.2.0.0/16",
|
||||
output: "01020000/ffff0000",
|
||||
},
|
||||
{
|
||||
input: "172.17.0.2/32",
|
||||
output: "ac110002/ffffffff",
|
||||
},
|
||||
{
|
||||
input: "foo",
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
output, err := hexCIDR(test.input)
|
||||
if test.expectErr {
|
||||
if err == nil {
|
||||
t.Error("unexpected non-error")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if output != test.output {
|
||||
t.Errorf("expected: %s, saw: %s", test.output, output)
|
||||
}
|
||||
input, err := asciiCIDR(output)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if input != test.input {
|
||||
t.Errorf("expected: %s, saw: %s", test.input, input)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tcFilterOutput = `filter parent 1: protocol ip pref 1 u32
|
||||
filter parent 1: protocol ip pref 1 u32 fh 800: ht divisor 1
|
||||
filter parent 1: protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1
|
||||
match ac110002/ffffffff at 16
|
||||
filter parent 1: protocol ip pref 1 u32 fh 800::801 order 2049 key ht 800 bkt 0 flowid 1:2
|
||||
match 01020000/ffff0000 at 16
|
||||
`
|
||||
|
||||
func TestFindCIDRClass(t *testing.T) {
|
||||
tests := []struct {
|
||||
cidr string
|
||||
output string
|
||||
expectErr bool
|
||||
expectNotFound bool
|
||||
expectedClass string
|
||||
expectedHandle string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
cidr: "172.17.0.2/32",
|
||||
output: tcFilterOutput,
|
||||
expectedClass: "1:1",
|
||||
expectedHandle: "800::800",
|
||||
},
|
||||
{
|
||||
cidr: "1.2.3.4/16",
|
||||
output: tcFilterOutput,
|
||||
expectedClass: "1:2",
|
||||
expectedHandle: "800::801",
|
||||
},
|
||||
{
|
||||
cidr: "2.2.3.4/16",
|
||||
output: tcFilterOutput,
|
||||
expectNotFound: true,
|
||||
},
|
||||
{
|
||||
err: errors.New("test error"),
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return []byte(test.output), test.err },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd {
|
||||
return exec.InitFakeCmd(&fcmd, cmd, args...)
|
||||
},
|
||||
},
|
||||
}
|
||||
shaper := &tcShaper{e: &fexec}
|
||||
class, handle, found, err := shaper.findCIDRClass(test.cidr)
|
||||
if test.expectErr {
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if test.expectNotFound {
|
||||
if found {
|
||||
t.Errorf("unexpectedly found an interface: %s %s", class, handle)
|
||||
}
|
||||
} else {
|
||||
if class != test.expectedClass {
|
||||
t.Errorf("expected: %s, found %s", test.expectedClass, class)
|
||||
}
|
||||
if handle != test.expectedHandle {
|
||||
t.Errorf("expected: %s, found %s", test.expectedHandle, handle)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCIDRs(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return []byte(tcFilterOutput), nil },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd {
|
||||
return exec.InitFakeCmd(&fcmd, cmd, args...)
|
||||
},
|
||||
},
|
||||
}
|
||||
shaper := &tcShaper{e: &fexec}
|
||||
cidrs, err := shaper.GetCIDRs()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
expectedCidrs := []string{"172.17.0.2/32", "1.2.0.0/16"}
|
||||
if !reflect.DeepEqual(cidrs, expectedCidrs) {
|
||||
t.Errorf("expected: %v, saw: %v", expectedCidrs, cidrs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLimit(t *testing.T) {
|
||||
tests := []struct {
|
||||
cidr string
|
||||
ingress *resource.Quantity
|
||||
egress *resource.Quantity
|
||||
expectErr bool
|
||||
expectedCalls int
|
||||
err error
|
||||
}{
|
||||
{
|
||||
cidr: "1.2.3.4/32",
|
||||
ingress: resource.NewQuantity(10, resource.DecimalSI),
|
||||
egress: resource.NewQuantity(20, resource.DecimalSI),
|
||||
expectedCalls: 6,
|
||||
},
|
||||
{
|
||||
cidr: "1.2.3.4/32",
|
||||
ingress: resource.NewQuantity(10, resource.DecimalSI),
|
||||
egress: nil,
|
||||
expectedCalls: 3,
|
||||
},
|
||||
{
|
||||
cidr: "1.2.3.4/32",
|
||||
ingress: nil,
|
||||
egress: resource.NewQuantity(20, resource.DecimalSI),
|
||||
expectedCalls: 3,
|
||||
},
|
||||
{
|
||||
cidr: "1.2.3.4/32",
|
||||
ingress: nil,
|
||||
egress: nil,
|
||||
expectedCalls: 0,
|
||||
},
|
||||
{
|
||||
err: errors.New("test error"),
|
||||
ingress: resource.NewQuantity(10, resource.DecimalSI),
|
||||
egress: resource.NewQuantity(20, resource.DecimalSI),
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return []byte(tcClassOutput), test.err },
|
||||
func() ([]byte, error) { return []byte{}, test.err },
|
||||
func() ([]byte, error) { return []byte{}, test.err },
|
||||
func() ([]byte, error) { return []byte(tcClassOutput2), test.err },
|
||||
func() ([]byte, error) { return []byte{}, test.err },
|
||||
func() ([]byte, error) { return []byte{}, test.err },
|
||||
},
|
||||
}
|
||||
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
iface := "cbr0"
|
||||
shaper := &tcShaper{e: &fexec, iface: iface}
|
||||
if err := shaper.Limit(test.cidr, test.ingress, test.egress); err != nil && !test.expectErr {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
return
|
||||
} else if err == nil && test.expectErr {
|
||||
t.Error("unexpected non-error")
|
||||
return
|
||||
}
|
||||
// No more testing in the error case
|
||||
if test.expectErr {
|
||||
if fcmd.CombinedOutputCalls != 1 {
|
||||
t.Errorf("unexpected number of calls: %d, expected: 1", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if fcmd.CombinedOutputCalls != test.expectedCalls {
|
||||
t.Errorf("unexpected number of calls: %d, expected: %d", fcmd.CombinedOutputCalls, test.expectedCalls)
|
||||
}
|
||||
|
||||
for ix := range fcmd.CombinedOutputLog {
|
||||
output := fcmd.CombinedOutputLog[ix]
|
||||
if output[0] != "tc" {
|
||||
t.Errorf("unexpected command: %s, expected tc", output[0])
|
||||
}
|
||||
if output[4] != iface {
|
||||
t.Errorf("unexpected interface: %s, expected %s (%v)", output[4], iface, output)
|
||||
}
|
||||
if ix == 1 {
|
||||
var expectedRate string
|
||||
if test.ingress != nil {
|
||||
expectedRate = makeKBitString(test.ingress)
|
||||
} else {
|
||||
expectedRate = makeKBitString(test.egress)
|
||||
}
|
||||
if output[11] != expectedRate {
|
||||
t.Errorf("unexpected ingress: %s, expected: %s", output[11], expectedRate)
|
||||
}
|
||||
if output[8] != "1:5" {
|
||||
t.Errorf("unexpected class: %s, expected: %s", output[8], "1:5")
|
||||
}
|
||||
}
|
||||
if ix == 2 {
|
||||
if output[15] != test.cidr {
|
||||
t.Errorf("unexpected cidr: %s, expected: %s", output[15], test.cidr)
|
||||
}
|
||||
if output[17] != "1:5" {
|
||||
t.Errorf("unexpected class: %s, expected: %s", output[17], "1:5")
|
||||
}
|
||||
}
|
||||
if ix == 4 {
|
||||
if output[11] != makeKBitString(test.egress) {
|
||||
t.Errorf("unexpected egress: %s, expected: %s", output[11], makeKBitString(test.egress))
|
||||
}
|
||||
if output[8] != "1:6" {
|
||||
t.Errorf("unexpected class: %s, expected: %s", output[8], "1:6")
|
||||
}
|
||||
}
|
||||
if ix == 5 {
|
||||
if output[15] != test.cidr {
|
||||
t.Errorf("unexpected cidr: %s, expected: %s", output[15], test.cidr)
|
||||
}
|
||||
if output[17] != "1:6" {
|
||||
t.Errorf("unexpected class: %s, expected: %s", output[17], "1:5")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReset(t *testing.T) {
|
||||
tests := []struct {
|
||||
cidr string
|
||||
err error
|
||||
expectErr bool
|
||||
expectedHandle string
|
||||
expectedClass string
|
||||
}{
|
||||
{
|
||||
cidr: "1.2.3.4/16",
|
||||
expectedHandle: "800::801",
|
||||
expectedClass: "1:2",
|
||||
},
|
||||
{
|
||||
cidr: "172.17.0.2/32",
|
||||
expectedHandle: "800::800",
|
||||
expectedClass: "1:1",
|
||||
},
|
||||
{
|
||||
err: errors.New("test error"),
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return []byte(tcFilterOutput), test.err },
|
||||
func() ([]byte, error) { return []byte{}, test.err },
|
||||
func() ([]byte, error) { return []byte{}, test.err },
|
||||
},
|
||||
}
|
||||
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
iface := "cbr0"
|
||||
shaper := &tcShaper{e: &fexec, iface: iface}
|
||||
|
||||
if err := shaper.Reset(test.cidr); err != nil && !test.expectErr {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
return
|
||||
} else if test.expectErr && err == nil {
|
||||
t.Error("unexpected non-error")
|
||||
return
|
||||
}
|
||||
|
||||
// No more testing in the error case
|
||||
if test.expectErr {
|
||||
if fcmd.CombinedOutputCalls != 1 {
|
||||
t.Errorf("unexpected number of calls: %d, expected: 1", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if fcmd.CombinedOutputCalls != 3 {
|
||||
t.Errorf("unexpected number of calls: %d, expected: 3", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
|
||||
for ix := range fcmd.CombinedOutputLog {
|
||||
output := fcmd.CombinedOutputLog[ix]
|
||||
if output[0] != "tc" {
|
||||
t.Errorf("unexpected command: %s, expected tc", output[0])
|
||||
}
|
||||
if output[4] != iface {
|
||||
t.Errorf("unexpected interface: %s, expected %s (%v)", output[4], iface, output)
|
||||
}
|
||||
if ix == 1 && output[12] != test.expectedHandle {
|
||||
t.Errorf("unexpected handle: %s, expected: %s", output[12], test.expectedHandle)
|
||||
}
|
||||
if ix == 2 && output[8] != test.expectedClass {
|
||||
t.Errorf("unexpected class: %s, expected: %s", output[8], test.expectedClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tcQdisc = "qdisc htb 1: root refcnt 2 r2q 10 default 30 direct_packets_stat 0\n"
|
||||
|
||||
func TestReconcileInterfaceExists(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return []byte(tcQdisc), nil },
|
||||
},
|
||||
}
|
||||
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
iface := "cbr0"
|
||||
shaper := &tcShaper{e: &fexec, iface: iface}
|
||||
err := shaper.ReconcileInterface()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if fcmd.CombinedOutputCalls != 1 {
|
||||
t.Errorf("unexpected number of calls: %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
|
||||
output := fcmd.CombinedOutputLog[0]
|
||||
if len(output) != 5 {
|
||||
t.Errorf("unexpected command: %v", output)
|
||||
}
|
||||
if output[0] != "tc" {
|
||||
t.Errorf("unexpected command: %s", output[0])
|
||||
}
|
||||
if output[4] != iface {
|
||||
t.Errorf("unexpected interface: %s, expected %s", output[4], iface)
|
||||
}
|
||||
if output[2] != "show" {
|
||||
t.Errorf("unexpected action: %s", output[2])
|
||||
}
|
||||
}
|
||||
|
||||
func testReconcileInterfaceHasNoData(t *testing.T, output string) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return []byte(output), nil },
|
||||
func() ([]byte, error) { return []byte(output), nil },
|
||||
},
|
||||
}
|
||||
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
iface := "cbr0"
|
||||
shaper := &tcShaper{e: &fexec, iface: iface}
|
||||
err := shaper.ReconcileInterface()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if fcmd.CombinedOutputCalls != 2 {
|
||||
t.Errorf("unexpected number of calls: %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
|
||||
for ix, output := range fcmd.CombinedOutputLog {
|
||||
if output[0] != "tc" {
|
||||
t.Errorf("unexpected command: %s", output[0])
|
||||
}
|
||||
if output[4] != iface {
|
||||
t.Errorf("unexpected interface: %s, expected %s", output[4], iface)
|
||||
}
|
||||
if ix == 0 {
|
||||
if len(output) != 5 {
|
||||
t.Errorf("unexpected command: %v", output)
|
||||
}
|
||||
if output[2] != "show" {
|
||||
t.Errorf("unexpected action: %s", output[2])
|
||||
}
|
||||
}
|
||||
if ix == 1 {
|
||||
if len(output) != 11 {
|
||||
t.Errorf("unexpected command: %v", output)
|
||||
}
|
||||
if output[2] != "add" {
|
||||
t.Errorf("unexpected action: %s", output[2])
|
||||
}
|
||||
if output[7] != "1:" {
|
||||
t.Errorf("unexpected root class: %s", output[7])
|
||||
}
|
||||
if output[8] != "htb" {
|
||||
t.Errorf("unexpected qdisc algo: %s", output[8])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReconcileInterfaceDoesntExist(t *testing.T) {
|
||||
testReconcileInterfaceHasNoData(t, "\n")
|
||||
}
|
||||
|
||||
var tcQdiscNoqueue = "qdisc noqueue 0: root refcnt 2 \n"
|
||||
|
||||
func TestReconcileInterfaceExistsWithNoqueue(t *testing.T) {
|
||||
testReconcileInterfaceHasNoData(t, tcQdiscNoqueue)
|
||||
}
|
||||
|
||||
var tcQdiscWrong = []string{
|
||||
"qdisc htb 2: root refcnt 2 r2q 10 default 30 direct_packets_stat 0\n",
|
||||
"qdisc foo 1: root refcnt 2 r2q 10 default 30 direct_packets_stat 0\n",
|
||||
}
|
||||
|
||||
func TestReconcileInterfaceIsWrong(t *testing.T) {
|
||||
for _, test := range tcQdiscWrong {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return []byte(test), nil },
|
||||
func() ([]byte, error) { return []byte("\n"), nil },
|
||||
func() ([]byte, error) { return []byte("\n"), nil },
|
||||
},
|
||||
}
|
||||
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
iface := "cbr0"
|
||||
shaper := &tcShaper{e: &fexec, iface: iface}
|
||||
err := shaper.ReconcileInterface()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if fcmd.CombinedOutputCalls != 3 {
|
||||
t.Errorf("unexpected number of calls: %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
|
||||
for ix, output := range fcmd.CombinedOutputLog {
|
||||
if output[0] != "tc" {
|
||||
t.Errorf("unexpected command: %s", output[0])
|
||||
}
|
||||
if output[4] != iface {
|
||||
t.Errorf("unexpected interface: %s, expected %s", output[4], iface)
|
||||
}
|
||||
if ix == 0 {
|
||||
if len(output) != 5 {
|
||||
t.Errorf("unexpected command: %v", output)
|
||||
}
|
||||
if output[2] != "show" {
|
||||
t.Errorf("unexpected action: %s", output[2])
|
||||
}
|
||||
}
|
||||
if ix == 1 {
|
||||
if len(output) != 8 {
|
||||
t.Errorf("unexpected command: %v", output)
|
||||
}
|
||||
if output[2] != "delete" {
|
||||
t.Errorf("unexpected action: %s", output[2])
|
||||
}
|
||||
if output[7] != strings.Split(test, " ")[2] {
|
||||
t.Errorf("unexpected class: %s, expected: %s", output[7], strings.Split(test, " ")[2])
|
||||
}
|
||||
}
|
||||
if ix == 2 {
|
||||
if len(output) != 11 {
|
||||
t.Errorf("unexpected command: %v", output)
|
||||
}
|
||||
if output[7] != "1:" {
|
||||
t.Errorf("unexpected root class: %s", output[7])
|
||||
}
|
||||
if output[8] != "htb" {
|
||||
t.Errorf("unexpected qdisc algo: %s", output[8])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
52
vendor/k8s.io/kubernetes/pkg/util/bandwidth/unsupported.go
generated
vendored
52
vendor/k8s.io/kubernetes/pkg/util/bandwidth/unsupported.go
generated
vendored
|
@ -1,52 +0,0 @@
|
|||
// +build !linux
|
||||
|
||||
/*
|
||||
Copyright 2015 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 bandwidth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
)
|
||||
|
||||
type unsupportedShaper struct {
|
||||
}
|
||||
|
||||
func NewTCShaper(iface string) BandwidthShaper {
|
||||
return &unsupportedShaper{}
|
||||
}
|
||||
|
||||
func (f *unsupportedShaper) Limit(cidr string, egress, ingress *resource.Quantity) error {
|
||||
return errors.New("unimplemented")
|
||||
}
|
||||
|
||||
func (f *unsupportedShaper) Reset(cidr string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *unsupportedShaper) ReconcileInterface() error {
|
||||
return errors.New("unimplemented")
|
||||
}
|
||||
|
||||
func (f *unsupportedShaper) ReconcileCIDR(cidr string, egress, ingress *resource.Quantity) error {
|
||||
return errors.New("unimplemented")
|
||||
}
|
||||
|
||||
func (f *unsupportedShaper) GetCIDRs() ([]string, error) {
|
||||
return []string{}, nil
|
||||
}
|
62
vendor/k8s.io/kubernetes/pkg/util/bandwidth/utils.go
generated
vendored
62
vendor/k8s.io/kubernetes/pkg/util/bandwidth/utils.go
generated
vendored
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 bandwidth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
)
|
||||
|
||||
var minRsrc = resource.MustParse("1k")
|
||||
var maxRsrc = resource.MustParse("1P")
|
||||
|
||||
func validateBandwidthIsReasonable(rsrc *resource.Quantity) error {
|
||||
if rsrc.Value() < minRsrc.Value() {
|
||||
return fmt.Errorf("resource is unreasonably small (< 1kbit)")
|
||||
}
|
||||
if rsrc.Value() > maxRsrc.Value() {
|
||||
return fmt.Errorf("resoruce is unreasonably large (> 1Pbit)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ExtractPodBandwidthResources(podAnnotations map[string]string) (ingress, egress *resource.Quantity, err error) {
|
||||
str, found := podAnnotations["kubernetes.io/ingress-bandwidth"]
|
||||
if found {
|
||||
ingressValue, err := resource.ParseQuantity(str)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ingress = &ingressValue
|
||||
if err := validateBandwidthIsReasonable(ingress); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
str, found = podAnnotations["kubernetes.io/egress-bandwidth"]
|
||||
if found {
|
||||
egressValue, err := resource.ParseQuantity(str)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
egress = &egressValue
|
||||
if err := validateBandwidthIsReasonable(egress); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
return ingress, egress, nil
|
||||
}
|
90
vendor/k8s.io/kubernetes/pkg/util/bandwidth/utils_test.go
generated
vendored
90
vendor/k8s.io/kubernetes/pkg/util/bandwidth/utils_test.go
generated
vendored
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 bandwidth
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
)
|
||||
|
||||
func TestExtractPodBandwidthResources(t *testing.T) {
|
||||
four, _ := resource.ParseQuantity("4M")
|
||||
ten, _ := resource.ParseQuantity("10M")
|
||||
twenty, _ := resource.ParseQuantity("20M")
|
||||
|
||||
testPod := func(ingress, egress string) *api.Pod {
|
||||
pod := &api.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}}}
|
||||
if len(ingress) != 0 {
|
||||
pod.Annotations["kubernetes.io/ingress-bandwidth"] = ingress
|
||||
}
|
||||
if len(egress) != 0 {
|
||||
pod.Annotations["kubernetes.io/egress-bandwidth"] = egress
|
||||
}
|
||||
return pod
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
pod *api.Pod
|
||||
expectedIngress *resource.Quantity
|
||||
expectedEgress *resource.Quantity
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
pod: &api.Pod{},
|
||||
},
|
||||
{
|
||||
pod: testPod("10M", ""),
|
||||
expectedIngress: &ten,
|
||||
},
|
||||
{
|
||||
pod: testPod("", "10M"),
|
||||
expectedEgress: &ten,
|
||||
},
|
||||
{
|
||||
pod: testPod("4M", "20M"),
|
||||
expectedIngress: &four,
|
||||
expectedEgress: &twenty,
|
||||
},
|
||||
{
|
||||
pod: testPod("foo", ""),
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
ingress, egress, err := ExtractPodBandwidthResources(test.pod.Annotations)
|
||||
if test.expectError {
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(ingress, test.expectedIngress) {
|
||||
t.Errorf("expected: %v, saw: %v", ingress, test.expectedIngress)
|
||||
}
|
||||
if !reflect.DeepEqual(egress, test.expectedEgress) {
|
||||
t.Errorf("expected: %v, saw: %v", egress, test.expectedEgress)
|
||||
}
|
||||
}
|
||||
}
|
30
vendor/k8s.io/kubernetes/pkg/util/chmod/BUILD
generated
vendored
30
vendor/k8s.io/kubernetes/pkg/util/chmod/BUILD
generated
vendored
|
@ -1,30 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"chmod.go",
|
||||
"doc.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
30
vendor/k8s.io/kubernetes/pkg/util/chown/BUILD
generated
vendored
30
vendor/k8s.io/kubernetes/pkg/util/chown/BUILD
generated
vendored
|
@ -1,30 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"chown.go",
|
||||
"doc.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
51
vendor/k8s.io/kubernetes/pkg/util/config/BUILD
generated
vendored
51
vendor/k8s.io/kubernetes/pkg/util/config/BUILD
generated
vendored
|
@ -1,51 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"config.go",
|
||||
"configuration_map.go",
|
||||
"doc.go",
|
||||
"feature_gate.go",
|
||||
"namedcertkey_flag.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:github.com/spf13/pflag",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"config_test.go",
|
||||
"feature_gate_test.go",
|
||||
"namedcertkey_flag_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor:github.com/spf13/pflag"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
140
vendor/k8s.io/kubernetes/pkg/util/config/config.go
generated
vendored
140
vendor/k8s.io/kubernetes/pkg/util/config/config.go
generated
vendored
|
@ -1,140 +0,0 @@
|
|||
/*
|
||||
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 config
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
)
|
||||
|
||||
type Merger interface {
|
||||
// Invoked when a change from a source is received. May also function as an incremental
|
||||
// merger if you wish to consume changes incrementally. Must be reentrant when more than
|
||||
// one source is defined.
|
||||
Merge(source string, update interface{}) error
|
||||
}
|
||||
|
||||
// MergeFunc implements the Merger interface
|
||||
type MergeFunc func(source string, update interface{}) error
|
||||
|
||||
func (f MergeFunc) Merge(source string, update interface{}) error {
|
||||
return f(source, update)
|
||||
}
|
||||
|
||||
// Mux is a class for merging configuration from multiple sources. Changes are
|
||||
// pushed via channels and sent to the merge function.
|
||||
type Mux struct {
|
||||
// Invoked when an update is sent to a source.
|
||||
merger Merger
|
||||
|
||||
// Sources and their lock.
|
||||
sourceLock sync.RWMutex
|
||||
// Maps source names to channels
|
||||
sources map[string]chan interface{}
|
||||
}
|
||||
|
||||
// NewMux creates a new mux that can merge changes from multiple sources.
|
||||
func NewMux(merger Merger) *Mux {
|
||||
mux := &Mux{
|
||||
sources: make(map[string]chan interface{}),
|
||||
merger: merger,
|
||||
}
|
||||
return mux
|
||||
}
|
||||
|
||||
// Channel returns a channel where a configuration source
|
||||
// can send updates of new configurations. Multiple calls with the same
|
||||
// source will return the same channel. This allows change and state based sources
|
||||
// to use the same channel. Different source names however will be treated as a
|
||||
// union.
|
||||
func (m *Mux) Channel(source string) chan interface{} {
|
||||
if len(source) == 0 {
|
||||
panic("Channel given an empty name")
|
||||
}
|
||||
m.sourceLock.Lock()
|
||||
defer m.sourceLock.Unlock()
|
||||
channel, exists := m.sources[source]
|
||||
if exists {
|
||||
return channel
|
||||
}
|
||||
newChannel := make(chan interface{})
|
||||
m.sources[source] = newChannel
|
||||
go wait.Until(func() { m.listen(source, newChannel) }, 0, wait.NeverStop)
|
||||
return newChannel
|
||||
}
|
||||
|
||||
func (m *Mux) listen(source string, listenChannel <-chan interface{}) {
|
||||
for update := range listenChannel {
|
||||
m.merger.Merge(source, update)
|
||||
}
|
||||
}
|
||||
|
||||
// Accessor is an interface for retrieving the current merge state.
|
||||
type Accessor interface {
|
||||
// MergedState returns a representation of the current merge state.
|
||||
// Must be reentrant when more than one source is defined.
|
||||
MergedState() interface{}
|
||||
}
|
||||
|
||||
// AccessorFunc implements the Accessor interface.
|
||||
type AccessorFunc func() interface{}
|
||||
|
||||
func (f AccessorFunc) MergedState() interface{} {
|
||||
return f()
|
||||
}
|
||||
|
||||
type Listener interface {
|
||||
// OnUpdate is invoked when a change is made to an object.
|
||||
OnUpdate(instance interface{})
|
||||
}
|
||||
|
||||
// ListenerFunc receives a representation of the change or object.
|
||||
type ListenerFunc func(instance interface{})
|
||||
|
||||
func (f ListenerFunc) OnUpdate(instance interface{}) {
|
||||
f(instance)
|
||||
}
|
||||
|
||||
type Broadcaster struct {
|
||||
// Listeners for changes and their lock.
|
||||
listenerLock sync.RWMutex
|
||||
listeners []Listener
|
||||
}
|
||||
|
||||
// NewBroadcaster registers a set of listeners that support the Listener interface
|
||||
// and notifies them all on changes.
|
||||
func NewBroadcaster() *Broadcaster {
|
||||
return &Broadcaster{}
|
||||
}
|
||||
|
||||
// Add registers listener to receive updates of changes.
|
||||
func (b *Broadcaster) Add(listener Listener) {
|
||||
b.listenerLock.Lock()
|
||||
defer b.listenerLock.Unlock()
|
||||
b.listeners = append(b.listeners, listener)
|
||||
}
|
||||
|
||||
// Notify notifies all listeners.
|
||||
func (b *Broadcaster) Notify(instance interface{}) {
|
||||
b.listenerLock.RLock()
|
||||
listeners := b.listeners
|
||||
b.listenerLock.RUnlock()
|
||||
for _, listener := range listeners {
|
||||
listener.OnUpdate(instance)
|
||||
}
|
||||
}
|
120
vendor/k8s.io/kubernetes/pkg/util/config/config_test.go
generated
vendored
120
vendor/k8s.io/kubernetes/pkg/util/config/config_test.go
generated
vendored
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
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 config
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConfigurationChannels(t *testing.T) {
|
||||
mux := NewMux(nil)
|
||||
channelOne := mux.Channel("one")
|
||||
if channelOne != mux.Channel("one") {
|
||||
t.Error("Didn't get the same muxuration channel back with the same name")
|
||||
}
|
||||
channelTwo := mux.Channel("two")
|
||||
if channelOne == channelTwo {
|
||||
t.Error("Got back the same muxuration channel for different names")
|
||||
}
|
||||
}
|
||||
|
||||
type MergeMock struct {
|
||||
source string
|
||||
update interface{}
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
func (m MergeMock) Merge(source string, update interface{}) error {
|
||||
if m.source != source {
|
||||
m.t.Errorf("Expected %s, Got %s", m.source, source)
|
||||
}
|
||||
if !reflect.DeepEqual(m.update, update) {
|
||||
m.t.Errorf("Expected %s, Got %s", m.update, update)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestMergeInvoked(t *testing.T) {
|
||||
merger := MergeMock{"one", "test", t}
|
||||
mux := NewMux(&merger)
|
||||
mux.Channel("one") <- "test"
|
||||
}
|
||||
|
||||
func TestMergeFuncInvoked(t *testing.T) {
|
||||
ch := make(chan bool)
|
||||
mux := NewMux(MergeFunc(func(source string, update interface{}) error {
|
||||
if source != "one" {
|
||||
t.Errorf("Expected %s, Got %s", "one", source)
|
||||
}
|
||||
if update.(string) != "test" {
|
||||
t.Errorf("Expected %s, Got %s", "test", update)
|
||||
}
|
||||
ch <- true
|
||||
return nil
|
||||
}))
|
||||
mux.Channel("one") <- "test"
|
||||
<-ch
|
||||
}
|
||||
|
||||
func TestSimultaneousMerge(t *testing.T) {
|
||||
ch := make(chan bool, 2)
|
||||
mux := NewMux(MergeFunc(func(source string, update interface{}) error {
|
||||
switch source {
|
||||
case "one":
|
||||
if update.(string) != "test" {
|
||||
t.Errorf("Expected %s, Got %s", "test", update)
|
||||
}
|
||||
case "two":
|
||||
if update.(string) != "test2" {
|
||||
t.Errorf("Expected %s, Got %s", "test2", update)
|
||||
}
|
||||
default:
|
||||
t.Errorf("Unexpected source, Got %s", update)
|
||||
}
|
||||
ch <- true
|
||||
return nil
|
||||
}))
|
||||
source := mux.Channel("one")
|
||||
source2 := mux.Channel("two")
|
||||
source <- "test"
|
||||
source2 <- "test2"
|
||||
<-ch
|
||||
<-ch
|
||||
}
|
||||
|
||||
func TestBroadcaster(t *testing.T) {
|
||||
b := NewBroadcaster()
|
||||
b.Notify(struct{}{})
|
||||
|
||||
ch := make(chan bool, 2)
|
||||
b.Add(ListenerFunc(func(object interface{}) {
|
||||
if object != "test" {
|
||||
t.Errorf("Expected %s, Got %s", "test", object)
|
||||
}
|
||||
ch <- true
|
||||
}))
|
||||
b.Add(ListenerFunc(func(object interface{}) {
|
||||
if object != "test" {
|
||||
t.Errorf("Expected %s, Got %s", "test", object)
|
||||
}
|
||||
ch <- true
|
||||
}))
|
||||
b.Notify("test")
|
||||
<-ch
|
||||
<-ch
|
||||
}
|
53
vendor/k8s.io/kubernetes/pkg/util/config/configuration_map.go
generated
vendored
53
vendor/k8s.io/kubernetes/pkg/util/config/configuration_map.go
generated
vendored
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
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 config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ConfigurationMap map[string]string
|
||||
|
||||
func (m *ConfigurationMap) String() string {
|
||||
pairs := []string{}
|
||||
for k, v := range *m {
|
||||
pairs = append(pairs, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
sort.Strings(pairs)
|
||||
return strings.Join(pairs, ",")
|
||||
}
|
||||
|
||||
func (m *ConfigurationMap) Set(value string) error {
|
||||
for _, s := range strings.Split(value, ",") {
|
||||
if len(s) == 0 {
|
||||
continue
|
||||
}
|
||||
arr := strings.SplitN(s, "=", 2)
|
||||
if len(arr) == 2 {
|
||||
(*m)[strings.TrimSpace(arr[0])] = strings.TrimSpace(arr[1])
|
||||
} else {
|
||||
(*m)[strings.TrimSpace(arr[0])] = ""
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*ConfigurationMap) Type() string {
|
||||
return "mapStringString"
|
||||
}
|
20
vendor/k8s.io/kubernetes/pkg/util/config/doc.go
generated
vendored
20
vendor/k8s.io/kubernetes/pkg/util/config/doc.go
generated
vendored
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
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 config provides utility objects for decoupling sources of configuration and the
|
||||
// actual configuration state. Consumers must implement the Merger interface to unify
|
||||
// the sources of change into an object.
|
||||
package config // import "k8s.io/kubernetes/pkg/util/config"
|
260
vendor/k8s.io/kubernetes/pkg/util/config/feature_gate.go
generated
vendored
260
vendor/k8s.io/kubernetes/pkg/util/config/feature_gate.go
generated
vendored
|
@ -1,260 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 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 config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
const (
|
||||
flagName = "feature-gates"
|
||||
|
||||
// All known feature keys
|
||||
// To add a new feature, define a key for it below and add
|
||||
// a featureSpec entry to knownFeatures.
|
||||
|
||||
// allAlphaGate is a global toggle for alpha features. Per-feature key
|
||||
// values override the default set by allAlphaGate. Examples:
|
||||
// AllAlpha=false,NewFeature=true will result in newFeature=true
|
||||
// AllAlpha=true,NewFeature=false will result in newFeature=false
|
||||
allAlphaGate = "AllAlpha"
|
||||
externalTrafficLocalOnly = "AllowExtTrafficLocalEndpoints"
|
||||
appArmor = "AppArmor"
|
||||
dynamicKubeletConfig = "DynamicKubeletConfig"
|
||||
dynamicVolumeProvisioning = "DynamicVolumeProvisioning"
|
||||
streamingProxyRedirects = "StreamingProxyRedirects"
|
||||
|
||||
// experimentalHostUserNamespaceDefaulting Default userns=host for containers
|
||||
// that are using other host namespaces, host mounts, the pod contains a privileged container,
|
||||
// or specific non-namespaced capabilities
|
||||
// (MKNOD, SYS_MODULE, SYS_TIME). This should only be enabled if user namespace remapping is enabled
|
||||
// in the docker daemon.
|
||||
experimentalHostUserNamespaceDefaultingGate = "ExperimentalHostUserNamespaceDefaulting"
|
||||
)
|
||||
|
||||
var (
|
||||
// Default values for recorded features. Every new feature gate should be
|
||||
// represented here.
|
||||
knownFeatures = map[string]featureSpec{
|
||||
allAlphaGate: {false, alpha},
|
||||
externalTrafficLocalOnly: {true, beta},
|
||||
appArmor: {true, beta},
|
||||
dynamicKubeletConfig: {false, alpha},
|
||||
dynamicVolumeProvisioning: {true, alpha},
|
||||
streamingProxyRedirects: {true, beta},
|
||||
experimentalHostUserNamespaceDefaultingGate: {false, alpha},
|
||||
}
|
||||
|
||||
// Special handling for a few gates.
|
||||
specialFeatures = map[string]func(f *featureGate, val bool){
|
||||
allAlphaGate: setUnsetAlphaGates,
|
||||
}
|
||||
|
||||
// DefaultFeatureGate is a shared global FeatureGate.
|
||||
DefaultFeatureGate = &featureGate{
|
||||
known: knownFeatures,
|
||||
special: specialFeatures,
|
||||
}
|
||||
)
|
||||
|
||||
type featureSpec struct {
|
||||
enabled bool
|
||||
prerelease prerelease
|
||||
}
|
||||
|
||||
type prerelease string
|
||||
|
||||
const (
|
||||
// Values for prerelease.
|
||||
alpha = prerelease("ALPHA")
|
||||
beta = prerelease("BETA")
|
||||
ga = prerelease("")
|
||||
)
|
||||
|
||||
// FeatureGate parses and stores flag gates for known features from
|
||||
// a string like feature1=true,feature2=false,...
|
||||
type FeatureGate interface {
|
||||
AddFlag(fs *pflag.FlagSet)
|
||||
Set(value string) error
|
||||
KnownFeatures() []string
|
||||
|
||||
// Every feature gate should add method here following this template:
|
||||
//
|
||||
// // owner: @username
|
||||
// // alpha: v1.4
|
||||
// MyFeature() bool
|
||||
|
||||
// owner: @timstclair
|
||||
// beta: v1.4
|
||||
AppArmor() bool
|
||||
|
||||
// owner: @girishkalele
|
||||
// alpha: v1.4
|
||||
ExternalTrafficLocalOnly() bool
|
||||
|
||||
// owner: @saad-ali
|
||||
// alpha: v1.3
|
||||
DynamicVolumeProvisioning() bool
|
||||
|
||||
// owner: @mtaufen
|
||||
// alpha: v1.4
|
||||
DynamicKubeletConfig() bool
|
||||
|
||||
// owner: timstclair
|
||||
// alpha: v1.5
|
||||
StreamingProxyRedirects() bool
|
||||
|
||||
// owner: @pweil-
|
||||
// alpha: v1.5
|
||||
ExperimentalHostUserNamespaceDefaulting() bool
|
||||
}
|
||||
|
||||
// featureGate implements FeatureGate as well as pflag.Value for flag parsing.
|
||||
type featureGate struct {
|
||||
known map[string]featureSpec
|
||||
special map[string]func(*featureGate, bool)
|
||||
enabled map[string]bool
|
||||
}
|
||||
|
||||
func setUnsetAlphaGates(f *featureGate, val bool) {
|
||||
for k, v := range f.known {
|
||||
if v.prerelease == alpha {
|
||||
if _, found := f.enabled[k]; !found {
|
||||
f.enabled[k] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set, String, and Type implement pflag.Value
|
||||
|
||||
// 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.enabled = make(map[string]bool)
|
||||
for _, s := range strings.Split(value, ",") {
|
||||
if len(s) == 0 {
|
||||
continue
|
||||
}
|
||||
arr := strings.SplitN(s, "=", 2)
|
||||
k := strings.TrimSpace(arr[0])
|
||||
_, ok := f.known[k]
|
||||
if !ok {
|
||||
return fmt.Errorf("unrecognized key: %s", k)
|
||||
}
|
||||
if len(arr) != 2 {
|
||||
return fmt.Errorf("missing bool value for %s", k)
|
||||
}
|
||||
v := strings.TrimSpace(arr[1])
|
||||
boolValue, err := strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid value of %s: %s, err: %v", k, v, err)
|
||||
}
|
||||
f.enabled[k] = boolValue
|
||||
|
||||
// Handle "special" features like "all alpha gates"
|
||||
if fn, found := f.special[k]; found {
|
||||
fn(f, boolValue)
|
||||
}
|
||||
}
|
||||
|
||||
glog.Infof("feature gates: %v", f.enabled)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *featureGate) String() string {
|
||||
pairs := []string{}
|
||||
for k, v := range f.enabled {
|
||||
pairs = append(pairs, fmt.Sprintf("%s=%t", k, v))
|
||||
}
|
||||
sort.Strings(pairs)
|
||||
return strings.Join(pairs, ",")
|
||||
}
|
||||
|
||||
func (f *featureGate) Type() string {
|
||||
return "mapStringBool"
|
||||
}
|
||||
|
||||
// ExternalTrafficLocalOnly returns value for AllowExtTrafficLocalEndpoints
|
||||
func (f *featureGate) ExternalTrafficLocalOnly() bool {
|
||||
return f.lookup(externalTrafficLocalOnly)
|
||||
}
|
||||
|
||||
// AppArmor returns the value for the AppArmor feature gate.
|
||||
func (f *featureGate) AppArmor() bool {
|
||||
return f.lookup(appArmor)
|
||||
}
|
||||
|
||||
// DynamicKubeletConfig returns value for dynamicKubeletConfig
|
||||
func (f *featureGate) DynamicKubeletConfig() bool {
|
||||
return f.lookup(dynamicKubeletConfig)
|
||||
}
|
||||
|
||||
// DynamicVolumeProvisioning returns value for dynamicVolumeProvisioning
|
||||
func (f *featureGate) DynamicVolumeProvisioning() bool {
|
||||
return f.lookup(dynamicVolumeProvisioning)
|
||||
}
|
||||
|
||||
// StreamingProxyRedirects controls whether the apiserver should intercept (and follow)
|
||||
// redirects from the backend (Kubelet) for streaming requests (exec/attach/port-forward).
|
||||
func (f *featureGate) StreamingProxyRedirects() bool {
|
||||
return f.lookup(streamingProxyRedirects)
|
||||
}
|
||||
|
||||
// ExperimentalHostUserNamespaceDefaulting returns value for experimentalHostUserNamespaceDefaulting
|
||||
func (f *featureGate) ExperimentalHostUserNamespaceDefaulting() bool {
|
||||
return f.lookup(experimentalHostUserNamespaceDefaultingGate)
|
||||
}
|
||||
|
||||
func (f *featureGate) lookup(key string) bool {
|
||||
defaultValue := f.known[key].enabled
|
||||
if f.enabled != nil {
|
||||
if v, ok := f.enabled[key]; ok {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return defaultValue
|
||||
|
||||
}
|
||||
|
||||
// AddFlag adds a flag for setting global feature gates to the specified FlagSet.
|
||||
func (f *featureGate) AddFlag(fs *pflag.FlagSet) {
|
||||
known := f.KnownFeatures()
|
||||
fs.Var(f, flagName, ""+
|
||||
"A set of key=value pairs that describe feature gates for alpha/experimental features. "+
|
||||
"Options are:\n"+strings.Join(known, "\n"))
|
||||
}
|
||||
|
||||
// Returns a string describing the FeatureGate's known features.
|
||||
func (f *featureGate) KnownFeatures() []string {
|
||||
var known []string
|
||||
for k, v := range f.known {
|
||||
pre := ""
|
||||
if v.prerelease != ga {
|
||||
pre = fmt.Sprintf("%s - ", v.prerelease)
|
||||
}
|
||||
known = append(known, fmt.Sprintf("%s=true|false (%sdefault=%t)", k, pre, v.enabled))
|
||||
}
|
||||
sort.Strings(known)
|
||||
return known
|
||||
}
|
159
vendor/k8s.io/kubernetes/pkg/util/config/feature_gate_test.go
generated
vendored
159
vendor/k8s.io/kubernetes/pkg/util/config/feature_gate_test.go
generated
vendored
|
@ -1,159 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 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 config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func TestFeatureGateFlag(t *testing.T) {
|
||||
// gates for testing
|
||||
const testAlphaGate = "TestAlpha"
|
||||
const testBetaGate = "TestBeta"
|
||||
|
||||
tests := []struct {
|
||||
arg string
|
||||
expect map[string]bool
|
||||
parseError string
|
||||
}{
|
||||
{
|
||||
arg: "",
|
||||
expect: map[string]bool{
|
||||
allAlphaGate: false,
|
||||
testAlphaGate: false,
|
||||
testBetaGate: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
arg: "fooBarBaz=maybeidk",
|
||||
expect: map[string]bool{
|
||||
allAlphaGate: false,
|
||||
testAlphaGate: false,
|
||||
testBetaGate: false,
|
||||
},
|
||||
parseError: "unrecognized key: fooBarBaz",
|
||||
},
|
||||
{
|
||||
arg: "AllAlpha=false",
|
||||
expect: map[string]bool{
|
||||
allAlphaGate: false,
|
||||
testAlphaGate: false,
|
||||
testBetaGate: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
arg: "AllAlpha=true",
|
||||
expect: map[string]bool{
|
||||
allAlphaGate: true,
|
||||
testAlphaGate: true,
|
||||
testBetaGate: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
arg: "AllAlpha=banana",
|
||||
expect: map[string]bool{
|
||||
allAlphaGate: false,
|
||||
testAlphaGate: false,
|
||||
testBetaGate: false,
|
||||
},
|
||||
parseError: "invalid value of AllAlpha",
|
||||
},
|
||||
{
|
||||
arg: "AllAlpha=false,TestAlpha=true",
|
||||
expect: map[string]bool{
|
||||
allAlphaGate: false,
|
||||
testAlphaGate: true,
|
||||
testBetaGate: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
arg: "TestAlpha=true,AllAlpha=false",
|
||||
expect: map[string]bool{
|
||||
allAlphaGate: false,
|
||||
testAlphaGate: true,
|
||||
testBetaGate: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
arg: "AllAlpha=true,TestAlpha=false",
|
||||
expect: map[string]bool{
|
||||
allAlphaGate: true,
|
||||
testAlphaGate: false,
|
||||
testBetaGate: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
arg: "TestAlpha=false,AllAlpha=true",
|
||||
expect: map[string]bool{
|
||||
allAlphaGate: true,
|
||||
testAlphaGate: false,
|
||||
testBetaGate: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
arg: "TestBeta=true,AllAlpha=false",
|
||||
expect: map[string]bool{
|
||||
allAlphaGate: false,
|
||||
testAlphaGate: false,
|
||||
testBetaGate: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, test := range tests {
|
||||
fs := pflag.NewFlagSet("testfeaturegateflag", pflag.ContinueOnError)
|
||||
f := DefaultFeatureGate
|
||||
f.known[testAlphaGate] = featureSpec{false, alpha}
|
||||
f.known[testBetaGate] = featureSpec{false, beta}
|
||||
f.AddFlag(fs)
|
||||
|
||||
err := fs.Parse([]string{fmt.Sprintf("--%s=%s", flagName, test.arg)})
|
||||
if test.parseError != "" {
|
||||
if !strings.Contains(err.Error(), test.parseError) {
|
||||
t.Errorf("%d: Parse() Expected %v, Got %v", i, test.parseError, err)
|
||||
}
|
||||
} else if err != nil {
|
||||
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])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFeatureGateFlagDefaults(t *testing.T) {
|
||||
// gates for testing
|
||||
const testAlphaGate = "TestAlpha"
|
||||
const testBetaGate = "TestBeta"
|
||||
|
||||
// Don't parse the flag, assert defaults are used.
|
||||
f := DefaultFeatureGate
|
||||
f.known[testAlphaGate] = featureSpec{false, alpha}
|
||||
f.known[testBetaGate] = featureSpec{true, beta}
|
||||
|
||||
if f.lookup(testAlphaGate) != false {
|
||||
t.Errorf("Expected false")
|
||||
}
|
||||
if f.lookup(testBetaGate) != true {
|
||||
t.Errorf("Expected true")
|
||||
}
|
||||
}
|
113
vendor/k8s.io/kubernetes/pkg/util/config/namedcertkey_flag.go
generated
vendored
113
vendor/k8s.io/kubernetes/pkg/util/config/namedcertkey_flag.go
generated
vendored
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 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 config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NamedCertKey is a flag value parsing "certfile,keyfile" and "certfile,keyfile:name,name,name".
|
||||
type NamedCertKey struct {
|
||||
Names []string
|
||||
CertFile, KeyFile string
|
||||
}
|
||||
|
||||
var _ flag.Value = &NamedCertKey{}
|
||||
|
||||
func (nkc *NamedCertKey) String() string {
|
||||
s := nkc.CertFile + "," + nkc.KeyFile
|
||||
if len(nkc.Names) > 0 {
|
||||
s = s + ":" + strings.Join(nkc.Names, ",")
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (nkc *NamedCertKey) Set(value string) error {
|
||||
cs := strings.SplitN(value, ":", 2)
|
||||
var keycert string
|
||||
if len(cs) == 2 {
|
||||
var names string
|
||||
keycert, names = strings.TrimSpace(cs[0]), strings.TrimSpace(cs[1])
|
||||
if names == "" {
|
||||
return errors.New("empty names list is not allowed")
|
||||
}
|
||||
nkc.Names = nil
|
||||
for _, name := range strings.Split(names, ",") {
|
||||
nkc.Names = append(nkc.Names, strings.TrimSpace(name))
|
||||
}
|
||||
} else {
|
||||
nkc.Names = nil
|
||||
keycert = strings.TrimSpace(cs[0])
|
||||
}
|
||||
cs = strings.Split(keycert, ",")
|
||||
if len(cs) != 2 {
|
||||
return errors.New("expected comma separated certificate and key file paths")
|
||||
}
|
||||
nkc.CertFile = strings.TrimSpace(cs[0])
|
||||
nkc.KeyFile = strings.TrimSpace(cs[1])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*NamedCertKey) Type() string {
|
||||
return "namedCertKey"
|
||||
}
|
||||
|
||||
// NamedCertKeyArray is a flag value parsing NamedCertKeys, each passed with its own
|
||||
// flag instance (in contrast to comma separated slices).
|
||||
type NamedCertKeyArray struct {
|
||||
value *[]NamedCertKey
|
||||
changed bool
|
||||
}
|
||||
|
||||
var _ flag.Value = &NamedCertKey{}
|
||||
|
||||
// NewNamedKeyCertArray creates a new NamedCertKeyArray with the internal value
|
||||
// pointing to p.
|
||||
func NewNamedCertKeyArray(p *[]NamedCertKey) *NamedCertKeyArray {
|
||||
return &NamedCertKeyArray{
|
||||
value: p,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *NamedCertKeyArray) Set(val string) error {
|
||||
nkc := NamedCertKey{}
|
||||
err := nkc.Set(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !a.changed {
|
||||
*a.value = []NamedCertKey{nkc}
|
||||
a.changed = true
|
||||
} else {
|
||||
*a.value = append(*a.value, nkc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *NamedCertKeyArray) Type() string {
|
||||
return "namedCertKey"
|
||||
}
|
||||
|
||||
func (a *NamedCertKeyArray) String() string {
|
||||
nkcs := make([]string, 0, len(*a.value))
|
||||
for i := range *a.value {
|
||||
nkcs = append(nkcs, (*a.value)[i].String())
|
||||
}
|
||||
return "[" + strings.Join(nkcs, ";") + "]"
|
||||
}
|
139
vendor/k8s.io/kubernetes/pkg/util/config/namedcertkey_flag_test.go
generated
vendored
139
vendor/k8s.io/kubernetes/pkg/util/config/namedcertkey_flag_test.go
generated
vendored
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 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 config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func TestNamedCertKeyArrayFlag(t *testing.T) {
|
||||
tests := []struct {
|
||||
args []string
|
||||
def []NamedCertKey
|
||||
expected []NamedCertKey
|
||||
parseError string
|
||||
}{
|
||||
{
|
||||
args: []string{},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
args: []string{"foo.crt,foo.key"},
|
||||
expected: []NamedCertKey{{
|
||||
KeyFile: "foo.key",
|
||||
CertFile: "foo.crt",
|
||||
}},
|
||||
},
|
||||
{
|
||||
args: []string{" foo.crt , foo.key "},
|
||||
expected: []NamedCertKey{{
|
||||
KeyFile: "foo.key",
|
||||
CertFile: "foo.crt",
|
||||
}},
|
||||
},
|
||||
{
|
||||
args: []string{"foo.crt,foo.key:abc"},
|
||||
expected: []NamedCertKey{{
|
||||
KeyFile: "foo.key",
|
||||
CertFile: "foo.crt",
|
||||
Names: []string{"abc"},
|
||||
}},
|
||||
},
|
||||
{
|
||||
args: []string{"foo.crt,foo.key: abc "},
|
||||
expected: []NamedCertKey{{
|
||||
KeyFile: "foo.key",
|
||||
CertFile: "foo.crt",
|
||||
Names: []string{"abc"},
|
||||
}},
|
||||
},
|
||||
{
|
||||
args: []string{"foo.crt,foo.key:"},
|
||||
parseError: "empty names list is not allowed",
|
||||
},
|
||||
{
|
||||
args: []string{""},
|
||||
parseError: "expected comma separated certificate and key file paths",
|
||||
},
|
||||
{
|
||||
args: []string{" "},
|
||||
parseError: "expected comma separated certificate and key file paths",
|
||||
},
|
||||
{
|
||||
args: []string{"a,b,c"},
|
||||
parseError: "expected comma separated certificate and key file paths",
|
||||
},
|
||||
{
|
||||
args: []string{"foo.crt,foo.key:abc,def,ghi"},
|
||||
expected: []NamedCertKey{{
|
||||
KeyFile: "foo.key",
|
||||
CertFile: "foo.crt",
|
||||
Names: []string{"abc", "def", "ghi"},
|
||||
}},
|
||||
},
|
||||
{
|
||||
args: []string{"foo.crt,foo.key:*.*.*"},
|
||||
expected: []NamedCertKey{{
|
||||
KeyFile: "foo.key",
|
||||
CertFile: "foo.crt",
|
||||
Names: []string{"*.*.*"},
|
||||
}},
|
||||
},
|
||||
{
|
||||
args: []string{"foo.crt,foo.key", "bar.crt,bar.key"},
|
||||
expected: []NamedCertKey{{
|
||||
KeyFile: "foo.key",
|
||||
CertFile: "foo.crt",
|
||||
}, {
|
||||
KeyFile: "bar.key",
|
||||
CertFile: "bar.crt",
|
||||
}},
|
||||
},
|
||||
}
|
||||
for i, test := range tests {
|
||||
fs := pflag.NewFlagSet("testNamedCertKeyArray", pflag.ContinueOnError)
|
||||
var nkcs []NamedCertKey
|
||||
for _, d := range test.def {
|
||||
nkcs = append(nkcs, d)
|
||||
}
|
||||
fs.Var(NewNamedCertKeyArray(&nkcs), "tls-sni-cert-key", "usage")
|
||||
|
||||
args := []string{}
|
||||
for _, a := range test.args {
|
||||
args = append(args, fmt.Sprintf("--tls-sni-cert-key=%s", a))
|
||||
}
|
||||
|
||||
err := fs.Parse(args)
|
||||
if test.parseError != "" {
|
||||
if err == nil {
|
||||
t.Errorf("%d: expected error %q, got nil", i, test.parseError)
|
||||
} else if !strings.Contains(err.Error(), test.parseError) {
|
||||
t.Errorf("%d: expected error %q, got %q", i, test.parseError, err)
|
||||
}
|
||||
} else if err != nil {
|
||||
t.Errorf("%d: expected nil error, got %v", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(nkcs, test.expected) {
|
||||
t.Errorf("%d: expected %+v, got %+v", i, test.expected, nkcs)
|
||||
}
|
||||
}
|
||||
}
|
35
vendor/k8s.io/kubernetes/pkg/util/configz/BUILD
generated
vendored
35
vendor/k8s.io/kubernetes/pkg/util/configz/BUILD
generated
vendored
|
@ -1,35 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["configz.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["configz_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
86
vendor/k8s.io/kubernetes/pkg/util/configz/configz.go
generated
vendored
86
vendor/k8s.io/kubernetes/pkg/util/configz/configz.go
generated
vendored
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 configz
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
configsGuard sync.RWMutex
|
||||
configs = map[string]*Config{}
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
val interface{}
|
||||
}
|
||||
|
||||
func InstallHandler(m mux) {
|
||||
m.Handle("/configz", http.HandlerFunc(handle))
|
||||
}
|
||||
|
||||
type mux interface {
|
||||
Handle(string, http.Handler)
|
||||
}
|
||||
|
||||
func New(name string) (*Config, error) {
|
||||
configsGuard.Lock()
|
||||
defer configsGuard.Unlock()
|
||||
if _, found := configs[name]; found {
|
||||
return nil, fmt.Errorf("register config %q twice", name)
|
||||
}
|
||||
newConfig := Config{}
|
||||
configs[name] = &newConfig
|
||||
return &newConfig, nil
|
||||
}
|
||||
|
||||
func Delete(name string) {
|
||||
configsGuard.Lock()
|
||||
defer configsGuard.Unlock()
|
||||
delete(configs, name)
|
||||
}
|
||||
|
||||
func (v *Config) Set(val interface{}) {
|
||||
configsGuard.Lock()
|
||||
defer configsGuard.Unlock()
|
||||
v.val = val
|
||||
}
|
||||
|
||||
func (v *Config) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.val)
|
||||
}
|
||||
|
||||
func handle(w http.ResponseWriter, r *http.Request) {
|
||||
if err := write(w); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func write(w io.Writer) error {
|
||||
configsGuard.Lock()
|
||||
defer configsGuard.Unlock()
|
||||
b, err := json.Marshal(configs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshaling json: %v", err)
|
||||
}
|
||||
_, err = w.Write(b)
|
||||
return err
|
||||
}
|
77
vendor/k8s.io/kubernetes/pkg/util/configz/configz_test.go
generated
vendored
77
vendor/k8s.io/kubernetes/pkg/util/configz/configz_test.go
generated
vendored
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 configz
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConfigz(t *testing.T) {
|
||||
v, err := New("testing")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
v.Set("blah")
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(handle))
|
||||
defer s.Close()
|
||||
|
||||
resp, err := http.Get(s.URL + "/configz")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if string(body) != `{"testing":"blah"}` {
|
||||
t.Fatalf("unexpected output: %v", err)
|
||||
}
|
||||
|
||||
v.Set("bing")
|
||||
resp, err = http.Get(s.URL + "/configz")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if string(body) != `{"testing":"bing"}` {
|
||||
t.Fatalf("unexpected output: %v", err)
|
||||
}
|
||||
|
||||
Delete("testing")
|
||||
resp, err = http.Get(s.URL + "/configz")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if string(body) != `{}` {
|
||||
t.Fatalf("unexpected output: %v", err)
|
||||
}
|
||||
}
|
27
vendor/k8s.io/kubernetes/pkg/util/crlf/BUILD
generated
vendored
27
vendor/k8s.io/kubernetes/pkg/util/crlf/BUILD
generated
vendored
|
@ -1,27 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["crlf.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
57
vendor/k8s.io/kubernetes/pkg/util/crlf/crlf.go
generated
vendored
57
vendor/k8s.io/kubernetes/pkg/util/crlf/crlf.go
generated
vendored
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 crlf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
type crlfWriter struct {
|
||||
io.Writer
|
||||
}
|
||||
|
||||
// NewCRLFWriter implements a CR/LF line ending writer used for normalizing
|
||||
// text for Windows platforms.
|
||||
func NewCRLFWriter(w io.Writer) io.Writer {
|
||||
return crlfWriter{w}
|
||||
}
|
||||
|
||||
func (w crlfWriter) Write(b []byte) (n int, err error) {
|
||||
for i, written := 0, 0; ; {
|
||||
next := bytes.Index(b[i:], []byte("\n"))
|
||||
if next == -1 {
|
||||
n, err := w.Writer.Write(b[i:])
|
||||
return written + n, err
|
||||
}
|
||||
next = next + i
|
||||
n, err := w.Writer.Write(b[i:next])
|
||||
if err != nil {
|
||||
return written + n, err
|
||||
}
|
||||
written += n
|
||||
n, err = w.Writer.Write([]byte("\r\n"))
|
||||
if err != nil {
|
||||
if n > 1 {
|
||||
n = 1
|
||||
}
|
||||
return written + n, err
|
||||
}
|
||||
written += 1
|
||||
i = next + 1
|
||||
}
|
||||
}
|
41
vendor/k8s.io/kubernetes/pkg/util/dbus/BUILD
generated
vendored
41
vendor/k8s.io/kubernetes/pkg/util/dbus/BUILD
generated
vendored
|
@ -1,41 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"dbus.go",
|
||||
"doc.go",
|
||||
"fake_dbus.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor:github.com/godbus/dbus"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["dbus_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor:github.com/godbus/dbus"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
133
vendor/k8s.io/kubernetes/pkg/util/dbus/dbus.go
generated
vendored
133
vendor/k8s.io/kubernetes/pkg/util/dbus/dbus.go
generated
vendored
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 dbus
|
||||
|
||||
import (
|
||||
godbus "github.com/godbus/dbus"
|
||||
)
|
||||
|
||||
// Interface is an interface that presents a subset of the godbus/dbus API. Use this
|
||||
// when you want to inject fakeable/mockable D-Bus behavior.
|
||||
type Interface interface {
|
||||
// SystemBus returns a connection to the system bus, connecting to it
|
||||
// first if necessary
|
||||
SystemBus() (Connection, error)
|
||||
// SessionBus returns a connection to the session bus, connecting to it
|
||||
// first if necessary
|
||||
SessionBus() (Connection, error)
|
||||
}
|
||||
|
||||
// Connection represents a D-Bus connection
|
||||
type Connection interface {
|
||||
// Returns an Object representing the bus itself
|
||||
BusObject() Object
|
||||
|
||||
// Object creates a representation of a remote D-Bus object
|
||||
Object(name, path string) Object
|
||||
|
||||
// Signal registers or unregisters a channel to receive D-Bus signals
|
||||
Signal(ch chan<- *godbus.Signal)
|
||||
}
|
||||
|
||||
// Object represents a remote D-Bus object
|
||||
type Object interface {
|
||||
// Call synchronously calls a D-Bus method
|
||||
Call(method string, flags godbus.Flags, args ...interface{}) Call
|
||||
}
|
||||
|
||||
// Call represents a pending or completed D-Bus method call
|
||||
type Call interface {
|
||||
// Store returns a completed call's return values, or an error
|
||||
Store(retvalues ...interface{}) error
|
||||
}
|
||||
|
||||
// Implements Interface in terms of actually talking to D-Bus
|
||||
type dbusImpl struct {
|
||||
systemBus *connImpl
|
||||
sessionBus *connImpl
|
||||
}
|
||||
|
||||
// Implements Connection as a godbus.Conn
|
||||
type connImpl struct {
|
||||
conn *godbus.Conn
|
||||
}
|
||||
|
||||
// Implements Object as a godbus.Object
|
||||
type objectImpl struct {
|
||||
object godbus.BusObject
|
||||
}
|
||||
|
||||
// Implements Call as a godbus.Call
|
||||
type callImpl struct {
|
||||
call *godbus.Call
|
||||
}
|
||||
|
||||
// New returns a new Interface which will use godbus to talk to D-Bus
|
||||
func New() Interface {
|
||||
return &dbusImpl{}
|
||||
}
|
||||
|
||||
// SystemBus is part of Interface
|
||||
func (db *dbusImpl) SystemBus() (Connection, error) {
|
||||
if db.systemBus == nil {
|
||||
bus, err := godbus.SystemBus()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db.systemBus = &connImpl{bus}
|
||||
}
|
||||
|
||||
return db.systemBus, nil
|
||||
}
|
||||
|
||||
// SessionBus is part of Interface
|
||||
func (db *dbusImpl) SessionBus() (Connection, error) {
|
||||
if db.sessionBus == nil {
|
||||
bus, err := godbus.SessionBus()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db.sessionBus = &connImpl{bus}
|
||||
}
|
||||
|
||||
return db.sessionBus, nil
|
||||
}
|
||||
|
||||
// BusObject is part of the Connection interface
|
||||
func (conn *connImpl) BusObject() Object {
|
||||
return &objectImpl{conn.conn.BusObject()}
|
||||
}
|
||||
|
||||
// Object is part of the Connection interface
|
||||
func (conn *connImpl) Object(name, path string) Object {
|
||||
return &objectImpl{conn.conn.Object(name, godbus.ObjectPath(path))}
|
||||
}
|
||||
|
||||
// Signal is part of the Connection interface
|
||||
func (conn *connImpl) Signal(ch chan<- *godbus.Signal) {
|
||||
conn.conn.Signal(ch)
|
||||
}
|
||||
|
||||
// Call is part of the Object interface
|
||||
func (obj *objectImpl) Call(method string, flags godbus.Flags, args ...interface{}) Call {
|
||||
return &callImpl{obj.object.Call(method, flags, args...)}
|
||||
}
|
||||
|
||||
// Store is part of the Call interface
|
||||
func (call *callImpl) Store(retvalues ...interface{}) error {
|
||||
return call.call.Store(retvalues...)
|
||||
}
|
249
vendor/k8s.io/kubernetes/pkg/util/dbus/dbus_test.go
generated
vendored
249
vendor/k8s.io/kubernetes/pkg/util/dbus/dbus_test.go
generated
vendored
|
@ -1,249 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 dbus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
godbus "github.com/godbus/dbus"
|
||||
)
|
||||
|
||||
const (
|
||||
DBusNameFlagAllowReplacement uint32 = 1 << (iota + 1)
|
||||
DBusNameFlagReplaceExisting
|
||||
DBusNameFlagDoNotQueue
|
||||
)
|
||||
|
||||
const (
|
||||
DBusRequestNameReplyPrimaryOwner uint32 = iota + 1
|
||||
DBusRequestNameReplyInQueue
|
||||
DBusRequestNameReplyExists
|
||||
DBusRequestNameReplyAlreadyOwner
|
||||
)
|
||||
|
||||
const (
|
||||
DBusReleaseNameReplyReleased uint32 = iota + 1
|
||||
DBusReleaseNameReplyNonExistent
|
||||
DBusReleaseNameReplyNotOwner
|
||||
)
|
||||
|
||||
func doDBusTest(t *testing.T, dbus Interface, real bool) {
|
||||
bus, err := dbus.SystemBus()
|
||||
if err != nil {
|
||||
if !real {
|
||||
t.Errorf("dbus.SystemBus() failed with fake Interface")
|
||||
}
|
||||
t.Skipf("D-Bus is not running: %v", err)
|
||||
}
|
||||
busObj := bus.BusObject()
|
||||
|
||||
id := ""
|
||||
err = busObj.Call("org.freedesktop.DBus.GetId", 0).Store(&id)
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if len(id) == 0 {
|
||||
t.Errorf("expected non-empty Id, got \"\"")
|
||||
}
|
||||
|
||||
// Switch to the session bus for the rest, since the system bus is more
|
||||
// locked down (and thus harder to trick into emitting signals).
|
||||
|
||||
bus, err = dbus.SessionBus()
|
||||
if err != nil {
|
||||
if !real {
|
||||
t.Errorf("dbus.SystemBus() failed with fake Interface")
|
||||
}
|
||||
t.Skipf("D-Bus session bus is not available: %v", err)
|
||||
}
|
||||
busObj = bus.BusObject()
|
||||
|
||||
name := fmt.Sprintf("io.kubernetes.dbus_test_%d", os.Getpid())
|
||||
owner := ""
|
||||
err = busObj.Call("org.freedesktop.DBus.GetNameOwner", 0, name).Store(&owner)
|
||||
if err == nil {
|
||||
t.Errorf("expected '%s' to be un-owned, but found owner %s", name, owner)
|
||||
}
|
||||
dbuserr, ok := err.(godbus.Error)
|
||||
if !ok {
|
||||
t.Errorf("expected godbus.Error, but got %#v", err)
|
||||
}
|
||||
if dbuserr.Name != "org.freedesktop.DBus.Error.NameHasNoOwner" {
|
||||
t.Errorf("expected NameHasNoOwner error but got %v", err)
|
||||
}
|
||||
|
||||
sigchan := make(chan *godbus.Signal, 10)
|
||||
bus.Signal(sigchan)
|
||||
|
||||
rule := fmt.Sprintf("type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged',path='/org/freedesktop/DBus',sender='org.freedesktop.DBus',arg0='%s'", name)
|
||||
err = busObj.Call("org.freedesktop.DBus.AddMatch", 0, rule).Store()
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
|
||||
var ret uint32
|
||||
err = busObj.Call("org.freedesktop.DBus.RequestName", 0, name, DBusNameFlagDoNotQueue).Store(&ret)
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if ret != DBusRequestNameReplyPrimaryOwner {
|
||||
t.Errorf("expected %v, got %v", DBusRequestNameReplyPrimaryOwner, ret)
|
||||
}
|
||||
|
||||
err = busObj.Call("org.freedesktop.DBus.GetNameOwner", 0, name).Store(&owner)
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
|
||||
var changedSignal, acquiredSignal, lostSignal *godbus.Signal
|
||||
|
||||
sig1 := <-sigchan
|
||||
sig2 := <-sigchan
|
||||
// We get two signals, but the order isn't guaranteed
|
||||
if sig1.Name == "org.freedesktop.DBus.NameOwnerChanged" {
|
||||
changedSignal = sig1
|
||||
acquiredSignal = sig2
|
||||
} else {
|
||||
acquiredSignal = sig1
|
||||
changedSignal = sig2
|
||||
}
|
||||
|
||||
if acquiredSignal.Sender != "org.freedesktop.DBus" || acquiredSignal.Name != "org.freedesktop.DBus.NameAcquired" {
|
||||
t.Errorf("expected NameAcquired signal, got %v", acquiredSignal)
|
||||
}
|
||||
acquiredName := acquiredSignal.Body[0].(string)
|
||||
if acquiredName != name {
|
||||
t.Errorf("unexpected NameAcquired arguments: %v", acquiredSignal)
|
||||
}
|
||||
|
||||
if changedSignal.Sender != "org.freedesktop.DBus" || changedSignal.Name != "org.freedesktop.DBus.NameOwnerChanged" {
|
||||
t.Errorf("expected NameOwnerChanged signal, got %v", changedSignal)
|
||||
}
|
||||
|
||||
changedName := changedSignal.Body[0].(string)
|
||||
oldOwner := changedSignal.Body[1].(string)
|
||||
newOwner := changedSignal.Body[2].(string)
|
||||
if changedName != name || oldOwner != "" || newOwner != owner {
|
||||
t.Errorf("unexpected NameOwnerChanged arguments: %v", changedSignal)
|
||||
}
|
||||
|
||||
err = busObj.Call("org.freedesktop.DBus.ReleaseName", 0, name).Store(&ret)
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if ret != DBusReleaseNameReplyReleased {
|
||||
t.Errorf("expected %v, got %v", DBusReleaseNameReplyReleased, ret)
|
||||
}
|
||||
|
||||
sig1 = <-sigchan
|
||||
sig2 = <-sigchan
|
||||
if sig1.Name == "org.freedesktop.DBus.NameOwnerChanged" {
|
||||
changedSignal = sig1
|
||||
lostSignal = sig2
|
||||
} else {
|
||||
lostSignal = sig1
|
||||
changedSignal = sig2
|
||||
}
|
||||
|
||||
if lostSignal.Sender != "org.freedesktop.DBus" || lostSignal.Name != "org.freedesktop.DBus.NameLost" {
|
||||
t.Errorf("expected NameLost signal, got %v", lostSignal)
|
||||
}
|
||||
lostName := lostSignal.Body[0].(string)
|
||||
if lostName != name {
|
||||
t.Errorf("unexpected NameLost arguments: %v", lostSignal)
|
||||
}
|
||||
|
||||
if changedSignal.Sender != "org.freedesktop.DBus" || changedSignal.Name != "org.freedesktop.DBus.NameOwnerChanged" {
|
||||
t.Errorf("expected NameOwnerChanged signal, got %v", changedSignal)
|
||||
}
|
||||
|
||||
changedName = changedSignal.Body[0].(string)
|
||||
oldOwner = changedSignal.Body[1].(string)
|
||||
newOwner = changedSignal.Body[2].(string)
|
||||
if changedName != name || oldOwner != owner || newOwner != "" {
|
||||
t.Errorf("unexpected NameOwnerChanged arguments: %v", changedSignal)
|
||||
}
|
||||
|
||||
if len(sigchan) != 0 {
|
||||
t.Errorf("unexpected extra signals (%d)", len(sigchan))
|
||||
}
|
||||
|
||||
// Unregister sigchan
|
||||
bus.Signal(sigchan)
|
||||
}
|
||||
|
||||
func TestRealDBus(t *testing.T) {
|
||||
dbus := New()
|
||||
doDBusTest(t, dbus, true)
|
||||
}
|
||||
|
||||
func TestFakeDBus(t *testing.T) {
|
||||
uniqueName := ":1.1"
|
||||
ownedName := ""
|
||||
|
||||
fakeSystem := NewFakeConnection()
|
||||
fakeSystem.SetBusObject(
|
||||
func(method string, args ...interface{}) ([]interface{}, error) {
|
||||
if method == "org.freedesktop.DBus.GetId" {
|
||||
return []interface{}{"foo"}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected method call '%s'", method)
|
||||
},
|
||||
)
|
||||
|
||||
fakeSession := NewFakeConnection()
|
||||
fakeSession.SetBusObject(
|
||||
func(method string, args ...interface{}) ([]interface{}, error) {
|
||||
if method == "org.freedesktop.DBus.GetNameOwner" {
|
||||
checkName := args[0].(string)
|
||||
if checkName != ownedName {
|
||||
return nil, godbus.Error{Name: "org.freedesktop.DBus.Error.NameHasNoOwner", Body: nil}
|
||||
} else {
|
||||
return []interface{}{uniqueName}, nil
|
||||
}
|
||||
} else if method == "org.freedesktop.DBus.RequestName" {
|
||||
reqName := args[0].(string)
|
||||
_ = args[1].(uint32)
|
||||
if ownedName != "" {
|
||||
return []interface{}{DBusRequestNameReplyAlreadyOwner}, nil
|
||||
}
|
||||
ownedName = reqName
|
||||
fakeSession.EmitSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameAcquired", reqName)
|
||||
fakeSession.EmitSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged", reqName, "", uniqueName)
|
||||
return []interface{}{DBusRequestNameReplyPrimaryOwner}, nil
|
||||
} else if method == "org.freedesktop.DBus.ReleaseName" {
|
||||
reqName := args[0].(string)
|
||||
if reqName != ownedName {
|
||||
return []interface{}{DBusReleaseNameReplyNotOwner}, nil
|
||||
}
|
||||
ownedName = ""
|
||||
fakeSession.EmitSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged", reqName, uniqueName, "")
|
||||
fakeSession.EmitSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameLost", reqName)
|
||||
return []interface{}{DBusReleaseNameReplyReleased}, nil
|
||||
} else if method == "org.freedesktop.DBus.AddMatch" {
|
||||
return nil, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("unexpected method call '%s'", method)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
dbus := NewFake(fakeSystem, fakeSession)
|
||||
doDBusTest(t, dbus, false)
|
||||
}
|
18
vendor/k8s.io/kubernetes/pkg/util/dbus/doc.go
generated
vendored
18
vendor/k8s.io/kubernetes/pkg/util/dbus/doc.go
generated
vendored
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 dbus provides an injectable interface and implementations for D-Bus communication
|
||||
package dbus // import "k8s.io/kubernetes/pkg/util/dbus"
|
135
vendor/k8s.io/kubernetes/pkg/util/dbus/fake_dbus.go
generated
vendored
135
vendor/k8s.io/kubernetes/pkg/util/dbus/fake_dbus.go
generated
vendored
|
@ -1,135 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 dbus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
godbus "github.com/godbus/dbus"
|
||||
)
|
||||
|
||||
// DBusFake is a simple fake Interface type.
|
||||
type DBusFake struct {
|
||||
systemBus *DBusFakeConnection
|
||||
sessionBus *DBusFakeConnection
|
||||
}
|
||||
|
||||
// DBusFakeConnection represents a fake D-Bus connection
|
||||
type DBusFakeConnection struct {
|
||||
busObject *fakeObject
|
||||
objects map[string]*fakeObject
|
||||
signalHandlers []chan<- *godbus.Signal
|
||||
}
|
||||
|
||||
// DBusFakeHandler is used to handle fake D-Bus method calls
|
||||
type DBusFakeHandler func(method string, args ...interface{}) ([]interface{}, error)
|
||||
|
||||
type fakeObject struct {
|
||||
handler DBusFakeHandler
|
||||
}
|
||||
|
||||
type fakeCall struct {
|
||||
ret []interface{}
|
||||
err error
|
||||
}
|
||||
|
||||
// NewFake returns a new Interface which will fake talking to D-Bus
|
||||
func NewFake(systemBus *DBusFakeConnection, sessionBus *DBusFakeConnection) *DBusFake {
|
||||
return &DBusFake{systemBus, sessionBus}
|
||||
}
|
||||
|
||||
func NewFakeConnection() *DBusFakeConnection {
|
||||
return &DBusFakeConnection{
|
||||
objects: make(map[string]*fakeObject),
|
||||
}
|
||||
}
|
||||
|
||||
// SystemBus is part of Interface
|
||||
func (db *DBusFake) SystemBus() (Connection, error) {
|
||||
if db.systemBus != nil {
|
||||
return db.systemBus, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("DBus is not running")
|
||||
}
|
||||
}
|
||||
|
||||
// SessionBus is part of Interface
|
||||
func (db *DBusFake) SessionBus() (Connection, error) {
|
||||
if db.sessionBus != nil {
|
||||
return db.sessionBus, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("DBus is not running")
|
||||
}
|
||||
}
|
||||
|
||||
// BusObject is part of the Connection interface
|
||||
func (conn *DBusFakeConnection) BusObject() Object {
|
||||
return conn.busObject
|
||||
}
|
||||
|
||||
// Object is part of the Connection interface
|
||||
func (conn *DBusFakeConnection) Object(name, path string) Object {
|
||||
return conn.objects[name+path]
|
||||
}
|
||||
|
||||
// Signal is part of the Connection interface
|
||||
func (conn *DBusFakeConnection) Signal(ch chan<- *godbus.Signal) {
|
||||
for i := range conn.signalHandlers {
|
||||
if conn.signalHandlers[i] == ch {
|
||||
conn.signalHandlers = append(conn.signalHandlers[:i], conn.signalHandlers[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
conn.signalHandlers = append(conn.signalHandlers, ch)
|
||||
}
|
||||
|
||||
// SetBusObject sets the handler for the BusObject of conn
|
||||
func (conn *DBusFakeConnection) SetBusObject(handler DBusFakeHandler) {
|
||||
conn.busObject = &fakeObject{handler}
|
||||
}
|
||||
|
||||
// AddObject adds a handler for the Object at name and path
|
||||
func (conn *DBusFakeConnection) AddObject(name, path string, handler DBusFakeHandler) {
|
||||
conn.objects[name+path] = &fakeObject{handler}
|
||||
}
|
||||
|
||||
// EmitSignal emits a signal on conn
|
||||
func (conn *DBusFakeConnection) EmitSignal(name, path, iface, signal string, args ...interface{}) {
|
||||
sig := &godbus.Signal{
|
||||
Sender: name,
|
||||
Path: godbus.ObjectPath(path),
|
||||
Name: iface + "." + signal,
|
||||
Body: args,
|
||||
}
|
||||
for _, ch := range conn.signalHandlers {
|
||||
ch <- sig
|
||||
}
|
||||
}
|
||||
|
||||
// Call is part of the Object interface
|
||||
func (obj *fakeObject) Call(method string, flags godbus.Flags, args ...interface{}) Call {
|
||||
ret, err := obj.handler(method, args...)
|
||||
return &fakeCall{ret, err}
|
||||
}
|
||||
|
||||
// Store is part of the Call interface
|
||||
func (call *fakeCall) Store(retvalues ...interface{}) error {
|
||||
if call.err != nil {
|
||||
return call.err
|
||||
}
|
||||
return godbus.Store(call.ret, retvalues...)
|
||||
}
|
37
vendor/k8s.io/kubernetes/pkg/util/ebtables/BUILD
generated
vendored
37
vendor/k8s.io/kubernetes/pkg/util/ebtables/BUILD
generated
vendored
|
@ -1,37 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["ebtables.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = ["//pkg/util/exec:go_default_library"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["ebtables_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//pkg/util/exec:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
190
vendor/k8s.io/kubernetes/pkg/util/ebtables/ebtables.go
generated
vendored
190
vendor/k8s.io/kubernetes/pkg/util/ebtables/ebtables.go
generated
vendored
|
@ -1,190 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 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 ebtables
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
utilexec "k8s.io/kubernetes/pkg/util/exec"
|
||||
)
|
||||
|
||||
const (
|
||||
cmdebtables = "ebtables"
|
||||
|
||||
// Flag to show full mac in output. The default representation omits leading zeroes.
|
||||
fullMac = "--Lmac2"
|
||||
)
|
||||
|
||||
type RulePosition string
|
||||
|
||||
const (
|
||||
Prepend RulePosition = "-I"
|
||||
Append RulePosition = "-A"
|
||||
)
|
||||
|
||||
type Table string
|
||||
|
||||
const (
|
||||
TableNAT Table = "nat"
|
||||
TableFilter Table = "filter"
|
||||
)
|
||||
|
||||
type Chain string
|
||||
|
||||
const (
|
||||
ChainPostrouting Chain = "POSTROUTING"
|
||||
ChainPrerouting Chain = "PREROUTING"
|
||||
ChainOutput Chain = "OUTPUT"
|
||||
ChainInput Chain = "INPUT"
|
||||
)
|
||||
|
||||
type operation string
|
||||
|
||||
const (
|
||||
opCreateChain operation = "-N"
|
||||
opFlushChain operation = "-F"
|
||||
opDeleteChain operation = "-X"
|
||||
opListChain operation = "-L"
|
||||
opAppendRule operation = "-A"
|
||||
opPrependRule operation = "-I"
|
||||
opDeleteRule operation = "-D"
|
||||
)
|
||||
|
||||
// An injectable interface for running ebtables commands. Implementations must be goroutine-safe.
|
||||
type Interface interface {
|
||||
// GetVersion returns the "X.Y.Z" semver string for ebtables.
|
||||
GetVersion() (string, error)
|
||||
// EnsureRule checks if the specified rule is present and, if not, creates it. If the rule existed, return true.
|
||||
// WARNING: ebtables does not provide check operation like iptables do. Hence we have to do a string match of args.
|
||||
// Input args must follow the format and sequence of ebtables list output. Otherwise, EnsureRule will always create
|
||||
// new rules and causing duplicates.
|
||||
EnsureRule(position RulePosition, table Table, chain Chain, args ...string) (bool, error)
|
||||
// EnsureChain checks if the specified chain is present and, if not, creates it. If the rule existed, return true.
|
||||
EnsureChain(table Table, chain Chain) (bool, error)
|
||||
// DeleteChain deletes the specified chain. If the chain did not exist, return error.
|
||||
DeleteChain(table Table, chain Chain) error
|
||||
// FlushChain flush the specified chain. If the chain did not exist, return error.
|
||||
FlushChain(table Table, chain Chain) error
|
||||
}
|
||||
|
||||
// runner implements Interface in terms of exec("ebtables").
|
||||
type runner struct {
|
||||
mu sync.Mutex
|
||||
exec utilexec.Interface
|
||||
}
|
||||
|
||||
// New returns a new Interface which will exec ebtables.
|
||||
func New(exec utilexec.Interface) Interface {
|
||||
runner := &runner{
|
||||
exec: exec,
|
||||
}
|
||||
return runner
|
||||
}
|
||||
|
||||
func makeFullArgs(table Table, op operation, chain Chain, args ...string) []string {
|
||||
return append([]string{"-t", string(table), string(op), string(chain)}, args...)
|
||||
}
|
||||
|
||||
// getEbtablesVersionString runs "ebtables --version" to get the version string
|
||||
// in the form "X.X.X"
|
||||
func getEbtablesVersionString(exec utilexec.Interface) (string, error) {
|
||||
// this doesn't access mutable state so we don't need to use the interface / runner
|
||||
bytes, err := exec.Command(cmdebtables, "--version").CombinedOutput()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
versionMatcher := regexp.MustCompile("v([0-9]+\\.[0-9]+\\.[0-9]+)")
|
||||
match := versionMatcher.FindStringSubmatch(string(bytes))
|
||||
if match == nil {
|
||||
return "", fmt.Errorf("no ebtables version found in string: %s", bytes)
|
||||
}
|
||||
return match[1], nil
|
||||
}
|
||||
|
||||
func (runner *runner) GetVersion() (string, error) {
|
||||
return getEbtablesVersionString(runner.exec)
|
||||
}
|
||||
|
||||
func (runner *runner) EnsureRule(position RulePosition, table Table, chain Chain, args ...string) (bool, error) {
|
||||
exist := true
|
||||
fullArgs := makeFullArgs(table, opListChain, chain, fullMac)
|
||||
out, err := runner.exec.Command(cmdebtables, fullArgs...).CombinedOutput()
|
||||
if err != nil {
|
||||
exist = false
|
||||
} else {
|
||||
exist = checkIfRuleExists(string(out), args...)
|
||||
}
|
||||
if !exist {
|
||||
fullArgs = makeFullArgs(table, operation(position), chain, args...)
|
||||
out, err := runner.exec.Command(cmdebtables, fullArgs...).CombinedOutput()
|
||||
if err != nil {
|
||||
return exist, fmt.Errorf("Failed to ensure rule: %v, output: %v", err, string(out))
|
||||
}
|
||||
}
|
||||
return exist, nil
|
||||
}
|
||||
|
||||
func (runner *runner) EnsureChain(table Table, chain Chain) (bool, error) {
|
||||
exist := true
|
||||
|
||||
args := makeFullArgs(table, opListChain, chain)
|
||||
_, err := runner.exec.Command(cmdebtables, args...).CombinedOutput()
|
||||
if err != nil {
|
||||
exist = false
|
||||
}
|
||||
if !exist {
|
||||
args = makeFullArgs(table, opCreateChain, chain)
|
||||
out, err := runner.exec.Command(cmdebtables, args...).CombinedOutput()
|
||||
if err != nil {
|
||||
return exist, fmt.Errorf("Failed to ensure %v chain: %v, output: %v", chain, err, string(out))
|
||||
}
|
||||
}
|
||||
return exist, nil
|
||||
}
|
||||
|
||||
// checkIfRuleExists takes the output of ebtables list chain and checks if the input rules exists
|
||||
// WARNING: checkIfRuleExists expects the input args matches the format and sequence of ebtables list output
|
||||
func checkIfRuleExists(listChainOutput string, args ...string) bool {
|
||||
rule := strings.Join(args, " ")
|
||||
for _, line := range strings.Split(listChainOutput, "\n") {
|
||||
if strings.TrimSpace(line) == rule {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (runner *runner) DeleteChain(table Table, chain Chain) error {
|
||||
fullArgs := makeFullArgs(table, opDeleteChain, chain)
|
||||
out, err := runner.exec.Command(cmdebtables, fullArgs...).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to delete %v chain %v: %v, output: %v", string(table), string(chain), err, string(out))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (runner *runner) FlushChain(table Table, chain Chain) error {
|
||||
fullArgs := makeFullArgs(table, opFlushChain, chain)
|
||||
out, err := runner.exec.Command(cmdebtables, fullArgs...).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to flush %v chain %v: %v, output: %v", string(table), string(chain), err, string(out))
|
||||
}
|
||||
return nil
|
||||
}
|
125
vendor/k8s.io/kubernetes/pkg/util/ebtables/ebtables_test.go
generated
vendored
125
vendor/k8s.io/kubernetes/pkg/util/ebtables/ebtables_test.go
generated
vendored
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 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 ebtables
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/exec"
|
||||
)
|
||||
|
||||
func testEnsureChain(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// Does not Exists
|
||||
func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 1} },
|
||||
// Success
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
// Exists
|
||||
func() ([]byte, error) { return nil, nil },
|
||||
// Does not Exists
|
||||
func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 1} },
|
||||
// Fail to create chain
|
||||
func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 2} },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
|
||||
runner := New(&fexec)
|
||||
exists, err := runner.EnsureChain(TableFilter, "TEST-CHAIN")
|
||||
if exists {
|
||||
t.Errorf("expected exists = false")
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("expected err = nil")
|
||||
}
|
||||
|
||||
exists, err = runner.EnsureChain(TableFilter, "TEST-CHAIN")
|
||||
if !exists {
|
||||
t.Errorf("expected exists = true")
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("expected err = nil")
|
||||
}
|
||||
|
||||
exists, err = runner.EnsureChain(TableFilter, "TEST-CHAIN")
|
||||
if exists {
|
||||
t.Errorf("expected exists = false")
|
||||
}
|
||||
errStr := "Failed to ensure TEST-CHAIN chain: exit 2, output:"
|
||||
if err == nil || !strings.Contains(err.Error(), errStr) {
|
||||
t.Errorf("expected error: %q", errStr)
|
||||
}
|
||||
}
|
||||
|
||||
func testEnsureRule(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// Exists
|
||||
func() ([]byte, error) {
|
||||
return []byte(`Bridge table: filter
|
||||
|
||||
Bridge chain: OUTPUT, entries: 4, policy: ACCEPT
|
||||
-j TEST
|
||||
`), nil
|
||||
},
|
||||
// Does not Exists.
|
||||
func() ([]byte, error) {
|
||||
return []byte(`Bridge table: filter
|
||||
|
||||
Bridge chain: TEST, entries: 0, policy: ACCEPT`), nil
|
||||
},
|
||||
// Fail to create
|
||||
func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 2} },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
|
||||
runner := New(&fexec)
|
||||
|
||||
exists, err := runner.EnsureRule(Append, TableFilter, ChainOutput, "-j", "TEST")
|
||||
if !exists {
|
||||
t.Errorf("expected exists = true")
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("expected err = nil")
|
||||
}
|
||||
|
||||
exists, err = runner.EnsureRule(Append, TableFilter, ChainOutput, "-j", "NEXT-TEST")
|
||||
if exists {
|
||||
t.Errorf("expected exists = false")
|
||||
}
|
||||
errStr := "Failed to ensure rule: exist 2, output: "
|
||||
if err == nil || err.Error() != errStr {
|
||||
t.Errorf("expected error: %q", errStr)
|
||||
}
|
||||
}
|
36
vendor/k8s.io/kubernetes/pkg/util/env/BUILD
generated
vendored
36
vendor/k8s.io/kubernetes/pkg/util/env/BUILD
generated
vendored
|
@ -1,36 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["env.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["env_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor:github.com/stretchr/testify/assert"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
51
vendor/k8s.io/kubernetes/pkg/util/env/env.go
generated
vendored
51
vendor/k8s.io/kubernetes/pkg/util/env/env.go
generated
vendored
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 env
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func GetEnvAsStringOrFallback(key, defaultValue string) string {
|
||||
if v := os.Getenv(key); v != "" {
|
||||
return v
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func GetEnvAsIntOrFallback(key string, defaultValue int) (int, error) {
|
||||
if v := os.Getenv(key); v != "" {
|
||||
value, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return defaultValue, err
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
return defaultValue, nil
|
||||
}
|
||||
|
||||
func GetEnvAsFloat64OrFallback(key string, defaultValue float64) (float64, error) {
|
||||
if v := os.Getenv(key); v != "" {
|
||||
value, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
return defaultValue, err
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
return defaultValue, nil
|
||||
}
|
80
vendor/k8s.io/kubernetes/pkg/util/env/env_test.go
generated
vendored
80
vendor/k8s.io/kubernetes/pkg/util/env/env_test.go
generated
vendored
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 env
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetEnvAsStringOrFallback(t *testing.T) {
|
||||
const expected = "foo"
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
key := "FLOCKER_SET_VAR"
|
||||
os.Setenv(key, expected)
|
||||
assert.Equal(expected, GetEnvAsStringOrFallback(key, "~"+expected))
|
||||
|
||||
key = "FLOCKER_UNSET_VAR"
|
||||
assert.Equal(expected, GetEnvAsStringOrFallback(key, expected))
|
||||
}
|
||||
|
||||
func TestGetEnvAsIntOrFallback(t *testing.T) {
|
||||
const expected = 1
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
key := "FLOCKER_SET_VAR"
|
||||
os.Setenv(key, strconv.Itoa(expected))
|
||||
returnVal, _ := GetEnvAsIntOrFallback(key, 1)
|
||||
assert.Equal(expected, returnVal)
|
||||
|
||||
key = "FLOCKER_UNSET_VAR"
|
||||
returnVal, _ = GetEnvAsIntOrFallback(key, expected)
|
||||
assert.Equal(expected, returnVal)
|
||||
|
||||
key = "FLOCKER_SET_VAR"
|
||||
os.Setenv(key, "not-an-int")
|
||||
returnVal, err := GetEnvAsIntOrFallback(key, 1)
|
||||
assert.Equal(expected, returnVal)
|
||||
assert.EqualError(err, "strconv.ParseInt: parsing \"not-an-int\": invalid syntax")
|
||||
}
|
||||
|
||||
func TestGetEnvAsFloat64OrFallback(t *testing.T) {
|
||||
const expected = 1.0
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
key := "FLOCKER_SET_VAR"
|
||||
os.Setenv(key, "1.0")
|
||||
returnVal, _ := GetEnvAsFloat64OrFallback(key, 2.0)
|
||||
assert.Equal(expected, returnVal)
|
||||
|
||||
key = "FLOCKER_UNSET_VAR"
|
||||
returnVal, _ = GetEnvAsFloat64OrFallback(key, 1.0)
|
||||
assert.Equal(expected, returnVal)
|
||||
|
||||
key = "FLOCKER_SET_VAR"
|
||||
os.Setenv(key, "not-a-float")
|
||||
returnVal, err := GetEnvAsFloat64OrFallback(key, 1.0)
|
||||
assert.Equal(expected, returnVal)
|
||||
assert.EqualError(err, "strconv.ParseFloat: parsing \"not-a-float\": invalid syntax")
|
||||
}
|
27
vendor/k8s.io/kubernetes/pkg/util/errors/BUILD
generated
vendored
27
vendor/k8s.io/kubernetes/pkg/util/errors/BUILD
generated
vendored
|
@ -1,27 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["doc.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
21
vendor/k8s.io/kubernetes/pkg/util/errors/doc.go
generated
vendored
21
vendor/k8s.io/kubernetes/pkg/util/errors/doc.go
generated
vendored
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 errors only exists until heapster rebases
|
||||
// TODO genericapiserver remove this empty package. Godep fails without this because heapster relies
|
||||
// on this package. This will allow us to start splitting packages, but will force
|
||||
// heapster to update on their next kube rebase.
|
||||
package errors
|
39
vendor/k8s.io/kubernetes/pkg/util/exec/BUILD
generated
vendored
39
vendor/k8s.io/kubernetes/pkg/util/exec/BUILD
generated
vendored
|
@ -1,39 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"exec.go",
|
||||
"fake_exec.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["exec_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
21
vendor/k8s.io/kubernetes/pkg/util/exec/exec.go
generated
vendored
21
vendor/k8s.io/kubernetes/pkg/util/exec/exec.go
generated
vendored
|
@ -20,6 +20,7 @@ import (
|
|||
"io"
|
||||
osexec "os/exec"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ErrExecutableNotFound is returned if the executable is not found.
|
||||
|
@ -48,6 +49,11 @@ type Cmd interface {
|
|||
SetDir(dir string)
|
||||
SetStdin(in io.Reader)
|
||||
SetStdout(out io.Writer)
|
||||
// Stops the command by sending SIGTERM. It is not guaranteed the
|
||||
// process will stop before this function returns. If the process is not
|
||||
// responding, an internal timer function will send a SIGKILL to force
|
||||
// terminate after 10 seconds.
|
||||
Stop()
|
||||
}
|
||||
|
||||
// ExitError is an interface that presents an API similar to os.ProcessState, which is
|
||||
|
@ -110,6 +116,21 @@ func (cmd *cmdWrapper) Output() ([]byte, error) {
|
|||
return out, nil
|
||||
}
|
||||
|
||||
// Stop is part of the Cmd interface.
|
||||
func (cmd *cmdWrapper) Stop() {
|
||||
c := (*osexec.Cmd)(cmd)
|
||||
if c.ProcessState.Exited() {
|
||||
return
|
||||
}
|
||||
c.Process.Signal(syscall.SIGTERM)
|
||||
time.AfterFunc(10*time.Second, func() {
|
||||
if c.ProcessState.Exited() {
|
||||
return
|
||||
}
|
||||
c.Process.Signal(syscall.SIGKILL)
|
||||
})
|
||||
}
|
||||
|
||||
func handleError(err error) error {
|
||||
if ee, ok := err.(*osexec.ExitError); ok {
|
||||
// Force a compile fail if exitErrorWrapper can't convert to ExitError.
|
||||
|
|
103
vendor/k8s.io/kubernetes/pkg/util/exec/exec_test.go
generated
vendored
103
vendor/k8s.io/kubernetes/pkg/util/exec/exec_test.go
generated
vendored
|
@ -1,103 +0,0 @@
|
|||
/*
|
||||
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 exec
|
||||
|
||||
import (
|
||||
osexec "os/exec"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestExecutorNoArgs(t *testing.T) {
|
||||
ex := New()
|
||||
|
||||
cmd := ex.Command("true")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if len(out) != 0 {
|
||||
t.Errorf("expected no output, got %q", string(out))
|
||||
}
|
||||
|
||||
cmd = ex.Command("false")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
t.Errorf("expected failure, got nil error")
|
||||
}
|
||||
if len(out) != 0 {
|
||||
t.Errorf("expected no output, got %q", string(out))
|
||||
}
|
||||
ee, ok := err.(ExitError)
|
||||
if !ok {
|
||||
t.Errorf("expected an ExitError, got %+v", err)
|
||||
}
|
||||
if ee.Exited() {
|
||||
if code := ee.ExitStatus(); code != 1 {
|
||||
t.Errorf("expected exit status 1, got %d", code)
|
||||
}
|
||||
}
|
||||
|
||||
cmd = ex.Command("/does/not/exist")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
t.Errorf("expected failure, got nil error")
|
||||
}
|
||||
if ee, ok := err.(ExitError); ok {
|
||||
t.Errorf("expected non-ExitError, got %+v", ee)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecutorWithArgs(t *testing.T) {
|
||||
ex := New()
|
||||
|
||||
cmd := ex.Command("echo", "stdout")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %+v", err)
|
||||
}
|
||||
if string(out) != "stdout\n" {
|
||||
t.Errorf("unexpected output: %q", string(out))
|
||||
}
|
||||
|
||||
cmd = ex.Command("/bin/sh", "-c", "echo stderr > /dev/stderr")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %+v", err)
|
||||
}
|
||||
if string(out) != "stderr\n" {
|
||||
t.Errorf("unexpected output: %q", string(out))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLookPath(t *testing.T) {
|
||||
ex := New()
|
||||
|
||||
shExpected, _ := osexec.LookPath("sh")
|
||||
sh, _ := ex.LookPath("sh")
|
||||
if sh != shExpected {
|
||||
t.Errorf("unexpected result for LookPath: got %s, expected %s", sh, shExpected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecutableNotFound(t *testing.T) {
|
||||
exec := New()
|
||||
cmd := exec.Command("fake_executable_name")
|
||||
_, err := cmd.CombinedOutput()
|
||||
if err != ErrExecutableNotFound {
|
||||
t.Errorf("Expected error ErrExecutableNotFound but got %v", err)
|
||||
}
|
||||
}
|
4
vendor/k8s.io/kubernetes/pkg/util/exec/fake_exec.go
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/util/exec/fake_exec.go
generated
vendored
|
@ -90,6 +90,10 @@ func (fake *FakeCmd) Output() ([]byte, error) {
|
|||
return nil, fmt.Errorf("unimplemented")
|
||||
}
|
||||
|
||||
func (fake *FakeCmd) Stop() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
// A simple fake ExitError type.
|
||||
type FakeExitError struct {
|
||||
Status int
|
||||
|
|
35
vendor/k8s.io/kubernetes/pkg/util/flag/BUILD
generated
vendored
35
vendor/k8s.io/kubernetes/pkg/util/flag/BUILD
generated
vendored
|
@ -1,35 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"flags.go",
|
||||
"string_flag.go",
|
||||
"tristate.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:github.com/spf13/pflag",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
51
vendor/k8s.io/kubernetes/pkg/util/flag/flags.go
generated
vendored
51
vendor/k8s.io/kubernetes/pkg/util/flag/flags.go
generated
vendored
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
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 flag
|
||||
|
||||
import (
|
||||
goflag "flag"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// WordSepNormalizeFunc changes all flags that contain "_" separators
|
||||
func WordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName {
|
||||
if strings.Contains(name, "_") {
|
||||
return pflag.NormalizedName(strings.Replace(name, "_", "-", -1))
|
||||
}
|
||||
return pflag.NormalizedName(name)
|
||||
}
|
||||
|
||||
// WarnWordSepNormalizeFunc changes and warns for flags that contain "_" separators
|
||||
func WarnWordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName {
|
||||
if strings.Contains(name, "_") {
|
||||
nname := strings.Replace(name, "_", "-", -1)
|
||||
glog.Warningf("%s is DEPRECATED and will be removed in a future version. Use %s instead.", name, nname)
|
||||
|
||||
return pflag.NormalizedName(nname)
|
||||
}
|
||||
return pflag.NormalizedName(name)
|
||||
}
|
||||
|
||||
// InitFlags normalizes and parses the command line flags
|
||||
func InitFlags() {
|
||||
pflag.CommandLine.SetNormalizeFunc(WordSepNormalizeFunc)
|
||||
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
|
||||
pflag.Parse()
|
||||
}
|
56
vendor/k8s.io/kubernetes/pkg/util/flag/string_flag.go
generated
vendored
56
vendor/k8s.io/kubernetes/pkg/util/flag/string_flag.go
generated
vendored
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
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 flag
|
||||
|
||||
// StringFlag is a string flag compatible with flags and pflags that keeps track of whether it had a value supplied or not.
|
||||
type StringFlag struct {
|
||||
// If Set has been invoked this value is true
|
||||
provided bool
|
||||
// The exact value provided on the flag
|
||||
value string
|
||||
}
|
||||
|
||||
func NewStringFlag(defaultVal string) StringFlag {
|
||||
return StringFlag{value: defaultVal}
|
||||
}
|
||||
|
||||
func (f *StringFlag) Default(value string) {
|
||||
f.value = value
|
||||
}
|
||||
|
||||
func (f StringFlag) String() string {
|
||||
return f.value
|
||||
}
|
||||
|
||||
func (f StringFlag) Value() string {
|
||||
return f.value
|
||||
}
|
||||
|
||||
func (f *StringFlag) Set(value string) error {
|
||||
f.value = value
|
||||
f.provided = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f StringFlag) Provided() bool {
|
||||
return f.provided
|
||||
}
|
||||
|
||||
func (f *StringFlag) Type() string {
|
||||
return "string"
|
||||
}
|
83
vendor/k8s.io/kubernetes/pkg/util/flag/tristate.go
generated
vendored
83
vendor/k8s.io/kubernetes/pkg/util/flag/tristate.go
generated
vendored
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
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 flag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Tristate is a flag compatible with flags and pflags that
|
||||
// keeps track of whether it had a value supplied or not.
|
||||
type Tristate int
|
||||
|
||||
const (
|
||||
Unset Tristate = iota // 0
|
||||
True
|
||||
False
|
||||
)
|
||||
|
||||
func (f *Tristate) Default(value bool) {
|
||||
*f = triFromBool(value)
|
||||
}
|
||||
|
||||
func (f Tristate) String() string {
|
||||
b := boolFromTri(f)
|
||||
return fmt.Sprintf("%t", b)
|
||||
}
|
||||
|
||||
func (f Tristate) Value() bool {
|
||||
b := boolFromTri(f)
|
||||
return b
|
||||
}
|
||||
|
||||
func (f *Tristate) Set(value string) error {
|
||||
boolVal, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*f = triFromBool(boolVal)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f Tristate) Provided() bool {
|
||||
if f != Unset {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *Tristate) Type() string {
|
||||
return "tristate"
|
||||
}
|
||||
|
||||
func boolFromTri(t Tristate) bool {
|
||||
if t == True {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func triFromBool(b bool) Tristate {
|
||||
if b {
|
||||
return True
|
||||
} else {
|
||||
return False
|
||||
}
|
||||
}
|
28
vendor/k8s.io/kubernetes/pkg/util/flock/BUILD
generated
vendored
28
vendor/k8s.io/kubernetes/pkg/util/flock/BUILD
generated
vendored
|
@ -1,28 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["flock_unix.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor:golang.org/x/sys/unix"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
24
vendor/k8s.io/kubernetes/pkg/util/flock/flock_other.go
generated
vendored
24
vendor/k8s.io/kubernetes/pkg/util/flock/flock_other.go
generated
vendored
|
@ -1,24 +0,0 @@
|
|||
// +build !linux,!darwin,!freebsd,!openbsd,!netbsd,!dragonfly
|
||||
|
||||
/*
|
||||
Copyright 2016 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 flock
|
||||
|
||||
// Acquire is not implemented on non-unix systems.
|
||||
func Acquire(path string) error {
|
||||
return nil
|
||||
}
|
51
vendor/k8s.io/kubernetes/pkg/util/flock/flock_unix.go
generated
vendored
51
vendor/k8s.io/kubernetes/pkg/util/flock/flock_unix.go
generated
vendored
|
@ -1,51 +0,0 @@
|
|||
// +build linux darwin freebsd openbsd netbsd dragonfly
|
||||
|
||||
/*
|
||||
Copyright 2016 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 flock
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var (
|
||||
// lock guards lockfile. Assignment is not atomic.
|
||||
lock sync.Mutex
|
||||
// os.File has a runtime.Finalizer so the fd will be closed if the struct
|
||||
// is garbage collected. Let's hold onto a reference so that doesn't happen.
|
||||
lockfile *os.File
|
||||
)
|
||||
|
||||
// Acquire acquires a lock on a file for the duration of the process. This method
|
||||
// is reentrant.
|
||||
func Acquire(path string) error {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
var err error
|
||||
if lockfile, err = os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
defer lockfile.Close()
|
||||
opts := unix.Flock_t{Type: unix.F_WRLCK}
|
||||
if err := unix.FcntlFlock(lockfile.Fd(), unix.F_SETLKW, &opts); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
27
vendor/k8s.io/kubernetes/pkg/util/framer/BUILD
generated
vendored
27
vendor/k8s.io/kubernetes/pkg/util/framer/BUILD
generated
vendored
|
@ -1,27 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["doc.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
21
vendor/k8s.io/kubernetes/pkg/util/framer/doc.go
generated
vendored
21
vendor/k8s.io/kubernetes/pkg/util/framer/doc.go
generated
vendored
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 framer only exists until heapster rebases
|
||||
// TODO genericapiserver remove this empty package. Godep fails without this because heapster relies
|
||||
// on this package. This will allow us to start splitting packages, but will force
|
||||
// heapster to update on their next kube rebase.
|
||||
package framer
|
44
vendor/k8s.io/kubernetes/pkg/util/goroutinemap/BUILD
generated
vendored
44
vendor/k8s.io/kubernetes/pkg/util/goroutinemap/BUILD
generated
vendored
|
@ -1,44 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["goroutinemap.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/util/goroutinemap/exponentialbackoff:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/runtime",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["goroutinemap_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor:k8s.io/apimachinery/pkg/util/wait"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/util/goroutinemap/exponentialbackoff:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
4
vendor/k8s.io/kubernetes/pkg/util/goroutinemap/OWNERS
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/util/goroutinemap/OWNERS
generated
vendored
|
@ -1,4 +0,0 @@
|
|||
approvers:
|
||||
- saad-ali
|
||||
reviewers:
|
||||
- saad-ali
|
27
vendor/k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff/BUILD
generated
vendored
27
vendor/k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff/BUILD
generated
vendored
|
@ -1,27 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["exponential_backoff.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
120
vendor/k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff/exponential_backoff.go
generated
vendored
120
vendor/k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff/exponential_backoff.go
generated
vendored
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 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 exponentialbackoff contains logic for implementing exponential
|
||||
// backoff for GoRoutineMap and NestedPendingOperations.
|
||||
package exponentialbackoff
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// initialDurationBeforeRetry is the amount of time after an error occurs
|
||||
// that GoroutineMap will refuse to allow another operation to start with
|
||||
// the same target (if exponentialBackOffOnError is enabled). Each
|
||||
// successive error results in a wait 2x times the previous.
|
||||
initialDurationBeforeRetry time.Duration = 500 * time.Millisecond
|
||||
|
||||
// maxDurationBeforeRetry is the maximum amount of time that
|
||||
// durationBeforeRetry will grow to due to exponential backoff.
|
||||
maxDurationBeforeRetry time.Duration = 2 * time.Minute
|
||||
)
|
||||
|
||||
// ExponentialBackoff contains the last occurrence of an error and the duration
|
||||
// that retries are not permitted.
|
||||
type ExponentialBackoff struct {
|
||||
lastError error
|
||||
lastErrorTime time.Time
|
||||
durationBeforeRetry time.Duration
|
||||
}
|
||||
|
||||
// SafeToRetry returns an error if the durationBeforeRetry period for the given
|
||||
// lastErrorTime has not yet expired. Otherwise it returns nil.
|
||||
func (expBackoff *ExponentialBackoff) SafeToRetry(operationName string) error {
|
||||
if time.Since(expBackoff.lastErrorTime) <= expBackoff.durationBeforeRetry {
|
||||
return NewExponentialBackoffError(operationName, *expBackoff)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (expBackoff *ExponentialBackoff) Update(err *error) {
|
||||
if expBackoff.durationBeforeRetry == 0 {
|
||||
expBackoff.durationBeforeRetry = initialDurationBeforeRetry
|
||||
} else {
|
||||
expBackoff.durationBeforeRetry = 2 * expBackoff.durationBeforeRetry
|
||||
if expBackoff.durationBeforeRetry > maxDurationBeforeRetry {
|
||||
expBackoff.durationBeforeRetry = maxDurationBeforeRetry
|
||||
}
|
||||
}
|
||||
|
||||
expBackoff.lastError = *err
|
||||
expBackoff.lastErrorTime = time.Now()
|
||||
}
|
||||
|
||||
func (expBackoff *ExponentialBackoff) GenerateNoRetriesPermittedMsg(
|
||||
operationName string) string {
|
||||
return fmt.Sprintf("Operation for %q failed. No retries permitted until %v (durationBeforeRetry %v). Error: %v",
|
||||
operationName,
|
||||
expBackoff.lastErrorTime.Add(expBackoff.durationBeforeRetry),
|
||||
expBackoff.durationBeforeRetry,
|
||||
expBackoff.lastError)
|
||||
}
|
||||
|
||||
// NewExponentialBackoffError returns a new instance of ExponentialBackoff error.
|
||||
func NewExponentialBackoffError(
|
||||
operationName string, expBackoff ExponentialBackoff) error {
|
||||
return exponentialBackoffError{
|
||||
operationName: operationName,
|
||||
expBackoff: expBackoff,
|
||||
}
|
||||
}
|
||||
|
||||
// IsExponentialBackoff returns true if an error returned from GoroutineMap
|
||||
// indicates that a new operation can not be started because
|
||||
// exponentialBackOffOnError is enabled and a previous operation with the same
|
||||
// operation failed within the durationBeforeRetry period.
|
||||
func IsExponentialBackoff(err error) bool {
|
||||
switch err.(type) {
|
||||
case exponentialBackoffError:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// exponentialBackoffError is the error returned returned from GoroutineMap when
|
||||
// a new operation can not be started because exponentialBackOffOnError is
|
||||
// enabled and a previous operation with the same operation failed within the
|
||||
// durationBeforeRetry period.
|
||||
type exponentialBackoffError struct {
|
||||
operationName string
|
||||
expBackoff ExponentialBackoff
|
||||
}
|
||||
|
||||
var _ error = exponentialBackoffError{}
|
||||
|
||||
func (err exponentialBackoffError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"Failed to create operation with name %q. An operation with that name failed at %v. No retries permitted until %v (%v). Last error: %q.",
|
||||
err.operationName,
|
||||
err.expBackoff.lastErrorTime,
|
||||
err.expBackoff.lastErrorTime.Add(err.expBackoff.durationBeforeRetry),
|
||||
err.expBackoff.durationBeforeRetry,
|
||||
err.expBackoff.lastError)
|
||||
}
|
243
vendor/k8s.io/kubernetes/pkg/util/goroutinemap/goroutinemap.go
generated
vendored
243
vendor/k8s.io/kubernetes/pkg/util/goroutinemap/goroutinemap.go
generated
vendored
|
@ -1,243 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 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 goroutinemap implements a data structure for managing go routines
|
||||
by name. It prevents the creation of new go routines if an existing go routine
|
||||
with the same name exists.
|
||||
*/
|
||||
package goroutinemap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
k8sRuntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff"
|
||||
)
|
||||
|
||||
const (
|
||||
// initialDurationBeforeRetry is the amount of time after an error occurs
|
||||
// that GoRoutineMap will refuse to allow another operation to start with
|
||||
// the same operation name (if exponentialBackOffOnError is enabled). Each
|
||||
// successive error results in a wait 2x times the previous.
|
||||
initialDurationBeforeRetry = 500 * time.Millisecond
|
||||
|
||||
// maxDurationBeforeRetry is the maximum amount of time that
|
||||
// durationBeforeRetry will grow to due to exponential backoff.
|
||||
maxDurationBeforeRetry = 2 * time.Minute
|
||||
)
|
||||
|
||||
// GoRoutineMap defines a type that can run named goroutines and track their
|
||||
// state. It prevents the creation of multiple goroutines with the same name
|
||||
// and may prevent recreation of a goroutine until after the a backoff time
|
||||
// has elapsed after the last goroutine with that name finished.
|
||||
type GoRoutineMap interface {
|
||||
// Run adds operation name to the list of running operations and spawns a
|
||||
// new go routine to execute the operation.
|
||||
// If an operation with the same operation name already exists, an
|
||||
// AlreadyExists or ExponentialBackoff error is returned.
|
||||
// Once the operation is complete, the go routine is terminated and the
|
||||
// operation name is removed from the list of executing operations allowing
|
||||
// a new operation to be started with the same operation name without error.
|
||||
Run(operationName string, operationFunc func() error) error
|
||||
|
||||
// Wait blocks until operations map is empty. This is typically
|
||||
// necessary during tests - the test should wait until all operations finish
|
||||
// and evaluate results after that.
|
||||
Wait()
|
||||
|
||||
// WaitForCompletion blocks until either all operations have successfully completed
|
||||
// or have failed but are not pending. The test should wait until operations are either
|
||||
// complete or have failed.
|
||||
WaitForCompletion()
|
||||
|
||||
// IsOperationPending returns true if the operation is pending (currently
|
||||
// running), otherwise returns false.
|
||||
IsOperationPending(operationName string) bool
|
||||
}
|
||||
|
||||
// NewGoRoutineMap returns a new instance of GoRoutineMap.
|
||||
func NewGoRoutineMap(exponentialBackOffOnError bool) GoRoutineMap {
|
||||
g := &goRoutineMap{
|
||||
operations: make(map[string]operation),
|
||||
exponentialBackOffOnError: exponentialBackOffOnError,
|
||||
}
|
||||
|
||||
g.cond = sync.NewCond(&g.lock)
|
||||
return g
|
||||
}
|
||||
|
||||
type goRoutineMap struct {
|
||||
operations map[string]operation
|
||||
exponentialBackOffOnError bool
|
||||
cond *sync.Cond
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// operation holds the state of a single goroutine.
|
||||
type operation struct {
|
||||
operationPending bool
|
||||
expBackoff exponentialbackoff.ExponentialBackoff
|
||||
}
|
||||
|
||||
func (grm *goRoutineMap) Run(
|
||||
operationName string,
|
||||
operationFunc func() error) error {
|
||||
grm.lock.Lock()
|
||||
defer grm.lock.Unlock()
|
||||
|
||||
existingOp, exists := grm.operations[operationName]
|
||||
if exists {
|
||||
// Operation with name exists
|
||||
if existingOp.operationPending {
|
||||
return NewAlreadyExistsError(operationName)
|
||||
}
|
||||
|
||||
if err := existingOp.expBackoff.SafeToRetry(operationName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
grm.operations[operationName] = operation{
|
||||
operationPending: true,
|
||||
expBackoff: existingOp.expBackoff,
|
||||
}
|
||||
go func() (err error) {
|
||||
// Handle unhandled panics (very unlikely)
|
||||
defer k8sRuntime.HandleCrash()
|
||||
// Handle completion of and error, if any, from operationFunc()
|
||||
defer grm.operationComplete(operationName, &err)
|
||||
// Handle panic, if any, from operationFunc()
|
||||
defer k8sRuntime.RecoverFromPanic(&err)
|
||||
return operationFunc()
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// operationComplete handles the completion of a goroutine run in the
|
||||
// goRoutineMap.
|
||||
func (grm *goRoutineMap) operationComplete(
|
||||
operationName string, err *error) {
|
||||
// Defer operations are executed in Last-In is First-Out order. In this case
|
||||
// the lock is acquired first when operationCompletes begins, and is
|
||||
// released when the method finishes, after the lock is released cond is
|
||||
// signaled to wake waiting goroutine.
|
||||
defer grm.cond.Signal()
|
||||
grm.lock.Lock()
|
||||
defer grm.lock.Unlock()
|
||||
|
||||
if *err == nil || !grm.exponentialBackOffOnError {
|
||||
// Operation completed without error, or exponentialBackOffOnError disabled
|
||||
delete(grm.operations, operationName)
|
||||
if *err != nil {
|
||||
// Log error
|
||||
glog.Errorf("operation for %q failed with: %v",
|
||||
operationName,
|
||||
*err)
|
||||
}
|
||||
} else {
|
||||
// Operation completed with error and exponentialBackOffOnError Enabled
|
||||
existingOp := grm.operations[operationName]
|
||||
existingOp.expBackoff.Update(err)
|
||||
existingOp.operationPending = false
|
||||
grm.operations[operationName] = existingOp
|
||||
|
||||
// Log error
|
||||
glog.Errorf("%v",
|
||||
existingOp.expBackoff.GenerateNoRetriesPermittedMsg(operationName))
|
||||
}
|
||||
}
|
||||
|
||||
func (grm *goRoutineMap) IsOperationPending(operationName string) bool {
|
||||
grm.lock.RLock()
|
||||
defer grm.lock.RUnlock()
|
||||
existingOp, exists := grm.operations[operationName]
|
||||
if exists && existingOp.operationPending {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (grm *goRoutineMap) Wait() {
|
||||
grm.lock.Lock()
|
||||
defer grm.lock.Unlock()
|
||||
|
||||
for len(grm.operations) > 0 {
|
||||
grm.cond.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
func (grm *goRoutineMap) WaitForCompletion() {
|
||||
grm.lock.Lock()
|
||||
defer grm.lock.Unlock()
|
||||
|
||||
for {
|
||||
if len(grm.operations) == 0 || grm.nothingPending() {
|
||||
break
|
||||
} else {
|
||||
grm.cond.Wait()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if any operation is pending. Already assumes caller has the
|
||||
// necessary locks
|
||||
func (grm *goRoutineMap) nothingPending() bool {
|
||||
nothingIsPending := true
|
||||
for _, operation := range grm.operations {
|
||||
if operation.operationPending {
|
||||
nothingIsPending = false
|
||||
break
|
||||
}
|
||||
}
|
||||
return nothingIsPending
|
||||
}
|
||||
|
||||
// NewAlreadyExistsError returns a new instance of AlreadyExists error.
|
||||
func NewAlreadyExistsError(operationName string) error {
|
||||
return alreadyExistsError{operationName}
|
||||
}
|
||||
|
||||
// IsAlreadyExists returns true if an error returned from GoRoutineMap indicates
|
||||
// a new operation can not be started because an operation with the same
|
||||
// operation name is already executing.
|
||||
func IsAlreadyExists(err error) bool {
|
||||
switch err.(type) {
|
||||
case alreadyExistsError:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// alreadyExistsError is the error returned by GoRoutineMap when a new operation
|
||||
// can not be started because an operation with the same operation name is
|
||||
// already executing.
|
||||
type alreadyExistsError struct {
|
||||
operationName string
|
||||
}
|
||||
|
||||
var _ error = alreadyExistsError{}
|
||||
|
||||
func (err alreadyExistsError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"Failed to create operation with name %q. An operation with that name is already executing.",
|
||||
err.operationName)
|
||||
}
|
531
vendor/k8s.io/kubernetes/pkg/util/goroutinemap/goroutinemap_test.go
generated
vendored
531
vendor/k8s.io/kubernetes/pkg/util/goroutinemap/goroutinemap_test.go
generated
vendored
|
@ -1,531 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 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 goroutinemap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
)
|
||||
|
||||
const (
|
||||
// testTimeout is a timeout of goroutines to finish. This _should_ be just a
|
||||
// "context switch" and it should take several ms, however, Clayton says "We
|
||||
// have had flakes due to tests that assumed that 15s is long enough to sleep")
|
||||
testTimeout time.Duration = 1 * time.Minute
|
||||
|
||||
// initialOperationWaitTimeShort is the initial amount of time the test will
|
||||
// wait for an operation to complete (each successive failure results in
|
||||
// exponential backoff).
|
||||
initialOperationWaitTimeShort time.Duration = 20 * time.Millisecond
|
||||
|
||||
// initialOperationWaitTimeLong is the initial amount of time the test will
|
||||
// wait for an operation to complete (each successive failure results in
|
||||
// exponential backoff).
|
||||
initialOperationWaitTimeLong time.Duration = 500 * time.Millisecond
|
||||
)
|
||||
|
||||
func Test_NewGoRoutineMap_Positive_SingleOp(t *testing.T) {
|
||||
// Arrange
|
||||
grm := NewGoRoutineMap(false /* exponentialBackOffOnError */)
|
||||
operationName := "operation-name"
|
||||
operation := func() error { return nil }
|
||||
|
||||
// Act
|
||||
err := grm.Run(operationName, operation)
|
||||
|
||||
// Assert
|
||||
if err != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewGoRoutineMap_Positive_TwoOps(t *testing.T) {
|
||||
// Arrange
|
||||
grm := NewGoRoutineMap(false /* exponentialBackOffOnError */)
|
||||
operation1Name := "operation1-name"
|
||||
operation2Name := "operation2-name"
|
||||
operation := func() error { return nil }
|
||||
|
||||
// Act
|
||||
err1 := grm.Run(operation1Name, operation)
|
||||
err2 := grm.Run(operation2Name, operation)
|
||||
|
||||
// Assert
|
||||
if err1 != nil {
|
||||
t.Fatalf("NewGoRoutine %q failed. Expected: <no error> Actual: <%v>", operation1Name, err1)
|
||||
}
|
||||
|
||||
if err2 != nil {
|
||||
t.Fatalf("NewGoRoutine %q failed. Expected: <no error> Actual: <%v>", operation2Name, err2)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewGoRoutineMap_Positive_SingleOpWithExpBackoff(t *testing.T) {
|
||||
// Arrange
|
||||
grm := NewGoRoutineMap(true /* exponentialBackOffOnError */)
|
||||
operationName := "operation-name"
|
||||
operation := func() error { return nil }
|
||||
|
||||
// Act
|
||||
err := grm.Run(operationName, operation)
|
||||
|
||||
// Assert
|
||||
if err != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewGoRoutineMap_Positive_SecondOpAfterFirstCompletes(t *testing.T) {
|
||||
// Arrange
|
||||
grm := NewGoRoutineMap(false /* exponentialBackOffOnError */)
|
||||
operationName := "operation-name"
|
||||
operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
|
||||
operation1 := generateCallbackFunc(operation1DoneCh)
|
||||
err1 := grm.Run(operationName, operation1)
|
||||
if err1 != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
|
||||
}
|
||||
operation2 := generateNoopFunc()
|
||||
<-operation1DoneCh // Force operation1 to complete
|
||||
|
||||
// Act
|
||||
err2 := retryWithExponentialBackOff(
|
||||
time.Duration(initialOperationWaitTimeShort),
|
||||
func() (bool, error) {
|
||||
err := grm.Run(operationName, operation2)
|
||||
if err != nil {
|
||||
t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
},
|
||||
)
|
||||
|
||||
// Assert
|
||||
if err2 != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err2)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewGoRoutineMap_Positive_SecondOpAfterFirstCompletesWithExpBackoff(t *testing.T) {
|
||||
// Arrange
|
||||
grm := NewGoRoutineMap(true /* exponentialBackOffOnError */)
|
||||
operationName := "operation-name"
|
||||
operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
|
||||
operation1 := generateCallbackFunc(operation1DoneCh)
|
||||
err1 := grm.Run(operationName, operation1)
|
||||
if err1 != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
|
||||
}
|
||||
operation2 := generateNoopFunc()
|
||||
<-operation1DoneCh // Force operation1 to complete
|
||||
|
||||
// Act
|
||||
err2 := retryWithExponentialBackOff(
|
||||
time.Duration(initialOperationWaitTimeShort),
|
||||
func() (bool, error) {
|
||||
err := grm.Run(operationName, operation2)
|
||||
if err != nil {
|
||||
t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
},
|
||||
)
|
||||
|
||||
// Assert
|
||||
if err2 != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err2)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewGoRoutineMap_Positive_SecondOpAfterFirstPanics(t *testing.T) {
|
||||
// Arrange
|
||||
grm := NewGoRoutineMap(false /* exponentialBackOffOnError */)
|
||||
operationName := "operation-name"
|
||||
operation1 := generatePanicFunc()
|
||||
err1 := grm.Run(operationName, operation1)
|
||||
if err1 != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
|
||||
}
|
||||
operation2 := generateNoopFunc()
|
||||
|
||||
// Act
|
||||
err2 := retryWithExponentialBackOff(
|
||||
time.Duration(initialOperationWaitTimeShort),
|
||||
func() (bool, error) {
|
||||
err := grm.Run(operationName, operation2)
|
||||
if err != nil {
|
||||
t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
},
|
||||
)
|
||||
|
||||
// Assert
|
||||
if err2 != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err2)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewGoRoutineMap_Positive_SecondOpAfterFirstPanicsWithExpBackoff(t *testing.T) {
|
||||
// Arrange
|
||||
grm := NewGoRoutineMap(true /* exponentialBackOffOnError */)
|
||||
operationName := "operation-name"
|
||||
operation1 := generatePanicFunc()
|
||||
err1 := grm.Run(operationName, operation1)
|
||||
if err1 != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
|
||||
}
|
||||
operation2 := generateNoopFunc()
|
||||
|
||||
// Act
|
||||
err2 := retryWithExponentialBackOff(
|
||||
time.Duration(initialOperationWaitTimeLong), // Longer duration to accommodate for backoff
|
||||
func() (bool, error) {
|
||||
err := grm.Run(operationName, operation2)
|
||||
if err != nil {
|
||||
t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
},
|
||||
)
|
||||
|
||||
// Assert
|
||||
if err2 != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err2)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewGoRoutineMap_Negative_SecondOpBeforeFirstCompletes(t *testing.T) {
|
||||
// Arrange
|
||||
grm := NewGoRoutineMap(false /* exponentialBackOffOnError */)
|
||||
operationName := "operation-name"
|
||||
operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
|
||||
operation1 := generateWaitFunc(operation1DoneCh)
|
||||
err1 := grm.Run(operationName, operation1)
|
||||
if err1 != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
|
||||
}
|
||||
operation2 := generateNoopFunc()
|
||||
|
||||
// Act
|
||||
err2 := grm.Run(operationName, operation2)
|
||||
|
||||
// Assert
|
||||
if err2 == nil {
|
||||
t.Fatalf("NewGoRoutine did not fail. Expected: <Failed to create operation with name \"%s\". An operation with that name already exists.> Actual: <no error>", operationName)
|
||||
}
|
||||
if !IsAlreadyExists(err2) {
|
||||
t.Fatalf("NewGoRoutine did not return alreadyExistsError, got: %v", err2)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewGoRoutineMap_Negative_SecondOpBeforeFirstCompletesWithExpBackoff(t *testing.T) {
|
||||
// Arrange
|
||||
grm := NewGoRoutineMap(true /* exponentialBackOffOnError */)
|
||||
operationName := "operation-name"
|
||||
operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
|
||||
operation1 := generateWaitFunc(operation1DoneCh)
|
||||
err1 := grm.Run(operationName, operation1)
|
||||
if err1 != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
|
||||
}
|
||||
operation2 := generateNoopFunc()
|
||||
|
||||
// Act
|
||||
err2 := grm.Run(operationName, operation2)
|
||||
|
||||
// Assert
|
||||
if err2 == nil {
|
||||
t.Fatalf("NewGoRoutine did not fail. Expected: <Failed to create operation with name \"%s\". An operation with that name already exists.> Actual: <no error>", operationName)
|
||||
}
|
||||
if !IsAlreadyExists(err2) {
|
||||
t.Fatalf("NewGoRoutine did not return alreadyExistsError, got: %v", err2)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewGoRoutineMap_Positive_ThirdOpAfterFirstCompletes(t *testing.T) {
|
||||
// Arrange
|
||||
grm := NewGoRoutineMap(false /* exponentialBackOffOnError */)
|
||||
operationName := "operation-name"
|
||||
operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
|
||||
operation1 := generateWaitFunc(operation1DoneCh)
|
||||
err1 := grm.Run(operationName, operation1)
|
||||
if err1 != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
|
||||
}
|
||||
operation2 := generateNoopFunc()
|
||||
operation3 := generateNoopFunc()
|
||||
|
||||
// Act
|
||||
err2 := grm.Run(operationName, operation2)
|
||||
|
||||
// Assert
|
||||
if err2 == nil {
|
||||
t.Fatalf("NewGoRoutine did not fail. Expected: <Failed to create operation with name \"%s\". An operation with that name already exists.> Actual: <no error>", operationName)
|
||||
}
|
||||
if !IsAlreadyExists(err2) {
|
||||
t.Fatalf("NewGoRoutine did not return alreadyExistsError, got: %v", err2)
|
||||
}
|
||||
|
||||
// Act
|
||||
operation1DoneCh <- true // Force operation1 to complete
|
||||
err3 := retryWithExponentialBackOff(
|
||||
time.Duration(initialOperationWaitTimeShort),
|
||||
func() (bool, error) {
|
||||
err := grm.Run(operationName, operation3)
|
||||
if err != nil {
|
||||
t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
},
|
||||
)
|
||||
|
||||
// Assert
|
||||
if err3 != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err3)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewGoRoutineMap_Positive_ThirdOpAfterFirstCompletesWithExpBackoff(t *testing.T) {
|
||||
// Arrange
|
||||
grm := NewGoRoutineMap(true /* exponentialBackOffOnError */)
|
||||
operationName := "operation-name"
|
||||
operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
|
||||
operation1 := generateWaitFunc(operation1DoneCh)
|
||||
err1 := grm.Run(operationName, operation1)
|
||||
if err1 != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
|
||||
}
|
||||
operation2 := generateNoopFunc()
|
||||
operation3 := generateNoopFunc()
|
||||
|
||||
// Act
|
||||
err2 := grm.Run(operationName, operation2)
|
||||
|
||||
// Assert
|
||||
if err2 == nil {
|
||||
t.Fatalf("NewGoRoutine did not fail. Expected: <Failed to create operation with name \"%s\". An operation with that name already exists.> Actual: <no error>", operationName)
|
||||
}
|
||||
if !IsAlreadyExists(err2) {
|
||||
t.Fatalf("NewGoRoutine did not return alreadyExistsError, got: %v", err2)
|
||||
}
|
||||
|
||||
// Act
|
||||
operation1DoneCh <- true // Force operation1 to complete
|
||||
err3 := retryWithExponentialBackOff(
|
||||
time.Duration(initialOperationWaitTimeShort),
|
||||
func() (bool, error) {
|
||||
err := grm.Run(operationName, operation3)
|
||||
if err != nil {
|
||||
t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
},
|
||||
)
|
||||
|
||||
// Assert
|
||||
if err3 != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err3)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewGoRoutineMap_Positive_WaitEmpty(t *testing.T) {
|
||||
// Test than Wait() on empty GoRoutineMap always succeeds without blocking
|
||||
// Arrange
|
||||
grm := NewGoRoutineMap(false /* exponentialBackOffOnError */)
|
||||
|
||||
// Act
|
||||
waitDoneCh := make(chan interface{}, 1)
|
||||
go func() {
|
||||
grm.Wait()
|
||||
waitDoneCh <- true
|
||||
}()
|
||||
|
||||
// Assert
|
||||
err := waitChannelWithTimeout(waitDoneCh, testTimeout)
|
||||
if err != nil {
|
||||
t.Errorf("Error waiting for GoRoutineMap.Wait: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewGoRoutineMap_Positive_WaitEmptyWithExpBackoff(t *testing.T) {
|
||||
// Test than Wait() on empty GoRoutineMap always succeeds without blocking
|
||||
// Arrange
|
||||
grm := NewGoRoutineMap(true /* exponentialBackOffOnError */)
|
||||
|
||||
// Act
|
||||
waitDoneCh := make(chan interface{}, 1)
|
||||
go func() {
|
||||
grm.Wait()
|
||||
waitDoneCh <- true
|
||||
}()
|
||||
|
||||
// Assert
|
||||
err := waitChannelWithTimeout(waitDoneCh, testTimeout)
|
||||
if err != nil {
|
||||
t.Errorf("Error waiting for GoRoutineMap.Wait: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewGoRoutineMap_Positive_Wait(t *testing.T) {
|
||||
// Test that Wait() really blocks until the last operation succeeds
|
||||
// Arrange
|
||||
grm := NewGoRoutineMap(false /* exponentialBackOffOnError */)
|
||||
operationName := "operation-name"
|
||||
operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
|
||||
operation1 := generateWaitFunc(operation1DoneCh)
|
||||
err := grm.Run(operationName, operation1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err)
|
||||
}
|
||||
|
||||
// Act
|
||||
waitDoneCh := make(chan interface{}, 1)
|
||||
go func() {
|
||||
grm.Wait()
|
||||
waitDoneCh <- true
|
||||
}()
|
||||
|
||||
// Finish the operation
|
||||
operation1DoneCh <- true
|
||||
|
||||
// Assert
|
||||
err = waitChannelWithTimeout(waitDoneCh, testTimeout)
|
||||
if err != nil {
|
||||
t.Fatalf("Error waiting for GoRoutineMap.Wait: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewGoRoutineMap_Positive_WaitWithExpBackoff(t *testing.T) {
|
||||
// Test that Wait() really blocks until the last operation succeeds
|
||||
// Arrange
|
||||
grm := NewGoRoutineMap(true /* exponentialBackOffOnError */)
|
||||
operationName := "operation-name"
|
||||
operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
|
||||
operation1 := generateWaitFunc(operation1DoneCh)
|
||||
err := grm.Run(operationName, operation1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err)
|
||||
}
|
||||
|
||||
// Act
|
||||
waitDoneCh := make(chan interface{}, 1)
|
||||
go func() {
|
||||
grm.Wait()
|
||||
waitDoneCh <- true
|
||||
}()
|
||||
|
||||
// Finish the operation
|
||||
operation1DoneCh <- true
|
||||
|
||||
// Assert
|
||||
err = waitChannelWithTimeout(waitDoneCh, testTimeout)
|
||||
if err != nil {
|
||||
t.Fatalf("Error waiting for GoRoutineMap.Wait: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewGoRoutineMap_WaitForCompletionWithExpBackoff(t *testing.T) {
|
||||
grm := NewGoRoutineMap(true /* exponentialBackOffOnError */)
|
||||
operationName := "operation-err"
|
||||
|
||||
operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
|
||||
operation1 := generateErrorFunc(operation1DoneCh)
|
||||
err := grm.Run(operationName, operation1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err)
|
||||
}
|
||||
|
||||
// Act
|
||||
waitDoneCh := make(chan interface{}, 1)
|
||||
go func() {
|
||||
grm.WaitForCompletion()
|
||||
waitDoneCh <- true
|
||||
}()
|
||||
|
||||
// Finish the operation
|
||||
operation1DoneCh <- true
|
||||
|
||||
// Assert that WaitForCompletion returns even if scheduled op had error
|
||||
err = waitChannelWithTimeout(waitDoneCh, testTimeout)
|
||||
if err != nil {
|
||||
t.Fatalf("Error waiting for GoRoutineMap.Wait: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func generateCallbackFunc(done chan<- interface{}) func() error {
|
||||
return func() error {
|
||||
done <- true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func generateErrorFunc(done <-chan interface{}) func() error {
|
||||
return func() error {
|
||||
<-done
|
||||
return fmt.Errorf("Generic error")
|
||||
}
|
||||
}
|
||||
|
||||
func generateWaitFunc(done <-chan interface{}) func() error {
|
||||
return func() error {
|
||||
<-done
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func generatePanicFunc() func() error {
|
||||
return func() error {
|
||||
panic("testing panic")
|
||||
}
|
||||
}
|
||||
|
||||
func generateNoopFunc() func() error {
|
||||
return func() error { return nil }
|
||||
}
|
||||
|
||||
func retryWithExponentialBackOff(initialDuration time.Duration, fn wait.ConditionFunc) error {
|
||||
backoff := wait.Backoff{
|
||||
Duration: initialDuration,
|
||||
Factor: 3,
|
||||
Jitter: 0,
|
||||
Steps: 4,
|
||||
}
|
||||
return wait.ExponentialBackoff(backoff, fn)
|
||||
}
|
||||
|
||||
func waitChannelWithTimeout(ch <-chan interface{}, timeout time.Duration) error {
|
||||
timer := time.NewTimer(timeout)
|
||||
defer timer.Stop()
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
// Success!
|
||||
return nil
|
||||
case <-timer.C:
|
||||
return fmt.Errorf("timeout after %v", timeout)
|
||||
}
|
||||
}
|
37
vendor/k8s.io/kubernetes/pkg/util/hash/BUILD
generated
vendored
37
vendor/k8s.io/kubernetes/pkg/util/hash/BUILD
generated
vendored
|
@ -1,37 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["hash.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor:github.com/davecgh/go-spew/spew"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["hash_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor:github.com/davecgh/go-spew/spew"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
147
vendor/k8s.io/kubernetes/pkg/util/hash/hash_test.go
generated
vendored
147
vendor/k8s.io/kubernetes/pkg/util/hash/hash_test.go
generated
vendored
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 hash
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/adler32"
|
||||
"testing"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
type A struct {
|
||||
x int
|
||||
y string
|
||||
}
|
||||
|
||||
type B struct {
|
||||
x []int
|
||||
y map[string]bool
|
||||
}
|
||||
|
||||
type C struct {
|
||||
x int
|
||||
y string
|
||||
}
|
||||
|
||||
func (c C) String() string {
|
||||
return fmt.Sprintf("%d:%s", c.x, c.y)
|
||||
}
|
||||
|
||||
func TestDeepHashObject(t *testing.T) {
|
||||
successCases := []func() interface{}{
|
||||
func() interface{} { return 8675309 },
|
||||
func() interface{} { return "Jenny, I got your number" },
|
||||
func() interface{} { return []string{"eight", "six", "seven"} },
|
||||
func() interface{} { return [...]int{5, 3, 0, 9} },
|
||||
func() interface{} { return map[int]string{8: "8", 6: "6", 7: "7"} },
|
||||
func() interface{} { return map[string]int{"5": 5, "3": 3, "0": 0, "9": 9} },
|
||||
func() interface{} { return A{867, "5309"} },
|
||||
func() interface{} { return &A{867, "5309"} },
|
||||
func() interface{} {
|
||||
return B{[]int{8, 6, 7}, map[string]bool{"5": true, "3": true, "0": true, "9": true}}
|
||||
},
|
||||
func() interface{} { return map[A]bool{A{8675309, "Jenny"}: true, A{9765683, "!Jenny"}: false} },
|
||||
func() interface{} { return map[C]bool{C{8675309, "Jenny"}: true, C{9765683, "!Jenny"}: false} },
|
||||
func() interface{} { return map[*A]bool{&A{8675309, "Jenny"}: true, &A{9765683, "!Jenny"}: false} },
|
||||
func() interface{} { return map[*C]bool{&C{8675309, "Jenny"}: true, &C{9765683, "!Jenny"}: false} },
|
||||
}
|
||||
|
||||
for _, tc := range successCases {
|
||||
hasher1 := adler32.New()
|
||||
DeepHashObject(hasher1, tc())
|
||||
hash1 := hasher1.Sum32()
|
||||
DeepHashObject(hasher1, tc())
|
||||
hash2 := hasher1.Sum32()
|
||||
if hash1 != hash2 {
|
||||
t.Fatalf("hash of the same object (%q) produced different results: %d vs %d", toString(tc()), hash1, hash2)
|
||||
}
|
||||
for i := 0; i < 100; i++ {
|
||||
hasher2 := adler32.New()
|
||||
|
||||
DeepHashObject(hasher1, tc())
|
||||
hash1a := hasher1.Sum32()
|
||||
DeepHashObject(hasher2, tc())
|
||||
hash2a := hasher2.Sum32()
|
||||
|
||||
if hash1a != hash1 {
|
||||
t.Errorf("repeated hash of the same object (%q) produced different results: %d vs %d", toString(tc()), hash1, hash1a)
|
||||
}
|
||||
if hash2a != hash2 {
|
||||
t.Errorf("repeated hash of the same object (%q) produced different results: %d vs %d", toString(tc()), hash2, hash2a)
|
||||
}
|
||||
if hash1a != hash2a {
|
||||
t.Errorf("hash of the same object produced (%q) different results: %d vs %d", toString(tc()), hash1a, hash2a)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toString(obj interface{}) string {
|
||||
return spew.Sprintf("%#v", obj)
|
||||
}
|
||||
|
||||
type wheel struct {
|
||||
radius uint32
|
||||
}
|
||||
|
||||
type unicycle struct {
|
||||
primaryWheel *wheel
|
||||
licencePlateID string
|
||||
tags map[string]string
|
||||
}
|
||||
|
||||
func TestDeepObjectPointer(t *testing.T) {
|
||||
// Arrange
|
||||
wheel1 := wheel{radius: 17}
|
||||
wheel2 := wheel{radius: 22}
|
||||
wheel3 := wheel{radius: 17}
|
||||
|
||||
myUni1 := unicycle{licencePlateID: "blah", primaryWheel: &wheel1, tags: map[string]string{"color": "blue", "name": "john"}}
|
||||
myUni2 := unicycle{licencePlateID: "blah", primaryWheel: &wheel2, tags: map[string]string{"color": "blue", "name": "john"}}
|
||||
myUni3 := unicycle{licencePlateID: "blah", primaryWheel: &wheel3, tags: map[string]string{"color": "blue", "name": "john"}}
|
||||
|
||||
// Run it more than once to verify determinism of hasher.
|
||||
for i := 0; i < 100; i++ {
|
||||
hasher1 := adler32.New()
|
||||
hasher2 := adler32.New()
|
||||
hasher3 := adler32.New()
|
||||
// Act
|
||||
DeepHashObject(hasher1, myUni1)
|
||||
hash1 := hasher1.Sum32()
|
||||
DeepHashObject(hasher1, myUni1)
|
||||
hash1a := hasher1.Sum32()
|
||||
DeepHashObject(hasher2, myUni2)
|
||||
hash2 := hasher2.Sum32()
|
||||
DeepHashObject(hasher3, myUni3)
|
||||
hash3 := hasher3.Sum32()
|
||||
|
||||
// Assert
|
||||
if hash1 != hash1a {
|
||||
t.Errorf("repeated hash of the same object produced different results: %d vs %d", hash1, hash1a)
|
||||
}
|
||||
|
||||
if hash1 == hash2 {
|
||||
t.Errorf("hash1 (%d) and hash2(%d) must be different because they have different values for wheel size", hash1, hash2)
|
||||
}
|
||||
|
||||
if hash1 != hash3 {
|
||||
t.Errorf("hash1 (%d) and hash3(%d) must be the same because although they point to different objects, they have the same values for wheel size", hash1, hash3)
|
||||
}
|
||||
}
|
||||
}
|
42
vendor/k8s.io/kubernetes/pkg/util/httpstream/BUILD
generated
vendored
42
vendor/k8s.io/kubernetes/pkg/util/httpstream/BUILD
generated
vendored
|
@ -1,42 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"httpstream.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["httpstream_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//pkg/api:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/util/httpstream/spdy:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
19
vendor/k8s.io/kubernetes/pkg/util/httpstream/doc.go
generated
vendored
19
vendor/k8s.io/kubernetes/pkg/util/httpstream/doc.go
generated
vendored
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 httpstream adds multiplexed streaming support to HTTP requests and
|
||||
// responses via connection upgrades.
|
||||
package httpstream // import "k8s.io/kubernetes/pkg/util/httpstream"
|
149
vendor/k8s.io/kubernetes/pkg/util/httpstream/httpstream.go
generated
vendored
149
vendor/k8s.io/kubernetes/pkg/util/httpstream/httpstream.go
generated
vendored
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 httpstream
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
HeaderConnection = "Connection"
|
||||
HeaderUpgrade = "Upgrade"
|
||||
HeaderProtocolVersion = "X-Stream-Protocol-Version"
|
||||
HeaderAcceptedProtocolVersions = "X-Accepted-Stream-Protocol-Versions"
|
||||
)
|
||||
|
||||
// NewStreamHandler defines a function that is called when a new Stream is
|
||||
// received. If no error is returned, the Stream is accepted; otherwise,
|
||||
// the stream is rejected. After the reply frame has been sent, replySent is closed.
|
||||
type NewStreamHandler func(stream Stream, replySent <-chan struct{}) error
|
||||
|
||||
// NoOpNewStreamHandler is a stream handler that accepts a new stream and
|
||||
// performs no other logic.
|
||||
func NoOpNewStreamHandler(stream Stream, replySent <-chan struct{}) error { return nil }
|
||||
|
||||
// Dialer knows how to open a streaming connection to a server.
|
||||
type Dialer interface {
|
||||
|
||||
// Dial opens a streaming connection to a server using one of the protocols
|
||||
// specified (in order of most preferred to least preferred).
|
||||
Dial(protocols ...string) (Connection, string, error)
|
||||
}
|
||||
|
||||
// UpgradeRoundTripper is a type of http.RoundTripper that is able to upgrade
|
||||
// HTTP requests to support multiplexed bidirectional streams. After RoundTrip()
|
||||
// is invoked, if the upgrade is successful, clients may retrieve the upgraded
|
||||
// connection by calling UpgradeRoundTripper.Connection().
|
||||
type UpgradeRoundTripper interface {
|
||||
http.RoundTripper
|
||||
// NewConnection validates the response and creates a new Connection.
|
||||
NewConnection(resp *http.Response) (Connection, error)
|
||||
}
|
||||
|
||||
// ResponseUpgrader knows how to upgrade HTTP requests and responses to
|
||||
// add streaming support to them.
|
||||
type ResponseUpgrader interface {
|
||||
// UpgradeResponse upgrades an HTTP response to one that supports multiplexed
|
||||
// streams. newStreamHandler will be called asynchronously whenever the
|
||||
// other end of the upgraded connection creates a new stream.
|
||||
UpgradeResponse(w http.ResponseWriter, req *http.Request, newStreamHandler NewStreamHandler) Connection
|
||||
}
|
||||
|
||||
// Connection represents an upgraded HTTP connection.
|
||||
type Connection interface {
|
||||
// CreateStream creates a new Stream with the supplied headers.
|
||||
CreateStream(headers http.Header) (Stream, error)
|
||||
// Close resets all streams and closes the connection.
|
||||
Close() error
|
||||
// CloseChan returns a channel that is closed when the underlying connection is closed.
|
||||
CloseChan() <-chan bool
|
||||
// SetIdleTimeout sets the amount of time the connection may remain idle before
|
||||
// it is automatically closed.
|
||||
SetIdleTimeout(timeout time.Duration)
|
||||
}
|
||||
|
||||
// Stream represents a bidirectional communications channel that is part of an
|
||||
// upgraded connection.
|
||||
type Stream interface {
|
||||
io.ReadWriteCloser
|
||||
// Reset closes both directions of the stream, indicating that neither client
|
||||
// or server can use it any more.
|
||||
Reset() error
|
||||
// Headers returns the headers used to create the stream.
|
||||
Headers() http.Header
|
||||
// Identifier returns the stream's ID.
|
||||
Identifier() uint32
|
||||
}
|
||||
|
||||
// IsUpgradeRequest returns true if the given request is a connection upgrade request
|
||||
func IsUpgradeRequest(req *http.Request) bool {
|
||||
for _, h := range req.Header[http.CanonicalHeaderKey(HeaderConnection)] {
|
||||
if strings.Contains(strings.ToLower(h), strings.ToLower(HeaderUpgrade)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func negotiateProtocol(clientProtocols, serverProtocols []string) string {
|
||||
for i := range clientProtocols {
|
||||
for j := range serverProtocols {
|
||||
if clientProtocols[i] == serverProtocols[j] {
|
||||
return clientProtocols[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Handshake performs a subprotocol negotiation. If the client did request a
|
||||
// subprotocol, Handshake will select the first common value found in
|
||||
// serverProtocols. If a match is found, Handshake adds a response header
|
||||
// indicating the chosen subprotocol. If no match is found, HTTP forbidden is
|
||||
// returned, along with a response header containing the list of protocols the
|
||||
// server can accept.
|
||||
func Handshake(req *http.Request, w http.ResponseWriter, serverProtocols []string) (string, error) {
|
||||
clientProtocols := req.Header[http.CanonicalHeaderKey(HeaderProtocolVersion)]
|
||||
if len(clientProtocols) == 0 {
|
||||
// Kube 1.0 clients didn't support subprotocol negotiation.
|
||||
// TODO require clientProtocols once Kube 1.0 is no longer supported
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if len(serverProtocols) == 0 {
|
||||
// Kube 1.0 servers didn't support subprotocol negotiation. This is mainly for testing.
|
||||
// TODO require serverProtocols once Kube 1.0 is no longer supported
|
||||
return "", nil
|
||||
}
|
||||
|
||||
negotiatedProtocol := negotiateProtocol(clientProtocols, serverProtocols)
|
||||
if len(negotiatedProtocol) == 0 {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
for i := range serverProtocols {
|
||||
w.Header().Add(HeaderAcceptedProtocolVersions, serverProtocols[i])
|
||||
}
|
||||
fmt.Fprintf(w, "unable to upgrade: unable to negotiate protocol: client supports %v, server accepts %v", clientProtocols, serverProtocols)
|
||||
return "", fmt.Errorf("unable to upgrade: unable to negotiate protocol: client supports %v, server supports %v", clientProtocols, serverProtocols)
|
||||
}
|
||||
|
||||
w.Header().Add(HeaderProtocolVersion, negotiatedProtocol)
|
||||
return negotiatedProtocol, nil
|
||||
}
|
127
vendor/k8s.io/kubernetes/pkg/util/httpstream/httpstream_test.go
generated
vendored
127
vendor/k8s.io/kubernetes/pkg/util/httpstream/httpstream_test.go
generated
vendored
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 httpstream
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
type responseWriter struct {
|
||||
header http.Header
|
||||
statusCode *int
|
||||
}
|
||||
|
||||
func newResponseWriter() *responseWriter {
|
||||
return &responseWriter{
|
||||
header: make(http.Header),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *responseWriter) Header() http.Header {
|
||||
return r.header
|
||||
}
|
||||
|
||||
func (r *responseWriter) WriteHeader(code int) {
|
||||
r.statusCode = &code
|
||||
}
|
||||
|
||||
func (r *responseWriter) Write([]byte) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func TestHandshake(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
clientProtocols []string
|
||||
serverProtocols []string
|
||||
expectedProtocol string
|
||||
expectError bool
|
||||
}{
|
||||
"no client protocols": {
|
||||
clientProtocols: []string{},
|
||||
serverProtocols: []string{"a", "b"},
|
||||
expectedProtocol: "",
|
||||
},
|
||||
"no common protocol": {
|
||||
clientProtocols: []string{"c"},
|
||||
serverProtocols: []string{"a", "b"},
|
||||
expectedProtocol: "",
|
||||
expectError: true,
|
||||
},
|
||||
"common protocol": {
|
||||
clientProtocols: []string{"b"},
|
||||
serverProtocols: []string{"a", "b"},
|
||||
expectedProtocol: "b",
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
req, err := http.NewRequest("GET", "http://www.example.com/", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: error creating request: %v", name, err)
|
||||
}
|
||||
|
||||
for _, p := range test.clientProtocols {
|
||||
req.Header.Add(HeaderProtocolVersion, p)
|
||||
}
|
||||
|
||||
w := newResponseWriter()
|
||||
negotiated, err := Handshake(req, w, test.serverProtocols)
|
||||
|
||||
// verify negotiated protocol
|
||||
if e, a := test.expectedProtocol, negotiated; e != a {
|
||||
t.Errorf("%s: protocol: expected %q, got %q", name, e, a)
|
||||
}
|
||||
|
||||
if test.expectError {
|
||||
if err == nil {
|
||||
t.Errorf("%s: expected error but did not get one", name)
|
||||
}
|
||||
if w.statusCode == nil {
|
||||
t.Errorf("%s: expected w.statusCode to be set", name)
|
||||
} else if e, a := http.StatusForbidden, *w.statusCode; e != a {
|
||||
t.Errorf("%s: w.statusCode: expected %d, got %d", name, e, a)
|
||||
}
|
||||
if e, a := test.serverProtocols, w.Header()[HeaderAcceptedProtocolVersions]; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%s: accepted server protocols: expected %v, got %v", name, e, a)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !test.expectError && err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", name, err)
|
||||
continue
|
||||
}
|
||||
if w.statusCode != nil {
|
||||
t.Errorf("%s: unexpected non-nil w.statusCode: %d", name, w.statusCode)
|
||||
}
|
||||
|
||||
if len(test.expectedProtocol) == 0 {
|
||||
if len(w.Header()[HeaderProtocolVersion]) > 0 {
|
||||
t.Errorf("%s: unexpected protocol version response header: %s", name, w.Header()[HeaderProtocolVersion])
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// verify response headers
|
||||
if e, a := []string{test.expectedProtocol}, w.Header()[HeaderProtocolVersion]; !api.Semantic.DeepEqual(e, a) {
|
||||
t.Errorf("%s: protocol response header: expected %v, got %v", name, e, a)
|
||||
}
|
||||
}
|
||||
}
|
57
vendor/k8s.io/kubernetes/pkg/util/httpstream/spdy/BUILD
generated
vendored
57
vendor/k8s.io/kubernetes/pkg/util/httpstream/spdy/BUILD
generated
vendored
|
@ -1,57 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"connection.go",
|
||||
"roundtripper.go",
|
||||
"upgrade.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/util/httpstream:go_default_library",
|
||||
"//third_party/forked/golang/netutil:go_default_library",
|
||||
"//vendor:github.com/docker/spdystream",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/runtime",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"connection_test.go",
|
||||
"roundtripper_test.go",
|
||||
"upgrade_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/util/httpstream:go_default_library",
|
||||
"//vendor:github.com/elazarl/goproxy",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
145
vendor/k8s.io/kubernetes/pkg/util/httpstream/spdy/connection.go
generated
vendored
145
vendor/k8s.io/kubernetes/pkg/util/httpstream/spdy/connection.go
generated
vendored
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 spdy
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/docker/spdystream"
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/util/httpstream"
|
||||
)
|
||||
|
||||
// connection maintains state about a spdystream.Connection and its associated
|
||||
// streams.
|
||||
type connection struct {
|
||||
conn *spdystream.Connection
|
||||
streams []httpstream.Stream
|
||||
streamLock sync.Mutex
|
||||
newStreamHandler httpstream.NewStreamHandler
|
||||
}
|
||||
|
||||
// NewClientConnection creates a new SPDY client connection.
|
||||
func NewClientConnection(conn net.Conn) (httpstream.Connection, error) {
|
||||
spdyConn, err := spdystream.NewConnection(conn, false)
|
||||
if err != nil {
|
||||
defer conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newConnection(spdyConn, httpstream.NoOpNewStreamHandler), nil
|
||||
}
|
||||
|
||||
// NewServerConnection creates a new SPDY server connection. newStreamHandler
|
||||
// will be invoked when the server receives a newly created stream from the
|
||||
// client.
|
||||
func NewServerConnection(conn net.Conn, newStreamHandler httpstream.NewStreamHandler) (httpstream.Connection, error) {
|
||||
spdyConn, err := spdystream.NewConnection(conn, true)
|
||||
if err != nil {
|
||||
defer conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newConnection(spdyConn, newStreamHandler), nil
|
||||
}
|
||||
|
||||
// newConnection returns a new connection wrapping conn. newStreamHandler
|
||||
// will be invoked when the server receives a newly created stream from the
|
||||
// client.
|
||||
func newConnection(conn *spdystream.Connection, newStreamHandler httpstream.NewStreamHandler) httpstream.Connection {
|
||||
c := &connection{conn: conn, newStreamHandler: newStreamHandler}
|
||||
go conn.Serve(c.newSpdyStream)
|
||||
return c
|
||||
}
|
||||
|
||||
// createStreamResponseTimeout indicates how long to wait for the other side to
|
||||
// acknowledge the new stream before timing out.
|
||||
const createStreamResponseTimeout = 30 * time.Second
|
||||
|
||||
// Close first sends a reset for all of the connection's streams, and then
|
||||
// closes the underlying spdystream.Connection.
|
||||
func (c *connection) Close() error {
|
||||
c.streamLock.Lock()
|
||||
for _, s := range c.streams {
|
||||
// calling Reset instead of Close ensures that all streams are fully torn down
|
||||
s.Reset()
|
||||
}
|
||||
c.streams = make([]httpstream.Stream, 0)
|
||||
c.streamLock.Unlock()
|
||||
|
||||
// now that all streams are fully torn down, it's safe to call close on the underlying connection,
|
||||
// which should be able to terminate immediately at this point, instead of waiting for any
|
||||
// remaining graceful stream termination.
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
// CreateStream creates a new stream with the specified headers and registers
|
||||
// it with the connection.
|
||||
func (c *connection) CreateStream(headers http.Header) (httpstream.Stream, error) {
|
||||
stream, err := c.conn.CreateStream(headers, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = stream.WaitTimeout(createStreamResponseTimeout); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.registerStream(stream)
|
||||
return stream, nil
|
||||
}
|
||||
|
||||
// registerStream adds the stream s to the connection's list of streams that
|
||||
// it owns.
|
||||
func (c *connection) registerStream(s httpstream.Stream) {
|
||||
c.streamLock.Lock()
|
||||
c.streams = append(c.streams, s)
|
||||
c.streamLock.Unlock()
|
||||
}
|
||||
|
||||
// CloseChan returns a channel that, when closed, indicates that the underlying
|
||||
// spdystream.Connection has been closed.
|
||||
func (c *connection) CloseChan() <-chan bool {
|
||||
return c.conn.CloseChan()
|
||||
}
|
||||
|
||||
// newSpdyStream is the internal new stream handler used by spdystream.Connection.Serve.
|
||||
// It calls connection's newStreamHandler, giving it the opportunity to accept or reject
|
||||
// the stream. If newStreamHandler returns an error, the stream is rejected. If not, the
|
||||
// stream is accepted and registered with the connection.
|
||||
func (c *connection) newSpdyStream(stream *spdystream.Stream) {
|
||||
replySent := make(chan struct{})
|
||||
err := c.newStreamHandler(stream, replySent)
|
||||
rejectStream := (err != nil)
|
||||
if rejectStream {
|
||||
glog.Warningf("Stream rejected: %v", err)
|
||||
stream.Reset()
|
||||
return
|
||||
}
|
||||
|
||||
c.registerStream(stream)
|
||||
stream.SendReply(http.Header{}, rejectStream)
|
||||
close(replySent)
|
||||
}
|
||||
|
||||
// SetIdleTimeout sets the amount of time the connection may remain idle before
|
||||
// it is automatically closed.
|
||||
func (c *connection) SetIdleTimeout(timeout time.Duration) {
|
||||
c.conn.SetIdleTimeout(timeout)
|
||||
}
|
164
vendor/k8s.io/kubernetes/pkg/util/httpstream/spdy/connection_test.go
generated
vendored
164
vendor/k8s.io/kubernetes/pkg/util/httpstream/spdy/connection_test.go
generated
vendored
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 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 spdy
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/httpstream"
|
||||
)
|
||||
|
||||
func runProxy(t *testing.T, backendUrl string, proxyUrl chan<- string, proxyDone chan<- struct{}) {
|
||||
listener, err := net.Listen("tcp4", "localhost:0")
|
||||
if err != nil {
|
||||
t.Fatalf("error listening: %v", err)
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
proxyUrl <- listener.Addr().String()
|
||||
|
||||
clientConn, err := listener.Accept()
|
||||
if err != nil {
|
||||
t.Errorf("proxy: error accepting client connection: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
backendConn, err := net.Dial("tcp4", backendUrl)
|
||||
if err != nil {
|
||||
t.Errorf("proxy: error dialing backend: %v", err)
|
||||
return
|
||||
}
|
||||
defer backendConn.Close()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
io.Copy(backendConn, clientConn)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
io.Copy(clientConn, backendConn)
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
proxyDone <- struct{}{}
|
||||
}
|
||||
|
||||
func runServer(t *testing.T, backendUrl chan<- string, serverDone chan<- struct{}) {
|
||||
listener, err := net.Listen("tcp4", "localhost:0")
|
||||
if err != nil {
|
||||
t.Fatalf("server: error listening: %v", err)
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
backendUrl <- listener.Addr().String()
|
||||
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
t.Errorf("server: error accepting connection: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
streamChan := make(chan httpstream.Stream)
|
||||
replySentChan := make(chan (<-chan struct{}))
|
||||
spdyConn, err := NewServerConnection(conn, func(stream httpstream.Stream, replySent <-chan struct{}) error {
|
||||
streamChan <- stream
|
||||
replySentChan <- replySent
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("server: error creating spdy connection: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
stream := <-streamChan
|
||||
replySent := <-replySentChan
|
||||
<-replySent
|
||||
|
||||
buf := make([]byte, 1)
|
||||
_, err = stream.Read(buf)
|
||||
if err != io.EOF {
|
||||
t.Errorf("server: unexpected read error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
<-spdyConn.CloseChan()
|
||||
raw := spdyConn.(*connection).conn
|
||||
if err := raw.Wait(15 * time.Second); err != nil {
|
||||
t.Errorf("server: timed out waiting for connection closure: %v", err)
|
||||
}
|
||||
|
||||
serverDone <- struct{}{}
|
||||
}
|
||||
|
||||
func TestConnectionCloseIsImmediateThroughAProxy(t *testing.T) {
|
||||
serverDone := make(chan struct{})
|
||||
backendUrlChan := make(chan string)
|
||||
go runServer(t, backendUrlChan, serverDone)
|
||||
backendUrl := <-backendUrlChan
|
||||
|
||||
proxyDone := make(chan struct{})
|
||||
proxyUrlChan := make(chan string)
|
||||
go runProxy(t, backendUrl, proxyUrlChan, proxyDone)
|
||||
proxyUrl := <-proxyUrlChan
|
||||
|
||||
conn, err := net.Dial("tcp4", proxyUrl)
|
||||
if err != nil {
|
||||
t.Fatalf("client: error connecting to proxy: %v", err)
|
||||
}
|
||||
|
||||
spdyConn, err := NewClientConnection(conn)
|
||||
if err != nil {
|
||||
t.Fatalf("client: error creating spdy connection: %v", err)
|
||||
}
|
||||
|
||||
if _, err := spdyConn.CreateStream(http.Header{}); err != nil {
|
||||
t.Fatalf("client: error creating stream: %v", err)
|
||||
}
|
||||
|
||||
spdyConn.Close()
|
||||
raw := spdyConn.(*connection).conn
|
||||
if err := raw.Wait(15 * time.Second); err != nil {
|
||||
t.Fatalf("client: timed out waiting for connection closure: %v", err)
|
||||
}
|
||||
|
||||
expired := time.NewTimer(15 * time.Second)
|
||||
defer expired.Stop()
|
||||
i := 0
|
||||
for {
|
||||
select {
|
||||
case <-expired.C:
|
||||
t.Fatalf("timed out waiting for proxy and/or server closure")
|
||||
case <-serverDone:
|
||||
i++
|
||||
case <-proxyDone:
|
||||
i++
|
||||
}
|
||||
if i == 2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
267
vendor/k8s.io/kubernetes/pkg/util/httpstream/spdy/roundtripper.go
generated
vendored
267
vendor/k8s.io/kubernetes/pkg/util/httpstream/spdy/roundtripper.go
generated
vendored
|
@ -1,267 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 spdy
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/util/httpstream"
|
||||
"k8s.io/kubernetes/third_party/forked/golang/netutil"
|
||||
)
|
||||
|
||||
// SpdyRoundTripper knows how to upgrade an HTTP request to one that supports
|
||||
// multiplexed streams. After RoundTrip() is invoked, Conn will be set
|
||||
// and usable. SpdyRoundTripper implements the UpgradeRoundTripper interface.
|
||||
type SpdyRoundTripper struct {
|
||||
//tlsConfig holds the TLS configuration settings to use when connecting
|
||||
//to the remote server.
|
||||
tlsConfig *tls.Config
|
||||
|
||||
/* TODO according to http://golang.org/pkg/net/http/#RoundTripper, a RoundTripper
|
||||
must be safe for use by multiple concurrent goroutines. If this is absolutely
|
||||
necessary, we could keep a map from http.Request to net.Conn. In practice,
|
||||
a client will create an http.Client, set the transport to a new insteace of
|
||||
SpdyRoundTripper, and use it a single time, so this hopefully won't be an issue.
|
||||
*/
|
||||
// conn is the underlying network connection to the remote server.
|
||||
conn net.Conn
|
||||
|
||||
// Dialer is the dialer used to connect. Used if non-nil.
|
||||
Dialer *net.Dialer
|
||||
|
||||
// proxier knows which proxy to use given a request, defaults to http.ProxyFromEnvironment
|
||||
// Used primarily for mocking the proxy discovery in tests.
|
||||
proxier func(req *http.Request) (*url.URL, error)
|
||||
}
|
||||
|
||||
// NewRoundTripper creates a new SpdyRoundTripper that will use
|
||||
// the specified tlsConfig.
|
||||
func NewRoundTripper(tlsConfig *tls.Config) httpstream.UpgradeRoundTripper {
|
||||
return NewSpdyRoundTripper(tlsConfig)
|
||||
}
|
||||
|
||||
// NewSpdyRoundTripper creates a new SpdyRoundTripper that will use
|
||||
// the specified tlsConfig. This function is mostly meant for unit tests.
|
||||
func NewSpdyRoundTripper(tlsConfig *tls.Config) *SpdyRoundTripper {
|
||||
return &SpdyRoundTripper{tlsConfig: tlsConfig}
|
||||
}
|
||||
|
||||
// implements pkg/util/net.TLSClientConfigHolder for proper TLS checking during proxying with a spdy roundtripper
|
||||
func (s *SpdyRoundTripper) TLSClientConfig() *tls.Config {
|
||||
return s.tlsConfig
|
||||
}
|
||||
|
||||
// dial dials the host specified by req, using TLS if appropriate, optionally
|
||||
// using a proxy server if one is configured via environment variables.
|
||||
func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) {
|
||||
proxier := s.proxier
|
||||
if proxier == nil {
|
||||
proxier = http.ProxyFromEnvironment
|
||||
}
|
||||
proxyURL, err := proxier(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if proxyURL == nil {
|
||||
return s.dialWithoutProxy(req.URL)
|
||||
}
|
||||
|
||||
// ensure we use a canonical host with proxyReq
|
||||
targetHost := netutil.CanonicalAddr(req.URL)
|
||||
|
||||
// proxying logic adapted from http://blog.h6t.eu/post/74098062923/golang-websocket-with-http-proxy-support
|
||||
proxyReq := http.Request{
|
||||
Method: "CONNECT",
|
||||
URL: &url.URL{},
|
||||
Host: targetHost,
|
||||
}
|
||||
|
||||
if pa := s.proxyAuth(proxyURL); pa != "" {
|
||||
proxyReq.Header = http.Header{}
|
||||
proxyReq.Header.Set("Proxy-Authorization", pa)
|
||||
}
|
||||
|
||||
proxyDialConn, err := s.dialWithoutProxy(proxyURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
proxyClientConn := httputil.NewProxyClientConn(proxyDialConn, nil)
|
||||
_, err = proxyClientConn.Do(&proxyReq)
|
||||
if err != nil && err != httputil.ErrPersistEOF {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rwc, _ := proxyClientConn.Hijack()
|
||||
|
||||
if req.URL.Scheme != "https" {
|
||||
return rwc, nil
|
||||
}
|
||||
|
||||
host, _, err := net.SplitHostPort(targetHost)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if s.tlsConfig == nil {
|
||||
s.tlsConfig = &tls.Config{}
|
||||
}
|
||||
|
||||
if len(s.tlsConfig.ServerName) == 0 {
|
||||
s.tlsConfig.ServerName = host
|
||||
}
|
||||
|
||||
tlsConn := tls.Client(rwc, s.tlsConfig)
|
||||
|
||||
// need to manually call Handshake() so we can call VerifyHostname() below
|
||||
if err := tlsConn.Handshake(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return if we were configured to skip validation
|
||||
if s.tlsConfig != nil && s.tlsConfig.InsecureSkipVerify {
|
||||
return tlsConn, nil
|
||||
}
|
||||
|
||||
if err := tlsConn.VerifyHostname(host); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tlsConn, nil
|
||||
}
|
||||
|
||||
// dialWithoutProxy dials the host specified by url, using TLS if appropriate.
|
||||
func (s *SpdyRoundTripper) dialWithoutProxy(url *url.URL) (net.Conn, error) {
|
||||
dialAddr := netutil.CanonicalAddr(url)
|
||||
|
||||
if url.Scheme == "http" {
|
||||
if s.Dialer == nil {
|
||||
return net.Dial("tcp", dialAddr)
|
||||
} else {
|
||||
return s.Dialer.Dial("tcp", dialAddr)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO validate the TLSClientConfig is set up?
|
||||
var conn *tls.Conn
|
||||
var err error
|
||||
if s.Dialer == nil {
|
||||
conn, err = tls.Dial("tcp", dialAddr, s.tlsConfig)
|
||||
} else {
|
||||
conn, err = tls.DialWithDialer(s.Dialer, "tcp", dialAddr, s.tlsConfig)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return if we were configured to skip validation
|
||||
if s.tlsConfig != nil && s.tlsConfig.InsecureSkipVerify {
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
host, _, err := net.SplitHostPort(dialAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = conn.VerifyHostname(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// proxyAuth returns, for a given proxy URL, the value to be used for the Proxy-Authorization header
|
||||
func (s *SpdyRoundTripper) proxyAuth(proxyURL *url.URL) string {
|
||||
if proxyURL == nil || proxyURL.User == nil {
|
||||
return ""
|
||||
}
|
||||
credentials := proxyURL.User.String()
|
||||
encodedAuth := base64.StdEncoding.EncodeToString([]byte(credentials))
|
||||
return fmt.Sprintf("Basic %s", encodedAuth)
|
||||
}
|
||||
|
||||
// RoundTrip executes the Request and upgrades it. After a successful upgrade,
|
||||
// clients may call SpdyRoundTripper.Connection() to retrieve the upgraded
|
||||
// connection.
|
||||
func (s *SpdyRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
// TODO what's the best way to clone the request?
|
||||
r := *req
|
||||
req = &r
|
||||
req.Header.Add(httpstream.HeaderConnection, httpstream.HeaderUpgrade)
|
||||
req.Header.Add(httpstream.HeaderUpgrade, HeaderSpdy31)
|
||||
|
||||
conn, err := s.dial(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = req.Write(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := http.ReadResponse(bufio.NewReader(conn), req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.conn = conn
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// NewConnection validates the upgrade response, creating and returning a new
|
||||
// httpstream.Connection if there were no errors.
|
||||
func (s *SpdyRoundTripper) NewConnection(resp *http.Response) (httpstream.Connection, error) {
|
||||
connectionHeader := strings.ToLower(resp.Header.Get(httpstream.HeaderConnection))
|
||||
upgradeHeader := strings.ToLower(resp.Header.Get(httpstream.HeaderUpgrade))
|
||||
if (resp.StatusCode != http.StatusSwitchingProtocols) || !strings.Contains(connectionHeader, strings.ToLower(httpstream.HeaderUpgrade)) || !strings.Contains(upgradeHeader, strings.ToLower(HeaderSpdy31)) {
|
||||
defer resp.Body.Close()
|
||||
responseError := ""
|
||||
responseErrorBytes, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
responseError = "unable to read error from server response"
|
||||
} else {
|
||||
// TODO: I don't belong here, I should be abstracted from this class
|
||||
if obj, _, err := api.Codecs.UniversalDecoder().Decode(responseErrorBytes, nil, &metav1.Status{}); err == nil {
|
||||
if status, ok := obj.(*metav1.Status); ok {
|
||||
return nil, &apierrors.StatusError{ErrStatus: *status}
|
||||
}
|
||||
}
|
||||
responseError = string(responseErrorBytes)
|
||||
responseError = strings.TrimSpace(responseError)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unable to upgrade connection: %s", responseError)
|
||||
}
|
||||
|
||||
return NewClientConnection(s.conn)
|
||||
}
|
424
vendor/k8s.io/kubernetes/pkg/util/httpstream/spdy/roundtripper_test.go
generated
vendored
424
vendor/k8s.io/kubernetes/pkg/util/httpstream/spdy/roundtripper_test.go
generated
vendored
|
@ -1,424 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 spdy
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/elazarl/goproxy"
|
||||
"k8s.io/kubernetes/pkg/util/httpstream"
|
||||
)
|
||||
|
||||
// be sure to unset environment variable https_proxy (if exported) before testing, otherwise the testing will fail unexpectedly.
|
||||
func TestRoundTripAndNewConnection(t *testing.T) {
|
||||
localhostPool := x509.NewCertPool()
|
||||
if !localhostPool.AppendCertsFromPEM(localhostCert) {
|
||||
t.Errorf("error setting up localhostCert pool")
|
||||
}
|
||||
|
||||
httpsServerInvalidHostname := func(h http.Handler) *httptest.Server {
|
||||
cert, err := tls.X509KeyPair(exampleCert, exampleKey)
|
||||
if err != nil {
|
||||
t.Errorf("https (invalid hostname): proxy_test: %v", err)
|
||||
}
|
||||
ts := httptest.NewUnstartedServer(h)
|
||||
ts.TLS = &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}
|
||||
ts.StartTLS()
|
||||
return ts
|
||||
}
|
||||
|
||||
httpsServerValidHostname := func(h http.Handler) *httptest.Server {
|
||||
cert, err := tls.X509KeyPair(localhostCert, localhostKey)
|
||||
if err != nil {
|
||||
t.Errorf("https (valid hostname): proxy_test: %v", err)
|
||||
}
|
||||
ts := httptest.NewUnstartedServer(h)
|
||||
ts.TLS = &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}
|
||||
ts.StartTLS()
|
||||
return ts
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
serverFunc func(http.Handler) *httptest.Server
|
||||
proxyServerFunc func(http.Handler) *httptest.Server
|
||||
proxyAuth *url.Userinfo
|
||||
clientTLS *tls.Config
|
||||
serverConnectionHeader string
|
||||
serverUpgradeHeader string
|
||||
serverStatusCode int
|
||||
shouldError bool
|
||||
}{
|
||||
"no headers": {
|
||||
serverFunc: httptest.NewServer,
|
||||
serverConnectionHeader: "",
|
||||
serverUpgradeHeader: "",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: true,
|
||||
},
|
||||
"no upgrade header": {
|
||||
serverFunc: httptest.NewServer,
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: true,
|
||||
},
|
||||
"no connection header": {
|
||||
serverFunc: httptest.NewServer,
|
||||
serverConnectionHeader: "",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: true,
|
||||
},
|
||||
"no switching protocol status code": {
|
||||
serverFunc: httptest.NewServer,
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusForbidden,
|
||||
shouldError: true,
|
||||
},
|
||||
"http": {
|
||||
serverFunc: httptest.NewServer,
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: false,
|
||||
},
|
||||
"https (invalid hostname + InsecureSkipVerify)": {
|
||||
serverFunc: httpsServerInvalidHostname,
|
||||
clientTLS: &tls.Config{InsecureSkipVerify: true},
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: false,
|
||||
},
|
||||
"https (invalid hostname + hostname verification)": {
|
||||
serverFunc: httpsServerInvalidHostname,
|
||||
clientTLS: &tls.Config{InsecureSkipVerify: false},
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: true,
|
||||
},
|
||||
"https (valid hostname + RootCAs)": {
|
||||
serverFunc: httpsServerValidHostname,
|
||||
clientTLS: &tls.Config{RootCAs: localhostPool},
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: false,
|
||||
},
|
||||
"proxied http->http": {
|
||||
serverFunc: httptest.NewServer,
|
||||
proxyServerFunc: httptest.NewServer,
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: false,
|
||||
},
|
||||
"proxied https (invalid hostname + InsecureSkipVerify) -> http": {
|
||||
serverFunc: httptest.NewServer,
|
||||
proxyServerFunc: httpsServerInvalidHostname,
|
||||
clientTLS: &tls.Config{InsecureSkipVerify: true},
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: false,
|
||||
},
|
||||
"proxied https with auth (invalid hostname + InsecureSkipVerify) -> http": {
|
||||
serverFunc: httptest.NewServer,
|
||||
proxyServerFunc: httpsServerInvalidHostname,
|
||||
proxyAuth: url.UserPassword("proxyuser", "proxypasswd"),
|
||||
clientTLS: &tls.Config{InsecureSkipVerify: true},
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: false,
|
||||
},
|
||||
"proxied https (invalid hostname + hostname verification) -> http": {
|
||||
serverFunc: httptest.NewServer,
|
||||
proxyServerFunc: httpsServerInvalidHostname,
|
||||
clientTLS: &tls.Config{InsecureSkipVerify: false},
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: true, // fails because the client doesn't trust the proxy
|
||||
},
|
||||
"proxied https (valid hostname + RootCAs) -> http": {
|
||||
serverFunc: httptest.NewServer,
|
||||
proxyServerFunc: httpsServerValidHostname,
|
||||
clientTLS: &tls.Config{RootCAs: localhostPool},
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: false,
|
||||
},
|
||||
"proxied https with auth (valid hostname + RootCAs) -> http": {
|
||||
serverFunc: httptest.NewServer,
|
||||
proxyServerFunc: httpsServerValidHostname,
|
||||
proxyAuth: url.UserPassword("proxyuser", "proxypasswd"),
|
||||
clientTLS: &tls.Config{RootCAs: localhostPool},
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: false,
|
||||
},
|
||||
"proxied https (invalid hostname + InsecureSkipVerify) -> https (invalid hostname)": {
|
||||
serverFunc: httpsServerInvalidHostname,
|
||||
proxyServerFunc: httpsServerInvalidHostname,
|
||||
clientTLS: &tls.Config{InsecureSkipVerify: true},
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: false, // works because the test proxy ignores TLS errors
|
||||
},
|
||||
"proxied https with auth (invalid hostname + InsecureSkipVerify) -> https (invalid hostname)": {
|
||||
serverFunc: httpsServerInvalidHostname,
|
||||
proxyServerFunc: httpsServerInvalidHostname,
|
||||
proxyAuth: url.UserPassword("proxyuser", "proxypasswd"),
|
||||
clientTLS: &tls.Config{InsecureSkipVerify: true},
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: false, // works because the test proxy ignores TLS errors
|
||||
},
|
||||
"proxied https (invalid hostname + hostname verification) -> https (invalid hostname)": {
|
||||
serverFunc: httpsServerInvalidHostname,
|
||||
proxyServerFunc: httpsServerInvalidHostname,
|
||||
clientTLS: &tls.Config{InsecureSkipVerify: false},
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: true, // fails because the client doesn't trust the proxy
|
||||
},
|
||||
"proxied https (valid hostname + RootCAs) -> https (valid hostname + RootCAs)": {
|
||||
serverFunc: httpsServerValidHostname,
|
||||
proxyServerFunc: httpsServerValidHostname,
|
||||
clientTLS: &tls.Config{RootCAs: localhostPool},
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: false,
|
||||
},
|
||||
"proxied https with auth (valid hostname + RootCAs) -> https (valid hostname + RootCAs)": {
|
||||
serverFunc: httpsServerValidHostname,
|
||||
proxyServerFunc: httpsServerValidHostname,
|
||||
proxyAuth: url.UserPassword("proxyuser", "proxypasswd"),
|
||||
clientTLS: &tls.Config{RootCAs: localhostPool},
|
||||
serverConnectionHeader: "Upgrade",
|
||||
serverUpgradeHeader: "SPDY/3.1",
|
||||
serverStatusCode: http.StatusSwitchingProtocols,
|
||||
shouldError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for k, testCase := range testCases {
|
||||
server := testCase.serverFunc(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
if testCase.shouldError {
|
||||
if e, a := httpstream.HeaderUpgrade, req.Header.Get(httpstream.HeaderConnection); e != a {
|
||||
t.Fatalf("%s: Expected connection=upgrade header, got '%s", k, a)
|
||||
}
|
||||
|
||||
w.Header().Set(httpstream.HeaderConnection, testCase.serverConnectionHeader)
|
||||
w.Header().Set(httpstream.HeaderUpgrade, testCase.serverUpgradeHeader)
|
||||
w.WriteHeader(testCase.serverStatusCode)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
streamCh := make(chan httpstream.Stream)
|
||||
|
||||
responseUpgrader := NewResponseUpgrader()
|
||||
spdyConn := responseUpgrader.UpgradeResponse(w, req, func(s httpstream.Stream, replySent <-chan struct{}) error {
|
||||
streamCh <- s
|
||||
return nil
|
||||
})
|
||||
if spdyConn == nil {
|
||||
t.Fatalf("%s: unexpected nil spdyConn", k)
|
||||
}
|
||||
defer spdyConn.Close()
|
||||
|
||||
stream := <-streamCh
|
||||
io.Copy(stream, stream)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
serverURL, err := url.Parse(server.URL)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: Error creating request: %s", k, err)
|
||||
}
|
||||
req, err := http.NewRequest("GET", server.URL, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: Error creating request: %s", k, err)
|
||||
}
|
||||
|
||||
spdyTransport := NewSpdyRoundTripper(testCase.clientTLS)
|
||||
|
||||
var proxierCalled bool
|
||||
var proxyCalledWithHost string
|
||||
var proxyCalledWithAuth bool
|
||||
var proxyCalledWithAuthHeader string
|
||||
if testCase.proxyServerFunc != nil {
|
||||
proxyHandler := goproxy.NewProxyHttpServer()
|
||||
|
||||
proxyHandler.OnRequest().HandleConnectFunc(func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
|
||||
proxyCalledWithHost = host
|
||||
|
||||
proxyAuthHeaderName := "Proxy-Authorization"
|
||||
_, proxyCalledWithAuth = ctx.Req.Header[proxyAuthHeaderName]
|
||||
proxyCalledWithAuthHeader = ctx.Req.Header.Get(proxyAuthHeaderName)
|
||||
return goproxy.OkConnect, host
|
||||
})
|
||||
|
||||
proxy := testCase.proxyServerFunc(proxyHandler)
|
||||
|
||||
spdyTransport.proxier = func(proxierReq *http.Request) (*url.URL, error) {
|
||||
proxierCalled = true
|
||||
proxyURL, err := url.Parse(proxy.URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
proxyURL.User = testCase.proxyAuth
|
||||
return proxyURL, nil
|
||||
}
|
||||
defer proxy.Close()
|
||||
}
|
||||
|
||||
client := &http.Client{Transport: spdyTransport}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
var conn httpstream.Connection
|
||||
if err == nil {
|
||||
conn, err = spdyTransport.NewConnection(resp)
|
||||
}
|
||||
haveErr := err != nil
|
||||
if e, a := testCase.shouldError, haveErr; e != a {
|
||||
t.Fatalf("%s: shouldError=%t, got %t: %v", k, e, a, err)
|
||||
}
|
||||
if testCase.shouldError {
|
||||
continue
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusSwitchingProtocols {
|
||||
t.Fatalf("%s: expected http 101 switching protocols, got %d", k, resp.StatusCode)
|
||||
}
|
||||
|
||||
stream, err := conn.CreateStream(http.Header{})
|
||||
if err != nil {
|
||||
t.Fatalf("%s: error creating client stream: %s", k, err)
|
||||
}
|
||||
|
||||
n, err := stream.Write([]byte("hello"))
|
||||
if err != nil {
|
||||
t.Fatalf("%s: error writing to stream: %s", k, err)
|
||||
}
|
||||
if n != 5 {
|
||||
t.Fatalf("%s: Expected to write 5 bytes, but actually wrote %d", k, n)
|
||||
}
|
||||
|
||||
b := make([]byte, 5)
|
||||
n, err = stream.Read(b)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: error reading from stream: %s", k, err)
|
||||
}
|
||||
if n != 5 {
|
||||
t.Fatalf("%s: Expected to read 5 bytes, but actually read %d", k, n)
|
||||
}
|
||||
if e, a := "hello", string(b[0:n]); e != a {
|
||||
t.Fatalf("%s: expected '%s', got '%s'", k, e, a)
|
||||
}
|
||||
|
||||
if testCase.proxyServerFunc != nil {
|
||||
if !proxierCalled {
|
||||
t.Fatalf("%s: Expected to use a proxy but proxier in SpdyRoundTripper wasn't called", k)
|
||||
}
|
||||
if proxyCalledWithHost != serverURL.Host {
|
||||
t.Fatalf("%s: Expected to see a call to the proxy for backend %q, got %q", k, serverURL.Host, proxyCalledWithHost)
|
||||
}
|
||||
}
|
||||
|
||||
var expectedProxyAuth string
|
||||
if testCase.proxyAuth != nil {
|
||||
encodedCredentials := base64.StdEncoding.EncodeToString([]byte(testCase.proxyAuth.String()))
|
||||
expectedProxyAuth = "Basic " + encodedCredentials
|
||||
}
|
||||
if len(expectedProxyAuth) == 0 && proxyCalledWithAuth {
|
||||
t.Fatalf("%s: Proxy authorization unexpected, got %q", k, proxyCalledWithAuthHeader)
|
||||
}
|
||||
if proxyCalledWithAuthHeader != expectedProxyAuth {
|
||||
t.Fatalf("%s: Expected to see a call to the proxy with credentials %q, got %q", k, testCase.proxyAuth, proxyCalledWithAuthHeader)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// exampleCert was generated from crypto/tls/generate_cert.go with the following command:
|
||||
// go run generate_cert.go --rsa-bits 512 --host example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
||||
var exampleCert = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIBcjCCAR6gAwIBAgIQBOUTYowZaENkZi0faI9DgTALBgkqhkiG9w0BAQswEjEQ
|
||||
MA4GA1UEChMHQWNtZSBDbzAgFw03MDAxMDEwMDAwMDBaGA8yMDg0MDEyOTE2MDAw
|
||||
MFowEjEQMA4GA1UEChMHQWNtZSBDbzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCZ
|
||||
xfR3sgeHBraGFfF/24tTn4PRVAHOf2UOOxSQRs+aYjNqimFqf/SRIblQgeXdBJDR
|
||||
gVK5F1Js2zwlehw0bHxRAgMBAAGjUDBOMA4GA1UdDwEB/wQEAwIApDATBgNVHSUE
|
||||
DDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MBYGA1UdEQQPMA2CC2V4YW1w
|
||||
bGUuY29tMAsGCSqGSIb3DQEBCwNBAI/mfBB8dm33IpUl+acSyWfL6gX5Wc0FFyVj
|
||||
dKeesE1XBuPX1My/rzU6Oy/YwX7LOL4FaeNUS6bbL4axSLPKYSs=
|
||||
-----END CERTIFICATE-----`)
|
||||
|
||||
var exampleKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBOgIBAAJBAJnF9HeyB4cGtoYV8X/bi1Ofg9FUAc5/ZQ47FJBGz5piM2qKYWp/
|
||||
9JEhuVCB5d0EkNGBUrkXUmzbPCV6HDRsfFECAwEAAQJBAJLH9yPuButniACTn5L5
|
||||
IJQw1mWQt6zBw9eCo41YWkA0866EgjC53aPZaRjXMp0uNJGdIsys2V5rCOOLWN2C
|
||||
ODECIQDICHsi8QQQ9wpuJy8X5l8MAfxHL+DIqI84wQTeVM91FQIhAMTME8A18/7h
|
||||
1Ad6drdnxAkuC0tX6Sx0LDozrmen+HFNAiAlcEDrt0RVkIcpOrg7tuhPLQf0oudl
|
||||
Zvb3Xlj069awSQIgcT15E/43w2+RASifzVNhQ2MCTr1sSA8lL+xzK+REmnUCIBhQ
|
||||
j4139pf8Re1J50zBxS/JlQfgDQi9sO9pYeiHIxNs
|
||||
-----END RSA PRIVATE KEY-----`)
|
||||
|
||||
// localhostCert was generated from crypto/tls/generate_cert.go with the following command:
|
||||
// go run generate_cert.go --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
||||
var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
|
||||
bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj
|
||||
bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa
|
||||
IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA
|
||||
AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
|
||||
EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA
|
||||
AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk
|
||||
Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA==
|
||||
-----END CERTIFICATE-----`)
|
||||
|
||||
// localhostKey is the private key for localhostCert.
|
||||
var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0
|
||||
0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV
|
||||
NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d
|
||||
AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW
|
||||
MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD
|
||||
EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA
|
||||
1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE=
|
||||
-----END RSA PRIVATE KEY-----`)
|
78
vendor/k8s.io/kubernetes/pkg/util/httpstream/spdy/upgrade.go
generated
vendored
78
vendor/k8s.io/kubernetes/pkg/util/httpstream/spdy/upgrade.go
generated
vendored
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 spdy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/httpstream"
|
||||
)
|
||||
|
||||
const HeaderSpdy31 = "SPDY/3.1"
|
||||
|
||||
// responseUpgrader knows how to upgrade HTTP responses. It
|
||||
// implements the httpstream.ResponseUpgrader interface.
|
||||
type responseUpgrader struct {
|
||||
}
|
||||
|
||||
// NewResponseUpgrader returns a new httpstream.ResponseUpgrader that is
|
||||
// capable of upgrading HTTP responses using SPDY/3.1 via the
|
||||
// spdystream package.
|
||||
func NewResponseUpgrader() httpstream.ResponseUpgrader {
|
||||
return responseUpgrader{}
|
||||
}
|
||||
|
||||
// UpgradeResponse upgrades an HTTP response to one that supports multiplexed
|
||||
// streams. newStreamHandler will be called synchronously whenever the
|
||||
// other end of the upgraded connection creates a new stream.
|
||||
func (u responseUpgrader) UpgradeResponse(w http.ResponseWriter, req *http.Request, newStreamHandler httpstream.NewStreamHandler) httpstream.Connection {
|
||||
connectionHeader := strings.ToLower(req.Header.Get(httpstream.HeaderConnection))
|
||||
upgradeHeader := strings.ToLower(req.Header.Get(httpstream.HeaderUpgrade))
|
||||
if !strings.Contains(connectionHeader, strings.ToLower(httpstream.HeaderUpgrade)) || !strings.Contains(upgradeHeader, strings.ToLower(HeaderSpdy31)) {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
fmt.Fprintf(w, "unable to upgrade: missing upgrade headers in request: %#v", req.Header)
|
||||
return nil
|
||||
}
|
||||
|
||||
hijacker, ok := w.(http.Hijacker)
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
fmt.Fprintf(w, "unable to upgrade: unable to hijack response")
|
||||
return nil
|
||||
}
|
||||
|
||||
w.Header().Add(httpstream.HeaderConnection, httpstream.HeaderUpgrade)
|
||||
w.Header().Add(httpstream.HeaderUpgrade, HeaderSpdy31)
|
||||
w.WriteHeader(http.StatusSwitchingProtocols)
|
||||
|
||||
conn, _, err := hijacker.Hijack()
|
||||
if err != nil {
|
||||
runtime.HandleError(fmt.Errorf("unable to upgrade: error hijacking response: %v", err))
|
||||
return nil
|
||||
}
|
||||
|
||||
spdyConn, err := NewServerConnection(conn, newStreamHandler)
|
||||
if err != nil {
|
||||
runtime.HandleError(fmt.Errorf("unable to upgrade: error creating SPDY server connection: %v", err))
|
||||
return nil
|
||||
}
|
||||
|
||||
return spdyConn
|
||||
}
|
93
vendor/k8s.io/kubernetes/pkg/util/httpstream/spdy/upgrade_test.go
generated
vendored
93
vendor/k8s.io/kubernetes/pkg/util/httpstream/spdy/upgrade_test.go
generated
vendored
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 spdy
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUpgradeResponse(t *testing.T) {
|
||||
testCases := []struct {
|
||||
connectionHeader string
|
||||
upgradeHeader string
|
||||
shouldError bool
|
||||
}{
|
||||
{
|
||||
connectionHeader: "",
|
||||
upgradeHeader: "",
|
||||
shouldError: true,
|
||||
},
|
||||
{
|
||||
connectionHeader: "Upgrade",
|
||||
upgradeHeader: "",
|
||||
shouldError: true,
|
||||
},
|
||||
{
|
||||
connectionHeader: "",
|
||||
upgradeHeader: "SPDY/3.1",
|
||||
shouldError: true,
|
||||
},
|
||||
{
|
||||
connectionHeader: "Upgrade",
|
||||
upgradeHeader: "SPDY/3.1",
|
||||
shouldError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, testCase := range testCases {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
upgrader := NewResponseUpgrader()
|
||||
conn := upgrader.UpgradeResponse(w, req, nil)
|
||||
haveErr := conn == nil
|
||||
if e, a := testCase.shouldError, haveErr; e != a {
|
||||
t.Fatalf("%d: expected shouldErr=%t, got %t", i, testCase.shouldError, haveErr)
|
||||
}
|
||||
if haveErr {
|
||||
return
|
||||
}
|
||||
if conn == nil {
|
||||
t.Fatalf("%d: unexpected nil conn", i)
|
||||
}
|
||||
defer conn.Close()
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
req, err := http.NewRequest("GET", server.URL, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: error creating request: %s", i, err)
|
||||
}
|
||||
|
||||
req.Header.Set("Connection", testCase.connectionHeader)
|
||||
req.Header.Set("Upgrade", testCase.upgradeHeader)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: unexpected non-nil err from client.Do: %s", i, err)
|
||||
}
|
||||
|
||||
if testCase.shouldError {
|
||||
continue
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusSwitchingProtocols {
|
||||
t.Fatalf("%d: expected status 101 switching protocols, got %d", i, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
}
|
40
vendor/k8s.io/kubernetes/pkg/util/i18n/BUILD
generated
vendored
40
vendor/k8s.io/kubernetes/pkg/util/i18n/BUILD
generated
vendored
|
@ -1,40 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["i18n.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/generated:go_default_library",
|
||||
"//vendor:github.com/chai2010/gettext-go/gettext",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["i18n_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
133
vendor/k8s.io/kubernetes/pkg/util/i18n/i18n.go
generated
vendored
133
vendor/k8s.io/kubernetes/pkg/util/i18n/i18n.go
generated
vendored
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 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 i18n
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/generated"
|
||||
|
||||
"github.com/chai2010/gettext-go/gettext"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
var knownTranslations = map[string][]string{
|
||||
"kubectl": {
|
||||
"default",
|
||||
"en_US",
|
||||
},
|
||||
// only used for unit tests.
|
||||
"test": {
|
||||
"default",
|
||||
"en_US",
|
||||
},
|
||||
}
|
||||
|
||||
func loadSystemLanguage() string {
|
||||
langStr := os.Getenv("LANG")
|
||||
if langStr == "" {
|
||||
glog.V(3).Infof("Couldn't find the LANG environment variable, defaulting to en-US")
|
||||
return "default"
|
||||
}
|
||||
pieces := strings.Split(langStr, ".")
|
||||
if len(pieces) == 0 {
|
||||
glog.V(3).Infof("Unexpected system language (%s), defaulting to en-US", langStr)
|
||||
return "default"
|
||||
}
|
||||
return pieces[0]
|
||||
}
|
||||
|
||||
func findLanguage(root string, getLanguageFn func() string) string {
|
||||
langStr := getLanguageFn()
|
||||
|
||||
translations := knownTranslations[root]
|
||||
if translations != nil {
|
||||
for ix := range translations {
|
||||
if translations[ix] == langStr {
|
||||
return langStr
|
||||
}
|
||||
}
|
||||
}
|
||||
glog.V(3).Infof("Couldn't find translations for %s, using default", langStr)
|
||||
return "default"
|
||||
}
|
||||
|
||||
// LoadTranslations loads translation files. getLanguageFn should return a language
|
||||
// string (e.g. 'en-US'). If getLanguageFn is nil, then the loadSystemLanguage function
|
||||
// is used, which uses the 'LANG' environment variable.
|
||||
func LoadTranslations(root string, getLanguageFn func() string) error {
|
||||
if getLanguageFn == nil {
|
||||
getLanguageFn = loadSystemLanguage
|
||||
}
|
||||
|
||||
langStr := findLanguage(root, getLanguageFn)
|
||||
translationFiles := []string{
|
||||
fmt.Sprintf("%s/%s/LC_MESSAGES/k8s.po", root, langStr),
|
||||
fmt.Sprintf("%s/%s/LC_MESSAGES/k8s.mo", root, langStr),
|
||||
}
|
||||
|
||||
glog.V(3).Infof("Setting language to %s", langStr)
|
||||
// TODO: list the directory and load all files.
|
||||
buf := new(bytes.Buffer)
|
||||
w := zip.NewWriter(buf)
|
||||
|
||||
// Make sure to check the error on Close.
|
||||
for _, file := range translationFiles {
|
||||
filename := "translations/" + file
|
||||
f, err := w.Create(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := generated.Asset(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := f.Write(data); err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
gettext.BindTextdomain("k8s", root+".zip", buf.Bytes())
|
||||
gettext.Textdomain("k8s")
|
||||
gettext.SetLocale(langStr)
|
||||
return nil
|
||||
}
|
||||
|
||||
// T translates a string, possibly substituting arguments into it along
|
||||
// the way. If len(args) is > 0, args1 is assumed to be the plural value
|
||||
// and plural translation is used.
|
||||
func T(defaultValue string, args ...int) string {
|
||||
if len(args) == 0 {
|
||||
return gettext.PGettext(defaultValue, defaultValue)
|
||||
}
|
||||
return fmt.Sprintf(gettext.PNGettext(defaultValue, defaultValue, defaultValue+".plural", args[0]),
|
||||
args[0])
|
||||
}
|
||||
|
||||
// Errorf produces an error with a translated error string.
|
||||
// Substitution is performed via the `T` function above, following
|
||||
// the same rules.
|
||||
func Errorf(defaultValue string, args ...int) error {
|
||||
return errors.New(T(defaultValue, args...))
|
||||
}
|
64
vendor/k8s.io/kubernetes/pkg/util/i18n/i18n_test.go
generated
vendored
64
vendor/k8s.io/kubernetes/pkg/util/i18n/i18n_test.go
generated
vendored
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 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 i18n
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTranslation(t *testing.T) {
|
||||
err := LoadTranslations("test", func() string { return "default" })
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
result := T("test_string")
|
||||
if result != "foo" {
|
||||
t.Errorf("expected: %s, saw: %s", "foo", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslationPlural(t *testing.T) {
|
||||
err := LoadTranslations("test", func() string { return "default" })
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
result := T("test_plural", 3)
|
||||
if result != "there were 3 items" {
|
||||
t.Errorf("expected: %s, saw: %s", "there were 3 items", result)
|
||||
}
|
||||
|
||||
result = T("test_plural", 1)
|
||||
if result != "there was 1 item" {
|
||||
t.Errorf("expected: %s, saw: %s", "there was 1 item", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslationEnUSEnv(t *testing.T) {
|
||||
os.Setenv("LANG", "en_US.UTF-8")
|
||||
err := LoadTranslations("test", nil)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
result := T("test_string")
|
||||
if result != "baz" {
|
||||
t.Errorf("expected: %s, saw: %s", "baz", result)
|
||||
}
|
||||
}
|
27
vendor/k8s.io/kubernetes/pkg/util/initsystem/BUILD
generated
vendored
27
vendor/k8s.io/kubernetes/pkg/util/initsystem/BUILD
generated
vendored
|
@ -1,27 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["initsystem.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
99
vendor/k8s.io/kubernetes/pkg/util/initsystem/initsystem.go
generated
vendored
99
vendor/k8s.io/kubernetes/pkg/util/initsystem/initsystem.go
generated
vendored
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 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 initsystem
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type InitSystem interface {
|
||||
// ServiceStart tries to start a specific service
|
||||
ServiceStart(service string) error
|
||||
|
||||
// ServiceStop tries to stop a specific service
|
||||
ServiceStop(service string) error
|
||||
|
||||
// ServiceExists ensures the service is defined for this init system.
|
||||
ServiceExists(service string) bool
|
||||
|
||||
// ServiceIsEnabled ensures the service is enabled to start on each boot.
|
||||
ServiceIsEnabled(service string) bool
|
||||
|
||||
// ServiceIsActive ensures the service is running, or attempting to run. (crash looping in the case of kubelet)
|
||||
ServiceIsActive(service string) bool
|
||||
}
|
||||
|
||||
type SystemdInitSystem struct{}
|
||||
|
||||
func (sysd SystemdInitSystem) ServiceStart(service string) error {
|
||||
args := []string{"start", service}
|
||||
_, err := exec.Command("systemctl", args...).Output()
|
||||
return err
|
||||
}
|
||||
|
||||
func (sysd SystemdInitSystem) ServiceStop(service string) error {
|
||||
args := []string{"stop", service}
|
||||
_, err := exec.Command("systemctl", args...).Output()
|
||||
return err
|
||||
}
|
||||
|
||||
func (sysd SystemdInitSystem) ServiceExists(service string) bool {
|
||||
args := []string{"status", service}
|
||||
outBytes, _ := exec.Command("systemctl", args...).Output()
|
||||
output := string(outBytes)
|
||||
if strings.Contains(output, "Loaded: not-found") {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (sysd SystemdInitSystem) ServiceIsEnabled(service string) bool {
|
||||
args := []string{"is-enabled", service}
|
||||
_, err := exec.Command("systemctl", args...).Output()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ServiceIsActive will check is the service is "active". In the case of
|
||||
// crash looping services (kubelet in our case) status will return as
|
||||
// "activating", so we will consider this active as well.
|
||||
func (sysd SystemdInitSystem) ServiceIsActive(service string) bool {
|
||||
args := []string{"is-active", service}
|
||||
// Ignoring error here, command returns non-0 if in "activating" status:
|
||||
outBytes, _ := exec.Command("systemctl", args...).Output()
|
||||
output := strings.TrimSpace(string(outBytes))
|
||||
if output == "active" || output == "activating" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// getInitSystem returns an InitSystem for the current system, or nil
|
||||
// if we cannot detect a supported init system for pre-flight checks.
|
||||
// This indicates we will skip init system checks, not an error.
|
||||
func GetInitSystem() (InitSystem, error) {
|
||||
// Assume existence of systemctl in path implies this is a systemd system:
|
||||
_, err := exec.LookPath("systemctl")
|
||||
if err == nil {
|
||||
return &SystemdInitSystem{}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("no supported init system detected, skipping checking for services")
|
||||
}
|
27
vendor/k8s.io/kubernetes/pkg/util/interrupt/BUILD
generated
vendored
27
vendor/k8s.io/kubernetes/pkg/util/interrupt/BUILD
generated
vendored
|
@ -1,27 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["interrupt.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
46
vendor/k8s.io/kubernetes/pkg/util/intstr/BUILD
generated
vendored
46
vendor/k8s.io/kubernetes/pkg/util/intstr/BUILD
generated
vendored
|
@ -1,46 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"generated.pb.go",
|
||||
"intstr.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor:github.com/go-openapi/spec",
|
||||
"//vendor:github.com/gogo/protobuf/proto",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:github.com/google/gofuzz",
|
||||
"//vendor:k8s.io/apimachinery/pkg/openapi",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["intstr_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor:github.com/ghodss/yaml"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
373
vendor/k8s.io/kubernetes/pkg/util/intstr/generated.pb.go
generated
vendored
373
vendor/k8s.io/kubernetes/pkg/util/intstr/generated.pb.go
generated
vendored
|
@ -1,373 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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.
|
||||
*/
|
||||
|
||||
// Code generated by protoc-gen-gogo.
|
||||
// source: k8s.io/kubernetes/pkg/util/intstr/generated.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package intstr is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
k8s.io/kubernetes/pkg/util/intstr/generated.proto
|
||||
|
||||
It has these top-level messages:
|
||||
IntOrString
|
||||
*/
|
||||
package intstr
|
||||
|
||||
import proto "github.com/gogo/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
|
||||
import io "io"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
const _ = proto.GoGoProtoPackageIsVersion1
|
||||
|
||||
func (m *IntOrString) Reset() { *m = IntOrString{} }
|
||||
func (*IntOrString) ProtoMessage() {}
|
||||
func (*IntOrString) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{0} }
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*IntOrString)(nil), "k8s.io.kubernetes.pkg.util.intstr.IntOrString")
|
||||
}
|
||||
func (m *IntOrString) Marshal() (data []byte, err error) {
|
||||
size := m.Size()
|
||||
data = make([]byte, size)
|
||||
n, err := m.MarshalTo(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data[:n], nil
|
||||
}
|
||||
|
||||
func (m *IntOrString) MarshalTo(data []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
data[i] = 0x8
|
||||
i++
|
||||
i = encodeVarintGenerated(data, i, uint64(m.Type))
|
||||
data[i] = 0x10
|
||||
i++
|
||||
i = encodeVarintGenerated(data, i, uint64(m.IntVal))
|
||||
data[i] = 0x1a
|
||||
i++
|
||||
i = encodeVarintGenerated(data, i, uint64(len(m.StrVal)))
|
||||
i += copy(data[i:], m.StrVal)
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func encodeFixed64Generated(data []byte, offset int, v uint64) int {
|
||||
data[offset] = uint8(v)
|
||||
data[offset+1] = uint8(v >> 8)
|
||||
data[offset+2] = uint8(v >> 16)
|
||||
data[offset+3] = uint8(v >> 24)
|
||||
data[offset+4] = uint8(v >> 32)
|
||||
data[offset+5] = uint8(v >> 40)
|
||||
data[offset+6] = uint8(v >> 48)
|
||||
data[offset+7] = uint8(v >> 56)
|
||||
return offset + 8
|
||||
}
|
||||
func encodeFixed32Generated(data []byte, offset int, v uint32) int {
|
||||
data[offset] = uint8(v)
|
||||
data[offset+1] = uint8(v >> 8)
|
||||
data[offset+2] = uint8(v >> 16)
|
||||
data[offset+3] = uint8(v >> 24)
|
||||
return offset + 4
|
||||
}
|
||||
func encodeVarintGenerated(data []byte, offset int, v uint64) int {
|
||||
for v >= 1<<7 {
|
||||
data[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
data[offset] = uint8(v)
|
||||
return offset + 1
|
||||
}
|
||||
func (m *IntOrString) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
n += 1 + sovGenerated(uint64(m.Type))
|
||||
n += 1 + sovGenerated(uint64(m.IntVal))
|
||||
l = len(m.StrVal)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
return n
|
||||
}
|
||||
|
||||
func sovGenerated(x uint64) (n int) {
|
||||
for {
|
||||
n++
|
||||
x >>= 7
|
||||
if x == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
func sozGenerated(x uint64) (n int) {
|
||||
return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *IntOrString) Unmarshal(data []byte) error {
|
||||
l := len(data)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: IntOrString: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: IntOrString: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType)
|
||||
}
|
||||
m.Type = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
m.Type |= (Type(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field IntVal", wireType)
|
||||
}
|
||||
m.IntVal = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
m.IntVal |= (int32(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field StrVal", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.StrVal = string(data[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(data[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipGenerated(data []byte) (n int, err error) {
|
||||
l := len(data)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if data[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
return iNdEx, nil
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
iNdEx += length
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthGenerated
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 3:
|
||||
for {
|
||||
var innerWire uint64
|
||||
var start int = iNdEx
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
innerWire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
innerWireType := int(innerWire & 0x7)
|
||||
if innerWireType == 4 {
|
||||
break
|
||||
}
|
||||
next, err := skipGenerated(data[start:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
iNdEx = start + next
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 4:
|
||||
return iNdEx, nil
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
return iNdEx, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow")
|
||||
)
|
||||
|
||||
var fileDescriptorGenerated = []byte{
|
||||
// 269 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x44, 0x8f, 0x31, 0x4e, 0xc3, 0x30,
|
||||
0x18, 0x85, 0x6d, 0x5a, 0x2a, 0x08, 0x12, 0x43, 0xc4, 0x50, 0x31, 0x38, 0x81, 0x01, 0x79, 0xc1,
|
||||
0x16, 0x1b, 0x62, 0xcc, 0xd6, 0x09, 0x29, 0x45, 0x0c, 0x6c, 0x0d, 0x18, 0x63, 0xa5, 0xd8, 0x96,
|
||||
0xf3, 0x67, 0xe8, 0xd6, 0x23, 0xc0, 0xc6, 0xc8, 0x71, 0x32, 0x76, 0x64, 0x40, 0x15, 0x31, 0xb7,
|
||||
0x60, 0x42, 0x71, 0x22, 0x75, 0xb2, 0xdf, 0x7b, 0xdf, 0x67, 0xc9, 0xd1, 0x55, 0x79, 0x5d, 0x31,
|
||||
0x65, 0x78, 0x59, 0x17, 0xc2, 0x69, 0x01, 0xa2, 0xe2, 0xb6, 0x94, 0xbc, 0x06, 0xb5, 0xe4, 0x4a,
|
||||
0x43, 0x05, 0x8e, 0x4b, 0xa1, 0x85, 0x5b, 0x80, 0x78, 0x62, 0xd6, 0x19, 0x30, 0xf1, 0x59, 0xaf,
|
||||
0xb0, 0x9d, 0xc2, 0x6c, 0x29, 0x59, 0xa7, 0xb0, 0x5e, 0x39, 0xbd, 0x94, 0x0a, 0x5e, 0xea, 0x82,
|
||||
0x3d, 0x9a, 0x57, 0x2e, 0x8d, 0x34, 0x3c, 0x98, 0x45, 0xfd, 0x1c, 0x52, 0x08, 0xe1, 0xd6, 0xbf,
|
||||
0x78, 0xfe, 0x8e, 0xa3, 0xa3, 0x99, 0x86, 0x5b, 0x37, 0x07, 0xa7, 0xb4, 0x8c, 0x69, 0x34, 0x86,
|
||||
0x95, 0x15, 0x53, 0x9c, 0x62, 0x3a, 0xca, 0x4e, 0x9a, 0x6d, 0x82, 0xfc, 0x36, 0x19, 0xdf, 0xad,
|
||||
0xac, 0xf8, 0x1b, 0xce, 0x3c, 0x10, 0xf1, 0x45, 0x34, 0x51, 0x1a, 0xee, 0x17, 0xcb, 0xe9, 0x5e,
|
||||
0x8a, 0xe9, 0x7e, 0x76, 0x3c, 0xb0, 0x93, 0x59, 0x68, 0xf3, 0x61, 0xed, 0xb8, 0x0a, 0x5c, 0xc7,
|
||||
0x8d, 0x52, 0x4c, 0x0f, 0x77, 0xdc, 0x3c, 0xb4, 0xf9, 0xb0, 0xde, 0x1c, 0x7c, 0x7c, 0x26, 0x68,
|
||||
0xfd, 0x9d, 0xa2, 0x8c, 0x36, 0x2d, 0x41, 0x9b, 0x96, 0xa0, 0xaf, 0x96, 0xa0, 0xb5, 0x27, 0xb8,
|
||||
0xf1, 0x04, 0x6f, 0x3c, 0xc1, 0x3f, 0x9e, 0xe0, 0xb7, 0x5f, 0x82, 0x1e, 0x26, 0xfd, 0x67, 0xff,
|
||||
0x03, 0x00, 0x00, 0xff, 0xff, 0x68, 0x57, 0xfb, 0xfa, 0x43, 0x01, 0x00, 0x00,
|
||||
}
|
43
vendor/k8s.io/kubernetes/pkg/util/intstr/generated.proto
generated
vendored
43
vendor/k8s.io/kubernetes/pkg/util/intstr/generated.proto
generated
vendored
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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.
|
||||
*/
|
||||
|
||||
|
||||
// This file was autogenerated by go-to-protobuf. Do not edit it manually!
|
||||
|
||||
syntax = 'proto2';
|
||||
|
||||
package k8s.io.kubernetes.pkg.util.intstr;
|
||||
|
||||
// Package-wide variables from generator "generated".
|
||||
option go_package = "intstr";
|
||||
|
||||
// IntOrString is a type that can hold an int32 or a string. When used in
|
||||
// JSON or YAML marshalling and unmarshalling, it produces or consumes the
|
||||
// inner type. This allows you to have, for example, a JSON field that can
|
||||
// accept a name or number.
|
||||
// TODO: Rename to Int32OrString
|
||||
//
|
||||
// +protobuf=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
// +k8s:openapi-gen=true
|
||||
message IntOrString {
|
||||
optional int64 type = 1;
|
||||
|
||||
optional int32 intVal = 2;
|
||||
|
||||
optional string strVal = 3;
|
||||
}
|
||||
|
177
vendor/k8s.io/kubernetes/pkg/util/intstr/intstr.go
generated
vendored
177
vendor/k8s.io/kubernetes/pkg/util/intstr/intstr.go
generated
vendored
|
@ -1,177 +0,0 @@
|
|||
/*
|
||||
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 intstr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/openapi"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/golang/glog"
|
||||
"github.com/google/gofuzz"
|
||||
)
|
||||
|
||||
// IntOrString is a type that can hold an int32 or a string. When used in
|
||||
// JSON or YAML marshalling and unmarshalling, it produces or consumes the
|
||||
// inner type. This allows you to have, for example, a JSON field that can
|
||||
// accept a name or number.
|
||||
// TODO: Rename to Int32OrString
|
||||
//
|
||||
// +protobuf=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
// +k8s:openapi-gen=true
|
||||
type IntOrString struct {
|
||||
Type Type `protobuf:"varint,1,opt,name=type,casttype=Type"`
|
||||
IntVal int32 `protobuf:"varint,2,opt,name=intVal"`
|
||||
StrVal string `protobuf:"bytes,3,opt,name=strVal"`
|
||||
}
|
||||
|
||||
// Type represents the stored type of IntOrString.
|
||||
type Type int
|
||||
|
||||
const (
|
||||
Int Type = iota // The IntOrString holds an int.
|
||||
String // The IntOrString holds a string.
|
||||
)
|
||||
|
||||
// FromInt creates an IntOrString object with an int32 value. It is
|
||||
// your responsibility not to call this method with a value greater
|
||||
// than int32.
|
||||
// TODO: convert to (val int32)
|
||||
func FromInt(val int) IntOrString {
|
||||
if val > math.MaxInt32 || val < math.MinInt32 {
|
||||
glog.Errorf("value: %d overflows int32\n%s\n", val, debug.Stack())
|
||||
}
|
||||
return IntOrString{Type: Int, IntVal: int32(val)}
|
||||
}
|
||||
|
||||
// FromString creates an IntOrString object with a string value.
|
||||
func FromString(val string) IntOrString {
|
||||
return IntOrString{Type: String, StrVal: val}
|
||||
}
|
||||
|
||||
// Parse the given string and try to convert it to an integer before
|
||||
// setting it as a string value.
|
||||
func Parse(val string) IntOrString {
|
||||
i, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
return FromString(val)
|
||||
}
|
||||
return FromInt(i)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaller interface.
|
||||
func (intstr *IntOrString) UnmarshalJSON(value []byte) error {
|
||||
if value[0] == '"' {
|
||||
intstr.Type = String
|
||||
return json.Unmarshal(value, &intstr.StrVal)
|
||||
}
|
||||
intstr.Type = Int
|
||||
return json.Unmarshal(value, &intstr.IntVal)
|
||||
}
|
||||
|
||||
// String returns the string value, or the Itoa of the int value.
|
||||
func (intstr *IntOrString) String() string {
|
||||
if intstr.Type == String {
|
||||
return intstr.StrVal
|
||||
}
|
||||
return strconv.Itoa(intstr.IntValue())
|
||||
}
|
||||
|
||||
// IntValue returns the IntVal if type Int, or if
|
||||
// it is a String, will attempt a conversion to int.
|
||||
func (intstr *IntOrString) IntValue() int {
|
||||
if intstr.Type == String {
|
||||
i, _ := strconv.Atoi(intstr.StrVal)
|
||||
return i
|
||||
}
|
||||
return int(intstr.IntVal)
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaller interface.
|
||||
func (intstr IntOrString) MarshalJSON() ([]byte, error) {
|
||||
switch intstr.Type {
|
||||
case Int:
|
||||
return json.Marshal(intstr.IntVal)
|
||||
case String:
|
||||
return json.Marshal(intstr.StrVal)
|
||||
default:
|
||||
return []byte{}, fmt.Errorf("impossible IntOrString.Type")
|
||||
}
|
||||
}
|
||||
|
||||
func (_ IntOrString) OpenAPIDefinition() openapi.OpenAPIDefinition {
|
||||
return openapi.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "int-or-string",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (intstr *IntOrString) Fuzz(c fuzz.Continue) {
|
||||
if intstr == nil {
|
||||
return
|
||||
}
|
||||
if c.RandBool() {
|
||||
intstr.Type = Int
|
||||
c.Fuzz(&intstr.IntVal)
|
||||
intstr.StrVal = ""
|
||||
} else {
|
||||
intstr.Type = String
|
||||
intstr.IntVal = 0
|
||||
c.Fuzz(&intstr.StrVal)
|
||||
}
|
||||
}
|
||||
|
||||
func GetValueFromIntOrPercent(intOrPercent *IntOrString, total int, roundUp bool) (int, error) {
|
||||
value, isPercent, err := getIntOrPercentValue(intOrPercent)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid value for IntOrString: %v", err)
|
||||
}
|
||||
if isPercent {
|
||||
if roundUp {
|
||||
value = int(math.Ceil(float64(value) * (float64(total)) / 100))
|
||||
} else {
|
||||
value = int(math.Floor(float64(value) * (float64(total)) / 100))
|
||||
}
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func getIntOrPercentValue(intOrStr *IntOrString) (int, bool, error) {
|
||||
switch intOrStr.Type {
|
||||
case Int:
|
||||
return intOrStr.IntValue(), false, nil
|
||||
case String:
|
||||
s := strings.Replace(intOrStr.StrVal, "%", "", -1)
|
||||
v, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return 0, false, fmt.Errorf("invalid value %q: %v", intOrStr.StrVal, err)
|
||||
}
|
||||
return int(v), true, nil
|
||||
}
|
||||
return 0, false, fmt.Errorf("invalid type: neither int nor percentage")
|
||||
}
|
176
vendor/k8s.io/kubernetes/pkg/util/intstr/intstr_test.go
generated
vendored
176
vendor/k8s.io/kubernetes/pkg/util/intstr/intstr_test.go
generated
vendored
|
@ -1,176 +0,0 @@
|
|||
/*
|
||||
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 intstr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
)
|
||||
|
||||
func TestFromInt(t *testing.T) {
|
||||
i := FromInt(93)
|
||||
if i.Type != Int || i.IntVal != 93 {
|
||||
t.Errorf("Expected IntVal=93, got %+v", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromString(t *testing.T) {
|
||||
i := FromString("76")
|
||||
if i.Type != String || i.StrVal != "76" {
|
||||
t.Errorf("Expected StrVal=\"76\", got %+v", i)
|
||||
}
|
||||
}
|
||||
|
||||
type IntOrStringHolder struct {
|
||||
IOrS IntOrString `json:"val"`
|
||||
}
|
||||
|
||||
func TestIntOrStringUnmarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result IntOrString
|
||||
}{
|
||||
{"{\"val\": 123}", FromInt(123)},
|
||||
{"{\"val\": \"123\"}", FromString("123")},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var result IntOrStringHolder
|
||||
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("Failed to unmarshal input '%v': %v", c.input, err)
|
||||
}
|
||||
if result.IOrS != c.result {
|
||||
t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntOrStringMarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input IntOrString
|
||||
result string
|
||||
}{
|
||||
{FromInt(123), "{\"val\":123}"},
|
||||
{FromString("123"), "{\"val\":\"123\"}"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := IntOrStringHolder{c.input}
|
||||
result, err := json.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal input '%v': %v", input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("Failed to marshal input '%v': expected: %+v, got %q", input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntOrStringMarshalJSONUnmarshalYAML(t *testing.T) {
|
||||
cases := []struct {
|
||||
input IntOrString
|
||||
}{
|
||||
{FromInt(123)},
|
||||
{FromString("123")},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := IntOrStringHolder{c.input}
|
||||
jsonMarshalled, err := json.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("1: Failed to marshal input: '%v': %v", input, err)
|
||||
}
|
||||
|
||||
var result IntOrStringHolder
|
||||
err = yaml.Unmarshal(jsonMarshalled, &result)
|
||||
if err != nil {
|
||||
t.Errorf("2: Failed to unmarshal '%+v': %v", string(jsonMarshalled), err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(input, result) {
|
||||
t.Errorf("3: Failed to marshal input '%+v': got %+v", input, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetValueFromIntOrPercent(t *testing.T) {
|
||||
tests := []struct {
|
||||
input IntOrString
|
||||
total int
|
||||
roundUp bool
|
||||
expectErr bool
|
||||
expectVal int
|
||||
}{
|
||||
{
|
||||
input: FromInt(123),
|
||||
expectErr: false,
|
||||
expectVal: 123,
|
||||
},
|
||||
{
|
||||
input: FromString("90%"),
|
||||
total: 100,
|
||||
roundUp: true,
|
||||
expectErr: false,
|
||||
expectVal: 90,
|
||||
},
|
||||
{
|
||||
input: FromString("90%"),
|
||||
total: 95,
|
||||
roundUp: true,
|
||||
expectErr: false,
|
||||
expectVal: 86,
|
||||
},
|
||||
{
|
||||
input: FromString("90%"),
|
||||
total: 95,
|
||||
roundUp: false,
|
||||
expectErr: false,
|
||||
expectVal: 85,
|
||||
},
|
||||
{
|
||||
input: FromString("%"),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
input: FromString("90#"),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
input: FromString("#%"),
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
t.Logf("test case %d", i)
|
||||
value, err := GetValueFromIntOrPercent(&test.input, test.total, test.roundUp)
|
||||
if test.expectErr && err == nil {
|
||||
t.Errorf("expected error, but got none")
|
||||
continue
|
||||
}
|
||||
if !test.expectErr && err != nil {
|
||||
t.Errorf("unexpected err: %v", err)
|
||||
continue
|
||||
}
|
||||
if test.expectVal != value {
|
||||
t.Errorf("expected %v, but got %v", test.expectVal, value)
|
||||
}
|
||||
}
|
||||
}
|
51
vendor/k8s.io/kubernetes/pkg/util/io/BUILD
generated
vendored
51
vendor/k8s.io/kubernetes/pkg/util/io/BUILD
generated
vendored
|
@ -1,51 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"io.go",
|
||||
"writer.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_xtest",
|
||||
srcs = ["io_test.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/util/io:go_default_library",
|
||||
"//pkg/volume:go_default_library",
|
||||
"//vendor:github.com/pborman/uuid",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/client-go/util/testing",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
55
vendor/k8s.io/kubernetes/pkg/util/io/io_test.go
generated
vendored
55
vendor/k8s.io/kubernetes/pkg/util/io/io_test.go
generated
vendored
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 io_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/pborman/uuid"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utiltesting "k8s.io/client-go/util/testing"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/util/io"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
)
|
||||
|
||||
func TestSavePodToFile(t *testing.T) {
|
||||
pod := volume.NewPersistentVolumeRecyclerPodTemplate()
|
||||
|
||||
// sets all default values on a pod for equality comparison after decoding from file
|
||||
codec := api.Codecs.LegacyCodec(api.Registry.GroupOrDie(api.GroupName).GroupVersion)
|
||||
encoded, err := runtime.Encode(codec, pod)
|
||||
runtime.DecodeInto(codec, encoded, pod)
|
||||
|
||||
tmpDir := utiltesting.MkTmpdirOrDie("kube-io-test")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
path := fmt.Sprintf("/%s/kube-io-test-%s", tmpDir, uuid.New())
|
||||
|
||||
if err := io.SavePodToFile(pod, path, 777); err != nil {
|
||||
t.Fatalf("failed to save pod to file: %v", err)
|
||||
}
|
||||
|
||||
podFromFile, err := io.LoadPodFromFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load pod from file: %v", err)
|
||||
}
|
||||
if !api.Semantic.DeepEqual(pod, podFromFile) {
|
||||
t.Errorf("\nexpected %#v\ngot %#v\n", pod, podFromFile)
|
||||
}
|
||||
}
|
55
vendor/k8s.io/kubernetes/pkg/util/iptables/BUILD
generated
vendored
55
vendor/k8s.io/kubernetes/pkg/util/iptables/BUILD
generated
vendored
|
@ -1,55 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"iptables.go",
|
||||
"save_restore.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/util/dbus:go_default_library",
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//vendor:github.com/godbus/dbus",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["iptables_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/util/dbus:go_default_library",
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/util/iptables/testing:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
18
vendor/k8s.io/kubernetes/pkg/util/iptables/doc.go
generated
vendored
18
vendor/k8s.io/kubernetes/pkg/util/iptables/doc.go
generated
vendored
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
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 iptables provides an interface and implementations for running iptables commands.
|
||||
package iptables // import "k8s.io/kubernetes/pkg/util/iptables"
|
582
vendor/k8s.io/kubernetes/pkg/util/iptables/iptables.go
generated
vendored
582
vendor/k8s.io/kubernetes/pkg/util/iptables/iptables.go
generated
vendored
|
@ -1,582 +0,0 @@
|
|||
/*
|
||||
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 iptables
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
godbus "github.com/godbus/dbus"
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
utildbus "k8s.io/kubernetes/pkg/util/dbus"
|
||||
utilexec "k8s.io/kubernetes/pkg/util/exec"
|
||||
utilversion "k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
||||
type RulePosition string
|
||||
|
||||
const (
|
||||
Prepend RulePosition = "-I"
|
||||
Append RulePosition = "-A"
|
||||
)
|
||||
|
||||
// An injectable interface for running iptables commands. Implementations must be goroutine-safe.
|
||||
type Interface interface {
|
||||
// GetVersion returns the "X.Y.Z" version string for iptables.
|
||||
GetVersion() (string, error)
|
||||
// EnsureChain checks if the specified chain exists and, if not, creates it. If the chain existed, return true.
|
||||
EnsureChain(table Table, chain Chain) (bool, error)
|
||||
// FlushChain clears the specified chain. If the chain did not exist, return error.
|
||||
FlushChain(table Table, chain Chain) error
|
||||
// DeleteChain deletes the specified chain. If the chain did not exist, return error.
|
||||
DeleteChain(table Table, chain Chain) error
|
||||
// EnsureRule checks if the specified rule is present and, if not, creates it. If the rule existed, return true.
|
||||
EnsureRule(position RulePosition, table Table, chain Chain, args ...string) (bool, error)
|
||||
// DeleteRule checks if the specified rule is present and, if so, deletes it.
|
||||
DeleteRule(table Table, chain Chain, args ...string) error
|
||||
// IsIpv6 returns true if this is managing ipv6 tables
|
||||
IsIpv6() bool
|
||||
// TODO: (BenTheElder) Unit-Test Save/SaveAll, Restore/RestoreAll
|
||||
// Save calls `iptables-save` for table.
|
||||
Save(table Table) ([]byte, error)
|
||||
// SaveAll calls `iptables-save`.
|
||||
SaveAll() ([]byte, error)
|
||||
// Restore runs `iptables-restore` passing data through []byte.
|
||||
// table is the Table to restore
|
||||
// data should be formatted like the output of Save()
|
||||
// flush sets the presence of the "--noflush" flag. see: FlushFlag
|
||||
// counters sets the "--counters" flag. see: RestoreCountersFlag
|
||||
Restore(table Table, data []byte, flush FlushFlag, counters RestoreCountersFlag) error
|
||||
// RestoreAll is the same as Restore except that no table is specified.
|
||||
RestoreAll(data []byte, flush FlushFlag, counters RestoreCountersFlag) error
|
||||
// AddReloadFunc adds a function to call on iptables reload
|
||||
AddReloadFunc(reloadFunc func())
|
||||
// Destroy cleans up resources used by the Interface
|
||||
Destroy()
|
||||
}
|
||||
|
||||
type Protocol byte
|
||||
|
||||
const (
|
||||
ProtocolIpv4 Protocol = iota + 1
|
||||
ProtocolIpv6
|
||||
)
|
||||
|
||||
type Table string
|
||||
|
||||
const (
|
||||
TableNAT Table = "nat"
|
||||
TableFilter Table = "filter"
|
||||
)
|
||||
|
||||
type Chain string
|
||||
|
||||
const (
|
||||
ChainPostrouting Chain = "POSTROUTING"
|
||||
ChainPrerouting Chain = "PREROUTING"
|
||||
ChainOutput Chain = "OUTPUT"
|
||||
ChainInput Chain = "INPUT"
|
||||
)
|
||||
|
||||
const (
|
||||
cmdIPTablesSave string = "iptables-save"
|
||||
cmdIPTablesRestore string = "iptables-restore"
|
||||
cmdIPTables string = "iptables"
|
||||
cmdIp6tables string = "ip6tables"
|
||||
)
|
||||
|
||||
// Option flag for Restore
|
||||
type RestoreCountersFlag bool
|
||||
|
||||
const RestoreCounters RestoreCountersFlag = true
|
||||
const NoRestoreCounters RestoreCountersFlag = false
|
||||
|
||||
// Option flag for Flush
|
||||
type FlushFlag bool
|
||||
|
||||
const FlushTables FlushFlag = true
|
||||
const NoFlushTables FlushFlag = false
|
||||
|
||||
// Versions of iptables less than this do not support the -C / --check flag
|
||||
// (test whether a rule exists).
|
||||
const MinCheckVersion = "1.4.11"
|
||||
|
||||
// Minimum iptables versions supporting the -w and -w2 flags
|
||||
const MinWaitVersion = "1.4.20"
|
||||
const MinWait2Version = "1.4.22"
|
||||
|
||||
// runner implements Interface in terms of exec("iptables").
|
||||
type runner struct {
|
||||
mu sync.Mutex
|
||||
exec utilexec.Interface
|
||||
dbus utildbus.Interface
|
||||
protocol Protocol
|
||||
hasCheck bool
|
||||
waitFlag []string
|
||||
|
||||
reloadFuncs []func()
|
||||
signal chan *godbus.Signal
|
||||
}
|
||||
|
||||
// New returns a new Interface which will exec iptables.
|
||||
func New(exec utilexec.Interface, dbus utildbus.Interface, protocol Protocol) Interface {
|
||||
vstring, err := getIPTablesVersionString(exec)
|
||||
if err != nil {
|
||||
glog.Warningf("Error checking iptables version, assuming version at least %s: %v", MinCheckVersion, err)
|
||||
vstring = MinCheckVersion
|
||||
}
|
||||
runner := &runner{
|
||||
exec: exec,
|
||||
dbus: dbus,
|
||||
protocol: protocol,
|
||||
hasCheck: getIPTablesHasCheckCommand(vstring),
|
||||
waitFlag: getIPTablesWaitFlag(vstring),
|
||||
}
|
||||
runner.connectToFirewallD()
|
||||
return runner
|
||||
}
|
||||
|
||||
// Destroy is part of Interface.
|
||||
func (runner *runner) Destroy() {
|
||||
if runner.signal != nil {
|
||||
runner.signal <- nil
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
firewalldName = "org.fedoraproject.FirewallD1"
|
||||
firewalldPath = "/org/fedoraproject/FirewallD1"
|
||||
firewalldInterface = "org.fedoraproject.FirewallD1"
|
||||
)
|
||||
|
||||
// Connects to D-Bus and listens for FirewallD start/restart. (On non-FirewallD-using
|
||||
// systems, this is effectively a no-op; we listen for the signals, but they will never be
|
||||
// emitted, so reload() will never be called.)
|
||||
func (runner *runner) connectToFirewallD() {
|
||||
bus, err := runner.dbus.SystemBus()
|
||||
if err != nil {
|
||||
glog.V(1).Infof("Could not connect to D-Bus system bus: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
rule := fmt.Sprintf("type='signal',sender='%s',path='%s',interface='%s',member='Reloaded'", firewalldName, firewalldPath, firewalldInterface)
|
||||
bus.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rule)
|
||||
|
||||
rule = fmt.Sprintf("type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged',path='/org/freedesktop/DBus',sender='org.freedesktop.DBus',arg0='%s'", firewalldName)
|
||||
bus.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rule)
|
||||
|
||||
runner.signal = make(chan *godbus.Signal, 10)
|
||||
bus.Signal(runner.signal)
|
||||
|
||||
go runner.dbusSignalHandler(bus)
|
||||
}
|
||||
|
||||
// GetVersion returns the version string.
|
||||
func (runner *runner) GetVersion() (string, error) {
|
||||
return getIPTablesVersionString(runner.exec)
|
||||
}
|
||||
|
||||
// EnsureChain is part of Interface.
|
||||
func (runner *runner) EnsureChain(table Table, chain Chain) (bool, error) {
|
||||
fullArgs := makeFullArgs(table, chain)
|
||||
|
||||
runner.mu.Lock()
|
||||
defer runner.mu.Unlock()
|
||||
|
||||
out, err := runner.run(opCreateChain, fullArgs)
|
||||
if err != nil {
|
||||
if ee, ok := err.(utilexec.ExitError); ok {
|
||||
if ee.Exited() && ee.ExitStatus() == 1 {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, fmt.Errorf("error creating chain %q: %v: %s", chain, err, out)
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// FlushChain is part of Interface.
|
||||
func (runner *runner) FlushChain(table Table, chain Chain) error {
|
||||
fullArgs := makeFullArgs(table, chain)
|
||||
|
||||
runner.mu.Lock()
|
||||
defer runner.mu.Unlock()
|
||||
|
||||
out, err := runner.run(opFlushChain, fullArgs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error flushing chain %q: %v: %s", chain, err, out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteChain is part of Interface.
|
||||
func (runner *runner) DeleteChain(table Table, chain Chain) error {
|
||||
fullArgs := makeFullArgs(table, chain)
|
||||
|
||||
runner.mu.Lock()
|
||||
defer runner.mu.Unlock()
|
||||
|
||||
// TODO: we could call iptables -S first, ignore the output and check for non-zero return (more like DeleteRule)
|
||||
out, err := runner.run(opDeleteChain, fullArgs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting chain %q: %v: %s", chain, err, out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureRule is part of Interface.
|
||||
func (runner *runner) EnsureRule(position RulePosition, table Table, chain Chain, args ...string) (bool, error) {
|
||||
fullArgs := makeFullArgs(table, chain, args...)
|
||||
|
||||
runner.mu.Lock()
|
||||
defer runner.mu.Unlock()
|
||||
|
||||
exists, err := runner.checkRule(table, chain, args...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if exists {
|
||||
return true, nil
|
||||
}
|
||||
out, err := runner.run(operation(position), fullArgs)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error appending rule: %v: %s", err, out)
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// DeleteRule is part of Interface.
|
||||
func (runner *runner) DeleteRule(table Table, chain Chain, args ...string) error {
|
||||
fullArgs := makeFullArgs(table, chain, args...)
|
||||
|
||||
runner.mu.Lock()
|
||||
defer runner.mu.Unlock()
|
||||
|
||||
exists, err := runner.checkRule(table, chain, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
out, err := runner.run(opDeleteRule, fullArgs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting rule: %v: %s", err, out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (runner *runner) IsIpv6() bool {
|
||||
return runner.protocol == ProtocolIpv6
|
||||
}
|
||||
|
||||
// Save is part of Interface.
|
||||
func (runner *runner) Save(table Table) ([]byte, error) {
|
||||
runner.mu.Lock()
|
||||
defer runner.mu.Unlock()
|
||||
|
||||
// run and return
|
||||
args := []string{"-t", string(table)}
|
||||
glog.V(4).Infof("running iptables-save %v", args)
|
||||
return runner.exec.Command(cmdIPTablesSave, args...).CombinedOutput()
|
||||
}
|
||||
|
||||
// SaveAll is part of Interface.
|
||||
func (runner *runner) SaveAll() ([]byte, error) {
|
||||
runner.mu.Lock()
|
||||
defer runner.mu.Unlock()
|
||||
|
||||
// run and return
|
||||
glog.V(4).Infof("running iptables-save")
|
||||
return runner.exec.Command(cmdIPTablesSave, []string{}...).CombinedOutput()
|
||||
}
|
||||
|
||||
// Restore is part of Interface.
|
||||
func (runner *runner) Restore(table Table, data []byte, flush FlushFlag, counters RestoreCountersFlag) error {
|
||||
// setup args
|
||||
args := []string{"-T", string(table)}
|
||||
return runner.restoreInternal(args, data, flush, counters)
|
||||
}
|
||||
|
||||
// RestoreAll is part of Interface.
|
||||
func (runner *runner) RestoreAll(data []byte, flush FlushFlag, counters RestoreCountersFlag) error {
|
||||
// setup args
|
||||
args := make([]string, 0)
|
||||
return runner.restoreInternal(args, data, flush, counters)
|
||||
}
|
||||
|
||||
// restoreInternal is the shared part of Restore/RestoreAll
|
||||
func (runner *runner) restoreInternal(args []string, data []byte, flush FlushFlag, counters RestoreCountersFlag) error {
|
||||
runner.mu.Lock()
|
||||
defer runner.mu.Unlock()
|
||||
|
||||
if !flush {
|
||||
args = append(args, "--noflush")
|
||||
}
|
||||
if counters {
|
||||
args = append(args, "--counters")
|
||||
}
|
||||
|
||||
// run the command and return the output or an error including the output and error
|
||||
glog.V(4).Infof("running iptables-restore %v", args)
|
||||
cmd := runner.exec.Command(cmdIPTablesRestore, args...)
|
||||
cmd.SetStdin(bytes.NewBuffer(data))
|
||||
b, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%v (%s)", err, b)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (runner *runner) iptablesCommand() string {
|
||||
if runner.IsIpv6() {
|
||||
return cmdIp6tables
|
||||
} else {
|
||||
return cmdIPTables
|
||||
}
|
||||
}
|
||||
|
||||
func (runner *runner) run(op operation, args []string) ([]byte, error) {
|
||||
iptablesCmd := runner.iptablesCommand()
|
||||
|
||||
fullArgs := append(runner.waitFlag, string(op))
|
||||
fullArgs = append(fullArgs, args...)
|
||||
glog.V(4).Infof("running iptables %s %v", string(op), args)
|
||||
return runner.exec.Command(iptablesCmd, fullArgs...).CombinedOutput()
|
||||
// Don't log err here - callers might not think it is an error.
|
||||
}
|
||||
|
||||
// Returns (bool, nil) if it was able to check the existence of the rule, or
|
||||
// (<undefined>, error) if the process of checking failed.
|
||||
func (runner *runner) checkRule(table Table, chain Chain, args ...string) (bool, error) {
|
||||
if runner.hasCheck {
|
||||
return runner.checkRuleUsingCheck(makeFullArgs(table, chain, args...))
|
||||
} else {
|
||||
return runner.checkRuleWithoutCheck(table, chain, args...)
|
||||
}
|
||||
}
|
||||
|
||||
var hexnumRE = regexp.MustCompile("0x0+([0-9])")
|
||||
|
||||
func trimhex(s string) string {
|
||||
return hexnumRE.ReplaceAllString(s, "0x$1")
|
||||
}
|
||||
|
||||
// Executes the rule check without using the "-C" flag, instead parsing iptables-save.
|
||||
// Present for compatibility with <1.4.11 versions of iptables. This is full
|
||||
// of hack and half-measures. We should nix this ASAP.
|
||||
func (runner *runner) checkRuleWithoutCheck(table Table, chain Chain, args ...string) (bool, error) {
|
||||
glog.V(1).Infof("running iptables-save -t %s", string(table))
|
||||
out, err := runner.exec.Command(cmdIPTablesSave, "-t", string(table)).CombinedOutput()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error checking rule: %v", err)
|
||||
}
|
||||
|
||||
// Sadly, iptables has inconsistent quoting rules for comments. Just remove all quotes.
|
||||
// Also, quoted multi-word comments (which are counted as a single arg)
|
||||
// will be unpacked into multiple args,
|
||||
// in order to compare against iptables-save output (which will be split at whitespace boundary)
|
||||
// e.g. a single arg('"this must be before the NodePort rules"') will be unquoted and unpacked into 7 args.
|
||||
var argsCopy []string
|
||||
for i := range args {
|
||||
tmpField := strings.Trim(args[i], "\"")
|
||||
tmpField = trimhex(tmpField)
|
||||
argsCopy = append(argsCopy, strings.Fields(tmpField)...)
|
||||
}
|
||||
argset := sets.NewString(argsCopy...)
|
||||
|
||||
for _, line := range strings.Split(string(out), "\n") {
|
||||
var fields = strings.Fields(line)
|
||||
|
||||
// Check that this is a rule for the correct chain, and that it has
|
||||
// the correct number of argument (+2 for "-A <chain name>")
|
||||
if !strings.HasPrefix(line, fmt.Sprintf("-A %s", string(chain))) || len(fields) != len(argsCopy)+2 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Sadly, iptables has inconsistent quoting rules for comments.
|
||||
// Just remove all quotes.
|
||||
for i := range fields {
|
||||
fields[i] = strings.Trim(fields[i], "\"")
|
||||
fields[i] = trimhex(fields[i])
|
||||
}
|
||||
|
||||
// TODO: This misses reorderings e.g. "-x foo ! -y bar" will match "! -x foo -y bar"
|
||||
if sets.NewString(fields...).IsSuperset(argset) {
|
||||
return true, nil
|
||||
}
|
||||
glog.V(5).Infof("DBG: fields is not a superset of args: fields=%v args=%v", fields, args)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Executes the rule check using the "-C" flag
|
||||
func (runner *runner) checkRuleUsingCheck(args []string) (bool, error) {
|
||||
out, err := runner.run(opCheckRule, args)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if ee, ok := err.(utilexec.ExitError); ok {
|
||||
// iptables uses exit(1) to indicate a failure of the operation,
|
||||
// as compared to a malformed commandline, for example.
|
||||
if ee.Exited() && ee.ExitStatus() == 1 {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return false, fmt.Errorf("error checking rule: %v: %s", err, out)
|
||||
}
|
||||
|
||||
type operation string
|
||||
|
||||
const (
|
||||
opCreateChain operation = "-N"
|
||||
opFlushChain operation = "-F"
|
||||
opDeleteChain operation = "-X"
|
||||
opAppendRule operation = "-A"
|
||||
opCheckRule operation = "-C"
|
||||
opDeleteRule operation = "-D"
|
||||
)
|
||||
|
||||
func makeFullArgs(table Table, chain Chain, args ...string) []string {
|
||||
return append([]string{string(chain), "-t", string(table)}, args...)
|
||||
}
|
||||
|
||||
// Checks if iptables has the "-C" flag
|
||||
func getIPTablesHasCheckCommand(vstring string) bool {
|
||||
minVersion, err := utilversion.ParseGeneric(MinCheckVersion)
|
||||
if err != nil {
|
||||
glog.Errorf("MinCheckVersion (%s) is not a valid version string: %v", MinCheckVersion, err)
|
||||
return true
|
||||
}
|
||||
version, err := utilversion.ParseGeneric(vstring)
|
||||
if err != nil {
|
||||
glog.Errorf("vstring (%s) is not a valid version string: %v", vstring, err)
|
||||
return true
|
||||
}
|
||||
return version.AtLeast(minVersion)
|
||||
}
|
||||
|
||||
// Checks if iptables version has a "wait" flag
|
||||
func getIPTablesWaitFlag(vstring string) []string {
|
||||
version, err := utilversion.ParseGeneric(vstring)
|
||||
if err != nil {
|
||||
glog.Errorf("vstring (%s) is not a valid version string: %v", vstring, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
minVersion, err := utilversion.ParseGeneric(MinWaitVersion)
|
||||
if err != nil {
|
||||
glog.Errorf("MinWaitVersion (%s) is not a valid version string: %v", MinWaitVersion, err)
|
||||
return nil
|
||||
}
|
||||
if version.LessThan(minVersion) {
|
||||
return nil
|
||||
}
|
||||
|
||||
minVersion, err = utilversion.ParseGeneric(MinWait2Version)
|
||||
if err != nil {
|
||||
glog.Errorf("MinWait2Version (%s) is not a valid version string: %v", MinWait2Version, err)
|
||||
return nil
|
||||
}
|
||||
if version.LessThan(minVersion) {
|
||||
return []string{"-w"}
|
||||
} else {
|
||||
return []string{"-w2"}
|
||||
}
|
||||
}
|
||||
|
||||
// getIPTablesVersionString runs "iptables --version" to get the version string
|
||||
// in the form "X.X.X"
|
||||
func getIPTablesVersionString(exec utilexec.Interface) (string, error) {
|
||||
// this doesn't access mutable state so we don't need to use the interface / runner
|
||||
bytes, err := exec.Command(cmdIPTables, "--version").CombinedOutput()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
versionMatcher := regexp.MustCompile("v([0-9]+(\\.[0-9]+)+)")
|
||||
match := versionMatcher.FindStringSubmatch(string(bytes))
|
||||
if match == nil {
|
||||
return "", fmt.Errorf("no iptables version found in string: %s", bytes)
|
||||
}
|
||||
return match[1], nil
|
||||
}
|
||||
|
||||
// goroutine to listen for D-Bus signals
|
||||
func (runner *runner) dbusSignalHandler(bus utildbus.Connection) {
|
||||
firewalld := bus.Object(firewalldName, firewalldPath)
|
||||
|
||||
for s := range runner.signal {
|
||||
if s == nil {
|
||||
// Unregister
|
||||
bus.Signal(runner.signal)
|
||||
return
|
||||
}
|
||||
|
||||
switch s.Name {
|
||||
case "org.freedesktop.DBus.NameOwnerChanged":
|
||||
name := s.Body[0].(string)
|
||||
new_owner := s.Body[2].(string)
|
||||
|
||||
if name != firewalldName || len(new_owner) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// FirewallD startup (specifically the part where it deletes
|
||||
// all existing iptables rules) may not yet be complete when
|
||||
// we get this signal, so make a dummy request to it to
|
||||
// synchronize.
|
||||
firewalld.Call(firewalldInterface+".getDefaultZone", 0)
|
||||
|
||||
runner.reload()
|
||||
case firewalldInterface + ".Reloaded":
|
||||
runner.reload()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AddReloadFunc is part of Interface
|
||||
func (runner *runner) AddReloadFunc(reloadFunc func()) {
|
||||
runner.reloadFuncs = append(runner.reloadFuncs, reloadFunc)
|
||||
}
|
||||
|
||||
// runs all reload funcs to re-sync iptables rules
|
||||
func (runner *runner) reload() {
|
||||
glog.V(1).Infof("reloading iptables rules")
|
||||
|
||||
for _, f := range runner.reloadFuncs {
|
||||
f()
|
||||
}
|
||||
}
|
||||
|
||||
// IsNotFoundError returns true if the error indicates "not found". It parses
|
||||
// the error string looking for known values, which is imperfect but works in
|
||||
// practice.
|
||||
func IsNotFoundError(err error) bool {
|
||||
es := err.Error()
|
||||
if strings.Contains(es, "No such file or directory") {
|
||||
return true
|
||||
}
|
||||
if strings.Contains(es, "No chain/target/match by that name") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
773
vendor/k8s.io/kubernetes/pkg/util/iptables/iptables_test.go
generated
vendored
773
vendor/k8s.io/kubernetes/pkg/util/iptables/iptables_test.go
generated
vendored
|
@ -1,773 +0,0 @@
|
|||
/*
|
||||
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 iptables
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/kubernetes/pkg/util/dbus"
|
||||
"k8s.io/kubernetes/pkg/util/exec"
|
||||
)
|
||||
|
||||
func getIPTablesCommand(protocol Protocol) string {
|
||||
if protocol == ProtocolIpv4 {
|
||||
return cmdIPTables
|
||||
}
|
||||
if protocol == ProtocolIpv6 {
|
||||
return cmdIp6tables
|
||||
}
|
||||
panic("Unknown protocol")
|
||||
}
|
||||
|
||||
func testEnsureChain(t *testing.T, protocol Protocol) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// iptables version check
|
||||
func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
|
||||
// Success.
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
// Exists.
|
||||
func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 1} },
|
||||
// Failure.
|
||||
func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 2} },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec, dbus.NewFake(nil, nil), protocol)
|
||||
defer runner.Destroy()
|
||||
// Success.
|
||||
exists, err := runner.EnsureChain(TableNAT, Chain("FOOBAR"))
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if exists {
|
||||
t.Errorf("expected exists = false")
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 2 {
|
||||
t.Errorf("expected 2 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
cmd := getIPTablesCommand(protocol)
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[1]...).HasAll(cmd, "-t", "nat", "-N", "FOOBAR") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[1])
|
||||
}
|
||||
// Exists.
|
||||
exists, err = runner.EnsureChain(TableNAT, Chain("FOOBAR"))
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if !exists {
|
||||
t.Errorf("expected exists = true")
|
||||
}
|
||||
// Failure.
|
||||
_, err = runner.EnsureChain(TableNAT, Chain("FOOBAR"))
|
||||
if err == nil {
|
||||
t.Errorf("expected failure")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureChainIpv4(t *testing.T) {
|
||||
testEnsureChain(t, ProtocolIpv4)
|
||||
}
|
||||
|
||||
func TestEnsureChainIpv6(t *testing.T) {
|
||||
testEnsureChain(t, ProtocolIpv6)
|
||||
}
|
||||
|
||||
func TestFlushChain(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// iptables version check
|
||||
func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
|
||||
// Success.
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
// Failure.
|
||||
func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 1} },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
|
||||
defer runner.Destroy()
|
||||
// Success.
|
||||
err := runner.FlushChain(TableNAT, Chain("FOOBAR"))
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 2 {
|
||||
t.Errorf("expected 2 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[1]...).HasAll("iptables", "-t", "nat", "-F", "FOOBAR") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[1])
|
||||
}
|
||||
// Failure.
|
||||
err = runner.FlushChain(TableNAT, Chain("FOOBAR"))
|
||||
if err == nil {
|
||||
t.Errorf("expected failure")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteChain(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// iptables version check
|
||||
func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
|
||||
// Success.
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
// Failure.
|
||||
func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 1} },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
|
||||
defer runner.Destroy()
|
||||
// Success.
|
||||
err := runner.DeleteChain(TableNAT, Chain("FOOBAR"))
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 2 {
|
||||
t.Errorf("expected 2 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[1]...).HasAll("iptables", "-t", "nat", "-X", "FOOBAR") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[1])
|
||||
}
|
||||
// Failure.
|
||||
err = runner.DeleteChain(TableNAT, Chain("FOOBAR"))
|
||||
if err == nil {
|
||||
t.Errorf("expected failure")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureRuleAlreadyExists(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// iptables version check
|
||||
func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
|
||||
// Success.
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
// iptables version check
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
// The second Command() call is checking the rule. Success of that exec means "done".
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
|
||||
defer runner.Destroy()
|
||||
exists, err := runner.EnsureRule(Append, TableNAT, ChainOutput, "abc", "123")
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if !exists {
|
||||
t.Errorf("expected exists = true")
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 2 {
|
||||
t.Errorf("expected 2 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[1]...).HasAll("iptables", "-t", "nat", "-C", "OUTPUT", "abc", "123") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureRuleNew(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// iptables version check
|
||||
func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
|
||||
// Status 1 on the first call.
|
||||
func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 1} },
|
||||
// Success on the second call.
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
// iptables version check
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
// The second Command() call is checking the rule. Failure of that means create it.
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
|
||||
defer runner.Destroy()
|
||||
exists, err := runner.EnsureRule(Append, TableNAT, ChainOutput, "abc", "123")
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if exists {
|
||||
t.Errorf("expected exists = false")
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 3 {
|
||||
t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[2]...).HasAll("iptables", "-t", "nat", "-A", "OUTPUT", "abc", "123") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[2])
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureRuleErrorChecking(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// iptables version check
|
||||
func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
|
||||
// Status 2 on the first call.
|
||||
func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 2} },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
// iptables version check
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
// The second Command() call is checking the rule. Failure of that means create it.
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
|
||||
defer runner.Destroy()
|
||||
_, err := runner.EnsureRule(Append, TableNAT, ChainOutput, "abc", "123")
|
||||
if err == nil {
|
||||
t.Errorf("expected failure")
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 2 {
|
||||
t.Errorf("expected 2 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureRuleErrorCreating(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// iptables version check
|
||||
func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
|
||||
// Status 1 on the first call.
|
||||
func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 1} },
|
||||
// Status 1 on the second call.
|
||||
func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 1} },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
// iptables version check
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
// The second Command() call is checking the rule. Failure of that means create it.
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
|
||||
defer runner.Destroy()
|
||||
_, err := runner.EnsureRule(Append, TableNAT, ChainOutput, "abc", "123")
|
||||
if err == nil {
|
||||
t.Errorf("expected failure")
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 3 {
|
||||
t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteRuleAlreadyExists(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// iptables version check
|
||||
func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
|
||||
// Status 1 on the first call.
|
||||
func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 1} },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
// iptables version check
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
// The second Command() call is checking the rule. Failure of that exec means "does not exist".
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
|
||||
defer runner.Destroy()
|
||||
err := runner.DeleteRule(TableNAT, ChainOutput, "abc", "123")
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 2 {
|
||||
t.Errorf("expected 2 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[1]...).HasAll("iptables", "-t", "nat", "-C", "OUTPUT", "abc", "123") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteRuleNew(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// iptables version check
|
||||
func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
|
||||
// Success on the first call.
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
// Success on the second call.
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
// iptables version check
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
// The second Command() call is checking the rule. Success of that means delete it.
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
|
||||
defer runner.Destroy()
|
||||
err := runner.DeleteRule(TableNAT, ChainOutput, "abc", "123")
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 3 {
|
||||
t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[2]...).HasAll("iptables", "-t", "nat", "-D", "OUTPUT", "abc", "123") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[2])
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteRuleErrorChecking(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// iptables version check
|
||||
func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
|
||||
// Status 2 on the first call.
|
||||
func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 2} },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
// iptables version check
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
// The second Command() call is checking the rule. Failure of that means create it.
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
|
||||
defer runner.Destroy()
|
||||
err := runner.DeleteRule(TableNAT, ChainOutput, "abc", "123")
|
||||
if err == nil {
|
||||
t.Errorf("expected failure")
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 2 {
|
||||
t.Errorf("expected 2 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteRuleErrorCreating(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// iptables version check
|
||||
func() ([]byte, error) { return []byte("iptables v1.9.22"), nil },
|
||||
// Success on the first call.
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
// Status 1 on the second call.
|
||||
func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 1} },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
// iptables version check
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
// The second Command() call is checking the rule. Success of that means delete it.
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
|
||||
defer runner.Destroy()
|
||||
err := runner.DeleteRule(TableNAT, ChainOutput, "abc", "123")
|
||||
if err == nil {
|
||||
t.Errorf("expected failure")
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 3 {
|
||||
t.Errorf("expected 3 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetIPTablesHasCheckCommand(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Version string
|
||||
Err bool
|
||||
Expected bool
|
||||
}{
|
||||
{"iptables v1.4.7", false, false},
|
||||
{"iptables v1.4.11", false, true},
|
||||
{"iptables v1.4.19.1", false, true},
|
||||
{"iptables v2.0.0", false, true},
|
||||
{"total junk", true, false},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return []byte(testCase.Version), nil },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
version, err := getIPTablesVersionString(&fexec)
|
||||
if (err != nil) != testCase.Err {
|
||||
t.Errorf("Expected error: %v, Got error: %v", testCase.Err, err)
|
||||
}
|
||||
if err == nil {
|
||||
check := getIPTablesHasCheckCommand(version)
|
||||
if testCase.Expected != check {
|
||||
t.Errorf("Expected result: %v, Got result: %v", testCase.Expected, check)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckRuleWithoutCheckPresent(t *testing.T) {
|
||||
iptables_save_output := `# Generated by iptables-save v1.4.7 on Wed Oct 29 14:56:01 2014
|
||||
*nat
|
||||
:PREROUTING ACCEPT [2136997:197881818]
|
||||
:POSTROUTING ACCEPT [4284525:258542680]
|
||||
:OUTPUT ACCEPT [5901660:357267963]
|
||||
-A PREROUTING -m addrtype --dst-type LOCAL -m mark --mark 0x00004000/0x00004000 -j DOCKER
|
||||
COMMIT
|
||||
# Completed on Wed Oct 29 14:56:01 2014`
|
||||
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// Success.
|
||||
func() ([]byte, error) { return []byte(iptables_save_output), nil },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
// The first Command() call is checking the rule. Success of that exec means "done".
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := &runner{exec: &fexec}
|
||||
exists, err := runner.checkRuleWithoutCheck(
|
||||
TableNAT, ChainPrerouting,
|
||||
"-m", "addrtype",
|
||||
"-m", "mark", "--mark", "0x4000/0x4000",
|
||||
"-j", "DOCKER",
|
||||
"--dst-type", "LOCAL")
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if !exists {
|
||||
t.Errorf("expected exists = true")
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 1 {
|
||||
t.Errorf("expected 1 CombinedOutput() call, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("iptables-save", "-t", "nat") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckRuleWithoutCheckAbsent(t *testing.T) {
|
||||
iptables_save_output := `# Generated by iptables-save v1.4.7 on Wed Oct 29 14:56:01 2014
|
||||
*nat
|
||||
:PREROUTING ACCEPT [2136997:197881818]
|
||||
:POSTROUTING ACCEPT [4284525:258542680]
|
||||
:OUTPUT ACCEPT [5901660:357267963]
|
||||
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
|
||||
COMMIT
|
||||
# Completed on Wed Oct 29 14:56:01 2014`
|
||||
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// Success.
|
||||
func() ([]byte, error) { return []byte(iptables_save_output), nil },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
// The first Command() call is checking the rule. Success of that exec means "done".
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := &runner{exec: &fexec}
|
||||
exists, err := runner.checkRuleWithoutCheck(TableNAT, ChainPrerouting, "-m", "addrtype", "-j", "DOCKER")
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if exists {
|
||||
t.Errorf("expected exists = false")
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 1 {
|
||||
t.Errorf("expected 1 CombinedOutput() call, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("iptables-save", "-t", "nat") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPTablesWaitFlag(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Version string
|
||||
Result string
|
||||
}{
|
||||
{"0.55.55", ""},
|
||||
{"1.0.55", ""},
|
||||
{"1.4.19", ""},
|
||||
{"1.4.20", "-w"},
|
||||
{"1.4.21", "-w"},
|
||||
{"1.4.22", "-w2"},
|
||||
{"1.5.0", "-w2"},
|
||||
{"2.0.0", "-w2"},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
result := getIPTablesWaitFlag(testCase.Version)
|
||||
if strings.Join(result, "") != testCase.Result {
|
||||
t.Errorf("For %s expected %v got %v", testCase.Version, testCase.Result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitFlagUnavailable(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// iptables version check
|
||||
func() ([]byte, error) { return []byte("iptables v1.4.19"), nil },
|
||||
// Success.
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
|
||||
defer runner.Destroy()
|
||||
err := runner.DeleteChain(TableNAT, Chain("FOOBAR"))
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 2 {
|
||||
t.Errorf("expected 2 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
if sets.NewString(fcmd.CombinedOutputLog[1]...).HasAny("-w", "-w2") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitFlagOld(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// iptables version check
|
||||
func() ([]byte, error) { return []byte("iptables v1.4.20"), nil },
|
||||
// Success.
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
|
||||
defer runner.Destroy()
|
||||
err := runner.DeleteChain(TableNAT, Chain("FOOBAR"))
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 2 {
|
||||
t.Errorf("expected 2 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[1]...).HasAll("iptables", "-w") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[1])
|
||||
}
|
||||
if sets.NewString(fcmd.CombinedOutputLog[1]...).HasAny("-w2") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitFlagNew(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// iptables version check
|
||||
func() ([]byte, error) { return []byte("iptables v1.4.22"), nil },
|
||||
// Success.
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec, dbus.NewFake(nil, nil), ProtocolIpv4)
|
||||
defer runner.Destroy()
|
||||
err := runner.DeleteChain(TableNAT, Chain("FOOBAR"))
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if fcmd.CombinedOutputCalls != 2 {
|
||||
t.Errorf("expected 2 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[1]...).HasAll("iptables", "-w2") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[1])
|
||||
}
|
||||
if sets.NewString(fcmd.CombinedOutputLog[1]...).HasAny("-w") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestReload(t *testing.T) {
|
||||
dbusConn := dbus.NewFakeConnection()
|
||||
dbusConn.SetBusObject(func(method string, args ...interface{}) ([]interface{}, error) { return nil, nil })
|
||||
dbusConn.AddObject(firewalldName, firewalldPath, func(method string, args ...interface{}) ([]interface{}, error) { return nil, nil })
|
||||
fdbus := dbus.NewFake(dbusConn, nil)
|
||||
|
||||
reloaded := make(chan bool, 2)
|
||||
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// iptables version check
|
||||
func() ([]byte, error) { return []byte("iptables v1.4.22"), nil },
|
||||
|
||||
// first reload
|
||||
// EnsureChain
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
// EnsureRule abc check
|
||||
func() ([]byte, error) { return []byte{}, &exec.FakeExitError{Status: 1} },
|
||||
// EnsureRule abc
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
|
||||
// second reload
|
||||
// EnsureChain
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
// EnsureRule abc check
|
||||
func() ([]byte, error) { return []byte{}, &exec.FakeExitError{Status: 1} },
|
||||
// EnsureRule abc
|
||||
func() ([]byte, error) { return []byte{}, nil },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
|
||||
runner := New(&fexec, fdbus, ProtocolIpv4)
|
||||
defer runner.Destroy()
|
||||
|
||||
runner.AddReloadFunc(func() {
|
||||
exists, err := runner.EnsureChain(TableNAT, Chain("FOOBAR"))
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if exists {
|
||||
t.Errorf("expected exists = false")
|
||||
}
|
||||
reloaded <- true
|
||||
})
|
||||
|
||||
runner.AddReloadFunc(func() {
|
||||
exists, err := runner.EnsureRule(Append, TableNAT, ChainOutput, "abc", "123")
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %v", err)
|
||||
}
|
||||
if exists {
|
||||
t.Errorf("expected exists = false")
|
||||
}
|
||||
reloaded <- true
|
||||
})
|
||||
|
||||
dbusConn.EmitSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged", firewalldName, "", ":1.1")
|
||||
<-reloaded
|
||||
<-reloaded
|
||||
|
||||
if fcmd.CombinedOutputCalls != 4 {
|
||||
t.Errorf("expected 4 CombinedOutput() calls total, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[1]...).HasAll("iptables", "-t", "nat", "-N", "FOOBAR") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[1])
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[2]...).HasAll("iptables", "-t", "nat", "-C", "OUTPUT", "abc", "123") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[2])
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[3]...).HasAll("iptables", "-t", "nat", "-A", "OUTPUT", "abc", "123") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[3])
|
||||
}
|
||||
|
||||
go func() { time.Sleep(time.Second / 100); reloaded <- true }()
|
||||
dbusConn.EmitSignal(firewalldName, firewalldPath, firewalldInterface, "DefaultZoneChanged", "public")
|
||||
dbusConn.EmitSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged", "io.k8s.Something", "", ":1.1")
|
||||
<-reloaded
|
||||
|
||||
if fcmd.CombinedOutputCalls != 4 {
|
||||
t.Errorf("Incorrect signal caused a reload")
|
||||
}
|
||||
|
||||
dbusConn.EmitSignal(firewalldName, firewalldPath, firewalldInterface, "Reloaded")
|
||||
<-reloaded
|
||||
<-reloaded
|
||||
|
||||
if fcmd.CombinedOutputCalls != 7 {
|
||||
t.Errorf("expected 7 CombinedOutput() calls total, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[4]...).HasAll("iptables", "-t", "nat", "-N", "FOOBAR") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[4])
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[5]...).HasAll("iptables", "-t", "nat", "-C", "OUTPUT", "abc", "123") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[5])
|
||||
}
|
||||
if !sets.NewString(fcmd.CombinedOutputLog[6]...).HasAll("iptables", "-t", "nat", "-A", "OUTPUT", "abc", "123") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[6])
|
||||
}
|
||||
}
|
108
vendor/k8s.io/kubernetes/pkg/util/iptables/save_restore.go
generated
vendored
108
vendor/k8s.io/kubernetes/pkg/util/iptables/save_restore.go
generated
vendored
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
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 iptables
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MakeChainLine return an iptables-save/restore formatted chain line given a Chain
|
||||
func MakeChainLine(chain Chain) string {
|
||||
return fmt.Sprintf(":%s - [0:0]", chain)
|
||||
}
|
||||
|
||||
// GetChainLines parses a table's iptables-save data to find chains in the table.
|
||||
// It returns a map of iptables.Chain to string where the string is the chain line from the save (with counters etc).
|
||||
func GetChainLines(table Table, save []byte) map[Chain]string {
|
||||
chainsMap := make(map[Chain]string)
|
||||
tablePrefix := "*" + string(table)
|
||||
readIndex := 0
|
||||
// find beginning of table
|
||||
for readIndex < len(save) {
|
||||
line, n := ReadLine(readIndex, save)
|
||||
readIndex = n
|
||||
if strings.HasPrefix(line, tablePrefix) {
|
||||
break
|
||||
}
|
||||
}
|
||||
// parse table lines
|
||||
for readIndex < len(save) {
|
||||
line, n := ReadLine(readIndex, save)
|
||||
readIndex = n
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "COMMIT") || strings.HasPrefix(line, "*") {
|
||||
break
|
||||
} else if strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
} else if strings.HasPrefix(line, ":") && len(line) > 1 {
|
||||
chain := Chain(strings.SplitN(line[1:], " ", 2)[0])
|
||||
chainsMap[chain] = line
|
||||
}
|
||||
}
|
||||
return chainsMap
|
||||
}
|
||||
|
||||
func ReadLine(readIndex int, byteArray []byte) (string, int) {
|
||||
currentReadIndex := readIndex
|
||||
|
||||
// consume left spaces
|
||||
for currentReadIndex < len(byteArray) {
|
||||
if byteArray[currentReadIndex] == ' ' {
|
||||
currentReadIndex++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// leftTrimIndex stores the left index of the line after the line is left-trimmed
|
||||
leftTrimIndex := currentReadIndex
|
||||
|
||||
// rightTrimIndex stores the right index of the line after the line is right-trimmed
|
||||
// it is set to -1 since the correct value has not yet been determined.
|
||||
rightTrimIndex := -1
|
||||
|
||||
for ; currentReadIndex < len(byteArray); currentReadIndex++ {
|
||||
if byteArray[currentReadIndex] == ' ' {
|
||||
// set rightTrimIndex
|
||||
if rightTrimIndex == -1 {
|
||||
rightTrimIndex = currentReadIndex
|
||||
}
|
||||
} else if (byteArray[currentReadIndex] == '\n') || (currentReadIndex == (len(byteArray) - 1)) {
|
||||
// end of line or byte buffer is reached
|
||||
if currentReadIndex <= leftTrimIndex {
|
||||
return "", currentReadIndex + 1
|
||||
}
|
||||
// set the rightTrimIndex
|
||||
if rightTrimIndex == -1 {
|
||||
rightTrimIndex = currentReadIndex
|
||||
if currentReadIndex == (len(byteArray)-1) && (byteArray[currentReadIndex] != '\n') {
|
||||
// ensure that the last character is part of the returned string,
|
||||
// unless the last character is '\n'
|
||||
rightTrimIndex = currentReadIndex + 1
|
||||
}
|
||||
}
|
||||
return string(byteArray[leftTrimIndex:rightTrimIndex]), currentReadIndex + 1
|
||||
} else {
|
||||
// unset rightTrimIndex
|
||||
rightTrimIndex = -1
|
||||
}
|
||||
}
|
||||
return "", currentReadIndex
|
||||
}
|
28
vendor/k8s.io/kubernetes/pkg/util/iptables/testing/BUILD
generated
vendored
28
vendor/k8s.io/kubernetes/pkg/util/iptables/testing/BUILD
generated
vendored
|
@ -1,28 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["fake.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = ["//pkg/util/iptables:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
122
vendor/k8s.io/kubernetes/pkg/util/iptables/testing/fake.go
generated
vendored
122
vendor/k8s.io/kubernetes/pkg/util/iptables/testing/fake.go
generated
vendored
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/iptables"
|
||||
)
|
||||
|
||||
const (
|
||||
Destination = "-d "
|
||||
Source = "-s "
|
||||
DPort = "--dport "
|
||||
Protocol = "-p "
|
||||
Jump = "-j "
|
||||
Reject = "REJECT"
|
||||
ToDest = "--to-destination "
|
||||
)
|
||||
|
||||
type Rule map[string]string
|
||||
|
||||
// no-op implementation of iptables Interface
|
||||
type FakeIPTables struct {
|
||||
Lines []byte
|
||||
}
|
||||
|
||||
func NewFake() *FakeIPTables {
|
||||
return &FakeIPTables{}
|
||||
}
|
||||
|
||||
func (*FakeIPTables) GetVersion() (string, error) {
|
||||
return "0.0.0", nil
|
||||
}
|
||||
|
||||
func (*FakeIPTables) EnsureChain(table iptables.Table, chain iptables.Chain) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (*FakeIPTables) FlushChain(table iptables.Table, chain iptables.Chain) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*FakeIPTables) DeleteChain(table iptables.Table, chain iptables.Chain) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*FakeIPTables) EnsureRule(position iptables.RulePosition, table iptables.Table, chain iptables.Chain, args ...string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (*FakeIPTables) DeleteRule(table iptables.Table, chain iptables.Chain, args ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*FakeIPTables) IsIpv6() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (*FakeIPTables) Save(table iptables.Table) ([]byte, error) {
|
||||
return make([]byte, 0), nil
|
||||
}
|
||||
|
||||
func (*FakeIPTables) SaveAll() ([]byte, error) {
|
||||
return make([]byte, 0), nil
|
||||
}
|
||||
|
||||
func (*FakeIPTables) Restore(table iptables.Table, data []byte, flush iptables.FlushFlag, counters iptables.RestoreCountersFlag) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FakeIPTables) RestoreAll(data []byte, flush iptables.FlushFlag, counters iptables.RestoreCountersFlag) error {
|
||||
f.Lines = data
|
||||
return nil
|
||||
}
|
||||
func (*FakeIPTables) AddReloadFunc(reloadFunc func()) {}
|
||||
|
||||
func (*FakeIPTables) Destroy() {}
|
||||
|
||||
func getToken(line, seperator string) string {
|
||||
tokens := strings.Split(line, seperator)
|
||||
if len(tokens) == 2 {
|
||||
return strings.Split(tokens[1], " ")[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetChain returns a list of rules for the given chain.
|
||||
// The chain name must match exactly.
|
||||
// The matching is pretty dumb, don't rely on it for anything but testing.
|
||||
func (f *FakeIPTables) GetRules(chainName string) (rules []Rule) {
|
||||
for _, l := range strings.Split(string(f.Lines), "\n") {
|
||||
if strings.Contains(l, fmt.Sprintf("-A %v", chainName)) {
|
||||
newRule := Rule(map[string]string{})
|
||||
for _, arg := range []string{Destination, Source, DPort, Protocol, Jump, ToDest} {
|
||||
tok := getToken(l, arg)
|
||||
if tok != "" {
|
||||
newRule[arg] = tok
|
||||
}
|
||||
}
|
||||
rules = append(rules, newRule)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var _ = iptables.Interface(&FakeIPTables{})
|
27
vendor/k8s.io/kubernetes/pkg/util/json/BUILD
generated
vendored
27
vendor/k8s.io/kubernetes/pkg/util/json/BUILD
generated
vendored
|
@ -1,27 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["doc.go"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
21
vendor/k8s.io/kubernetes/pkg/util/json/doc.go
generated
vendored
21
vendor/k8s.io/kubernetes/pkg/util/json/doc.go
generated
vendored
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 json only exists until heapster rebases
|
||||
// TODO genericapiserver remove this empty package. Godep fails without this because heapster relies
|
||||
// on this package. This will allow us to start splitting packages, but will force
|
||||
// heapster to update on their next kube rebase.
|
||||
package json
|
36
vendor/k8s.io/kubernetes/pkg/util/keymutex/BUILD
generated
vendored
36
vendor/k8s.io/kubernetes/pkg/util/keymutex/BUILD
generated
vendored
|
@ -1,36 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["keymutex.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor:github.com/golang/glog"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["keymutex_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
83
vendor/k8s.io/kubernetes/pkg/util/keymutex/keymutex.go
generated
vendored
83
vendor/k8s.io/kubernetes/pkg/util/keymutex/keymutex.go
generated
vendored
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 keymutex
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// KeyMutex is a thread-safe interface for acquiring locks on arbitrary strings.
|
||||
type KeyMutex interface {
|
||||
// Acquires a lock associated with the specified ID, creates the lock if one doesn't already exist.
|
||||
LockKey(id string)
|
||||
|
||||
// Releases the lock associated with the specified ID.
|
||||
// Returns an error if the specified ID doesn't exist.
|
||||
UnlockKey(id string) error
|
||||
}
|
||||
|
||||
// Returns a new instance of a key mutex.
|
||||
func NewKeyMutex() KeyMutex {
|
||||
return &keyMutex{
|
||||
mutexMap: make(map[string]*sync.Mutex),
|
||||
}
|
||||
}
|
||||
|
||||
type keyMutex struct {
|
||||
sync.RWMutex
|
||||
mutexMap map[string]*sync.Mutex
|
||||
}
|
||||
|
||||
// Acquires a lock associated with the specified ID (creates the lock if one doesn't already exist).
|
||||
func (km *keyMutex) LockKey(id string) {
|
||||
glog.V(5).Infof("LockKey(...) called for id %q\r\n", id)
|
||||
mutex := km.getOrCreateLock(id)
|
||||
mutex.Lock()
|
||||
glog.V(5).Infof("LockKey(...) for id %q completed.\r\n", id)
|
||||
}
|
||||
|
||||
// Releases the lock associated with the specified ID.
|
||||
// Returns an error if the specified ID doesn't exist.
|
||||
func (km *keyMutex) UnlockKey(id string) error {
|
||||
glog.V(5).Infof("UnlockKey(...) called for id %q\r\n", id)
|
||||
km.RLock()
|
||||
defer km.RUnlock()
|
||||
mutex, exists := km.mutexMap[id]
|
||||
if !exists {
|
||||
return fmt.Errorf("id %q not found", id)
|
||||
}
|
||||
glog.V(5).Infof("UnlockKey(...) for id. Mutex found, trying to unlock it. %q\r\n", id)
|
||||
|
||||
mutex.Unlock()
|
||||
glog.V(5).Infof("UnlockKey(...) for id %q completed.\r\n", id)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns lock associated with the specified ID, or creates the lock if one doesn't already exist.
|
||||
func (km *keyMutex) getOrCreateLock(id string) *sync.Mutex {
|
||||
km.Lock()
|
||||
defer km.Unlock()
|
||||
|
||||
if _, exists := km.mutexMap[id]; !exists {
|
||||
km.mutexMap[id] = &sync.Mutex{}
|
||||
}
|
||||
|
||||
return km.mutexMap[id]
|
||||
}
|
111
vendor/k8s.io/kubernetes/pkg/util/keymutex/keymutex_test.go
generated
vendored
111
vendor/k8s.io/kubernetes/pkg/util/keymutex/keymutex_test.go
generated
vendored
|
@ -1,111 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 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 keymutex
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
callbackTimeout = 1 * time.Second
|
||||
)
|
||||
|
||||
func Test_SingleLock_NoUnlock(t *testing.T) {
|
||||
// Arrange
|
||||
km := NewKeyMutex()
|
||||
key := "fakeid"
|
||||
callbackCh := make(chan interface{})
|
||||
|
||||
// Act
|
||||
go lockAndCallback(km, key, callbackCh)
|
||||
|
||||
// Assert
|
||||
verifyCallbackHappens(t, callbackCh)
|
||||
}
|
||||
|
||||
func Test_SingleLock_SingleUnlock(t *testing.T) {
|
||||
// Arrange
|
||||
km := NewKeyMutex()
|
||||
key := "fakeid"
|
||||
callbackCh := make(chan interface{})
|
||||
|
||||
// Act & Assert
|
||||
go lockAndCallback(km, key, callbackCh)
|
||||
verifyCallbackHappens(t, callbackCh)
|
||||
km.UnlockKey(key)
|
||||
}
|
||||
|
||||
func Test_DoubleLock_DoubleUnlock(t *testing.T) {
|
||||
// Arrange
|
||||
km := NewKeyMutex()
|
||||
key := "fakeid"
|
||||
callbackCh1stLock := make(chan interface{})
|
||||
callbackCh2ndLock := make(chan interface{})
|
||||
|
||||
// Act & Assert
|
||||
go lockAndCallback(km, key, callbackCh1stLock)
|
||||
verifyCallbackHappens(t, callbackCh1stLock)
|
||||
go lockAndCallback(km, key, callbackCh2ndLock)
|
||||
verifyCallbackDoesntHappens(t, callbackCh2ndLock)
|
||||
km.UnlockKey(key)
|
||||
verifyCallbackHappens(t, callbackCh2ndLock)
|
||||
km.UnlockKey(key)
|
||||
}
|
||||
|
||||
func lockAndCallback(km KeyMutex, id string, callbackCh chan<- interface{}) {
|
||||
km.LockKey(id)
|
||||
callbackCh <- true
|
||||
}
|
||||
|
||||
func verifyCallbackHappens(t *testing.T, callbackCh <-chan interface{}) bool {
|
||||
select {
|
||||
case <-callbackCh:
|
||||
return true
|
||||
case <-time.After(callbackTimeout):
|
||||
t.Fatalf("Timed out waiting for callback.")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func verifyCallbackDoesntHappens(t *testing.T, callbackCh <-chan interface{}) bool {
|
||||
select {
|
||||
case <-callbackCh:
|
||||
t.Fatalf("Unexpected callback.")
|
||||
return false
|
||||
case <-time.After(callbackTimeout):
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func verifyNoError(t *testing.T, err error, name string) {
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected response on %q. Expected: <no error> Actual: <%v>", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
func verifyError(t *testing.T, err error, name string) {
|
||||
if err == nil {
|
||||
t.Fatalf("Unexpected response on %q. Expected: <error> Actual: <no error>", name)
|
||||
}
|
||||
}
|
||||
|
||||
func verifyMsg(t *testing.T, expected, actual string) {
|
||||
if actual != expected {
|
||||
t.Fatalf("Unexpected testMsg value. Expected: <%v> Actual: <%v>", expected, actual)
|
||||
}
|
||||
}
|
0
vendor/k8s.io/kubernetes/pkg/util/labels/.readonly
generated
vendored
0
vendor/k8s.io/kubernetes/pkg/util/labels/.readonly
generated
vendored
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue