Bumping k8s dependencies to 1.13

This commit is contained in:
Cheng Xing
2018-11-16 14:08:25 -08:00
parent 305407125c
commit b4c0b68ec7
8002 changed files with 884099 additions and 276228 deletions

View File

@@ -16,6 +16,7 @@ filegroup(
"//pkg/util/config:all-srcs",
"//pkg/util/configz:all-srcs",
"//pkg/util/conntrack:all-srcs",
"//pkg/util/coverage:all-srcs",
"//pkg/util/dbus:all-srcs",
"//pkg/util/ebtables:all-srcs",
"//pkg/util/env:all-srcs",
@@ -46,7 +47,6 @@ filegroup(
"//pkg/util/oom:all-srcs",
"//pkg/util/parsers:all-srcs",
"//pkg/util/pod:all-srcs",
"//pkg/util/pointer:all-srcs",
"//pkg/util/procfs:all-srcs",
"//pkg/util/reflector/prometheus:all-srcs",
"//pkg/util/removeall:all-srcs",

View File

@@ -14,8 +14,8 @@ go_library(
],
importpath = "k8s.io/kubernetes/pkg/util/async",
deps = [
"//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/client-go/util/flowcontrol:go_default_library",
],
)

View File

@@ -12,50 +12,17 @@ go_library(
"doc.go",
"fake_shaper.go",
"interfaces.go",
"linux.go",
"unsupported.go",
"utils.go",
] + select({
"@io_bazel_rules_go//go/platform:android": [
"unsupported.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"unsupported.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"unsupported.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"unsupported.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"linux.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"unsupported.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"unsupported.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"unsupported.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"unsupported.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"unsupported.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"unsupported.go",
],
"//conditions:default": [],
}),
],
importpath = "k8s.io/kubernetes/pkg/util/bandwidth",
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
] + select({
"@io_bazel_rules_go//go/platform:linux": [
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
"//conditions:default": [],
@@ -65,18 +32,14 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"linux_test.go",
"utils_test.go",
] + select({
"@io_bazel_rules_go//go/platform:linux": [
"linux_test.go",
],
"//conditions:default": [],
}),
],
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
] + select({
"@io_bazel_rules_go//go/platform:linux": [
"//vendor/k8s.io/utils/exec:go_default_library",

View File

@@ -13,7 +13,7 @@ go_library(
"doc.go",
],
importpath = "k8s.io/kubernetes/pkg/util/config",
deps = ["//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library"],
deps = ["//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library"],
)
go_test(

View File

@@ -2,27 +2,23 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"conntrack.go",
],
srcs = ["conntrack.go"],
importpath = "k8s.io/kubernetes/pkg/util/conntrack",
visibility = ["//visibility:public"],
deps = [
"//pkg/util/net:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"conntrack_test.go",
],
srcs = ["conntrack_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/util/net:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
"//vendor/k8s.io/utils/exec/testing:go_default_library",
],

25
vendor/k8s.io/kubernetes/pkg/util/coverage/BUILD generated vendored Normal file
View File

@@ -0,0 +1,25 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"coverage_disabled.go",
"fake_test_deps.go",
],
importpath = "k8s.io/kubernetes/pkg/util/coverage",
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

8
vendor/k8s.io/kubernetes/pkg/util/coverage/OWNERS generated vendored Normal file
View File

@@ -0,0 +1,8 @@
approvers:
- bentheelder
- spiffxp
reviewers:
- bentheelder
- spiffxp
labels:
- sig/testing

91
vendor/k8s.io/kubernetes/pkg/util/coverage/coverage.go generated vendored Normal file
View File

@@ -0,0 +1,91 @@
// +build coverage
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package coverage provides tools for coverage-instrumented binaries to collect and
// flush coverage information.
package coverage
import (
"flag"
"fmt"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/util/wait"
"os"
"testing"
"time"
)
var coverageFile string
// tempCoveragePath returns a temporary file to write coverage information to.
// The file is in the same directory as the destination, ensuring os.Rename will work.
func tempCoveragePath() string {
return coverageFile + ".tmp"
}
// InitCoverage is called from the dummy unit test to prepare Go's coverage framework.
// Clients should never need to call it.
func InitCoverage(name string) {
// We read the coverage destination in from the KUBE_COVERAGE_FILE env var,
// or if it's empty we just use a default in /tmp
coverageFile = os.Getenv("KUBE_COVERAGE_FILE")
if coverageFile == "" {
coverageFile = "/tmp/k8s-" + name + ".cov"
}
fmt.Println("Dumping coverage information to " + coverageFile)
flushInterval := 5 * time.Second
requestedInterval := os.Getenv("KUBE_COVERAGE_FLUSH_INTERVAL")
if requestedInterval != "" {
if duration, err := time.ParseDuration(requestedInterval); err == nil {
flushInterval = duration
} else {
panic("Invalid KUBE_COVERAGE_FLUSH_INTERVAL value; try something like '30s'.")
}
}
// Set up the unit test framework with the required arguments to activate test coverage.
flag.CommandLine.Parse([]string{"-test.coverprofile", tempCoveragePath()})
// Begin periodic logging
go wait.Forever(FlushCoverage, flushInterval)
}
// FlushCoverage flushes collected coverage information to disk.
// The destination file is configured at startup and cannot be changed.
// Calling this function also sends a line like "coverage: 5% of statements" to stdout.
func FlushCoverage() {
// We're not actually going to run any tests, but we need Go to think we did so it writes
// coverage information to disk. To achieve this, we create a bunch of empty test suites and
// have it "run" them.
tests := []testing.InternalTest{}
benchmarks := []testing.InternalBenchmark{}
examples := []testing.InternalExample{}
var deps fakeTestDeps
dummyRun := testing.MainStart(deps, tests, benchmarks, examples)
dummyRun.Run()
// Once it writes to the temporary path, we move it to the intended path.
// This gets us atomic updates from the perspective of another process trying to access
// the file.
if err := os.Rename(tempCoveragePath(), coverageFile); err != nil {
glog.Errorf("Couldn't move coverage file from %s to %s", coverageFile, tempCoveragePath())
}
}

View File

@@ -0,0 +1,29 @@
// +build !coverage
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package coverage
// InitCoverage is illegal when not running with coverage.
func InitCoverage(name string) {
panic("Called InitCoverage when not built with coverage instrumentation.")
}
// FlushCoverage is a no-op when not running with coverage.
func FlushCoverage() {
}

View File

@@ -0,0 +1,54 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package coverage
import (
"io"
)
// This is an implementation of testing.testDeps. It doesn't need to do anything, because
// no tests are actually run. It does need a concrete implementation of at least ImportPath,
// which is called unconditionally when running tests.
type fakeTestDeps struct{}
func (fakeTestDeps) ImportPath() string {
return ""
}
func (fakeTestDeps) MatchString(pat, str string) (bool, error) {
return false, nil
}
func (fakeTestDeps) StartCPUProfile(io.Writer) error {
return nil
}
func (fakeTestDeps) StopCPUProfile() {}
func (fakeTestDeps) StartTestLog(io.Writer) {}
func (fakeTestDeps) StopTestLog() error {
return nil
}
func (fakeTestDeps) WriteHeapProfile(io.Writer) error {
return nil
}
func (fakeTestDeps) WriteProfileTo(string, io.Writer, int) error {
return nil
}

View File

@@ -3,6 +3,7 @@ package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
@@ -10,6 +11,7 @@ go_library(
srcs = ["flags.go"],
importpath = "k8s.io/kubernetes/pkg/util/flag",
deps = [
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
],
@@ -27,3 +29,10 @@ filegroup(
srcs = [":package-srcs"],
tags = ["automanaged"],
)
go_test(
name = "go_default_test",
srcs = ["flags_test.go"],
embed = [":go_default_library"],
deps = ["//vendor/github.com/spf13/pflag:go_default_library"],
)

View File

@@ -17,8 +17,14 @@ limitations under the License.
package flag
import (
"fmt"
"net"
"strconv"
"github.com/golang/glog"
"github.com/spf13/pflag"
utilnet "k8s.io/apimachinery/pkg/util/net"
)
// PrintFlags logs the flags in the flagset
@@ -27,3 +33,129 @@ func PrintFlags(flags *pflag.FlagSet) {
glog.V(1).Infof("FLAG: --%s=%q", flag.Name, flag.Value)
})
}
// TODO(mikedanese): remove these flag wrapper types when we remove command line flags
var (
_ pflag.Value = &IPVar{}
_ pflag.Value = &IPPortVar{}
_ pflag.Value = &PortRangeVar{}
)
// IPVar is used for validating a command line option that represents an IP. It implements the pflag.Value interface
type IPVar struct {
Val *string
}
// Set sets the flag value
func (v IPVar) Set(s string) error {
if len(s) == 0 {
v.Val = nil
return nil
}
if net.ParseIP(s) == nil {
return fmt.Errorf("%q is not a valid IP address", s)
}
if v.Val == nil {
// it's okay to panic here since this is programmer error
panic("the string pointer passed into IPVar should not be nil")
}
*v.Val = s
return nil
}
// String returns the flag value
func (v IPVar) String() string {
if v.Val == nil {
return ""
}
return *v.Val
}
// Type gets the flag type
func (v IPVar) Type() string {
return "ip"
}
// IPPortVar is used for validating a command line option that represents an IP and a port. It implements the pflag.Value interface
type IPPortVar struct {
Val *string
}
// Set sets the flag value
func (v IPPortVar) Set(s string) error {
if len(s) == 0 {
v.Val = nil
return nil
}
if v.Val == nil {
// it's okay to panic here since this is programmer error
panic("the string pointer passed into IPPortVar should not be nil")
}
// Both IP and IP:port are valid.
// Attempt to parse into IP first.
if net.ParseIP(s) != nil {
*v.Val = s
return nil
}
// Can not parse into IP, now assume IP:port.
host, port, err := net.SplitHostPort(s)
if err != nil {
return fmt.Errorf("%q is not in a valid format (ip or ip:port): %v", s, err)
}
if net.ParseIP(host) == nil {
return fmt.Errorf("%q is not a valid IP address", host)
}
if _, err := strconv.Atoi(port); err != nil {
return fmt.Errorf("%q is not a valid number", port)
}
*v.Val = s
return nil
}
// String returns the flag value
func (v IPPortVar) String() string {
if v.Val == nil {
return ""
}
return *v.Val
}
// Type gets the flag type
func (v IPPortVar) Type() string {
return "ipport"
}
// PortRangeVar is used for validating a command line option that represents a port range. It implements the pflag.Value interface
type PortRangeVar struct {
Val *string
}
// Set sets the flag value
func (v PortRangeVar) Set(s string) error {
if _, err := utilnet.ParsePortRange(s); err != nil {
return fmt.Errorf("%q is not a valid port range: %v", s, err)
}
if v.Val == nil {
// it's okay to panic here since this is programmer error
panic("the string pointer passed into PortRangeVar should not be nil")
}
*v.Val = s
return nil
}
// String returns the flag value
func (v PortRangeVar) String() string {
if v.Val == nil {
return ""
}
return *v.Val
}
// Type gets the flag type
func (v PortRangeVar) Type() string {
return "port-range"
}

165
vendor/k8s.io/kubernetes/pkg/util/flag/flags_test.go generated vendored Normal file
View File

@@ -0,0 +1,165 @@
/*
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 flag
import (
"strings"
"testing"
"github.com/spf13/pflag"
)
func TestIPVar(t *testing.T) {
defaultIP := "0.0.0.0"
testCases := []struct {
argc string
expectErr bool
expectVal string
}{
{
argc: "blah --ip=1.2.3.4",
expectVal: "1.2.3.4",
},
{
argc: "blah --ip=1.2.3.4a",
expectErr: true,
expectVal: defaultIP,
},
}
for _, tc := range testCases {
fs := pflag.NewFlagSet("blah", pflag.PanicOnError)
ip := defaultIP
fs.Var(IPVar{&ip}, "ip", "the ip")
var err error
func() {
defer func() {
if r := recover(); r != nil {
err = r.(error)
}
}()
fs.Parse(strings.Split(tc.argc, " "))
}()
if tc.expectErr && err == nil {
t.Errorf("did not observe an expected error")
continue
}
if !tc.expectErr && err != nil {
t.Errorf("observed an unexpected error: %v", err)
continue
}
if tc.expectVal != ip {
t.Errorf("unexpected ip: expected %q, saw %q", tc.expectVal, ip)
}
}
}
func TestIPPortVar(t *testing.T) {
defaultIPPort := "0.0.0.0:8080"
testCases := []struct {
desc string
argc string
expectErr bool
expectVal string
}{
{
desc: "valid ipv4 1",
argc: "blah --ipport=0.0.0.0",
expectVal: "0.0.0.0",
},
{
desc: "valid ipv4 2",
argc: "blah --ipport=127.0.0.1",
expectVal: "127.0.0.1",
},
{
desc: "invalid IP",
argc: "blah --ipport=invalidip",
expectErr: true,
expectVal: defaultIPPort,
},
{
desc: "valid ipv4 with port",
argc: "blah --ipport=0.0.0.0:8080",
expectVal: "0.0.0.0:8080",
},
{
desc: "invalid ipv4 with invalid port",
argc: "blah --ipport=0.0.0.0:invalidport",
expectErr: true,
expectVal: defaultIPPort,
},
{
desc: "invalid IP with port",
argc: "blah --ipport=invalidip:8080",
expectErr: true,
expectVal: defaultIPPort,
},
{
desc: "valid ipv6 1",
argc: "blah --ipport=::1",
expectVal: "::1",
},
{
desc: "valid ipv6 2",
argc: "blah --ipport=::",
expectVal: "::",
},
{
desc: "valid ipv6 with port",
argc: "blah --ipport=[::1]:8080",
expectVal: "[::1]:8080",
},
{
desc: "invalid ipv6 with port without bracket",
argc: "blah --ipport=fd00:f00d:600d:f00d:8080",
expectErr: true,
expectVal: defaultIPPort,
},
}
for _, tc := range testCases {
fs := pflag.NewFlagSet("blah", pflag.PanicOnError)
ipport := defaultIPPort
fs.Var(IPPortVar{&ipport}, "ipport", "the ip:port")
var err error
func() {
defer func() {
if r := recover(); r != nil {
err = r.(error)
}
}()
fs.Parse(strings.Split(tc.argc, " "))
}()
if tc.expectErr && err == nil {
t.Errorf("%q: Did not observe an expected error", tc.desc)
continue
}
if !tc.expectErr && err != nil {
t.Errorf("%q: Observed an unexpected error: %v", tc.desc, err)
continue
}
if tc.expectVal != ipport {
t.Errorf("%q: Unexpected ipport: expected %q, saw %q", tc.desc, tc.expectVal, ipport)
}
}
}

View File

@@ -7,42 +7,10 @@ load(
go_library(
name = "go_default_library",
srcs = select({
"@io_bazel_rules_go//go/platform:android": [
"flock_other.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"flock_unix.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"flock_unix.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"flock_unix.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"flock_unix.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"flock_other.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"flock_unix.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"flock_unix.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"flock_other.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"flock_other.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"flock_other.go",
],
"//conditions:default": [],
}),
srcs = [
"flock_other.go",
"flock_unix.go",
],
importpath = "k8s.io/kubernetes/pkg/util/flock",
deps = select({
"@io_bazel_rules_go//go/platform:darwin": [

View File

@@ -12,8 +12,8 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/util/goroutinemap",
deps = [
"//pkg/util/goroutinemap/exponentialbackoff:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
],
)
@@ -21,7 +21,7 @@ go_test(
name = "go_default_test",
srcs = ["goroutinemap_test.go"],
embed = [":go_default_library"],
deps = ["//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library"],
deps = ["//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library"],
)
filegroup(

View File

@@ -7,15 +7,8 @@ load(
go_library(
name = "go_default_library",
srcs = [
"consistentread.go",
"writer.go",
],
srcs = ["consistentread.go"],
importpath = "k8s.io/kubernetes/pkg/util/io",
deps = [
"//pkg/util/nsenter:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
],
)
filegroup(

View File

@@ -1,87 +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
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"k8s.io/kubernetes/pkg/util/nsenter"
"github.com/golang/glog"
)
// Writer is an interface which allows to write data to a file.
type Writer interface {
// WriteFile mimics ioutil.WriteFile.
WriteFile(filename string, data []byte, perm os.FileMode) error
}
// StdWriter implements Writer interface and uses standard libraries
// for writing data to files.
type StdWriter struct {
}
// WriteFile directly calls ioutil.WriteFile.
func (writer *StdWriter) WriteFile(filename string, data []byte, perm os.FileMode) error {
return ioutil.WriteFile(filename, data, perm)
}
// NsenterWriter is implementation of Writer interface that allows writing data
// to file using nsenter command.
// If a program (e.g. kubelet) runs in a container it may want to write data to
// a mounted device. Since in Docker, mount propagation mode is set to private,
// it will not see the mounted device in its own namespace. To work around this
// limitation one has to first enter hosts namespace (by using 'nsenter') and
// only then write data.
type NsenterWriter struct {
ne *nsenter.Nsenter
}
// NewNsenterWriter creates a new Writer that allows writing data to file using
// nsenter command.
func NewNsenterWriter(ne *nsenter.Nsenter) *NsenterWriter {
return &NsenterWriter{
ne: ne,
}
}
// WriteFile calls 'nsenter cat - > <the file>' and 'nsenter chmod' to create a
// file on the host.
func (writer *NsenterWriter) WriteFile(filename string, data []byte, perm os.FileMode) error {
echoArgs := []string{"-c", fmt.Sprintf("cat > %s", filename)}
glog.V(5).Infof("nsenter: write data to file %s by nsenter", filename)
command := writer.ne.Exec("sh", echoArgs)
command.SetStdin(bytes.NewBuffer(data))
outputBytes, err := command.CombinedOutput()
if err != nil {
glog.Errorf("Output from writing to %q: %v", filename, string(outputBytes))
return err
}
chmodArgs := []string{fmt.Sprintf("%o", perm), filename}
glog.V(5).Infof("nsenter: change permissions of file %s to %s", filename, chmodArgs[0])
outputBytes, err = writer.ne.Exec("chmod", chmodArgs).CombinedOutput()
if err != nil {
glog.Errorf("Output from chmod command: %v", string(outputBytes))
return err
}
return nil
}

View File

@@ -19,7 +19,7 @@ go_test(
srcs = ["ipset_test.go"],
embed = [":go_default_library"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
"//vendor/k8s.io/utils/exec/testing:go_default_library",
],

View File

@@ -2,6 +2,7 @@ reviewers:
- thockin
- brendandburns
- m1093782566
- islinwb
approvers:
- thockin
- brendandburns

View File

@@ -52,7 +52,7 @@ type Interface interface {
GetVersion() (string, error)
}
// IPSetCmd represents the ipset util. We use ipset command for ipset execute.
// IPSetCmd represents the ipset util. We use ipset command for ipset execute.
const IPSetCmd = "ipset"
// EntryMemberPattern is the regular expression pattern of ipset member list.
@@ -72,7 +72,7 @@ var EntryMemberPattern = "(?m)^(.*\n)*Members:\n"
// ipset version output is similar to "v6.10".
var VersionPattern = "v[0-9]+\\.[0-9]+"
// IPSet implements an Interface to an set.
// IPSet implements an Interface to a set.
type IPSet struct {
// Name is the set name.
Name string
@@ -111,7 +111,7 @@ func (set *IPSet) Validate() bool {
}
// check hash size value of ipset
if set.HashSize <= 0 {
glog.Errorf("Invalid hashsize value %d, should be >0", set.HashSize)
return false
}
// check max elem value of ipset
@@ -123,6 +123,28 @@ func (set *IPSet) Validate() bool {
return true
}
//setIPSetDefaults sets some IPSet fields if not present to their default values.
func (set *IPSet) setIPSetDefaults() {
// Setting default values if not present
if set.HashSize == 0 {
set.HashSize = 1024
}
if set.MaxElem == 0 {
set.MaxElem = 65536
}
// Default protocol is IPv4
if set.HashFamily == "" {
set.HashFamily = ProtocolFamilyIPV4
}
// Default ipset type is "hash:ip,port"
if len(set.SetType) == 0 {
set.SetType = HashIPPort
}
if len(set.PortRange) == 0 {
set.PortRange = DefaultPortRange
}
}
// Entry represents a ipset entry.
type Entry struct {
// IP is the entry's IP. The IP address protocol corresponds to the HashFamily of IPSet.
@@ -131,7 +153,7 @@ type Entry struct {
// Port is the entry's Port.
Port int
// Protocol is the entry's Protocol. The protocols of entries in the same ip set are all
// the same. The accepted protocols are TCP and UDP.
// the same. The accepted protocols are TCP, UDP and SCTP.
Protocol string
// Net is the entry's IP network address. Network address with zero prefix size can NOT
// be stored.
@@ -150,31 +172,13 @@ func (e *Entry) Validate(set *IPSet) bool {
}
switch e.SetType {
case HashIPPort:
// set default protocol to tcp if empty
if len(e.Protocol) == 0 {
e.Protocol = ProtocolTCP
}
if net.ParseIP(e.IP) == nil {
glog.Errorf("Error parsing entry %v ip address %v for ipset %v", e, e.IP, set)
return false
}
if valid := validateProtocol(e.Protocol); !valid {
//check if IP and Protocol of Entry is valid.
if valid := e.checkIPandProtocol(set); !valid {
return false
}
case HashIPPortIP:
// set default protocol to tcp if empty
if len(e.Protocol) == 0 {
e.Protocol = ProtocolTCP
}
if net.ParseIP(e.IP) == nil {
glog.Errorf("Error parsing entry %v ip address %v for ipset %v", e, e.IP, set)
return false
}
if valid := validateProtocol(e.Protocol); !valid {
//check if IP and Protocol of Entry is valid.
if valid := e.checkIPandProtocol(set); !valid {
return false
}
@@ -184,23 +188,14 @@ func (e *Entry) Validate(set *IPSet) bool {
return false
}
case HashIPPortNet:
// set default protocol to tcp if empty
if len(e.Protocol) == 0 {
e.Protocol = ProtocolTCP
}
if net.ParseIP(e.IP) == nil {
glog.Errorf("Error parsing entry %v ip address %v for ipset %v", e, e.IP, set)
return false
}
if valid := validateProtocol(e.Protocol); !valid {
//check if IP and Protocol of Entry is valid.
if valid := e.checkIPandProtocol(set); !valid {
return false
}
// Net can not be empty for `hash:ip,port,net` type ip set
if _, ipNet, _ := net.ParseCIDR(e.Net); ipNet == nil {
glog.Errorf("Error parsing entry %v ip net %v for ipset %v", e, e.Net, set)
if _, ipNet, err := net.ParseCIDR(e.Net); ipNet == nil {
glog.Errorf("Error parsing entry %v ip net %v for ipset %v, error: %v", e, e.Net, set, err)
return false
}
case BitmapPort:
@@ -246,6 +241,23 @@ func (e *Entry) String() string {
return ""
}
// checkIPandProtocol checks if IP and Protocol of Entry is valid.
func (e *Entry) checkIPandProtocol(set *IPSet) bool {
// set default protocol to tcp if empty
if len(e.Protocol) == 0 {
e.Protocol = ProtocolTCP
} else if !validateProtocol(e.Protocol) {
return false
}
if net.ParseIP(e.IP) == nil {
glog.Errorf("Error parsing entry %v ip address %v for ipset %v", e, e.IP, set)
return false
}
return true
}
type runner struct {
exec utilexec.Interface
}
@@ -257,26 +269,10 @@ func New(exec utilexec.Interface) Interface {
}
}
// CreateSet creates a new set, it will ignore error when the set already exists if ignoreExistErr=true.
// CreateSet creates a new set, it will ignore error when the set already exists if ignoreExistErr=true.
func (runner *runner) CreateSet(set *IPSet, ignoreExistErr bool) error {
// Setting default values if not present
if set.HashSize == 0 {
set.HashSize = 1024
}
if set.MaxElem == 0 {
set.MaxElem = 65536
}
// Default protocol is IPv4
if set.HashFamily == "" {
set.HashFamily = ProtocolFamilyIPV4
}
// Default ipset type is "hash:ip,port"
if len(set.SetType) == 0 {
set.SetType = HashIPPort
}
if len(set.PortRange) == 0 {
set.PortRange = DefaultPortRange
}
// sets some IPSet fields if not present to their default values.
set.setIPSetDefaults()
// Validate ipset before creating
valid := set.Validate()
@@ -289,7 +285,7 @@ func (runner *runner) CreateSet(set *IPSet, ignoreExistErr bool) error {
// If ignoreExistErr is set to true, then the -exist option of ipset will be specified, ipset ignores the error
// otherwise raised when the same set (setname and create parameters are identical) already exists.
func (runner *runner) createSet(set *IPSet, ignoreExistErr bool) error {
args := []string{"create", set.Name, string(set.SetType), "comment"}
args := []string{"create", set.Name, string(set.SetType)}
if set.SetType == HashIPPortIP || set.SetType == HashIPPort {
args = append(args,
"family", set.HashFamily,
@@ -313,7 +309,7 @@ func (runner *runner) createSet(set *IPSet, ignoreExistErr bool) error {
// If the -exist option is specified, ipset ignores the error otherwise raised when
// the same set (setname and create parameters are identical) already exists.
func (runner *runner) AddEntry(entry string, set *IPSet, ignoreExistErr bool) error {
args := []string{"add", set.Name, entry, "comment", set.Comment}
args := []string{"add", set.Name, entry}
if ignoreExistErr {
args = append(args, "-exist")
}
@@ -325,7 +321,6 @@ func (runner *runner) AddEntry(entry string, set *IPSet, ignoreExistErr bool) er
// DelEntry is used to delete the specified entry from the set.
func (runner *runner) DelEntry(entry string, set string) error {
entry = strings.Split(entry, " comment")[0]
if _, err := runner.exec.Command(IPSetCmd, "del", set, entry).CombinedOutput(); err != nil {
return fmt.Errorf("error deleting entry %s: from set: %s, error: %v", entry, set, err)
}
@@ -487,10 +482,10 @@ func IsNotFoundError(err error) bool {
// checks if given protocol is supported in entry
func validateProtocol(protocol string) bool {
if protocol == ProtocolTCP || protocol == ProtocolUDP {
if protocol == ProtocolTCP || protocol == ProtocolUDP || protocol == ProtocolSCTP {
return true
}
glog.Errorf("Invalid entry's protocol: %s, supported protocols are [%s, %s]", protocol, ProtocolTCP, ProtocolUDP)
glog.Errorf("Invalid entry's protocol: %s, supported protocols are [%s, %s]", protocol, ProtocolTCP, ProtocolUDP, ProtocolSCTP)
return false
}

View File

@@ -346,6 +346,22 @@ var testCases = []struct {
},
delCombinedOutputLog: []string{"ipset", "del", "SIX", "80"},
},
{ // case 7
entry: &Entry{
IP: "192.168.1.2",
Port: 80,
Protocol: ProtocolSCTP,
SetType: HashIPPort,
},
set: &IPSet{
Name: "SETTE",
},
addCombinedOutputLog: [][]string{
{"ipset", "add", "SETTE", "192.168.1.2,sctp:80"},
{"ipset", "add", "SETTE", "192.168.1.2,sctp:80", "-exist"},
},
delCombinedOutputLog: []string{"ipset", "del", "SETTE", "192.168.1.2,sctp:80"},
},
}
func TestAddEntry(t *testing.T) {
@@ -755,6 +771,10 @@ func Test_validateFamily(t *testing.T) {
family: "",
valid: false,
},
{ // case[8]
family: "sctp",
valid: false,
},
}
for i := range testCases {
valid := validateHashFamily(testCases[i].family)
@@ -804,6 +824,10 @@ func Test_validateProtocol(t *testing.T) {
protocol: "",
valid: false,
},
{ // case[8]
protocol: ProtocolSCTP,
valid: true,
},
}
for i := range testCases {
valid := validateProtocol(testCases[i].protocol)
@@ -904,6 +928,150 @@ func TestValidateIPSet(t *testing.T) {
}
}
func Test_setIPSetDefaults(t *testing.T) {
testCases := []struct {
name string
set *IPSet
expect *IPSet
}{
{
name: "test all the IPSet fields not present",
set: &IPSet{
Name: "test1",
},
expect: &IPSet{
Name: "test1",
SetType: HashIPPort,
HashFamily: ProtocolFamilyIPV4,
HashSize: 1024,
MaxElem: 65536,
PortRange: DefaultPortRange,
},
},
{
name: "test all the IPSet fields present",
set: &IPSet{
Name: "test2",
SetType: BitmapPort,
HashFamily: ProtocolFamilyIPV6,
HashSize: 65535,
MaxElem: 2048,
PortRange: DefaultPortRange,
},
expect: &IPSet{
Name: "test2",
SetType: BitmapPort,
HashFamily: ProtocolFamilyIPV6,
HashSize: 65535,
MaxElem: 2048,
PortRange: DefaultPortRange,
},
},
{
name: "test part of the IPSet fields present",
set: &IPSet{
Name: "test3",
SetType: BitmapPort,
HashFamily: ProtocolFamilyIPV6,
HashSize: 65535,
},
expect: &IPSet{
Name: "test3",
SetType: BitmapPort,
HashFamily: ProtocolFamilyIPV6,
HashSize: 65535,
MaxElem: 65536,
PortRange: DefaultPortRange,
},
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
test.set.setIPSetDefaults()
if !reflect.DeepEqual(test.set, test.expect) {
t.Errorf("expected ipset struct: %v, got ipset struct: %v", test.expect, test.set)
}
})
}
}
func Test_checkIPandProtocol(t *testing.T) {
testset := &IPSet{
Name: "test1",
SetType: HashIPPort,
HashFamily: ProtocolFamilyIPV4,
HashSize: 1024,
MaxElem: 65536,
PortRange: DefaultPortRange,
}
testCases := []struct {
name string
entry *Entry
valid bool
}{
{
name: "valid IP with ProtocolTCP",
entry: &Entry{
SetType: HashIPPort,
IP: "1.2.3.4",
Protocol: ProtocolTCP,
Port: 8080,
},
valid: true,
},
{
name: "valid IP with ProtocolUDP",
entry: &Entry{
SetType: HashIPPort,
IP: "1.2.3.4",
Protocol: ProtocolUDP,
Port: 8080,
},
valid: true,
},
{
name: "valid IP with nil Protocol",
entry: &Entry{
SetType: HashIPPort,
IP: "1.2.3.4",
Port: 8080,
},
valid: true,
},
{
name: "valid IP with invalid Protocol",
entry: &Entry{
SetType: HashIPPort,
IP: "1.2.3.4",
Protocol: "invalidProtocol",
Port: 8080,
},
valid: false,
},
{
name: "invalid IP with ProtocolTCP",
entry: &Entry{
SetType: HashIPPort,
IP: "1.2.3.423",
Protocol: ProtocolTCP,
Port: 8080,
},
valid: false,
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
result := test.entry.checkIPandProtocol(testset)
if result != test.valid {
t.Errorf("expected valid: %v, got valid: %v", test.valid, result)
}
})
}
}
func Test_parsePortRange(t *testing.T) {
testCases := []struct {
portRange string
@@ -1257,16 +1425,16 @@ func TestValidateEntry(t *testing.T) {
},
{ // case[19]
entry: &Entry{
SetType: HashIPPortIP,
IP: "10.20.30.40",
Protocol: "SCTP ",
Port: 8090,
IP2: "10.20.30.41",
SetType: HashIPPortIP,
IP: "10.20.30.40",
Protocol: ProtocolSCTP,
Port: 8090,
IP2: "10.20.30.41",
},
set: &IPSet{
Name: "unsupported-protocol",
Name: "sctp",
},
valid: false,
valid: true,
},
{ // case[20]
entry: &Entry{
@@ -1408,3 +1576,72 @@ func TestValidateEntry(t *testing.T) {
}
}
}
func TestEntryString(t *testing.T) {
testCases := []struct {
name string
entry *Entry
expect string
}{
{
name: "test when SetType is HashIPPort",
entry: &Entry{
SetType: HashIPPort,
IP: "1.2.3.4",
Protocol: ProtocolTCP,
Port: 8080,
},
expect: "1.2.3.4,tcp:8080",
},
{
name: "test when SetType is HashIPPortIP",
entry: &Entry{
SetType: HashIPPortIP,
IP: "1.2.3.8",
Protocol: ProtocolUDP,
Port: 8081,
IP2: "1.2.3.8",
},
expect: "1.2.3.8,udp:8081,1.2.3.8",
},
{
name: "test when SetType is HashIPPortNet",
entry: &Entry{
SetType: HashIPPortNet,
IP: "192.168.1.2",
Protocol: ProtocolUDP,
Port: 80,
Net: "10.0.1.0/24",
},
expect: "192.168.1.2,udp:80,10.0.1.0/24",
},
{
name: "test when SetType is BitmapPort",
entry: &Entry{
SetType: BitmapPort,
Port: 80,
},
expect: "80",
},
{
name: "test when SetType is unknown",
entry: &Entry{
SetType: "unknown",
IP: "192.168.1.2",
Protocol: ProtocolUDP,
Port: 80,
Net: "10.0.1.0/24",
},
expect: "",
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
result := test.entry.String()
if result != test.expect {
t.Errorf("Unexpected mismatch, expected: %s, got: %s", test.expect, result)
}
})
}
}

View File

@@ -7,7 +7,7 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//pkg/util/ipset:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
],
)
@@ -31,6 +31,6 @@ go_test(
embed = [":go_default_library"],
deps = [
"//pkg/util/ipset:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
],
)

View File

@@ -49,6 +49,8 @@ const (
ProtocolTCP = "tcp"
// ProtocolUDP represents UDP protocol.
ProtocolUDP = "udp"
// ProtocolSCTP represents SCTP protocol.
ProtocolSCTP = "sctp"
)
// ValidIPSetTypes defines the supported ip set type.

View File

@@ -11,56 +11,24 @@ go_library(
srcs = [
"doc.go",
"iptables.go",
"iptables_linux.go",
"iptables_unsupported.go",
"save_restore.go",
] + select({
"@io_bazel_rules_go//go/platform:android": [
"iptables_unsupported.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"iptables_unsupported.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"iptables_unsupported.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"iptables_unsupported.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"iptables_linux.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"iptables_unsupported.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"iptables_unsupported.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"iptables_unsupported.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"iptables_unsupported.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"iptables_unsupported.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"iptables_unsupported.go",
],
"//conditions:default": [],
}),
],
importpath = "k8s.io/kubernetes/pkg/util/iptables",
deps = [
"//pkg/util/dbus:go_default_library",
"//pkg/util/version:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/trace:go_default_library",
"//vendor/github.com/godbus/dbus:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
] + select({
"@io_bazel_rules_go//go/platform:linux": [
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
],
"//conditions:default": [],
}),
@@ -68,17 +36,15 @@ go_library(
go_test(
name = "go_default_test",
srcs = select({
"@io_bazel_rules_go//go/platform:linux": [
"iptables_test.go",
],
"//conditions:default": [],
}),
srcs = [
"iptables_test.go",
"save_restore_test.go",
],
embed = [":go_default_library"],
deps = select({
"@io_bazel_rules_go//go/platform:linux": [
"//pkg/util/dbus:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
"//vendor/k8s.io/utils/exec/testing:go_default_library",
],

View File

@@ -28,6 +28,7 @@ import (
godbus "github.com/godbus/dbus"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/util/sets"
utiltrace "k8s.io/apiserver/pkg/util/trace"
utildbus "k8s.io/kubernetes/pkg/util/dbus"
utilversion "k8s.io/kubernetes/pkg/util/version"
utilexec "k8s.io/utils/exec"
@@ -137,6 +138,7 @@ type runner struct {
dbus utildbus.Interface
protocol Protocol
hasCheck bool
hasListener bool
waitFlag []string
restoreWaitFlag []string
lockfilePath string
@@ -163,13 +165,11 @@ func newInternal(exec utilexec.Interface, dbus utildbus.Interface, protocol Prot
dbus: dbus,
protocol: protocol,
hasCheck: getIPTablesHasCheckCommand(vstring),
hasListener: false,
waitFlag: getIPTablesWaitFlag(vstring),
restoreWaitFlag: getIPTablesRestoreWaitFlag(exec, protocol),
lockfilePath: lockfilePath,
}
// TODO this needs to be moved to a separate Start() or Run() function so that New() has zero side
// effects.
runner.connectToFirewallD()
return runner
}
@@ -200,6 +200,7 @@ func (runner *runner) connectToFirewallD() {
glog.V(1).Infof("Could not connect to D-Bus system bus: %s", err)
return
}
runner.hasListener = true
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)
@@ -317,6 +318,9 @@ func (runner *runner) SaveInto(table Table, buffer *bytes.Buffer) error {
runner.mu.Lock()
defer runner.mu.Unlock()
trace := utiltrace.New("iptables save")
defer trace.LogIfLong(2 * time.Second)
// run and return
iptablesSaveCmd := iptablesSaveCommand(runner.protocol)
args := []string{"-t", string(table)}
@@ -355,6 +359,9 @@ func (runner *runner) restoreInternal(args []string, data []byte, flush FlushFla
runner.mu.Lock()
defer runner.mu.Unlock()
trace := utiltrace.New("iptables restore")
defer trace.LogIfLong(2 * time.Second)
if !flush {
args = append(args, "--noflush")
}
@@ -370,6 +377,7 @@ func (runner *runner) restoreInternal(args []string, data []byte, flush FlushFla
if err != nil {
return err
}
trace.Step("Locks grabbed")
defer func(locker iptablesLocker) {
if err := locker.Close(); err != nil {
glog.Errorf("Failed to close iptables locks: %v", err)
@@ -669,6 +677,15 @@ func (runner *runner) dbusSignalHandler(bus utildbus.Connection) {
// AddReloadFunc is part of Interface
func (runner *runner) AddReloadFunc(reloadFunc func()) {
runner.mu.Lock()
defer runner.mu.Unlock()
// We only need to listen to firewalld if there are Reload functions, so lazy
// initialize the listener.
if !runner.hasListener {
runner.connectToFirewallD()
}
runner.reloadFuncs = append(runner.reloadFuncs, reloadFunc)
}

View File

@@ -17,8 +17,13 @@ limitations under the License.
package iptables
import (
"bytes"
"fmt"
"strings"
)
var (
commitBytes = []byte("COMMIT")
spaceBytes = []byte(" ")
)
// MakeChainLine return an iptables-save/restore formatted chain line given a Chain
@@ -27,41 +32,43 @@ func MakeChainLine(chain Chain) string {
}
// 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)
// It returns a map of iptables.Chain to []byte where the []byte is the chain line
// from save (with counters etc.).
// Note that to avoid allocations memory is SHARED with save.
func GetChainLines(table Table, save []byte) map[Chain][]byte {
chainsMap := make(map[Chain][]byte)
tablePrefix := []byte("*" + string(table))
readIndex := 0
// find beginning of table
for readIndex < len(save) {
line, n := ReadLine(readIndex, save)
line, n := readLine(readIndex, save)
readIndex = n
if strings.HasPrefix(line, tablePrefix) {
if bytes.HasPrefix(line, tablePrefix) {
break
}
}
// parse table lines
for readIndex < len(save) {
line, n := ReadLine(readIndex, save)
line, n := readLine(readIndex, save)
readIndex = n
if len(line) == 0 {
continue
}
if strings.HasPrefix(line, "COMMIT") || strings.HasPrefix(line, "*") {
if bytes.HasPrefix(line, commitBytes) || line[0] == '*' {
break
} else if strings.HasPrefix(line, "#") {
} else if line[0] == '#' {
continue
} else if strings.HasPrefix(line, ":") && len(line) > 1 {
} else if line[0] == ':' && len(line) > 1 {
// We assume that the <line> contains space - chain lines have 3 fields,
// space delimited. If there is no space, this line will panic.
chain := Chain(line[1:strings.Index(line, " ")])
chain := Chain(line[1:bytes.Index(line, spaceBytes)])
chainsMap[chain] = line
}
}
return chainsMap
}
func ReadLine(readIndex int, byteArray []byte) (string, int) {
func readLine(readIndex int, byteArray []byte) ([]byte, int) {
currentReadIndex := readIndex
// consume left spaces
@@ -89,7 +96,7 @@ func ReadLine(readIndex int, byteArray []byte) (string, int) {
} else if (byteArray[currentReadIndex] == '\n') || (currentReadIndex == (len(byteArray) - 1)) {
// end of line or byte buffer is reached
if currentReadIndex <= leftTrimIndex {
return "", currentReadIndex + 1
return nil, currentReadIndex + 1
}
// set the rightTrimIndex
if rightTrimIndex == -1 {
@@ -100,11 +107,12 @@ func ReadLine(readIndex int, byteArray []byte) (string, int) {
rightTrimIndex = currentReadIndex + 1
}
}
return string(byteArray[leftTrimIndex:rightTrimIndex]), currentReadIndex + 1
// Avoid unnecessary allocation.
return byteArray[leftTrimIndex:rightTrimIndex], currentReadIndex + 1
} else {
// unset rightTrimIndex
rightTrimIndex = -1
}
}
return "", currentReadIndex
return nil, currentReadIndex
}

View File

@@ -0,0 +1,53 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package iptables
import (
"testing"
)
func TestReadLinesFromByteBuffer(t *testing.T) {
testFn := func(byteArray []byte, expected []string) {
index := 0
readIndex := 0
for ; readIndex < len(byteArray); index++ {
line, n := readLine(readIndex, byteArray)
readIndex = n
if expected[index] != string(line) {
t.Errorf("expected:%q, actual:%q", expected[index], line)
}
} // for
if readIndex < len(byteArray) {
t.Errorf("Byte buffer was only partially read. Buffer length is:%d, readIndex is:%d", len(byteArray), readIndex)
}
if index < len(expected) {
t.Errorf("All expected strings were not compared. expected arr length:%d, matched count:%d", len(expected), index-1)
}
}
byteArray1 := []byte("\n Line 1 \n\n\n L ine4 \nLine 5 \n \n")
expected1 := []string{"", "Line 1", "", "", "L ine4", "Line 5", ""}
testFn(byteArray1, expected1)
byteArray1 = []byte("")
expected1 = []string{}
testFn(byteArray1, expected1)
byteArray1 = []byte("\n\n")
expected1 = []string{"", ""}
testFn(byteArray1, expected1)
}

View File

@@ -9,14 +9,10 @@ load(
go_test(
name = "go_default_test",
srcs = [
"ipvs_linux_test.go",
"ipvs_test.go",
] + select({
"@io_bazel_rules_go//go/platform:linux": [
"ipvs_linux_test.go",
"kernelcheck_linux_test.go",
],
"//conditions:default": [],
}),
"kernelcheck_linux_test.go",
],
embed = [":go_default_library"],
deps = select({
"@io_bazel_rules_go//go/platform:linux": [
@@ -32,53 +28,11 @@ go_library(
name = "go_default_library",
srcs = [
"ipvs.go",
] + select({
"@io_bazel_rules_go//go/platform:android": [
"ipvs_unsupported.go",
"kernelcheck_unsupported.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"ipvs_unsupported.go",
"kernelcheck_unsupported.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"ipvs_unsupported.go",
"kernelcheck_unsupported.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"ipvs_unsupported.go",
"kernelcheck_unsupported.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"ipvs_linux.go",
"kernelcheck_linux.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"ipvs_unsupported.go",
"kernelcheck_unsupported.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"ipvs_unsupported.go",
"kernelcheck_unsupported.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"ipvs_unsupported.go",
"kernelcheck_unsupported.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"ipvs_unsupported.go",
"kernelcheck_unsupported.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"ipvs_unsupported.go",
"kernelcheck_unsupported.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"ipvs_unsupported.go",
"kernelcheck_unsupported.go",
],
"//conditions:default": [],
}),
"ipvs_linux.go",
"ipvs_unsupported.go",
"kernelcheck_linux.go",
"kernelcheck_unsupported.go",
],
importpath = "k8s.io/kubernetes/pkg/util/ipvs",
deps = select({
"@io_bazel_rules_go//go/platform:android": [
@@ -94,9 +48,9 @@ go_library(
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:linux": [
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/github.com/docker/libnetwork/ipvs:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:nacl": [

View File

@@ -41,6 +41,8 @@ type Interface interface {
GetRealServers(*VirtualServer) ([]*RealServer, error)
// DeleteRealServer deletes the specified real server from the specified virtual server.
DeleteRealServer(*VirtualServer, *RealServer) error
// UpdateRealServer updates the specified real server from the specified virtual server.
UpdateRealServer(*VirtualServer, *RealServer) error
}
// VirtualServer is an user-oriented definition of an IPVS virtual server in its entirety.
@@ -91,9 +93,11 @@ func (svc *VirtualServer) String() string {
// RealServer is an user-oriented definition of an IPVS real server in its entirety.
type RealServer struct {
Address net.IP
Port uint16
Weight int
Address net.IP
Port uint16
Weight int
ActiveConn int
InactiveConn int
}
func (rs *RealServer) String() string {
@@ -104,6 +108,5 @@ func (rs *RealServer) String() string {
// We don't use struct == since it doesn't work because of slice.
func (rs *RealServer) Equal(other *RealServer) bool {
return rs.Address.Equal(other.Address) &&
rs.Port == other.Port &&
rs.Weight == other.Weight
rs.Port == other.Port
}

View File

@@ -144,6 +144,18 @@ func (runner *runner) DeleteRealServer(vs *VirtualServer, rs *RealServer) error
return runner.ipvsHandle.DelDestination(svc, dst)
}
func (runner *runner) UpdateRealServer(vs *VirtualServer, rs *RealServer) error {
svc, err := toIPVSService(vs)
if err != nil {
return err
}
dst, err := toIPVSDestination(rs)
if err != nil {
return err
}
return runner.ipvsHandle.UpdateDestination(svc, dst)
}
// GetRealServers is part of ipvs.Interface.
func (runner *runner) GetRealServers(vs *VirtualServer) ([]*RealServer, error) {
svc, err := toIPVSService(vs)
@@ -203,9 +215,11 @@ func toRealServer(dst *libipvs.Destination) (*RealServer, error) {
return nil, errors.New("ipvs destination should not be empty")
}
return &RealServer{
Address: dst.Address,
Port: dst.Port,
Weight: dst.Weight,
Address: dst.Address,
Port: dst.Port,
Weight: dst.Weight,
ActiveConn: dst.ActiveConnections,
InactiveConn: dst.InactiveConnections,
}, nil
}
@@ -252,6 +266,8 @@ func stringToProtocol(protocol string) uint16 {
return uint16(syscall.IPPROTO_TCP)
case "udp":
return uint16(syscall.IPPROTO_UDP)
case "sctp":
return uint16(syscall.IPPROTO_SCTP)
}
return uint16(0)
}
@@ -263,6 +279,8 @@ func protocolToString(proto Protocol) string {
return "TCP"
case syscall.IPPROTO_UDP:
return "UDP"
case syscall.IPPROTO_SCTP:
return "SCTP"
}
return ""
}

View File

@@ -147,6 +147,30 @@ func Test_toVirtualServer(t *testing.T) {
false,
"",
},
{
libipvs.Service{
Protocol: syscall.IPPROTO_SCTP,
Port: 80,
FWMark: 0,
SchedName: "",
Flags: uint32(FlagPersistent + FlagHashed),
Timeout: 0,
Netmask: 0xffffffff,
AddressFamily: syscall.AF_INET,
Address: nil,
PEName: "",
},
VirtualServer{
Address: net.ParseIP("0.0.0.0"),
Protocol: "SCTP",
Port: 80,
Scheduler: "",
Flags: ServiceFlags(FlagPersistent),
Timeout: 0,
},
false,
"",
},
}
for i := range Tests {
@@ -359,10 +383,10 @@ func Test_toIPVSDestination(t *testing.T) {
func Test_stringToProtocol(t *testing.T) {
tests := []string{
"TCP", "UDP", "ICMP",
"TCP", "UDP", "ICMP", "SCTP",
}
expected := []uint16{
uint16(syscall.IPPROTO_TCP), uint16(syscall.IPPROTO_UDP), uint16(0),
uint16(syscall.IPPROTO_TCP), uint16(syscall.IPPROTO_UDP), uint16(0), uint16(syscall.IPPROTO_SCTP),
}
for i := range tests {
got := stringToProtocol(tests[i])
@@ -375,10 +399,10 @@ func Test_stringToProtocol(t *testing.T) {
func Test_protocolToString(t *testing.T) {
tests := []Protocol{
syscall.IPPROTO_TCP, syscall.IPPROTO_UDP, Protocol(0),
syscall.IPPROTO_TCP, syscall.IPPROTO_UDP, Protocol(0), syscall.IPPROTO_SCTP,
}
expected := []string{
"TCP", "UDP", "",
"TCP", "UDP", "", "SCTP",
}
for i := range tests {
got := protocolToString(tests[i])

View File

@@ -188,6 +188,46 @@ func TestVirtualServerEqual(t *testing.T) {
equal: true,
reason: "All fields equal",
},
{
svcA: &VirtualServer{
Address: net.ParseIP("2012::beef"),
Protocol: "TCP",
Port: 0,
Scheduler: "wrr",
Flags: 0,
Timeout: 0,
},
svcB: &VirtualServer{
Address: net.ParseIP("2012::beeef"),
Protocol: "SCTP",
Port: 0,
Scheduler: "wrr",
Flags: 0,
Timeout: 0,
},
equal: false,
reason: "Protocol not equal",
},
{
svcA: &VirtualServer{
Address: net.ParseIP("1.2.3.4"),
Protocol: "SCTP",
Port: 80,
Scheduler: "rr",
Flags: 0x1,
Timeout: 10800,
},
svcB: &VirtualServer{
Address: net.ParseIP("1.2.3.4"),
Protocol: "SCTP",
Port: 80,
Scheduler: "rr",
Flags: 0x1,
Timeout: 10800,
},
equal: true,
reason: "All fields equal",
},
}
for i := range Tests {
@@ -209,12 +249,10 @@ func TestRealServerEqual(t *testing.T) {
rsA: &RealServer{
Address: net.ParseIP("10.20.30.40"),
Port: 80,
Weight: 1,
},
rsB: &RealServer{
Address: net.ParseIP("10.20.30.41"),
Port: 80,
Weight: 1,
},
equal: false,
reason: "IPv4 address not equal",
@@ -223,12 +261,10 @@ func TestRealServerEqual(t *testing.T) {
rsA: &RealServer{
Address: net.ParseIP("2012::beef"),
Port: 80,
Weight: 1,
},
rsB: &RealServer{
Address: net.ParseIP("2017::beef"),
Port: 80,
Weight: 1,
},
equal: false,
reason: "IPv6 address not equal",
@@ -237,40 +273,22 @@ func TestRealServerEqual(t *testing.T) {
rsA: &RealServer{
Address: net.ParseIP("2012::beef"),
Port: 80,
Weight: 1,
},
rsB: &RealServer{
Address: net.ParseIP("2012::beef"),
Port: 8080,
Weight: 1,
},
equal: false,
reason: "Port not equal",
},
{
rsA: &RealServer{
Address: net.ParseIP("10.20.30.40"),
Port: 8080,
Weight: 1,
},
rsB: &RealServer{
Address: net.ParseIP("10.20.30.40"),
Port: 8080,
Weight: 10,
},
equal: false,
reason: "Weight not equal",
},
{
rsA: &RealServer{
Address: net.ParseIP("1.2.3.4"),
Port: 3080,
Weight: 10,
},
rsB: &RealServer{
Address: net.ParseIP("1.2.3.4"),
Port: 3080,
Weight: 10,
},
equal: true,
reason: "All fields equal",
@@ -279,12 +297,10 @@ func TestRealServerEqual(t *testing.T) {
rsA: &RealServer{
Address: net.ParseIP("2012::beef"),
Port: 3080,
Weight: 10,
},
rsB: &RealServer{
Address: net.ParseIP("2012::beef"),
Port: 3080,
Weight: 10,
},
equal: true,
reason: "All fields equal",

View File

@@ -68,4 +68,8 @@ func (runner *runner) DeleteRealServer(*VirtualServer, *RealServer) error {
return fmt.Errorf("IPVS not supported for this platform")
}
func (runner *runner) UpdateRealServer(*VirtualServer, *RealServer) error {
return fmt.Errorf("IPVS not supported for this platform")
}
var _ = Interface(&runner{})

View File

@@ -193,4 +193,13 @@ func (f *FakeIPVS) DeleteRealServer(serv *utilipvs.VirtualServer, dest *utilipvs
return nil
}
// UpdateRealServer is a fake implementation, it deletes the old real server then add new real server
func (f *FakeIPVS) UpdateRealServer(serv *utilipvs.VirtualServer, dest *utilipvs.RealServer) error {
err := f.DeleteRealServer(serv, dest)
if err != nil {
return err
}
return f.AddRealServer(serv, dest)
}
var _ = utilipvs.Interface(&FakeIPVS{})

View File

@@ -71,12 +71,22 @@ func TestVirtualServer(t *testing.T) {
if err != nil {
t.Errorf("Unexpected error when add virtual server, error: %v", err)
}
// Add another virtual server
vs3 := &utilipvs.VirtualServer{
Address: net.ParseIP("10::40"),
Port: uint16(7777),
Protocol: string("SCTP"),
}
err = fake.AddVirtualServer(vs3)
if err != nil {
t.Errorf("Unexpected error when add virtual server, error: %v", err)
}
// List all virtual servers
list, err := fake.GetVirtualServers()
if err != nil {
t.Errorf("Fail to list virtual servers, error: %v", err)
}
if len(list) != 2 {
if len(list) != 3 {
t.Errorf("Expect 2 virtual servers, got: %d", len(list))
}
// Delete a virtual server
@@ -114,9 +124,9 @@ func TestRealServer(t *testing.T) {
Protocol: string("TCP"),
}
rss := []*utilipvs.RealServer{
{net.ParseIP("172.16.2.1"), 8080, 1},
{net.ParseIP("172.16.2.2"), 8080, 2},
{net.ParseIP("172.16.2.3"), 8080, 3},
{Address: net.ParseIP("172.16.2.1"), Port: 8080, Weight: 1},
{Address: net.ParseIP("172.16.2.2"), Port: 8080, Weight: 2},
{Address: net.ParseIP("172.16.2.3"), Port: 8080, Weight: 3},
}
err := fake.AddVirtualServer(vs)
if err != nil {

View File

@@ -8,7 +8,10 @@ load(
go_library(
name = "go_default_library",
srcs = ["keymutex.go"],
srcs = [
"hashed.go",
"keymutex.go",
],
importpath = "k8s.io/kubernetes/pkg/util/keymutex",
deps = ["//vendor/github.com/golang/glog:go_default_library"],
)

64
vendor/k8s.io/kubernetes/pkg/util/keymutex/hashed.go generated vendored Normal file
View File

@@ -0,0 +1,64 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package keymutex
import (
"hash/fnv"
"runtime"
"sync"
"github.com/golang/glog"
)
// NewHashed returns a new instance of KeyMutex which hashes arbitrary keys to
// a fixed set of locks. `n` specifies number of locks, if n <= 0, we use
// number of cpus.
// Note that because it uses fixed set of locks, different keys may share same
// lock, so it's possible to wait on same lock.
func NewHashed(n int) KeyMutex {
if n <= 0 {
n = runtime.NumCPU()
}
return &hashedKeyMutex{
mutexes: make([]sync.Mutex, n),
}
}
type hashedKeyMutex struct {
mutexes []sync.Mutex
}
// Acquires a lock associated with the specified ID.
func (km *hashedKeyMutex) LockKey(id string) {
glog.V(5).Infof("hashedKeyMutex.LockKey(...) called for id %q\r\n", id)
km.mutexes[km.hash(id)%len(km.mutexes)].Lock()
glog.V(5).Infof("hashedKeyMutex.LockKey(...) for id %q completed.\r\n", id)
}
// Releases the lock associated with the specified ID.
func (km *hashedKeyMutex) UnlockKey(id string) error {
glog.V(5).Infof("hashedKeyMutex.UnlockKey(...) called for id %q\r\n", id)
km.mutexes[km.hash(id)%len(km.mutexes)].Unlock()
glog.V(5).Infof("hashedKeyMutex.UnlockKey(...) for id %q completed.\r\n", id)
return nil
}
func (km *hashedKeyMutex) hash(id string) int {
h := fnv.New32a()
h.Write([]byte(id))
return int(h.Sum32())
}

View File

@@ -16,13 +16,6 @@ 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.
@@ -32,52 +25,3 @@ type KeyMutex interface {
// 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]
}

View File

@@ -25,46 +25,58 @@ const (
callbackTimeout = 1 * time.Second
)
func newKeyMutexes() []KeyMutex {
return []KeyMutex{
NewHashed(0),
NewHashed(1),
NewHashed(2),
NewHashed(4),
}
}
func Test_SingleLock_NoUnlock(t *testing.T) {
// Arrange
km := NewKeyMutex()
key := "fakeid"
callbackCh := make(chan interface{})
for _, km := range newKeyMutexes() {
// Arrange
key := "fakeid"
callbackCh := make(chan interface{})
// Act
go lockAndCallback(km, key, callbackCh)
// Act
go lockAndCallback(km, key, callbackCh)
// Assert
verifyCallbackHappens(t, callbackCh)
// Assert
verifyCallbackHappens(t, callbackCh)
}
}
func Test_SingleLock_SingleUnlock(t *testing.T) {
// Arrange
km := NewKeyMutex()
key := "fakeid"
callbackCh := make(chan interface{})
for _, km := range newKeyMutexes() {
// Arrange
key := "fakeid"
callbackCh := make(chan interface{})
// Act & Assert
go lockAndCallback(km, key, callbackCh)
verifyCallbackHappens(t, callbackCh)
km.UnlockKey(key)
// 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{})
for _, km := range newKeyMutexes() {
// Arrange
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)
// 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{}) {

View File

@@ -13,14 +13,14 @@ go_library(
"labels.go",
],
importpath = "k8s.io/kubernetes/pkg/util/labels",
deps = ["//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library"],
deps = ["//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library"],
)
go_test(
name = "go_default_test",
srcs = ["labels_test.go"],
embed = [":go_default_library"],
deps = ["//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library"],
deps = ["//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library"],
)
filegroup(

View File

@@ -11,9 +11,8 @@ go_library(
srcs = ["util.go"],
importpath = "k8s.io/kubernetes/pkg/util/metrics",
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
"//vendor/k8s.io/client-go/util/flowcontrol:go_default_library",
],
)
@@ -22,7 +21,7 @@ go_test(
srcs = ["util_test.go"],
embed = [":go_default_library"],
deps = [
"//vendor/k8s.io/client-go/util/flowcontrol:go_default_library",
"//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library",
],
)

View File

@@ -19,21 +19,15 @@ package metrics
import (
"fmt"
"sync"
"time"
"k8s.io/client-go/util/flowcontrol"
"github.com/golang/glog"
"github.com/prometheus/client_golang/prometheus"
)
const (
updatePeriod = 5 * time.Second
)
var (
metricsLock sync.Mutex
rateLimiterMetrics = make(map[string]rateLimiterMetric)
rateLimiterMetrics = make(map[string]*rateLimiterMetric)
)
type rateLimiterMetric struct {
@@ -46,7 +40,8 @@ func registerRateLimiterMetric(ownerName string) error {
defer metricsLock.Unlock()
if _, ok := rateLimiterMetrics[ownerName]; ok {
return fmt.Errorf("Rate Limiter Metric for %v already registered", ownerName)
// only register once in Prometheus. We happen to see an ownerName reused in parallel integration tests.
return nil
}
metric := prometheus.NewGauge(prometheus.GaugeOpts{
Name: "rate_limiter_use",
@@ -57,7 +52,7 @@ func registerRateLimiterMetric(ownerName string) error {
return fmt.Errorf("error registering rate limiter usage metric: %v", err)
}
stopCh := make(chan struct{})
rateLimiterMetrics[ownerName] = rateLimiterMetric{
rateLimiterMetrics[ownerName] = &rateLimiterMetric{
metric: metric,
stopCh: stopCh,
}
@@ -79,22 +74,3 @@ func RegisterMetricAndTrackRateLimiterUsage(ownerName string, rateLimiter flowco
// }, updatePeriod, rateLimiterMetrics[ownerName].stopCh)
return nil
}
// UnregisterMetricAndUntrackRateLimiterUsage unregisters a metric ownerName_rate_limiter_use from prometheus and
// stops the goroutine that updates this metric
func UnregisterMetricAndUntrackRateLimiterUsage(ownerName string) bool {
metricsLock.Lock()
defer metricsLock.Unlock()
rlm, ok := rateLimiterMetrics[ownerName]
if !ok {
glog.Warningf("Rate Limiter Metric for %v not registered", ownerName)
return false
}
close(rlm.stopCh)
prometheus.Unregister(rlm.metric)
delete(rateLimiterMetrics, ownerName)
return true
}

View File

@@ -57,27 +57,3 @@ func TestRegisterMetricAndTrackRateLimiterUsage(t *testing.T) {
}
}
}
func TestUnregisterMetricAndUntrackRateLimiterUsage(t *testing.T) {
RegisterMetricAndTrackRateLimiterUsage("owner_name", flowcontrol.NewTokenBucketRateLimiter(1, 1))
testCases := []struct {
ownerName string
ok bool
}{
{
ownerName: "owner_name",
ok: true,
},
{
ownerName: "owner_name",
ok: false,
},
}
for i, tc := range testCases {
ok := UnregisterMetricAndUntrackRateLimiterUsage(tc.ownerName)
if tc.ok != ok {
t.Errorf("Case[%d] Expected %v, got %v", i, tc.ok, ok)
}
}
}

View File

@@ -5,66 +5,16 @@ go_library(
srcs = [
"doc.go",
"exec.go",
"exec_mount.go",
"exec_mount_unsupported.go",
"fake.go",
"mount.go",
] + select({
"@io_bazel_rules_go//go/platform:android": [
"exec_mount_unsupported.go",
"mount_unsupported.go",
"nsenter_mount_unsupported.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"exec_mount_unsupported.go",
"mount_unsupported.go",
"nsenter_mount_unsupported.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"exec_mount_unsupported.go",
"mount_unsupported.go",
"nsenter_mount_unsupported.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"exec_mount_unsupported.go",
"mount_unsupported.go",
"nsenter_mount_unsupported.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"exec_mount.go",
"mount_linux.go",
"nsenter_mount.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"exec_mount_unsupported.go",
"mount_unsupported.go",
"nsenter_mount_unsupported.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"exec_mount_unsupported.go",
"mount_unsupported.go",
"nsenter_mount_unsupported.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"exec_mount_unsupported.go",
"mount_unsupported.go",
"nsenter_mount_unsupported.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"exec_mount_unsupported.go",
"mount_unsupported.go",
"nsenter_mount_unsupported.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"exec_mount_unsupported.go",
"mount_unsupported.go",
"nsenter_mount_unsupported.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"exec_mount_unsupported.go",
"mount_windows.go",
"nsenter_mount_unsupported.go",
],
"//conditions:default": [],
}),
"mount_linux.go",
"mount_unsupported.go",
"mount_windows.go",
"nsenter_mount.go",
"nsenter_mount_unsupported.go",
],
importpath = "k8s.io/kubernetes/pkg/util/mount",
visibility = ["//visibility:public"],
deps = [
@@ -87,8 +37,8 @@ go_library(
"//pkg/util/file:go_default_library",
"//pkg/util/io:go_default_library",
"//pkg/util/nsenter:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
],
"@io_bazel_rules_go//go/platform:nacl": [
"//pkg/util/nsenter:go_default_library",
@@ -116,18 +66,12 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"exec_mount_test.go",
"mount_linux_test.go",
"mount_windows_test.go",
"nsenter_mount_test.go",
"safe_format_and_mount_test.go",
] + select({
"@io_bazel_rules_go//go/platform:linux": [
"exec_mount_test.go",
"mount_linux_test.go",
"nsenter_mount_test.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"mount_windows_test.go",
],
"//conditions:default": [],
}),
],
embed = [":go_default_library"],
deps = [
"//vendor/k8s.io/utils/exec/testing:go_default_library",

View File

@@ -140,6 +140,10 @@ func (m *execMounter) ExistsPath(pathname string) (bool, error) {
return m.wrappedMounter.ExistsPath(pathname)
}
func (m *execMounter) EvalHostSymlinks(pathname string) (string, error) {
return m.wrappedMounter.EvalHostSymlinks(pathname)
}
func (m *execMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) {
return m.wrappedMounter.PrepareSafeSubpath(subPath)
}

View File

@@ -19,9 +19,7 @@ limitations under the License.
package mount
import (
"errors"
"fmt"
"os"
"reflect"
"strings"
"testing"
@@ -47,7 +45,7 @@ func TestMount(t *testing.T) {
return nil, nil
})
wrappedMounter := &fakeMounter{t}
wrappedMounter := &fakeMounter{FakeMounter: &FakeMounter{}, t: t}
mounter := NewExecMounter(exec, wrappedMounter)
mounter.Mount(sourcePath, destinationPath, fsType, mountOptions)
@@ -75,7 +73,7 @@ func TestBindMount(t *testing.T) {
return nil, nil
})
wrappedMounter := &fakeMounter{t}
wrappedMounter := &fakeMounter{FakeMounter: &FakeMounter{}, t: t}
mounter := NewExecMounter(exec, wrappedMounter)
bindOptions := append(mountOptions, "bind")
mounter.Mount(sourcePath, destinationPath, fsType, bindOptions)
@@ -94,7 +92,7 @@ func TestUnmount(t *testing.T) {
return nil, nil
})
wrappedMounter := &fakeMounter{t}
wrappedMounter := &fakeMounter{&FakeMounter{}, t}
mounter := NewExecMounter(exec, wrappedMounter)
mounter.Unmount(destinationPath)
@@ -102,6 +100,7 @@ func TestUnmount(t *testing.T) {
/* Fake wrapped mounter */
type fakeMounter struct {
*FakeMounter
t *testing.T
}
@@ -116,67 +115,3 @@ func (fm *fakeMounter) Unmount(target string) error {
fm.t.Errorf("Unexpected wrapped mount call")
return fmt.Errorf("Unexpected wrapped mount call")
}
func (fm *fakeMounter) List() ([]MountPoint, error) {
return nil, nil
}
func (fm *fakeMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
return false
}
func (fm *fakeMounter) IsNotMountPoint(file string) (bool, error) {
return false, nil
}
func (fm *fakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
return false, nil
}
func (fm *fakeMounter) DeviceOpened(pathname string) (bool, error) {
return false, nil
}
func (fm *fakeMounter) PathIsDevice(pathname string) (bool, error) {
return false, nil
}
func (fm *fakeMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
return "", nil
}
func (fm *fakeMounter) MakeRShared(path string) error {
return nil
}
func (fm *fakeMounter) MakeFile(pathname string) error {
return nil
}
func (fm *fakeMounter) MakeDir(pathname string) error {
return nil
}
func (fm *fakeMounter) ExistsPath(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
func (fm *fakeMounter) GetFileType(pathname string) (FileType, error) {
return FileTypeFile, nil
}
func (fm *fakeMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) {
return subPath.Path, nil, nil
}
func (fm *fakeMounter) CleanSubPaths(podDir string, volumeName string) error {
return nil
}
func (fm *fakeMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
return nil
}
func (fm *fakeMounter) GetMountRefs(pathname string) ([]string, error) {
return nil, errors.New("not implemented")
}
func (fm *fakeMounter) GetFSGroup(pathname string) (int64, error) {
return -1, errors.New("not implemented")
}
func (fm *fakeMounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
func (fm *fakeMounter) GetMode(pathname string) (os.FileMode, error) {
return 0, errors.New("not implemented")
}

View File

@@ -87,6 +87,10 @@ func (mounter *execMounter) ExistsPath(pathname string) (bool, error) {
return true, errors.New("not implemented")
}
func (m *execMounter) EvalHostSymlinks(pathname string) (string, error) {
return "", errors.New("not implemented")
}
func (mounter *execMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) {
return subPath.Path, nil, nil
}

View File

@@ -29,6 +29,7 @@ import (
type FakeMounter struct {
MountPoints []MountPoint
Log []FakeAction
Filesystem map[string]FileType
// Some tests run things in parallel, make sure the mounter does not produce
// any golang's DATA RACE warnings.
mutex sync.Mutex
@@ -190,7 +191,10 @@ func (f *FakeMounter) MakeRShared(path string) error {
}
func (f *FakeMounter) GetFileType(pathname string) (FileType, error) {
return FileType("fake"), nil
if t, ok := f.Filesystem[pathname]; ok {
return t, nil
}
return FileType("Directory"), nil
}
func (f *FakeMounter) MakeDir(pathname string) error {
@@ -202,7 +206,14 @@ func (f *FakeMounter) MakeFile(pathname string) error {
}
func (f *FakeMounter) ExistsPath(pathname string) (bool, error) {
return false, errors.New("not implemented")
if _, ok := f.Filesystem[pathname]; ok {
return true, nil
}
return false, nil
}
func (f *FakeMounter) EvalHostSymlinks(pathname string) (string, error) {
return pathname, nil
}
func (f *FakeMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) {

View File

@@ -96,6 +96,9 @@ type Interface interface {
// Will operate in the host mount namespace if kubelet is running in a container.
// Error is returned on any other error than "file not found".
ExistsPath(pathname string) (bool, error)
// EvalHostSymlinks returns the path name after evaluating symlinks.
// Will operate in the host mount namespace if kubelet is running in a container.
EvalHostSymlinks(pathname string) (string, error)
// CleanSubPaths removes any bind-mounts created by PrepareSafeSubpath in given
// pod volume directory.
CleanSubPaths(podDir string, volumeName string) error
@@ -328,8 +331,8 @@ func HasMountRefs(mountPath string, mountRefs []string) bool {
return count > 0
}
// pathWithinBase checks if give path is within given base directory.
func pathWithinBase(fullPath, basePath string) bool {
// PathWithinBase checks if give path is within given base directory.
func PathWithinBase(fullPath, basePath string) bool {
rel, err := filepath.Rel(basePath, fullPath)
if err != nil {
return false

View File

@@ -155,41 +155,6 @@ func (m *Mounter) doMount(mounterPath string, mountCmd string, source string, ta
return err
}
// GetMountRefs finds all other references to the device referenced
// by mountPath; returns a list of paths.
func GetMountRefs(mounter Interface, mountPath string) ([]string, error) {
mps, err := mounter.List()
if err != nil {
return nil, err
}
// Find the device name.
deviceName := ""
// If mountPath is symlink, need get its target path.
slTarget, err := filepath.EvalSymlinks(mountPath)
if err != nil {
slTarget = mountPath
}
for i := range mps {
if mps[i].Path == slTarget {
deviceName = mps[i].Device
break
}
}
// Find all references to the device.
var refs []string
if deviceName == "" {
glog.Warningf("could not determine device for path: %q", mountPath)
} else {
for i := range mps {
if mps[i].Device == deviceName && mps[i].Path != slTarget {
refs = append(refs, mps[i].Path)
}
}
}
return refs, nil
}
// detectSystemd returns true if OS runs with systemd as init. When not sure
// (permission errors, ...), it returns false.
// There may be different ways how to detect systemd, this one makes sure that
@@ -352,7 +317,7 @@ func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginDir string) (str
// the mount path reference should match the given plugin directory. In case no mount path reference
// matches, returns the volume name taken from its given mountPath
func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (string, error) {
refs, err := GetMountRefs(mounter, mountPath)
refs, err := mounter.GetMountRefs(mountPath)
if err != nil {
glog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err)
return "", err
@@ -454,6 +419,10 @@ func (mounter *Mounter) ExistsPath(pathname string) (bool, error) {
return utilfile.FileExists(pathname)
}
func (mounter *Mounter) EvalHostSymlinks(pathname string) (string, error) {
return filepath.EvalSymlinks(pathname)
}
// formatAndMount uses unix utils to format and mount the given disk
func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, fstype string, options []string) error {
readOnly := false
@@ -583,7 +552,7 @@ func (mounter *SafeFormatAndMount) GetDiskFormat(disk string) (string, error) {
}
if len(pttype) > 0 {
glog.V(4).Infof("Disk %s detected partition table type: %s", pttype)
glog.V(4).Infof("Disk %s detected partition table type: %s", disk, pttype)
// Returns a special non-empty string as filesystem type, then kubelet
// will not format it.
return "unknown data, probably partitions", nil
@@ -696,7 +665,7 @@ func findMountInfo(path, mountInfoPath string) (mountInfo, error) {
// point that is prefix of 'path' - that's the mount where path resides
var info *mountInfo
for i := len(infos) - 1; i >= 0; i-- {
if pathWithinBase(path, infos[i].mountPoint) {
if PathWithinBase(path, infos[i].mountPoint) {
info = &infos[i]
break
}
@@ -767,7 +736,7 @@ func (mounter *Mounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string,
// This implementation is shared between Linux and NsEnterMounter
func safeOpenSubPath(mounter Interface, subpath Subpath) (int, error) {
if !pathWithinBase(subpath.Path, subpath.VolumePath) {
if !PathWithinBase(subpath.Path, subpath.VolumePath) {
return -1, fmt.Errorf("subpath %q not within volume path %q", subpath.Path, subpath.VolumePath)
}
fd, err := doSafeOpen(subpath.Path, subpath.VolumePath)
@@ -995,7 +964,7 @@ func cleanSubPath(mounter Interface, subpath Subpath) error {
// removeEmptyDirs works backwards from endDir to baseDir and removes each directory
// if it is empty. It stops once it encounters a directory that has content
func removeEmptyDirs(baseDir, endDir string) error {
if !pathWithinBase(endDir, baseDir) {
if !PathWithinBase(endDir, baseDir) {
return fmt.Errorf("endDir %q is not within baseDir %q", endDir, baseDir)
}
@@ -1036,6 +1005,11 @@ func (mounter *Mounter) SafeMakeDir(subdir string, base string, perm os.FileMode
}
func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) {
if _, err := os.Stat(pathname); os.IsNotExist(err) {
return []string{}, nil
} else if err != nil {
return nil, err
}
realpath, err := filepath.EvalSymlinks(pathname)
if err != nil {
return nil, err
@@ -1083,7 +1057,7 @@ func getMode(pathname string) (os.FileMode, error) {
func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
glog.V(4).Infof("Creating directory %q within base %q", pathname, base)
if !pathWithinBase(pathname, base) {
if !PathWithinBase(pathname, base) {
return fmt.Errorf("path %s is outside of allowed base %s", pathname, base)
}
@@ -1110,7 +1084,7 @@ func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
if err != nil {
return fmt.Errorf("error opening directory %s: %s", existingPath, err)
}
if !pathWithinBase(fullExistingPath, base) {
if !PathWithinBase(fullExistingPath, base) {
return fmt.Errorf("path %s is outside of allowed base %s", fullExistingPath, err)
}
@@ -1272,7 +1246,7 @@ func doSafeOpen(pathname string, base string) (int, error) {
// sure the user cannot change already existing directories into symlinks.
for _, seg := range segments {
currentPath = filepath.Join(currentPath, seg)
if !pathWithinBase(currentPath, base) {
if !PathWithinBase(currentPath, base) {
return -1, fmt.Errorf("path %s is outside of allowed base %s", currentPath, base)
}
@@ -1329,7 +1303,7 @@ func searchMountPoints(hostSource, mountInfoPath string) ([]string, error) {
// We need search in backward order because it's possible for later mounts
// to overlap earlier mounts.
for i := len(mis) - 1; i >= 0; i-- {
if hostSource == mis[i].mountPoint || pathWithinBase(hostSource, mis[i].mountPoint) {
if hostSource == mis[i].mountPoint || PathWithinBase(hostSource, mis[i].mountPoint) {
// If it's a mount point or path under a mount point.
mountID = mis[i].id
rootPath = filepath.Join(mis[i].root, strings.TrimPrefix(hostSource, mis[i].mountPoint))

View File

@@ -110,10 +110,14 @@ func TestGetMountRefs(t *testing.T) {
"/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd2",
},
},
{
"/var/fake/directory/that/doesnt/exist",
[]string{},
},
}
for i, test := range tests {
if refs, err := GetMountRefs(fm, test.mountPath); err != nil || !setEquivalent(test.expectedRefs, refs) {
if refs, err := fm.GetMountRefs(test.mountPath); err != nil || !setEquivalent(test.expectedRefs, refs) {
t.Errorf("%d. getMountRefs(%q) = %v, %v; expected %v, nil", i, test.mountPath, refs, err, test.expectedRefs)
}
}
@@ -413,7 +417,7 @@ func TestPathWithinBase(t *testing.T) {
},
}
for _, test := range tests {
if pathWithinBase(test.fullPath, test.basePath) != test.expected {
if PathWithinBase(test.fullPath, test.basePath) != test.expected {
t.Errorf("test %q failed: expected %v", test.name, test.expected)
}

View File

@@ -46,12 +46,6 @@ func (mounter *Mounter) Unmount(target string) error {
return unsupportedErr
}
// GetMountRefs finds all other references to the device referenced
// by mountPath; returns a list of paths.
func GetMountRefs(mounter Interface, mountPath string) ([]string, error) {
return []string{}, unsupportedErr
}
func (mounter *Mounter) List() ([]MountPoint, error) {
return []MountPoint{}, unsupportedErr
}
@@ -112,6 +106,10 @@ func (mounter *Mounter) ExistsPath(pathname string) (bool, error) {
return true, errors.New("not implemented")
}
func (mounter *Mounter) EvalHostSymlinks(pathname string) (string, error) {
return "", unsupportedErr
}
func (mounter *Mounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) {
return subPath.Path, nil, unsupportedErr
}

View File

@@ -83,14 +83,20 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio
return fmt.Errorf("azureMount: only cifs mount is supported now, fstype: %q, mounting source (%q), target (%q), with options (%q)", fstype, source, target, options)
}
cmdLine := fmt.Sprintf(`$User = "%s";$PWord = ConvertTo-SecureString -String "%s" -AsPlainText -Force;`+
`$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord`,
options[0], options[1])
bindSource = source
cmdLine += fmt.Sprintf(";New-SmbGlobalMapping -RemotePath %s -Credential $Credential", source)
if output, err := exec.Command("powershell", "/c", cmdLine).CombinedOutput(); err != nil {
// use PowerShell Environment Variables to store user input string to prevent command line injection
// https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-5.1
cmdLine := fmt.Sprintf(`$PWord = ConvertTo-SecureString -String $Env:smbpassword -AsPlainText -Force` +
`;$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Env:smbuser, $PWord` +
`;New-SmbGlobalMapping -RemotePath $Env:smbremotepath -Credential $Credential`)
cmd := exec.Command("powershell", "/c", cmdLine)
cmd.Env = append(os.Environ(),
fmt.Sprintf("smbuser=%s", options[0]),
fmt.Sprintf("smbpassword=%s", options[1]),
fmt.Sprintf("smbremotepath=%s", source))
if output, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("azureMount: SmbGlobalMapping failed: %v, only SMB mount is supported now, output: %q", err, string(output))
}
}
@@ -114,16 +120,6 @@ func (mounter *Mounter) Unmount(target string) error {
return nil
}
// GetMountRefs finds all other references to the device(drive) referenced
// by mountPath; returns a list of paths.
func GetMountRefs(mounter Interface, mountPath string) ([]string, error) {
refs, err := getAllParentLinks(normalizeWindowsPath(mountPath))
if err != nil {
return nil, err
}
return refs, nil
}
// List returns a list of all mounted filesystems. todo
func (mounter *Mounter) List() ([]MountPoint, error) {
return []MountPoint{}, nil
@@ -170,7 +166,7 @@ func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginDir string) (str
// the mount path reference should match the given plugin directory. In case no mount path reference
// matches, returns the volume name taken from its given mountPath
func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (string, error) {
refs, err := GetMountRefs(mounter, mountPath)
refs, err := mounter.GetMountRefs(mountPath)
if err != nil {
glog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err)
return "", err
@@ -242,6 +238,11 @@ func (mounter *Mounter) ExistsPath(pathname string) (bool, error) {
return utilfile.FileExists(pathname)
}
// EvalHostSymlinks returns the path name after evaluating symlinks
func (mounter *Mounter) EvalHostSymlinks(pathname string) (string, error) {
return filepath.EvalSymlinks(pathname)
}
// check whether hostPath is within volume path
// this func will lock all intermediate subpath directories, need to close handle outside of this func after container started
func lockAndCheckSubPath(volumePath, hostPath string) ([]uintptr, error) {
@@ -308,7 +309,7 @@ func lockAndCheckSubPathWithoutSymlink(volumePath, subPath string) ([]uintptr, e
break
}
if !pathWithinBase(currentFullPath, volumePath) {
if !PathWithinBase(currentFullPath, volumePath) {
errorResult = fmt.Errorf("SubPath %q not within volume path %q", currentFullPath, volumePath)
break
}
@@ -457,12 +458,14 @@ func getAllParentLinks(path string) ([]string, error) {
return links, nil
}
// GetMountRefs : empty implementation here since there is no place to query all mount points on Windows
func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) {
realpath, err := filepath.EvalSymlinks(pathname)
if err != nil {
if _, err := os.Stat(normalizeWindowsPath(pathname)); os.IsNotExist(err) {
return []string{}, nil
} else if err != nil {
return nil, err
}
return getMountRefsByDev(mounter, realpath)
return []string{pathname}, nil
}
// Note that on windows, it always returns 0. We actually don't set FSGroup on
@@ -498,7 +501,7 @@ func (mounter *Mounter) SafeMakeDir(subdir string, base string, perm os.FileMode
func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
glog.V(4).Infof("Creating directory %q within base %q", pathname, base)
if !pathWithinBase(pathname, base) {
if !PathWithinBase(pathname, base) {
return fmt.Errorf("path %s is outside of allowed base %s", pathname, base)
}
@@ -533,7 +536,7 @@ func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
if err != nil {
return fmt.Errorf("cannot read link %s: %s", base, err)
}
if !pathWithinBase(fullExistingPath, fullBasePath) {
if !PathWithinBase(fullExistingPath, fullBasePath) {
return fmt.Errorf("path %s is outside of allowed base %s", fullExistingPath, err)
}

View File

@@ -111,30 +111,25 @@ func setEquivalent(set1, set2 []string) bool {
// this func must run in admin mode, otherwise it will fail
func TestGetMountRefs(t *testing.T) {
fm := &FakeMounter{MountPoints: []MountPoint{}}
mountPath := `c:\secondmountpath`
expectedRefs := []string{`c:\`, `c:\firstmountpath`, mountPath}
// remove symbolic links first
for i := 1; i < len(expectedRefs); i++ {
removeLink(expectedRefs[i])
tests := []struct {
mountPath string
expectedRefs []string
}{
{
mountPath: `c:\windows`,
expectedRefs: []string{`c:\windows`},
},
{
mountPath: `c:\doesnotexist`,
expectedRefs: []string{},
},
}
// create symbolic links
for i := 1; i < len(expectedRefs); i++ {
if err := makeLink(expectedRefs[i], expectedRefs[i-1]); err != nil {
t.Errorf("makeLink failed: %v", err)
}
}
mounter := Mounter{"fake/path"}
if refs, err := GetMountRefs(fm, mountPath); err != nil || !setEquivalent(expectedRefs, refs) {
t.Errorf("getMountRefs(%q) = %v, error: %v; expected %v", mountPath, refs, err, expectedRefs)
}
// remove symbolic links
for i := 1; i < len(expectedRefs); i++ {
if err := removeLink(expectedRefs[i]); err != nil {
t.Errorf("removeLink failed: %v", err)
for _, test := range tests {
if refs, err := mounter.GetMountRefs(test.mountPath); err != nil || !setEquivalent(test.expectedRefs, refs) {
t.Errorf("getMountRefs(%q) = %v, error: %v; expected %v", test.mountPath, refs, err, test.expectedRefs)
}
}
}
@@ -576,8 +571,8 @@ func TestPathWithinBase(t *testing.T) {
}
for _, test := range tests {
result := pathWithinBase(test.fullPath, test.basePath)
assert.Equal(t, result, test.expectedResult, "Expect result not equal with pathWithinBase(%s, %s) return: %q, expected: %q",
result := PathWithinBase(test.fullPath, test.basePath)
assert.Equal(t, result, test.expectedResult, "Expect result not equal with PathWithinBase(%s, %s) return: %q, expected: %q",
test.fullPath, test.basePath, result, test.expectedResult)
}
}

View File

@@ -287,6 +287,10 @@ func (mounter *NsenterMounter) ExistsPath(pathname string) (bool, error) {
return utilfile.FileExists(kubeletpath)
}
func (mounter *NsenterMounter) EvalHostSymlinks(pathname string) (string, error) {
return mounter.ne.EvalSymlinks(pathname, true)
}
func (mounter *NsenterMounter) CleanSubPaths(podDir string, volumeName string) error {
return doCleanSubPaths(mounter, podDir, volumeName)
}
@@ -316,7 +320,7 @@ func (mounter *NsenterMounter) SafeMakeDir(subdir string, base string, perm os.F
evaluatedBase = filepath.Clean(evaluatedBase)
rootDir := filepath.Clean(mounter.rootDir)
if pathWithinBase(evaluatedBase, rootDir) {
if PathWithinBase(evaluatedBase, rootDir) {
// Base is in /var/lib/kubelet. This directory is shared between the
// container with kubelet and the host. We don't need to add '/rootfs'.
// This is useful when /rootfs is mounted as read-only - we can still
@@ -333,6 +337,13 @@ func (mounter *NsenterMounter) SafeMakeDir(subdir string, base string, perm os.F
}
func (mounter *NsenterMounter) GetMountRefs(pathname string) ([]string, error) {
exists, err := mounter.ExistsPath(pathname)
if err != nil {
return nil, err
}
if !exists {
return []string{}, nil
}
hostpath, err := mounter.ne.EvalSymlinks(pathname, true /* mustExist */)
if err != nil {
return nil, err

View File

@@ -21,6 +21,7 @@ package mount
import (
"io/ioutil"
"os"
"os/user"
"path/filepath"
"strings"
"testing"
@@ -168,6 +169,12 @@ func newFakeNsenterMounter(tmpdir string, t *testing.T) (mounter *NsenterMounter
}
func TestNsenterExistsFile(t *testing.T) {
user, err := user.Current()
if err != nil {
t.Error(err)
}
isRoot := user.Username == "root"
tests := []struct {
name string
prepare func(base, rootfs string) (string, error)
@@ -227,8 +234,8 @@ func TestNsenterExistsFile(t *testing.T) {
return path, nil
},
expectedOutput: false,
expectError: true,
expectedOutput: isRoot, // ExistsPath success when running as root
expectError: !isRoot, // ExistsPath must fail when running as not-root
},
{
name: "relative symlink to existing file",

View File

@@ -89,6 +89,10 @@ func (*NsenterMounter) ExistsPath(pathname string) (bool, error) {
return true, errors.New("not implemented")
}
func (*NsenterMounter) EvalHostSymlinks(pathname string) (string, error) {
return "", errors.New("not implemented")
}
func (*NsenterMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
return nil
}

View File

@@ -11,15 +11,13 @@ go_library(
srcs = ["node.go"],
importpath = "k8s.io/kubernetes/pkg/util/node",
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/kubelet/apis:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
],
)
@@ -29,8 +27,8 @@ go_test(
embed = [":go_default_library"],
deps = [
"//pkg/kubelet/apis:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
],
)

View File

@@ -24,14 +24,12 @@ import (
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch"
clientset "k8s.io/client-go/kubernetes"
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
api "k8s.io/kubernetes/pkg/apis/core"
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
)
@@ -43,16 +41,23 @@ const (
)
// GetHostname returns OS's hostname if 'hostnameOverride' is empty; otherwise, return 'hostnameOverride'.
func GetHostname(hostnameOverride string) string {
hostname := hostnameOverride
if hostname == "" {
nodename, err := os.Hostname()
func GetHostname(hostnameOverride string) (string, error) {
hostName := hostnameOverride
if len(hostName) == 0 {
nodeName, err := os.Hostname()
if err != nil {
glog.Fatalf("Couldn't determine hostname: %v", err)
return "", fmt.Errorf("couldn't determine hostname: %v", err)
}
hostname = nodename
hostName = nodeName
}
return strings.ToLower(strings.TrimSpace(hostname))
// Trim whitespaces first to avoid getting an empty hostname
// For linux, the hostname is read from file /proc/sys/kernel/hostname directly
hostName = strings.TrimSpace(hostName)
if len(hostName) == 0 {
return "", fmt.Errorf("empty hostname is invalid")
}
return strings.ToLower(hostName), nil
}
// GetPreferredNodeAddress returns the address of the provided node, using the provided preference order.
@@ -64,13 +69,6 @@ func GetPreferredNodeAddress(node *v1.Node, preferredAddressTypes []v1.NodeAddre
return address.Address, nil
}
}
// If hostname was requested and no Hostname address was registered...
if addressType == v1.NodeHostName {
// ...fall back to the kubernetes.io/hostname label for compatibility with kubelets before 1.5
if hostname, ok := node.Labels[kubeletapis.LabelHostname]; ok && len(hostname) > 0 {
return hostname, nil
}
}
}
return "", fmt.Errorf("no preferred addresses found; known addresses: %v", node.Status.Addresses)
}
@@ -93,24 +91,6 @@ func GetNodeHostIP(node *v1.Node) (net.IP, error) {
return nil, fmt.Errorf("host IP unknown; known addresses: %v", addresses)
}
// InternalGetNodeHostIP returns the provided node's IP, based on the priority:
// 1. NodeInternalIP
// 2. NodeExternalIP
func InternalGetNodeHostIP(node *api.Node) (net.IP, error) {
addresses := node.Status.Addresses
addressMap := make(map[api.NodeAddressType][]api.NodeAddress)
for i := range addresses {
addressMap[addresses[i].Type] = append(addressMap[addresses[i].Type], addresses[i])
}
if addresses, ok := addressMap[api.NodeInternalIP]; ok {
return net.ParseIP(addresses[0].Address), nil
}
if addresses, ok := addressMap[api.NodeExternalIP]; ok {
return net.ParseIP(addresses[0].Address), nil
}
return nil, fmt.Errorf("host IP unknown; known addresses: %v", addresses)
}
// GetZoneKey is a helper function that builds a string identifier that is unique per failure-zone;
// it returns empty-string for no zone.
func GetZoneKey(node *v1.Node) string {

View File

@@ -61,13 +61,13 @@ func TestGetPreferredAddress(t *testing.T) {
Preferences: []v1.NodeAddressType{v1.NodeHostName, v1.NodeExternalIP},
ExpectAddress: "status-hostname",
},
"found label address": {
"label address ignored": {
Labels: map[string]string{kubeletapis.LabelHostname: "label-hostname"},
Addresses: []v1.NodeAddress{
{Type: v1.NodeExternalIP, Address: "1.2.3.5"},
},
Preferences: []v1.NodeAddressType{v1.NodeHostName, v1.NodeExternalIP},
ExpectAddress: "label-hostname",
ExpectAddress: "1.2.3.5",
},
}
@@ -89,3 +89,35 @@ func TestGetPreferredAddress(t *testing.T) {
}
}
}
func TestGetHostname(t *testing.T) {
testCases := []struct {
hostName string
expectedHostName string
expectError bool
}{
{
hostName: " ",
expectError: true,
},
{
hostName: " abc ",
expectedHostName: "abc",
expectError: false,
},
}
for idx, test := range testCases {
hostName, err := GetHostname(test.hostName)
if err != nil && !test.expectError {
t.Errorf("[%d]: unexpected error: %s", idx, err)
}
if err == nil && test.expectError {
t.Errorf("[%d]: expected error, got none", idx)
}
if test.expectedHostName != hostName {
t.Errorf("[%d]: expected output %q, got %q", idx, test.expectedHostName, hostName)
}
}
}

View File

@@ -2,42 +2,12 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = select({
"@io_bazel_rules_go//go/platform:android": [
"nsenter_unsupported.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"nsenter_unsupported.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"nsenter_unsupported.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"nsenter_unsupported.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"nsenter.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"nsenter_unsupported.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"nsenter_unsupported.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"nsenter_unsupported.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"nsenter_unsupported.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"nsenter_unsupported.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"nsenter_unsupported.go",
],
"//conditions:default": [],
}),
srcs = [
"exec.go",
"exec_unsupported.go",
"nsenter.go",
"nsenter_unsupported.go",
],
importpath = "k8s.io/kubernetes/pkg/util/nsenter",
visibility = ["//visibility:public"],
deps = select({
@@ -95,12 +65,7 @@ filegroup(
go_test(
name = "go_default_test",
srcs = select({
"@io_bazel_rules_go//go/platform:linux": [
"nsenter_test.go",
],
"//conditions:default": [],
}),
srcs = ["nsenter_test.go"],
embed = [":go_default_library"],
deps = select({
"@io_bazel_rules_go//go/platform:linux": [

8
vendor/k8s.io/kubernetes/pkg/util/nsenter/OWNERS generated vendored Normal file
View File

@@ -0,0 +1,8 @@
reviewers:
- jsafrane
- msau42
- cofyc
approvers:
- jsafrane
- msau42
- cofyc

67
vendor/k8s.io/kubernetes/pkg/util/nsenter/exec.go generated vendored Normal file
View File

@@ -0,0 +1,67 @@
// +build linux
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package nsenter
import (
"context"
"fmt"
"path/filepath"
"github.com/golang/glog"
"k8s.io/utils/exec"
)
// Executor wraps executor interface to be executed via nsenter
type Executor struct {
// Exec implementation
executor exec.Interface
// Path to the host's root proc path
hostProcMountNsPath string
}
// NewNsenterExecutor returns new nsenter based executor
func NewNsenterExecutor(hostRootFsPath string, executor exec.Interface) *Executor {
hostProcMountNsPath := filepath.Join(hostRootFsPath, mountNsPath)
nsExecutor := &Executor{
hostProcMountNsPath: hostProcMountNsPath,
executor: executor,
}
return nsExecutor
}
// Command returns a command wrapped with nenter
func (nsExecutor *Executor) Command(cmd string, args ...string) exec.Cmd {
fullArgs := append([]string{fmt.Sprintf("--mount=%s", nsExecutor.hostProcMountNsPath), "--"},
append([]string{cmd}, args...)...)
glog.V(5).Infof("Running nsenter command: %v %v", nsenterPath, fullArgs)
return nsExecutor.executor.Command(nsenterPath, fullArgs...)
}
// CommandContext returns a CommandContext wrapped with nsenter
func (nsExecutor *Executor) CommandContext(ctx context.Context, cmd string, args ...string) exec.Cmd {
fullArgs := append([]string{fmt.Sprintf("--mount=%s", nsExecutor.hostProcMountNsPath), "--"},
append([]string{cmd}, args...)...)
glog.V(5).Infof("Running nsenter command: %v %v", nsenterPath, fullArgs)
return nsExecutor.executor.CommandContext(ctx, nsenterPath, fullArgs...)
}
// LookPath returns a LookPath wrapped with nsenter
func (nsExecutor *Executor) LookPath(file string) (string, error) {
return "", fmt.Errorf("not implemented, error looking up : %s", file)
}

View File

@@ -0,0 +1,58 @@
// +build !linux
/*
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 nsenter
import (
"context"
"fmt"
"k8s.io/utils/exec"
)
// Executor wraps executor interface to be executed via nsenter
type Executor struct {
// Exec implementation
executor exec.Interface
// Path to the host's root proc path
hostProcMountNsPath string
}
// NewNsenterExecutor returns new nsenter based executor
func NewNsenterExecutor(hostRootFsPath string, executor exec.Interface) *Executor {
nsExecutor := &Executor{
hostProcMountNsPath: hostRootFsPath,
executor: executor,
}
return nsExecutor
}
// Command returns a command wrapped with nenter
func (nsExecutor *Executor) Command(cmd string, args ...string) exec.Cmd {
return nil
}
// CommandContext returns a CommandContext wrapped with nsenter
func (nsExecutor *Executor) CommandContext(ctx context.Context, cmd string, args ...string) exec.Cmd {
return nil
}
// LookPath returns a LookPath wrapped with nsenter
func (nsExecutor *Executor) LookPath(file string) (string, error) {
return "", fmt.Errorf("not implemented, error looking up : %s", file)
}

View File

@@ -12,42 +12,9 @@ go_library(
"doc.go",
"oom.go",
"oom_fake.go",
] + select({
"@io_bazel_rules_go//go/platform:android": [
"oom_unsupported.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"oom_unsupported.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"oom_unsupported.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"oom_unsupported.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"oom_linux.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"oom_unsupported.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"oom_unsupported.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"oom_unsupported.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"oom_unsupported.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"oom_unsupported.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"oom_unsupported.go",
],
"//conditions:default": [],
}),
"oom_linux.go",
"oom_unsupported.go",
],
importpath = "k8s.io/kubernetes/pkg/util/oom",
deps = select({
"@io_bazel_rules_go//go/platform:linux": [
@@ -60,12 +27,7 @@ go_library(
go_test(
name = "go_default_test",
srcs = select({
"@io_bazel_rules_go//go/platform:linux": [
"oom_linux_test.go",
],
"//conditions:default": [],
}),
srcs = ["oom_linux_test.go"],
embed = [":go_default_library"],
deps = select({
"@io_bazel_rules_go//go/platform:linux": [

View File

@@ -6,10 +6,10 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/util/pod",
visibility = ["//visibility:public"],
deps = [
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
],
)
@@ -18,9 +18,9 @@ go_test(
srcs = ["pod_test.go"],
embed = [":go_default_library"],
deps = [
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
],
)

View File

@@ -1,32 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = ["pointer_test.go"],
embed = [":go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["pointer.go"],
importpath = "k8s.io/kubernetes/pkg/util/pointer",
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@@ -1,71 +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 pointer
import (
"fmt"
"reflect"
)
// AllPtrFieldsNil tests whether all pointer fields in a struct are nil. This is useful when,
// for example, an API struct is handled by plugins which need to distinguish
// "no plugin accepted this spec" from "this spec is empty".
//
// This function is only valid for structs and pointers to structs. Any other
// type will cause a panic. Passing a typed nil pointer will return true.
func AllPtrFieldsNil(obj interface{}) bool {
v := reflect.ValueOf(obj)
if !v.IsValid() {
panic(fmt.Sprintf("reflect.ValueOf() produced a non-valid Value for %#v", obj))
}
if v.Kind() == reflect.Ptr {
if v.IsNil() {
return true
}
v = v.Elem()
}
for i := 0; i < v.NumField(); i++ {
if v.Field(i).Kind() == reflect.Ptr && !v.Field(i).IsNil() {
return false
}
}
return true
}
// Int32Ptr returns a pointer to an int32
func Int32Ptr(i int32) *int32 {
return &i
}
// Int64Ptr returns a pointer to an int64
func Int64Ptr(i int64) *int64 {
return &i
}
// Int32PtrDerefOr dereference the int32 ptr and returns it i not nil,
// else returns def.
func Int32PtrDerefOr(ptr *int32, def int32) int32 {
if ptr != nil {
return *ptr
}
return def
}
// BoolPtr returns a pointer to a bool
func BoolPtr(b bool) *bool {
return &b
}

View File

@@ -1,66 +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 pointer
import (
"testing"
)
func TestAllPtrFieldsNil(t *testing.T) {
testCases := []struct {
obj interface{}
expected bool
}{
{struct{}{}, true},
{struct{ Foo int }{12345}, true},
{&struct{ Foo int }{12345}, true},
{struct{ Foo *int }{nil}, true},
{&struct{ Foo *int }{nil}, true},
{struct {
Foo int
Bar *int
}{12345, nil}, true},
{&struct {
Foo int
Bar *int
}{12345, nil}, true},
{struct {
Foo *int
Bar *int
}{nil, nil}, true},
{&struct {
Foo *int
Bar *int
}{nil, nil}, true},
{struct{ Foo *int }{new(int)}, false},
{&struct{ Foo *int }{new(int)}, false},
{struct {
Foo *int
Bar *int
}{nil, new(int)}, false},
{&struct {
Foo *int
Bar *int
}{nil, new(int)}, false},
{(*struct{})(nil), true},
}
for i, tc := range testCases {
if AllPtrFieldsNil(tc.obj) != tc.expected {
t.Errorf("case[%d]: expected %t, got %t", i, tc.expected, !tc.expected)
}
}
}

View File

@@ -12,47 +12,14 @@ go_library(
"doc.go",
"procfs.go",
"procfs_fake.go",
] + select({
"@io_bazel_rules_go//go/platform:android": [
"procfs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"procfs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"procfs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"procfs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"procfs_linux.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"procfs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"procfs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"procfs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"procfs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"procfs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"procfs_unsupported.go",
],
"//conditions:default": [],
}),
"procfs_linux.go",
"procfs_unsupported.go",
],
importpath = "k8s.io/kubernetes/pkg/util/procfs",
deps = select({
"@io_bazel_rules_go//go/platform:linux": [
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
],
"//conditions:default": [],
}),
@@ -60,12 +27,7 @@ go_library(
go_test(
name = "go_default_test",
srcs = select({
"@io_bazel_rules_go//go/platform:linux": [
"procfs_linux_test.go",
],
"//conditions:default": [],
}),
srcs = ["procfs_linux_test.go"],
data = [
"example_proc_cgroup",
],

View File

@@ -10,8 +10,8 @@ go_library(
srcs = ["prometheus.go"],
importpath = "k8s.io/kubernetes/pkg/util/reflector/prometheus",
deps = [
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
],
)

View File

@@ -12,7 +12,7 @@ go_test(
embed = [":go_default_library"],
deps = [
"//pkg/util/mount:go_default_library",
"//vendor/k8s.io/client-go/util/testing:go_default_library",
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
],
)

View File

@@ -27,87 +27,12 @@ import (
"k8s.io/kubernetes/pkg/util/mount"
)
type fakeMounter struct{}
var _ mount.Interface = &fakeMounter{}
func (mounter *fakeMounter) Mount(source string, target string, fstype string, options []string) error {
return errors.New("not implemented")
type fakeMounter struct {
mount.FakeMounter
}
func (mounter *fakeMounter) Unmount(target string) error {
return errors.New("not implemented")
}
func (mounter *fakeMounter) List() ([]mount.MountPoint, error) {
return nil, errors.New("not implemented")
}
func (mounter fakeMounter) DeviceOpened(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
func (mounter *fakeMounter) PathIsDevice(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
func (mounter *fakeMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
return "", errors.New("not implemented")
}
func (mounter *fakeMounter) IsMountPointMatch(mp mount.MountPoint, dir string) bool {
return mp.Path == dir
}
func (mounter *fakeMounter) IsNotMountPoint(dir string) (bool, error) {
return mount.IsNotMountPoint(mounter, dir)
}
func (mounter *fakeMounter) GetFileType(pathname string) (mount.FileType, error) {
return mount.FileType("fake"), errors.New("not implemented")
}
func (mounter *fakeMounter) MakeDir(pathname string) error {
return nil
}
func (mounter *fakeMounter) MakeFile(pathname string) error {
return nil
}
func (mounter *fakeMounter) ExistsPath(pathname string) (bool, error) {
return true, errors.New("not implemented")
}
func (mounter *fakeMounter) PrepareSafeSubpath(subPath mount.Subpath) (newHostPath string, cleanupAction func(), err error) {
return "", nil, nil
}
func (mounter *fakeMounter) CleanSubPaths(_, _ string) error {
return nil
}
func (mounter *fakeMounter) SafeMakeDir(_, _ string, _ os.FileMode) error {
return nil
}
func (mounter *fakeMounter) GetMountRefs(pathname string) ([]string, error) {
return nil, errors.New("not implemented")
}
func (mounter *fakeMounter) GetFSGroup(pathname string) (int64, error) {
return -1, errors.New("not implemented")
}
func (mounter *fakeMounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
func (mounter *fakeMounter) GetMode(pathname string) (os.FileMode, error) {
return 0, errors.New("not implemented")
}
func (mounter *fakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
// IsLikelyNotMountPoint overrides mount.FakeMounter.IsLikelyNotMountPoint for our use.
func (f *fakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
name := path.Base(file)
if strings.HasPrefix(name, "mount") {
return false, nil
@@ -118,10 +43,6 @@ func (mounter *fakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
return true, nil
}
func (mounter *fakeMounter) MakeRShared(path string) error {
return nil
}
func TestRemoveAllOneFilesystem(t *testing.T) {
tests := []struct {
name string

View File

@@ -2,42 +2,10 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = select({
"@io_bazel_rules_go//go/platform:android": [
"resizefs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"resizefs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"resizefs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"resizefs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"resizefs_linux.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"resizefs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"resizefs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"resizefs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"resizefs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"resizefs_unsupported.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"resizefs_unsupported.go",
],
"//conditions:default": [],
}),
srcs = [
"resizefs_linux.go",
"resizefs_unsupported.go",
],
importpath = "k8s.io/kubernetes/pkg/util/resizefs",
visibility = ["//visibility:public"],
deps = select({

View File

@@ -7,42 +7,10 @@ load(
go_library(
name = "go_default_library",
srcs = select({
"@io_bazel_rules_go//go/platform:android": [
"resource_container_unsupported.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"resource_container_unsupported.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"resource_container_unsupported.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"resource_container_unsupported.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"resource_container_linux.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"resource_container_unsupported.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"resource_container_unsupported.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"resource_container_unsupported.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"resource_container_unsupported.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"resource_container_unsupported.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"resource_container_unsupported.go",
],
"//conditions:default": [],
}),
srcs = [
"resource_container_linux.go",
"resource_container_unsupported.go",
],
importpath = "k8s.io/kubernetes/pkg/util/resourcecontainer",
deps = select({
"@io_bazel_rules_go//go/platform:linux": [

View File

@@ -7,42 +7,10 @@ load(
go_library(
name = "go_default_library",
srcs = select({
"@io_bazel_rules_go//go/platform:android": [
"rlimit_unsupported.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"rlimit_unsupported.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"rlimit_unsupported.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"rlimit_unsupported.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"rlimit_linux.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"rlimit_unsupported.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"rlimit_unsupported.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"rlimit_unsupported.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"rlimit_unsupported.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"rlimit_unsupported.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"rlimit_unsupported.go",
],
"//conditions:default": [],
}),
srcs = [
"rlimit_linux.go",
"rlimit_unsupported.go",
],
importpath = "k8s.io/kubernetes/pkg/util/rlimit",
deps = select({
"@io_bazel_rules_go//go/platform:linux": [

View File

@@ -10,42 +10,9 @@ go_library(
srcs = [
"doc.go",
"selinux.go",
] + select({
"@io_bazel_rules_go//go/platform:android": [
"selinux_unsupported.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"selinux_unsupported.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"selinux_unsupported.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"selinux_unsupported.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"selinux_linux.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"selinux_unsupported.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"selinux_unsupported.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"selinux_unsupported.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"selinux_unsupported.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"selinux_unsupported.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"selinux_unsupported.go",
],
"//conditions:default": [],
}),
"selinux_linux.go",
"selinux_unsupported.go",
],
importpath = "k8s.io/kubernetes/pkg/util/selinux",
deps = select({
"@io_bazel_rules_go//go/platform:linux": [

View File

@@ -10,7 +10,7 @@ go_library(
name = "go_default_library",
srcs = ["slice.go"],
importpath = "k8s.io/kubernetes/pkg/util/slice",
deps = ["//vendor/k8s.io/apimachinery/pkg/util/rand:go_default_library"],
deps = ["//staging/src/k8s.io/apimachinery/pkg/util/rand:go_default_library"],
)
go_test(

View File

@@ -17,8 +17,8 @@ go_test(
srcs = ["system_utils_test.go"],
embed = [":go_default_library"],
deps = [
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
],
)

View File

@@ -13,10 +13,10 @@ go_library(
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/helper:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library",
],
)
@@ -26,8 +26,8 @@ go_test(
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
],
)

View File

@@ -7,86 +7,54 @@ load(
go_library(
name = "go_default_library",
srcs = select({
"@io_bazel_rules_go//go/platform:android": [
"setsize.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"setsize.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"setsize.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"setsize.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"setsize.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"setsize.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"setsize.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"setsize.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"setsize.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"setsize.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"setsize_unsupported.go",
],
"//conditions:default": [],
}),
srcs = [
"setsize.go",
"setsize_unsupported.go",
],
importpath = "k8s.io/kubernetes/pkg/util/term",
deps = select({
"@io_bazel_rules_go//go/platform:android": [
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
"//vendor/github.com/docker/docker/pkg/term:go_default_library",
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
],
"@io_bazel_rules_go//go/platform:darwin": [
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
"//vendor/github.com/docker/docker/pkg/term:go_default_library",
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
"//vendor/github.com/docker/docker/pkg/term:go_default_library",
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
"//vendor/github.com/docker/docker/pkg/term:go_default_library",
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
],
"@io_bazel_rules_go//go/platform:linux": [
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
"//vendor/github.com/docker/docker/pkg/term:go_default_library",
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
],
"@io_bazel_rules_go//go/platform:nacl": [
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
"//vendor/github.com/docker/docker/pkg/term:go_default_library",
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
"//vendor/github.com/docker/docker/pkg/term:go_default_library",
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
"//vendor/github.com/docker/docker/pkg/term:go_default_library",
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
],
"@io_bazel_rules_go//go/platform:plan9": [
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
"//vendor/github.com/docker/docker/pkg/term:go_default_library",
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
],
"@io_bazel_rules_go//go/platform:solaris": [
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
"//vendor/github.com/docker/docker/pkg/term:go_default_library",
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
],
"@io_bazel_rules_go//go/platform:windows": [
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
"//staging/src/k8s.io/client-go/tools/remotecommand:go_default_library",
],
"//conditions:default": [],
}),

View File

@@ -10,8 +10,8 @@ go_library(
srcs = ["prometheus.go"],
importpath = "k8s.io/kubernetes/pkg/util/workqueue/prometheus",
deps = [
"//staging/src/k8s.io/client-go/util/workqueue:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
"//vendor/k8s.io/client-go/util/workqueue:go_default_library",
],
)