Fresh dep ensure

This commit is contained in:
Mike Cronce
2018-11-26 13:23:56 -05:00
parent 93cb8a04d7
commit 407478ab9a
9016 changed files with 551394 additions and 279685 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",
@ -34,7 +35,6 @@ filegroup(
"//pkg/util/ipvs:all-srcs",
"//pkg/util/keymutex:all-srcs",
"//pkg/util/labels:all-srcs",
"//pkg/util/limitwriter:all-srcs",
"//pkg/util/maps:all-srcs",
"//pkg/util/metrics:all-srcs",
"//pkg/util/mount:all-srcs",
@ -46,7 +46,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",
@ -60,11 +59,7 @@ filegroup(
"//pkg/util/system:all-srcs",
"//pkg/util/tail:all-srcs",
"//pkg/util/taints:all-srcs",
"//pkg/util/template:all-srcs",
"//pkg/util/term:all-srcs",
"//pkg/util/threading:all-srcs",
"//pkg/util/tolerations:all-srcs",
"//pkg/util/version:all-srcs",
"//pkg/util/workqueue/prometheus:all-srcs",
],
tags = ["automanaged"],

View File

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

View File

@ -23,7 +23,7 @@ import (
"k8s.io/client-go/util/flowcontrol"
"github.com/golang/glog"
"k8s.io/klog"
)
// BoundedFrequencyRunner manages runs of a user-provided function.
@ -167,13 +167,13 @@ func construct(name string, fn func(), minInterval, maxInterval time.Duration, b
// Loop handles the periodic timer and run requests. This is expected to be
// called as a goroutine.
func (bfr *BoundedFrequencyRunner) Loop(stop <-chan struct{}) {
glog.V(3).Infof("%s Loop running", bfr.name)
klog.V(3).Infof("%s Loop running", bfr.name)
bfr.timer.Reset(bfr.maxInterval)
for {
select {
case <-stop:
bfr.stop()
glog.V(3).Infof("%s Loop stopping", bfr.name)
klog.V(3).Infof("%s Loop stopping", bfr.name)
return
case <-bfr.timer.C():
bfr.tryRun()
@ -218,7 +218,7 @@ func (bfr *BoundedFrequencyRunner) tryRun() {
bfr.lastRun = bfr.timer.Now()
bfr.timer.Stop()
bfr.timer.Reset(bfr.maxInterval)
glog.V(3).Infof("%s: ran, next possible in %v, periodic in %v", bfr.name, bfr.minInterval, bfr.maxInterval)
klog.V(3).Infof("%s: ran, next possible in %v, periodic in %v", bfr.name, bfr.minInterval, bfr.maxInterval)
return
}
@ -227,13 +227,13 @@ func (bfr *BoundedFrequencyRunner) tryRun() {
elapsed := bfr.timer.Since(bfr.lastRun) // how long since last run
nextPossible := bfr.minInterval - elapsed // time to next possible run
nextScheduled := bfr.maxInterval - elapsed // time to next periodic run
glog.V(4).Infof("%s: %v since last run, possible in %v, scheduled in %v", bfr.name, elapsed, nextPossible, nextScheduled)
klog.V(4).Infof("%s: %v since last run, possible in %v, scheduled in %v", bfr.name, elapsed, nextPossible, nextScheduled)
if nextPossible < nextScheduled {
// Set the timer for ASAP, but don't drain here. Assuming Loop is running,
// it might get a delivery in the mean time, but that is OK.
bfr.timer.Stop()
bfr.timer.Reset(nextPossible)
glog.V(3).Infof("%s: throttled, scheduling run in %v", bfr.name, nextPossible)
klog.V(3).Infof("%s: throttled, scheduling run in %v", bfr.name, nextPossible)
}
}

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": [
"//vendor/github.com/golang/glog: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/klog: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

@ -30,7 +30,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/utils/exec"
"github.com/golang/glog"
"k8s.io/klog"
)
// tcShaper provides an implementation of the BandwidthShaper interface on Linux using the 'tc' tool.
@ -53,10 +53,10 @@ func NewTCShaper(iface string) BandwidthShaper {
}
func (t *tcShaper) execAndLog(cmdStr string, args ...string) error {
glog.V(6).Infof("Running: %s %s", cmdStr, strings.Join(args, " "))
klog.V(6).Infof("Running: %s %s", cmdStr, strings.Join(args, " "))
cmd := t.e.Command(cmdStr, args...)
out, err := cmd.CombinedOutput()
glog.V(6).Infof("Output from tc: %s", string(out))
klog.V(6).Infof("Output from tc: %s", string(out))
return err
}
@ -259,7 +259,7 @@ func (t *tcShaper) ReconcileInterface() error {
return err
}
if !exists {
glog.V(4).Info("Didn't find bandwidth interface, creating")
klog.V(4).Info("Didn't find bandwidth interface, creating")
return t.initializeInterface()
}
fields := strings.Split(output, " ")

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"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/klog"
"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 {
klog.Errorf("Couldn't move coverage file from %s to %s", coverageFile, tempCoveragePath())
}
}

View File

@ -1,7 +1,7 @@
// +build windows
// +build !coverage
/*
Copyright 2016 The Kubernetes Authors.
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.
@ -16,13 +16,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package term
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() {
import (
"k8s.io/client-go/tools/remotecommand"
)
func SetSize(fd uintptr, size remotecommand.TerminalSize) error {
// NOP
return nil
}

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

@ -209,9 +209,8 @@ func TestFakeDBus(t *testing.T) {
checkName := args[0].(string)
if checkName != ownedName {
return nil, godbus.Error{Name: "org.freedesktop.DBus.Error.NameHasNoOwner", Body: nil}
} else {
return []interface{}{uniqueName}, nil
}
return []interface{}{uniqueName}, nil
} else if method == "org.freedesktop.DBus.RequestName" {
reqName := args[0].(string)
_ = args[1].(uint32)

View File

@ -23,25 +23,25 @@ import (
godbus "github.com/godbus/dbus"
)
// DBusFake is a simple fake Interface type.
type DBusFake struct {
systemBus *DBusFakeConnection
sessionBus *DBusFakeConnection
// Fake is a simple fake Interface type.
type Fake struct {
systemBus *FakeConnection
sessionBus *FakeConnection
}
// DBusFakeConnection represents a fake D-Bus connection
type DBusFakeConnection struct {
// FakeConnection represents a fake D-Bus connection
type FakeConnection struct {
lock sync.Mutex
busObject *fakeObject
objects map[string]*fakeObject
signalHandlers []chan<- *godbus.Signal
}
// DBusFakeHandler is used to handle fake D-Bus method calls
type DBusFakeHandler func(method string, args ...interface{}) ([]interface{}, error)
// FakeHandler is used to handle fake D-Bus method calls
type FakeHandler func(method string, args ...interface{}) ([]interface{}, error)
type fakeObject struct {
handler DBusFakeHandler
handler FakeHandler
}
type fakeCall struct {
@ -50,46 +50,45 @@ type fakeCall struct {
}
// NewFake returns a new Interface which will fake talking to D-Bus
func NewFake(systemBus *DBusFakeConnection, sessionBus *DBusFakeConnection) *DBusFake {
return &DBusFake{systemBus, sessionBus}
func NewFake(systemBus *FakeConnection, sessionBus *FakeConnection) *Fake {
return &Fake{systemBus, sessionBus}
}
func NewFakeConnection() *DBusFakeConnection {
return &DBusFakeConnection{
// NewFakeConnection returns a FakeConnection Interface
func NewFakeConnection() *FakeConnection {
return &FakeConnection{
objects: make(map[string]*fakeObject),
}
}
// SystemBus is part of Interface
func (db *DBusFake) SystemBus() (Connection, error) {
func (db *Fake) SystemBus() (Connection, error) {
if db.systemBus != nil {
return db.systemBus, nil
} else {
return nil, fmt.Errorf("DBus is not running")
}
return nil, fmt.Errorf("DBus is not running")
}
// SessionBus is part of Interface
func (db *DBusFake) SessionBus() (Connection, error) {
func (db *Fake) SessionBus() (Connection, error) {
if db.sessionBus != nil {
return db.sessionBus, nil
} else {
return nil, fmt.Errorf("DBus is not running")
}
return nil, fmt.Errorf("DBus is not running")
}
// BusObject is part of the Connection interface
func (conn *DBusFakeConnection) BusObject() Object {
func (conn *FakeConnection) BusObject() Object {
return conn.busObject
}
// Object is part of the Connection interface
func (conn *DBusFakeConnection) Object(name, path string) Object {
func (conn *FakeConnection) Object(name, path string) Object {
return conn.objects[name+path]
}
// Signal is part of the Connection interface
func (conn *DBusFakeConnection) Signal(ch chan<- *godbus.Signal) {
func (conn *FakeConnection) Signal(ch chan<- *godbus.Signal) {
conn.lock.Lock()
defer conn.lock.Unlock()
for i := range conn.signalHandlers {
@ -102,17 +101,17 @@ func (conn *DBusFakeConnection) Signal(ch chan<- *godbus.Signal) {
}
// SetBusObject sets the handler for the BusObject of conn
func (conn *DBusFakeConnection) SetBusObject(handler DBusFakeHandler) {
func (conn *FakeConnection) SetBusObject(handler FakeHandler) {
conn.busObject = &fakeObject{handler}
}
// AddObject adds a handler for the Object at name and path
func (conn *DBusFakeConnection) AddObject(name, path string, handler DBusFakeHandler) {
func (conn *FakeConnection) AddObject(name, path string, handler FakeHandler) {
conn.objects[name+path] = &fakeObject{handler}
}
// EmitSignal emits a signal on conn
func (conn *DBusFakeConnection) EmitSignal(name, path, iface, signal string, args ...interface{}) {
func (conn *FakeConnection) EmitSignal(name, path, iface, signal string, args ...interface{}) {
conn.lock.Lock()
defer conn.lock.Unlock()
sig := &godbus.Signal{

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,8 +11,9 @@ go_library(
srcs = ["flags.go"],
importpath = "k8s.io/kubernetes/pkg/util/flag",
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/klog: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,13 +17,145 @@ limitations under the License.
package flag
import (
"github.com/golang/glog"
"fmt"
"net"
"strconv"
"github.com/spf13/pflag"
"k8s.io/klog"
utilnet "k8s.io/apimachinery/pkg/util/net"
)
// PrintFlags logs the flags in the flagset
func PrintFlags(flags *pflag.FlagSet) {
flags.VisitAll(func(flag *pflag.Flag) {
glog.V(1).Infof("FLAG: --%s=%q", flag.Name, flag.Value)
klog.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",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/k8s.io/klog: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

@ -25,8 +25,8 @@ import (
"fmt"
"sync"
"github.com/golang/glog"
k8sRuntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff"
)
@ -135,7 +135,7 @@ func (grm *goRoutineMap) operationComplete(
delete(grm.operations, operationName)
if *err != nil {
// Log error
glog.Errorf("operation for %q failed with: %v",
klog.Errorf("operation for %q failed with: %v",
operationName,
*err)
}
@ -147,7 +147,7 @@ func (grm *goRoutineMap) operationComplete(
grm.operations[operationName] = existingOp
// Log error
glog.Errorf("%v",
klog.Errorf("%v",
existingOp.expBackoff.GenerateNoRetriesPermittedMsg(operationName))
}
}

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

@ -14,7 +14,7 @@ go_library(
],
importpath = "k8s.io/kubernetes/pkg/util/ipconfig",
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
)

View File

@ -21,15 +21,15 @@ import (
"strings"
"sync"
"github.com/golang/glog"
"k8s.io/klog"
utilexec "k8s.io/utils/exec"
)
// Interface is an injectable interface for running ipconfig commands. Implementations must be goroutine-safe.
type Interface interface {
// GetDnsSuffixSearchList returns the list of DNS suffix to search
GetDnsSuffixSearchList() ([]string, error)
// GetDNSSuffixSearchList returns the list of DNS suffix to search
GetDNSSuffixSearchList() ([]string, error)
}
const (
@ -54,8 +54,8 @@ func New(exec utilexec.Interface) Interface {
return runner
}
// GetDnsSuffixSearchList returns the list of DNS suffix to search
func (runner *runner) GetDnsSuffixSearchList() ([]string, error) {
// GetDNSSuffixSearchList returns the list of DNS suffix to search
func (runner *runner) GetDNSSuffixSearchList() ([]string, error) {
// Parse the DNS suffix search list from ipconfig output
// ipconfig /all on Windows displays the entry of DNS suffix search list
// An example output contains:
@ -66,7 +66,7 @@ func (runner *runner) GetDnsSuffixSearchList() ([]string, error) {
// TODO: this does not work when the label is localized
suffixList := []string{}
if runtime.GOOS != "windows" {
glog.V(1).Infof("ipconfig not supported on GOOS=%s", runtime.GOOS)
klog.V(1).Infof("ipconfig not supported on GOOS=%s", runtime.GOOS)
return suffixList, nil
}
@ -92,7 +92,7 @@ func (runner *runner) GetDnsSuffixSearchList() ([]string, error) {
}
}
} else {
glog.V(1).Infof("Running %s %s failed: %v", cmdIpconfig, cmdDefaultArgs, err)
klog.V(1).Infof("Running %s %s failed: %v", cmdIpconfig, cmdDefaultArgs, err)
}
return suffixList, err

View File

@ -22,11 +22,11 @@ import (
"k8s.io/utils/exec"
)
func TestGetDnsSuffixSearchList(t *testing.T) {
func TestGetDNSSuffixSearchList(t *testing.T) {
// Simple test
ipconfigInterface := New(exec.New())
_, err := ipconfigInterface.GetDnsSuffixSearchList()
_, err := ipconfigInterface.GetDNSSuffixSearchList()
if err != nil {
t.Errorf("expected success, got %v", err)
}

View File

@ -9,7 +9,7 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/util/ipset",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
)
@ -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

@ -24,7 +24,7 @@ import (
"strconv"
"strings"
"github.com/golang/glog"
"k8s.io/klog"
utilexec "k8s.io/utils/exec"
)
@ -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,18 +111,40 @@ func (set *IPSet) Validate() bool {
}
// check hash size value of ipset
if set.HashSize <= 0 {
klog.Errorf("Invalid hashsize value %d, should be >0", set.HashSize)
return false
}
// check max elem value of ipset
if set.MaxElem <= 0 {
glog.Errorf("Invalid maxelem value %d, should be >0", set.MaxElem)
klog.Errorf("Invalid maxelem value %d, should be >0", set.MaxElem)
return false
}
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.
@ -145,77 +167,50 @@ type Entry struct {
// Validate checks if a given ipset entry is valid or not. The set parameter is the ipset that entry belongs to.
func (e *Entry) Validate(set *IPSet) bool {
if e.Port < 0 {
glog.Errorf("Entry %v port number %d should be >=0 for ipset %v", e, e.Port, set)
klog.Errorf("Entry %v port number %d should be >=0 for ipset %v", e, e.Port, set)
return false
}
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
}
// IP2 can not be empty for `hash:ip,port,ip` type ip set
if net.ParseIP(e.IP2) == nil {
glog.Errorf("Error parsing entry %v second ip address %v for ipset %v", e, e.IP2, set)
klog.Errorf("Error parsing entry %v second ip address %v for ipset %v", e, e.IP2, set)
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 {
klog.Errorf("Error parsing entry %v ip net %v for ipset %v, error: %v", e, e.Net, set, err)
return false
}
case BitmapPort:
// check if port number satisfies its ipset's requirement of port range
if set == nil {
glog.Errorf("Unable to reference ip set where the entry %v exists", e)
klog.Errorf("Unable to reference ip set where the entry %v exists", e)
return false
}
begin, end, err := parsePortRange(set.PortRange)
if err != nil {
glog.Errorf("Failed to parse set %v port range %s for ipset %v, error: %v", set, set.PortRange, set, err)
klog.Errorf("Failed to parse set %v port range %s for ipset %v, error: %v", set, set.PortRange, set, err)
return false
}
if e.Port < begin || e.Port > end {
glog.Errorf("Entry %v port number %d is not in the port range %s of its ipset %v", e, e.Port, set.PortRange, set)
klog.Errorf("Entry %v port number %d is not in the port range %s of its ipset %v", e, e.Port, set.PortRange, set)
return false
}
}
@ -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 {
klog.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()
@ -290,7 +286,7 @@ func (runner *runner) CreateSet(set *IPSet, ignoreExistErr bool) 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)}
if set.SetType == HashIPPortIP || set.SetType == HashIPPort {
if set.SetType == HashIPPortIP || set.SetType == HashIPPort || set.SetType == HashIPPortNet {
args = append(args,
"family", set.HashFamily,
"hashsize", strconv.Itoa(set.HashSize),
@ -428,17 +424,17 @@ func getIPSetVersionString(exec utilexec.Interface) (string, error) {
func validatePortRange(portRange string) bool {
strs := strings.Split(portRange, "-")
if len(strs) != 2 {
glog.Errorf("port range should be in the format of `a-b`")
klog.Errorf("port range should be in the format of `a-b`")
return false
}
for i := range strs {
num, err := strconv.Atoi(strs[i])
if err != nil {
glog.Errorf("Failed to parse %s, error: %v", strs[i], err)
klog.Errorf("Failed to parse %s, error: %v", strs[i], err)
return false
}
if num < 0 {
glog.Errorf("port number %d should be >=0", num)
klog.Errorf("port number %d should be >=0", num)
return false
}
}
@ -452,7 +448,7 @@ func validateIPSetType(set Type) bool {
return true
}
}
glog.Errorf("Currently supported ipset types are: %v, %s is not supported", ValidIPSetTypes, set)
klog.Errorf("Currently supported ipset types are: %v, %s is not supported", ValidIPSetTypes, set)
return false
}
@ -461,7 +457,7 @@ func validateHashFamily(family string) bool {
if family == ProtocolFamilyIPV4 || family == ProtocolFamilyIPV6 {
return true
}
glog.Errorf("Currently supported ip set hash families are: [%s, %s], %s is not supported", ProtocolFamilyIPV4, ProtocolFamilyIPV6, family)
klog.Errorf("Currently supported ip set hash families are: [%s, %s], %s is not supported", ProtocolFamilyIPV4, ProtocolFamilyIPV6, family)
return false
}
@ -486,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)
klog.Errorf("Invalid entry's protocol: %s, supported protocols are [%s, %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/apimachinery/pkg/util/version: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/klog: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

@ -26,10 +26,11 @@ import (
"time"
godbus "github.com/godbus/dbus"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/util/sets"
utilversion "k8s.io/apimachinery/pkg/util/version"
utiltrace "k8s.io/apiserver/pkg/util/trace"
"k8s.io/klog"
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
@ -150,7 +152,7 @@ type runner struct {
func newInternal(exec utilexec.Interface, dbus utildbus.Interface, protocol Protocol, lockfilePath string) Interface {
vstring, err := getIPTablesVersionString(exec, protocol)
if err != nil {
glog.Warningf("Error checking iptables version, assuming version at least %s: %v", MinCheckVersion, err)
klog.Warningf("Error checking iptables version, assuming version at least %s: %v", MinCheckVersion, err)
vstring = MinCheckVersion
}
@ -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
}
@ -197,9 +197,10 @@ const (
func (runner *runner) connectToFirewallD() {
bus, err := runner.dbus.SystemBus()
if err != nil {
glog.V(1).Infof("Could not connect to D-Bus system bus: %s", err)
klog.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,10 +318,13 @@ 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)}
glog.V(4).Infof("running %s %v", iptablesSaveCmd, args)
klog.V(4).Infof("running %s %v", iptablesSaveCmd, args)
cmd := runner.exec.Command(iptablesSaveCmd, args...)
// Since CombinedOutput() doesn't support redirecting it to a buffer,
// we need to workaround it by redirecting stdout and stderr to buffer
@ -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,9 +377,10 @@ 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)
klog.Errorf("Failed to close iptables locks: %v", err)
}
}(locker)
}
@ -380,7 +388,7 @@ func (runner *runner) restoreInternal(args []string, data []byte, flush FlushFla
// run the command and return the output or an error including the output and error
fullArgs := append(runner.restoreWaitFlag, args...)
iptablesRestoreCmd := iptablesRestoreCommand(runner.protocol)
glog.V(4).Infof("running %s %v", iptablesRestoreCmd, fullArgs)
klog.V(4).Infof("running %s %v", iptablesRestoreCmd, fullArgs)
cmd := runner.exec.Command(iptablesRestoreCmd, fullArgs...)
cmd.SetStdin(bytes.NewBuffer(data))
b, err := cmd.CombinedOutput()
@ -422,7 +430,7 @@ func (runner *runner) runContext(ctx context.Context, op operation, args []strin
iptablesCmd := iptablesCommand(runner.protocol)
fullArgs := append(runner.waitFlag, string(op))
fullArgs = append(fullArgs, args...)
glog.V(5).Infof("running iptables %s %v", string(op), args)
klog.V(5).Infof("running iptables %s %v", string(op), args)
if ctx == nil {
return runner.exec.Command(iptablesCmd, fullArgs...).CombinedOutput()
}
@ -450,7 +458,7 @@ func trimhex(s string) string {
// of hack and half-measures. We should nix this ASAP.
func (runner *runner) checkRuleWithoutCheck(table Table, chain Chain, args ...string) (bool, error) {
iptablesSaveCmd := iptablesSaveCommand(runner.protocol)
glog.V(1).Infof("running %s -t %s", iptablesSaveCmd, string(table))
klog.V(1).Infof("running %s -t %s", iptablesSaveCmd, string(table))
out, err := runner.exec.Command(iptablesSaveCmd, "-t", string(table)).CombinedOutput()
if err != nil {
return false, fmt.Errorf("error checking rule: %v", err)
@ -489,7 +497,7 @@ func (runner *runner) checkRuleWithoutCheck(table Table, chain Chain, args ...st
if sets.NewString(fields...).IsSuperset(argset) {
return true, nil
}
glog.V(5).Infof("DBG: fields is not a superset of args: fields=%v args=%v", fields, args)
klog.V(5).Infof("DBG: fields is not a superset of args: fields=%v args=%v", fields, args)
}
return false, nil
@ -536,12 +544,12 @@ func makeFullArgs(table Table, chain Chain, args ...string) []string {
func getIPTablesHasCheckCommand(vstring string) bool {
minVersion, err := utilversion.ParseGeneric(MinCheckVersion)
if err != nil {
glog.Errorf("MinCheckVersion (%s) is not a valid version string: %v", MinCheckVersion, err)
klog.Errorf("MinCheckVersion (%s) is not a valid version string: %v", MinCheckVersion, err)
return true
}
version, err := utilversion.ParseGeneric(vstring)
if err != nil {
glog.Errorf("vstring (%s) is not a valid version string: %v", vstring, err)
klog.Errorf("vstring (%s) is not a valid version string: %v", vstring, err)
return true
}
return version.AtLeast(minVersion)
@ -551,13 +559,13 @@ func getIPTablesHasCheckCommand(vstring string) bool {
func getIPTablesWaitFlag(vstring string) []string {
version, err := utilversion.ParseGeneric(vstring)
if err != nil {
glog.Errorf("vstring (%s) is not a valid version string: %v", vstring, err)
klog.Errorf("vstring (%s) is not a valid version string: %v", vstring, err)
return nil
}
minVersion, err := utilversion.ParseGeneric(WaitMinVersion)
if err != nil {
glog.Errorf("WaitMinVersion (%s) is not a valid version string: %v", WaitMinVersion, err)
klog.Errorf("WaitMinVersion (%s) is not a valid version string: %v", WaitMinVersion, err)
return nil
}
if version.LessThan(minVersion) {
@ -566,7 +574,7 @@ func getIPTablesWaitFlag(vstring string) []string {
minVersion, err = utilversion.ParseGeneric(WaitSecondsMinVersion)
if err != nil {
glog.Errorf("WaitSecondsMinVersion (%s) is not a valid version string: %v", WaitSecondsMinVersion, err)
klog.Errorf("WaitSecondsMinVersion (%s) is not a valid version string: %v", WaitSecondsMinVersion, err)
return nil
}
if version.LessThan(minVersion) {
@ -600,11 +608,11 @@ func getIPTablesVersionString(exec utilexec.Interface, protocol Protocol) (strin
func getIPTablesRestoreWaitFlag(exec utilexec.Interface, protocol Protocol) []string {
vstring, err := getIPTablesRestoreVersionString(exec, protocol)
if err != nil || vstring == "" {
glog.V(3).Infof("couldn't get iptables-restore version; assuming it doesn't support --wait")
klog.V(3).Infof("couldn't get iptables-restore version; assuming it doesn't support --wait")
return nil
}
if _, err := utilversion.ParseGeneric(vstring); err != nil {
glog.V(3).Infof("couldn't parse iptables-restore version; assuming it doesn't support --wait")
klog.V(3).Infof("couldn't parse iptables-restore version; assuming it doesn't support --wait")
return nil
}
@ -669,12 +677,21 @@ 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)
}
// runs all reload funcs to re-sync iptables rules
func (runner *runner) reload() {
glog.V(1).Infof("reloading iptables rules")
klog.V(1).Infof("reloading iptables rules")
for _, f := range runner.reloadFuncs {
f()

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,90 +28,20 @@ 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": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:darwin": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
deps = [
"//staging/src/k8s.io/apimachinery/pkg/util/version: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/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": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:plan9": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:solaris": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:windows": [
"//vendor/k8s.io/utils/exec:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
"//conditions:default": [],
}),

View File

@ -19,6 +19,11 @@ package ipvs
import (
"net"
"strconv"
"strings"
"fmt"
"k8s.io/apimachinery/pkg/util/version"
"k8s.io/utils/exec"
)
// Interface is an injectable interface for running ipvs commands. Implementations must be goroutine-safe.
@ -41,6 +46,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.
@ -65,14 +72,21 @@ const (
IPVSProxyMode = "ipvs"
)
// Sets of IPVS required kernel modules.
var ipvsModules = []string{
"ip_vs",
"ip_vs_rr",
"ip_vs_wrr",
"ip_vs_sh",
"nf_conntrack_ipv4",
}
// IPVS required kernel modules.
const (
// ModIPVS is the kernel module "ip_vs"
ModIPVS string = "ip_vs"
// ModIPVSRR is the kernel module "ip_vs_rr"
ModIPVSRR string = "ip_vs_rr"
// ModIPVSWRR is the kernel module "ip_vs_wrr"
ModIPVSWRR string = "ip_vs_wrr"
// ModIPVSSH is the kernel module "ip_vs_sh"
ModIPVSSH string = "ip_vs_sh"
// ModNfConntrackIPV4 is the module "nf_conntrack_ipv4"
ModNfConntrackIPV4 string = "nf_conntrack_ipv4"
// ModNfConntrack is the kernel module "nf_conntrack"
ModNfConntrack string = "nf_conntrack"
)
// Equal check the equality of virtual server.
// We don't use struct == since it doesn't work because of slice.
@ -91,9 +105,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 +120,31 @@ 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
}
// GetKernelVersionAndIPVSMods returns the linux kernel version and the required ipvs modules
func GetKernelVersionAndIPVSMods(Executor exec.Interface) (kernelVersion string, ipvsModules []string, err error) {
kernelVersionFile := "/proc/sys/kernel/osrelease"
out, err := Executor.Command("cut", "-f1", "-d", " ", kernelVersionFile).CombinedOutput()
if err != nil {
return "", nil, fmt.Errorf("error getting os release kernel version: %v(%s)", err, out)
}
kernelVersion = strings.TrimSpace(string(out))
// parse kernel version
ver1, err := version.ParseGeneric(kernelVersion)
if err != nil {
return kernelVersion, nil, fmt.Errorf("error parsing kernel version: %v(%s)", err, kernelVersion)
}
// "nf_conntrack_ipv4" has been removed since v4.19
// see https://github.com/torvalds/linux/commit/a0ae2562c6c4b2721d9fddba63b7286c13517d9f
ver2, _ := version.ParseGeneric("4.19")
// get required ipvs modules
if ver1.LessThan(ver2) {
ipvsModules = append(ipvsModules, ModIPVS, ModIPVSRR, ModIPVSWRR, ModIPVSSH, ModNfConntrackIPV4)
} else {
ipvsModules = append(ipvsModules, ModIPVS, ModIPVSRR, ModIPVSWRR, ModIPVSSH, ModNfConntrack)
}
return kernelVersion, ipvsModules, nil
}

View File

@ -26,7 +26,7 @@ import (
"syscall"
libipvs "github.com/docker/libnetwork/ipvs"
"github.com/golang/glog"
"k8s.io/klog"
utilexec "k8s.io/utils/exec"
)
@ -43,7 +43,7 @@ type Protocol uint16
func New(exec utilexec.Interface) Interface {
handle, err := libipvs.New("")
if err != nil {
glog.Errorf("IPVS interface can't be initialized, error: %v", err)
klog.Errorf("IPVS interface can't be initialized, error: %v", err)
return nil
}
return &runner{
@ -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

@ -26,7 +26,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
utilsexec "k8s.io/utils/exec"
"github.com/golang/glog"
"k8s.io/klog"
)
// RequiredIPVSKernelModulesAvailableCheck tests IPVS required kernel modules.
@ -42,7 +42,12 @@ func (r RequiredIPVSKernelModulesAvailableCheck) Name() string {
// Check try to validates IPVS required kernel modules exists or not.
// The name of function can not be changed.
func (r RequiredIPVSKernelModulesAvailableCheck) Check() (warnings, errors []error) {
glog.V(1).Infoln("validating the kernel module IPVS required exists in machine or not")
klog.V(1).Infoln("validating the kernel module IPVS required exists in machine or not")
kernelVersion, ipvsModules, err := GetKernelVersionAndIPVSMods(r.Executor)
if err != nil {
errors = append(errors, err)
}
// Find out loaded kernel modules
out, err := r.Executor.Command("cut", "-f1", "-d", " ", "/proc/modules").CombinedOutput()
@ -60,14 +65,6 @@ func (r RequiredIPVSKernelModulesAvailableCheck) Check() (warnings, errors []err
// Check builtin modules exist or not
if len(modules) != 0 {
kernelVersionFile := "/proc/sys/kernel/osrelease"
b, err := r.Executor.Command("cut", "-f1", "-d", " ", kernelVersionFile).CombinedOutput()
if err != nil {
errors = append(errors, fmt.Errorf("error getting os release kernel version: %v(%s)", err, out))
return nil, errors
}
kernelVersion := strings.TrimSpace(string(b))
builtinModsFilePath := fmt.Sprintf("/lib/modules/%s/modules.builtin", kernelVersion)
out, err := r.Executor.Command("cut", "-f1", "-d", " ", builtinModsFilePath).CombinedOutput()
if err != nil {

View File

@ -97,8 +97,8 @@ func TestRequiredIPVSKernelModulesAvailableCheck(t *testing.T) {
for i, tc := range cases {
fcmd := fakeexec.FakeCmd{
CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
func() ([]byte, error) { return []byte(cases[i].loadedKernel), nil },
func() ([]byte, error) { return []byte(cases[i].kernelVersion), nil },
func() ([]byte, error) { return []byte(cases[i].loadedKernel), nil },
func() ([]byte, error) { return []byte(cases[i].builtinKernel), nil },
},
}

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,9 +8,12 @@ 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"],
deps = ["//vendor/k8s.io/klog:go_default_library"],
)
go_test(

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"
"k8s.io/klog"
)
// 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) {
klog.V(5).Infof("hashedKeyMutex.LockKey(...) called for id %q\r\n", id)
km.mutexes[km.hash(id)%len(km.mutexes)].Lock()
klog.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 {
klog.V(5).Infof("hashedKeyMutex.UnlockKey(...) called for id %q\r\n", id)
km.mutexes[km.hash(id)%len(km.mutexes)].Unlock()
klog.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

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

View File

@ -1,19 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package limitwriter provides a writer that only allows a certain number of bytes to be
// written.
package limitwriter // import "k8s.io/kubernetes/pkg/util/limitwriter"

View File

@ -1,53 +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 limitwriter
import (
"errors"
"io"
)
// New creates a writer that is limited to writing at most n bytes to w. This writer is not
// thread safe.
func New(w io.Writer, n int64) io.Writer {
return &limitWriter{
w: w,
n: n,
}
}
// ErrMaximumWrite is returned when all bytes have been written.
var ErrMaximumWrite = errors.New("maximum write")
type limitWriter struct {
w io.Writer
n int64
}
func (w *limitWriter) Write(p []byte) (n int, err error) {
if int64(len(p)) > w.n {
p = p[:w.n]
}
if w.n > 0 {
n, err = w.w.Write(p)
w.n -= int64(n)
}
if w.n == 0 {
err = ErrMaximumWrite
}
return
}

View File

@ -1,93 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package limitwriter
import (
"reflect"
"testing"
)
type recordingWriter struct {
Wrote [][]byte
}
func (r *recordingWriter) Write(data []byte) (int, error) {
r.Wrote = append(r.Wrote, data)
return len(data), nil
}
func TestLimitWriter(t *testing.T) {
testcases := map[string]struct {
Limit int64
Writes [][]byte
ExpectedRecordedWrites [][]byte
ExpectedReportedWrites []int
ExpectedReportedErrors []error
}{
"empty": {},
"empty write": {
Limit: 1000,
Writes: [][]byte{{}},
ExpectedRecordedWrites: [][]byte{{}},
ExpectedReportedWrites: []int{0},
ExpectedReportedErrors: []error{nil},
},
"unlimited write": {
Limit: 1000,
Writes: [][]byte{[]byte(`foo`)},
ExpectedRecordedWrites: [][]byte{[]byte(`foo`)},
ExpectedReportedWrites: []int{3},
ExpectedReportedErrors: []error{nil},
},
"limited write": {
Limit: 5,
Writes: [][]byte{[]byte(``), []byte(`1`), []byte(`23`), []byte(`456789`), []byte(`10`), []byte(``)},
ExpectedRecordedWrites: [][]byte{[]byte(``), []byte(`1`), []byte(`23`), []byte(`45`)},
ExpectedReportedWrites: []int{0, 1, 2, 2, 0, 0},
ExpectedReportedErrors: []error{nil, nil, nil, ErrMaximumWrite, ErrMaximumWrite, ErrMaximumWrite},
},
}
for k, tc := range testcases {
var reportedWrites []int
var reportedErrors []error
recordingWriter := &recordingWriter{}
limitwriter := New(recordingWriter, tc.Limit)
for _, w := range tc.Writes {
n, err := limitwriter.Write(w)
reportedWrites = append(reportedWrites, n)
reportedErrors = append(reportedErrors, err)
}
if !reflect.DeepEqual(recordingWriter.Wrote, tc.ExpectedRecordedWrites) {
t.Errorf("%s: expected recorded writes %v, got %v", k, tc.ExpectedRecordedWrites, recordingWriter.Wrote)
}
if !reflect.DeepEqual(reportedWrites, tc.ExpectedReportedWrites) {
t.Errorf("%s: expected reported writes %v, got %v", k, tc.ExpectedReportedWrites, reportedWrites)
}
if !reflect.DeepEqual(reportedErrors, tc.ExpectedReportedErrors) {
t.Errorf("%s: expected reported errors %v, got %v", k, tc.ExpectedReportedErrors, reportedErrors)
}
}
}

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,70 +5,20 @@ 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 = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
] + select({
"@io_bazel_rules_go//go/platform:android": [
@ -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,26 +66,21 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"exec_mount_test.go",
"mount_linux_test.go",
"mount_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",
] + select({
"@io_bazel_rules_go//go/platform:linux": [
"//pkg/util/nsenter:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:windows": [

View File

@ -22,7 +22,7 @@ import (
"fmt"
"os"
"github.com/golang/glog"
"k8s.io/klog"
)
// ExecMounter is a mounter that uses provided Exec interface to mount and
@ -44,10 +44,10 @@ var _ Interface = &execMounter{}
// Mount runs mount(8) using given exec interface.
func (m *execMounter) Mount(source string, target string, fstype string, options []string) error {
bind, bindRemountOpts := isBind(options)
bind, bindOpts, bindRemountOpts := isBind(options)
if bind {
err := m.doExecMount(source, target, fstype, []string{"bind"})
err := m.doExecMount(source, target, fstype, bindOpts)
if err != nil {
return err
}
@ -59,10 +59,10 @@ func (m *execMounter) Mount(source string, target string, fstype string, options
// doExecMount calls exec(mount <what> <where>) using given exec interface.
func (m *execMounter) doExecMount(source, target, fstype string, options []string) error {
glog.V(5).Infof("Exec Mounting %s %s %s %v", source, target, fstype, options)
klog.V(5).Infof("Exec Mounting %s %s %s %v", source, target, fstype, options)
mountArgs := makeMountArgs(source, target, fstype, options)
output, err := m.exec.Run("mount", mountArgs...)
glog.V(5).Infof("Exec mounted %v: %v: %s", mountArgs, err, string(output))
klog.V(5).Infof("Exec mounted %v: %v: %s", mountArgs, err, string(output))
if err != nil {
return fmt.Errorf("mount failed: %v\nMounting command: %s\nMounting arguments: %s %s %s %v\nOutput: %s\n",
err, "mount", source, target, fstype, options, string(output))
@ -75,9 +75,9 @@ func (m *execMounter) doExecMount(source, target, fstype string, options []strin
func (m *execMounter) Unmount(target string) error {
outputBytes, err := m.exec.Run("umount", target)
if err == nil {
glog.V(5).Infof("Exec unmounted %s: %s", target, string(outputBytes))
klog.V(5).Infof("Exec unmounted %s: %s", target, string(outputBytes))
} else {
glog.V(5).Infof("Failed to exec unmount %s: err: %q, umount output: %s", target, err, string(outputBytes))
klog.V(5).Infof("Failed to exec unmount %s: err: %q, umount output: %s", target, err, string(outputBytes))
}
return err
@ -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

@ -22,13 +22,14 @@ import (
"path/filepath"
"sync"
"github.com/golang/glog"
"k8s.io/klog"
)
// FakeMounter implements mount.Interface for tests.
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
@ -82,11 +83,8 @@ func (f *FakeMounter) Mount(source string, target string, fstype string, options
}
}
}
// find 'ro' option
if option == "ro" {
// reuse MountPoint.Opts field to mark mount as readonly
opts = append(opts, "ro")
}
// reuse MountPoint.Opts field to mark mount as readonly
opts = append(opts, option)
}
// If target is a symlink, get its absolute path
@ -94,9 +92,8 @@ func (f *FakeMounter) Mount(source string, target string, fstype string, options
if err != nil {
absTarget = target
}
f.MountPoints = append(f.MountPoints, MountPoint{Device: source, Path: absTarget, Type: fstype, Opts: opts})
glog.V(5).Infof("Fake mounter: mounted %s to %s", source, absTarget)
klog.V(5).Infof("Fake mounter: mounted %s to %s", source, absTarget)
f.Log = append(f.Log, FakeAction{Action: FakeActionMount, Target: absTarget, Source: source, FSType: fstype})
return nil
}
@ -114,7 +111,7 @@ func (f *FakeMounter) Unmount(target string) error {
newMountpoints := []MountPoint{}
for _, mp := range f.MountPoints {
if mp.Path == absTarget {
glog.V(5).Infof("Fake mounter: unmounted %s from %s", mp.Device, absTarget)
klog.V(5).Infof("Fake mounter: unmounted %s from %s", mp.Device, absTarget)
// Don't copy it to newMountpoints
continue
}
@ -157,11 +154,11 @@ func (f *FakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
for _, mp := range f.MountPoints {
if mp.Path == absFile {
glog.V(5).Infof("isLikelyNotMountPoint for %s: mounted %s, false", file, mp.Path)
klog.V(5).Infof("isLikelyNotMountPoint for %s: mounted %s, false", file, mp.Path)
return false, nil
}
}
glog.V(5).Infof("isLikelyNotMountPoint for %s: true", file)
klog.V(5).Infof("isLikelyNotMountPoint for %s: true", file)
return true, nil
}
@ -190,7 +187,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 +202,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
@ -264,6 +267,13 @@ func IsNotMountPoint(mounter Interface, file string) (bool, error) {
if notMnt == false {
return notMnt, nil
}
// Resolve any symlinks in file, kernel would do the same and use the resolved path in /proc/mounts
resolvedFile, err := mounter.EvalHostSymlinks(file)
if err != nil {
return true, err
}
// check all mountpoints since IsLikelyNotMountPoint
// is not reliable for some mountpoint types
mountPoints, mountPointsErr := mounter.List()
@ -271,7 +281,7 @@ func IsNotMountPoint(mounter Interface, file string) (bool, error) {
return notMnt, mountPointsErr
}
for _, mp := range mountPoints {
if mounter.IsMountPointMatch(mp, file) {
if mounter.IsMountPointMatch(mp, resolvedFile) {
notMnt = false
break
}
@ -283,7 +293,7 @@ func IsNotMountPoint(mounter Interface, file string) (bool, error) {
// use in case of bind mount, due to the fact that bind mount doesn't respect mount options.
// The list equals:
// options - 'bind' + 'remount' (no duplicate)
func isBind(options []string) (bool, []string) {
func isBind(options []string) (bool, []string, []string) {
// Because we have an FD opened on the subpath bind mount, the "bind" option
// needs to be included, otherwise the mount target will error as busy if you
// remount as readonly.
@ -292,22 +302,36 @@ func isBind(options []string) (bool, []string) {
// volume mount to be read only.
bindRemountOpts := []string{"bind", "remount"}
bind := false
bindOpts := []string{"bind"}
if len(options) != 0 {
for _, option := range options {
switch option {
case "bind":
bind = true
break
case "remount":
break
default:
bindRemountOpts = append(bindRemountOpts, option)
}
// _netdev is a userspace mount option and does not automatically get added when
// bind mount is created and hence we must carry it over.
if checkForNetDev(options) {
bindOpts = append(bindOpts, "_netdev")
}
for _, option := range options {
switch option {
case "bind":
bind = true
break
case "remount":
break
default:
bindRemountOpts = append(bindRemountOpts, option)
}
}
return bind, bindRemountOpts
return bind, bindOpts, bindRemountOpts
}
func checkForNetDev(options []string) bool {
for _, option := range options {
if option == "_netdev" {
return true
}
}
return false
}
// TODO: this is a workaround for the unmount device issue caused by gci mounter.
@ -328,8 +352,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

@ -30,9 +30,9 @@ import (
"strings"
"syscall"
"github.com/golang/glog"
"golang.org/x/sys/unix"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/klog"
utilfile "k8s.io/kubernetes/pkg/util/file"
utilio "k8s.io/kubernetes/pkg/util/io"
utilexec "k8s.io/utils/exec"
@ -89,9 +89,9 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio
// Path to mounter binary if containerized mounter is needed. Otherwise, it is set to empty.
// All Linux distros are expected to be shipped with a mount utility that a support bind mounts.
mounterPath := ""
bind, bindRemountOpts := isBind(options)
bind, bindOpts, bindRemountOpts := isBind(options)
if bind {
err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, []string{"bind"})
err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindOpts)
if err != nil {
return err
}
@ -143,60 +143,25 @@ func (m *Mounter) doMount(mounterPath string, mountCmd string, source string, ta
// No code here, mountCmd and mountArgs are already populated.
}
glog.V(4).Infof("Mounting cmd (%s) with arguments (%s)", mountCmd, mountArgs)
klog.V(4).Infof("Mounting cmd (%s) with arguments (%s)", mountCmd, mountArgs)
command := exec.Command(mountCmd, mountArgs...)
output, err := command.CombinedOutput()
if err != nil {
args := strings.Join(mountArgs, " ")
glog.Errorf("Mount failed: %v\nMounting command: %s\nMounting arguments: %s\nOutput: %s\n", err, mountCmd, args, string(output))
klog.Errorf("Mount failed: %v\nMounting command: %s\nMounting arguments: %s\nOutput: %s\n", err, mountCmd, args, string(output))
return fmt.Errorf("mount failed: %v\nMounting command: %s\nMounting arguments: %s\nOutput: %s\n",
err, mountCmd, args, string(output))
}
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
// systemd-runs (needed by Mount()) works.
func detectSystemd() bool {
if _, err := exec.LookPath("systemd-run"); err != nil {
glog.V(2).Infof("Detected OS without systemd")
klog.V(2).Infof("Detected OS without systemd")
return false
}
// Try to run systemd-run --scope /bin/true, that should be enough
@ -206,12 +171,12 @@ func detectSystemd() bool {
cmd := exec.Command("systemd-run", "--description=Kubernetes systemd probe", "--scope", "true")
output, err := cmd.CombinedOutput()
if err != nil {
glog.V(2).Infof("Cannot run systemd-run, assuming non-systemd OS")
glog.V(4).Infof("systemd-run failed with: %v", err)
glog.V(4).Infof("systemd-run output: %s", string(output))
klog.V(2).Infof("Cannot run systemd-run, assuming non-systemd OS")
klog.V(4).Infof("systemd-run failed with: %v", err)
klog.V(4).Infof("systemd-run output: %s", string(output))
return false
}
glog.V(2).Infof("Detected OS with systemd")
klog.V(2).Infof("Detected OS with systemd")
return true
}
@ -243,7 +208,7 @@ func addSystemdScope(systemdRunPath, mountName, command string, args []string) (
// Unmount unmounts the target.
func (mounter *Mounter) Unmount(target string) error {
glog.V(4).Infof("Unmounting %s", target)
klog.V(4).Infof("Unmounting %s", target)
command := exec.Command("umount", target)
output, err := command.CombinedOutput()
if err != nil {
@ -325,7 +290,7 @@ func exclusiveOpenFailsOnDevice(pathname string) (bool, error) {
}
if !isDevice {
glog.Errorf("Path %q is not referring to a device.", pathname)
klog.Errorf("Path %q is not referring to a device.", pathname)
return false, nil
}
fd, errno := unix.Open(pathname, unix.O_RDONLY|unix.O_EXCL, 0)
@ -352,13 +317,13 @@ 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)
klog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err)
return "", err
}
if len(refs) == 0 {
glog.V(4).Infof("Directory %s is not mounted", mountPath)
klog.V(4).Infof("Directory %s is not mounted", mountPath)
return "", fmt.Errorf("directory %s is not mounted", mountPath)
}
basemountPath := path.Join(pluginDir, MountsInGlobalPDPath)
@ -366,7 +331,7 @@ func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (str
if strings.HasPrefix(ref, basemountPath) {
volumeID, err := filepath.Rel(basemountPath, ref)
if err != nil {
glog.Errorf("Failed to get volume id from mount %s - %v", mountPath, err)
klog.Errorf("Failed to get volume id from mount %s - %v", mountPath, err)
return "", err
}
return volumeID, nil
@ -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
@ -468,26 +437,26 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
if !readOnly {
// Run fsck on the disk to fix repairable issues, only do this for volumes requested as rw.
glog.V(4).Infof("Checking for issues with fsck on disk: %s", source)
klog.V(4).Infof("Checking for issues with fsck on disk: %s", source)
args := []string{"-a", source}
out, err := mounter.Exec.Run("fsck", args...)
if err != nil {
ee, isExitError := err.(utilexec.ExitError)
switch {
case err == utilexec.ErrExecutableNotFound:
glog.Warningf("'fsck' not found on system; continuing mount without running 'fsck'.")
klog.Warningf("'fsck' not found on system; continuing mount without running 'fsck'.")
case isExitError && ee.ExitStatus() == fsckErrorsCorrected:
glog.Infof("Device %s has errors which were corrected by fsck.", source)
klog.Infof("Device %s has errors which were corrected by fsck.", source)
case isExitError && ee.ExitStatus() == fsckErrorsUncorrected:
return fmt.Errorf("'fsck' found errors on device %s but could not correct them: %s.", source, string(out))
case isExitError && ee.ExitStatus() > fsckErrorsUncorrected:
glog.Infof("`fsck` error %s", string(out))
klog.Infof("`fsck` error %s", string(out))
}
}
}
// Try to mount the disk
glog.V(4).Infof("Attempting to mount disk: %s %s %s", fstype, source, target)
klog.V(4).Infof("Attempting to mount disk: %s %s %s", fstype, source, target)
mountErr := mounter.Interface.Mount(source, target, fstype, options)
if mountErr != nil {
// Mount failed. This indicates either that the disk is unformatted or
@ -516,14 +485,14 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
source,
}
}
glog.Infof("Disk %q appears to be unformatted, attempting to format as type: %q with options: %v", source, fstype, args)
klog.Infof("Disk %q appears to be unformatted, attempting to format as type: %q with options: %v", source, fstype, args)
_, err := mounter.Exec.Run("mkfs."+fstype, args...)
if err == nil {
// the disk has been formatted successfully try to mount it again.
glog.Infof("Disk successfully formatted (mkfs): %s - %s %s", fstype, source, target)
klog.Infof("Disk successfully formatted (mkfs): %s - %s %s", fstype, source, target)
return mounter.Interface.Mount(source, target, fstype, options)
}
glog.Errorf("format of disk %q failed: type:(%q) target:(%q) options:(%q)error:(%v)", source, fstype, target, options, err)
klog.Errorf("format of disk %q failed: type:(%q) target:(%q) options:(%q)error:(%v)", source, fstype, target, options, err)
return err
} else {
// Disk is already formatted and failed to mount
@ -542,10 +511,10 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
// GetDiskFormat uses 'blkid' to see if the given disk is unformated
func (mounter *SafeFormatAndMount) GetDiskFormat(disk string) (string, error) {
args := []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", disk}
glog.V(4).Infof("Attempting to determine if disk %q is formatted using blkid with args: (%v)", disk, args)
klog.V(4).Infof("Attempting to determine if disk %q is formatted using blkid with args: (%v)", disk, args)
dataOut, err := mounter.Exec.Run("blkid", args...)
output := string(dataOut)
glog.V(4).Infof("Output: %q, err: %v", output, err)
klog.V(4).Infof("Output: %q, err: %v", output, err)
if err != nil {
if exit, ok := err.(utilexec.ExitError); ok {
@ -557,7 +526,7 @@ func (mounter *SafeFormatAndMount) GetDiskFormat(disk string) (string, error) {
return "", nil
}
}
glog.Errorf("Could not determine if disk %q is formatted (%v)", disk, err)
klog.Errorf("Could not determine if disk %q is formatted (%v)", disk, err)
return "", err
}
@ -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)
klog.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
}
@ -717,11 +686,11 @@ func doMakeRShared(path string, mountInfoFilename string) error {
return err
}
if shared {
glog.V(4).Infof("Directory %s is already on a shared mount", path)
klog.V(4).Infof("Directory %s is already on a shared mount", path)
return nil
}
glog.V(2).Infof("Bind-mounting %q with shared mount propagation", path)
klog.V(2).Infof("Bind-mounting %q with shared mount propagation", path)
// mount --bind /var/lib/kubelet /var/lib/kubelet
if err := syscall.Mount(path, path, "" /*fstype*/, syscall.MS_BIND, "" /*data*/); err != nil {
return fmt.Errorf("failed to bind-mount %s: %v", path, err)
@ -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)
@ -797,7 +766,7 @@ func prepareSubpathTarget(mounter Interface, subpath Subpath) (bool, string, err
}
if !notMount {
// It's already mounted
glog.V(5).Infof("Skipping bind-mounting subpath %s: already mounted", bindPathTarget)
klog.V(5).Infof("Skipping bind-mounting subpath %s: already mounted", bindPathTarget)
return true, bindPathTarget, nil
}
@ -850,7 +819,7 @@ func doBindSubPath(mounter Interface, subpath Subpath) (hostPath string, err err
if err != nil {
return "", fmt.Errorf("error resolving symlinks in %q: %v", subpath.Path, err)
}
glog.V(5).Infof("doBindSubPath %q (%q) for volumepath %q", subpath.Path, newPath, subpath.VolumePath)
klog.V(5).Infof("doBindSubPath %q (%q) for volumepath %q", subpath.Path, newPath, subpath.VolumePath)
subpath.VolumePath = newVolumePath
subpath.Path = newPath
@ -872,9 +841,9 @@ func doBindSubPath(mounter Interface, subpath Subpath) (hostPath string, err err
defer func() {
// Cleanup subpath on error
if !success {
glog.V(4).Infof("doBindSubPath() failed for %q, cleaning up subpath", bindPathTarget)
klog.V(4).Infof("doBindSubPath() failed for %q, cleaning up subpath", bindPathTarget)
if cleanErr := cleanSubPath(mounter, subpath); cleanErr != nil {
glog.Errorf("Failed to clean subpath %q: %v", bindPathTarget, cleanErr)
klog.Errorf("Failed to clean subpath %q: %v", bindPathTarget, cleanErr)
}
}
}()
@ -884,13 +853,13 @@ func doBindSubPath(mounter Interface, subpath Subpath) (hostPath string, err err
// Do the bind mount
options := []string{"bind"}
glog.V(5).Infof("bind mounting %q at %q", mountSource, bindPathTarget)
klog.V(5).Infof("bind mounting %q at %q", mountSource, bindPathTarget)
if err = mounter.Mount(mountSource, bindPathTarget, "" /*fstype*/, options); err != nil {
return "", fmt.Errorf("error mounting %s: %s", subpath.Path, err)
}
success = true
glog.V(3).Infof("Bound SubPath %s into %s", subpath.Path, bindPathTarget)
klog.V(3).Infof("Bound SubPath %s into %s", subpath.Path, bindPathTarget)
return bindPathTarget, nil
}
@ -902,7 +871,7 @@ func (mounter *Mounter) CleanSubPaths(podDir string, volumeName string) error {
func doCleanSubPaths(mounter Interface, podDir string, volumeName string) error {
// scan /var/lib/kubelet/pods/<uid>/volume-subpaths/<volume>/*
subPathDir := filepath.Join(podDir, containerSubPathDirectoryName, volumeName)
glog.V(4).Infof("Cleaning up subpath mounts for %s", subPathDir)
klog.V(4).Infof("Cleaning up subpath mounts for %s", subPathDir)
containerDirs, err := ioutil.ReadDir(subPathDir)
if err != nil {
@ -914,10 +883,10 @@ func doCleanSubPaths(mounter Interface, podDir string, volumeName string) error
for _, containerDir := range containerDirs {
if !containerDir.IsDir() {
glog.V(4).Infof("Container file is not a directory: %s", containerDir.Name())
klog.V(4).Infof("Container file is not a directory: %s", containerDir.Name())
continue
}
glog.V(4).Infof("Cleaning up subpath mounts for container %s", containerDir.Name())
klog.V(4).Infof("Cleaning up subpath mounts for container %s", containerDir.Name())
// scan /var/lib/kubelet/pods/<uid>/volume-subpaths/<volume>/<container name>/*
fullContainerDirPath := filepath.Join(subPathDir, containerDir.Name())
@ -934,27 +903,27 @@ func doCleanSubPaths(mounter Interface, podDir string, volumeName string) error
if err := os.Remove(fullContainerDirPath); err != nil {
return fmt.Errorf("error deleting %s: %s", fullContainerDirPath, err)
}
glog.V(5).Infof("Removed %s", fullContainerDirPath)
klog.V(5).Infof("Removed %s", fullContainerDirPath)
}
// Whole pod volume subpaths have been cleaned up, remove its subpath directory.
if err := os.Remove(subPathDir); err != nil {
return fmt.Errorf("error deleting %s: %s", subPathDir, err)
}
glog.V(5).Infof("Removed %s", subPathDir)
klog.V(5).Infof("Removed %s", subPathDir)
// Remove entire subpath directory if it's the last one
podSubPathDir := filepath.Join(podDir, containerSubPathDirectoryName)
if err := os.Remove(podSubPathDir); err != nil && !os.IsExist(err) {
return fmt.Errorf("error deleting %s: %s", podSubPathDir, err)
}
glog.V(5).Infof("Removed %s", podSubPathDir)
klog.V(5).Infof("Removed %s", podSubPathDir)
return nil
}
// doCleanSubPath tears down the single subpath bind mount
func doCleanSubPath(mounter Interface, fullContainerDirPath, subPathIndex string) error {
// process /var/lib/kubelet/pods/<uid>/volume-subpaths/<volume>/<container name>/<subPathName>
glog.V(4).Infof("Cleaning up subpath mounts for subpath %v", subPathIndex)
klog.V(4).Infof("Cleaning up subpath mounts for subpath %v", subPathIndex)
fullSubPath := filepath.Join(fullContainerDirPath, subPathIndex)
notMnt, err := IsNotMountPoint(mounter, fullSubPath)
if err != nil {
@ -965,13 +934,13 @@ func doCleanSubPath(mounter Interface, fullContainerDirPath, subPathIndex string
if err = mounter.Unmount(fullSubPath); err != nil {
return fmt.Errorf("error unmounting %s: %s", fullSubPath, err)
}
glog.V(5).Infof("Unmounted %s", fullSubPath)
klog.V(5).Infof("Unmounted %s", fullSubPath)
}
// Remove it *non*-recursively, just in case there were some hiccups.
if err = os.Remove(fullSubPath); err != nil {
return fmt.Errorf("error deleting %s: %s", fullSubPath, err)
}
glog.V(5).Infof("Removed %s", fullSubPath)
klog.V(5).Infof("Removed %s", fullSubPath)
return nil
}
@ -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)
}
@ -1003,7 +972,7 @@ func removeEmptyDirs(baseDir, endDir string) error {
s, err := os.Stat(curDir)
if err != nil {
if os.IsNotExist(err) {
glog.V(5).Infof("curDir %q doesn't exist, skipping", curDir)
klog.V(5).Infof("curDir %q doesn't exist, skipping", curDir)
continue
}
return fmt.Errorf("error stat %q: %v", curDir, err)
@ -1014,12 +983,12 @@ func removeEmptyDirs(baseDir, endDir string) error {
err = os.Remove(curDir)
if os.IsExist(err) {
glog.V(5).Infof("Directory %q not empty, not removing", curDir)
klog.V(5).Infof("Directory %q not empty, not removing", curDir)
break
} else if err != nil {
return fmt.Errorf("error removing directory %q: %v", curDir, err)
}
glog.V(5).Infof("Removed directory %q", curDir)
klog.V(5).Infof("Removed directory %q", curDir)
}
return nil
}
@ -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
@ -1081,9 +1055,9 @@ func getMode(pathname string) (os.FileMode, error) {
// and base must be either already resolved symlinks or thet will be resolved in
// kubelet's mount namespace (in case it runs containerized).
func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
glog.V(4).Infof("Creating directory %q within base %q", pathname, base)
klog.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)
}
@ -1094,7 +1068,7 @@ func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
if s.IsDir() {
// The directory already exists. It can be outside of the parent,
// but there is no race-proof check.
glog.V(4).Infof("Directory %s already exists", pathname)
klog.V(4).Infof("Directory %s already exists", pathname)
return nil
}
return &os.PathError{Op: "mkdir", Path: pathname, Err: syscall.ENOTDIR}
@ -1110,11 +1084,11 @@ 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)
}
glog.V(4).Infof("%q already exists, %q to create", fullExistingPath, filepath.Join(toCreate...))
klog.V(4).Infof("%q already exists, %q to create", fullExistingPath, filepath.Join(toCreate...))
parentFD, err := doSafeOpen(fullExistingPath, base)
if err != nil {
return fmt.Errorf("cannot open directory %s: %s", existingPath, err)
@ -1123,12 +1097,12 @@ func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
defer func() {
if parentFD != -1 {
if err = syscall.Close(parentFD); err != nil {
glog.V(4).Infof("Closing FD %v failed for safemkdir(%v): %v", parentFD, pathname, err)
klog.V(4).Infof("Closing FD %v failed for safemkdir(%v): %v", parentFD, pathname, err)
}
}
if childFD != -1 {
if err = syscall.Close(childFD); err != nil {
glog.V(4).Infof("Closing FD %v failed for safemkdir(%v): %v", childFD, pathname, err)
klog.V(4).Infof("Closing FD %v failed for safemkdir(%v): %v", childFD, pathname, err)
}
}
}()
@ -1138,7 +1112,7 @@ func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
// created directory into symlink.
for _, dir := range toCreate {
currentPath = filepath.Join(currentPath, dir)
glog.V(4).Infof("Creating %s", dir)
klog.V(4).Infof("Creating %s", dir)
err = syscall.Mkdirat(parentFD, currentPath, uint32(perm))
if err != nil {
return fmt.Errorf("cannot create directory %s: %s", currentPath, err)
@ -1157,7 +1131,7 @@ func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
// and user either gets error or the file that it can already access.
if err = syscall.Close(parentFD); err != nil {
glog.V(4).Infof("Closing FD %v failed for safemkdir(%v): %v", parentFD, pathname, err)
klog.V(4).Infof("Closing FD %v failed for safemkdir(%v): %v", parentFD, pathname, err)
}
parentFD = childFD
childFD = -1
@ -1206,7 +1180,7 @@ func findExistingPrefix(base, pathname string) (string, []string, error) {
}
defer func() {
if err = syscall.Close(fd); err != nil {
glog.V(4).Infof("Closing FD %v failed for findExistingPrefix(%v): %v", fd, pathname, err)
klog.V(4).Infof("Closing FD %v failed for findExistingPrefix(%v): %v", fd, pathname, err)
}
}()
for i, dir := range dirs {
@ -1220,7 +1194,7 @@ func findExistingPrefix(base, pathname string) (string, []string, error) {
return base, nil, err
}
if err = syscall.Close(fd); err != nil {
glog.V(4).Infof("Closing FD %v failed for findExistingPrefix(%v): %v", fd, pathname, err)
klog.V(4).Infof("Closing FD %v failed for findExistingPrefix(%v): %v", fd, pathname, err)
}
fd = childFD
currentPath = filepath.Join(currentPath, dir)
@ -1252,7 +1226,7 @@ func doSafeOpen(pathname string, base string) (int, error) {
defer func() {
if parentFD != -1 {
if err = syscall.Close(parentFD); err != nil {
glog.V(4).Infof("Closing FD %v failed for safeopen(%v): %v", parentFD, pathname, err)
klog.V(4).Infof("Closing FD %v failed for safeopen(%v): %v", parentFD, pathname, err)
}
}
}()
@ -1261,7 +1235,7 @@ func doSafeOpen(pathname string, base string) (int, error) {
defer func() {
if childFD != -1 {
if err = syscall.Close(childFD); err != nil {
glog.V(4).Infof("Closing FD %v failed for safeopen(%v): %v", childFD, pathname, err)
klog.V(4).Infof("Closing FD %v failed for safeopen(%v): %v", childFD, pathname, err)
}
}
}()
@ -1272,11 +1246,11 @@ 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)
}
glog.V(5).Infof("Opening path %s", currentPath)
klog.V(5).Infof("Opening path %s", currentPath)
childFD, err = syscall.Openat(parentFD, seg, openFDFlags, 0)
if err != nil {
return -1, fmt.Errorf("cannot open %s: %s", currentPath, err)
@ -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

@ -32,7 +32,7 @@ import (
"k8s.io/utils/exec"
"github.com/golang/glog"
"k8s.io/klog"
)
func TestReadProcMountsFrom(t *testing.T) {
@ -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)
}
@ -630,7 +634,7 @@ func TestSafeMakeDir(t *testing.T) {
}
for _, test := range tests {
glog.V(4).Infof("test %q", test.name)
klog.V(4).Infof("test %q", test.name)
base, err := ioutil.TempDir("", "safe-make-dir-"+test.name+"-")
if err != nil {
t.Fatalf(err.Error())
@ -642,7 +646,7 @@ func TestSafeMakeDir(t *testing.T) {
t.Errorf("test %q: %s", test.name, err)
}
if err != nil {
glog.Infof("got error: %s", err)
klog.Infof("got error: %s", err)
}
if err == nil && test.expectError {
t.Errorf("test %q: expected error, got none", test.name)
@ -788,7 +792,7 @@ func TestRemoveEmptyDirs(t *testing.T) {
}
for _, test := range tests {
glog.V(4).Infof("test %q", test.name)
klog.V(4).Infof("test %q", test.name)
base, err := ioutil.TempDir("", "remove-empty-dirs-"+test.name+"-")
if err != nil {
t.Fatalf(err.Error())
@ -959,7 +963,7 @@ func TestCleanSubPaths(t *testing.T) {
}
for _, test := range tests {
glog.V(4).Infof("test %q", test.name)
klog.V(4).Infof("test %q", test.name)
base, err := ioutil.TempDir("", "clean-subpaths-"+test.name+"-")
if err != nil {
t.Fatalf(err.Error())
@ -1215,7 +1219,7 @@ func TestBindSubPath(t *testing.T) {
}
for _, test := range tests {
glog.V(4).Infof("test %q", test.name)
klog.V(4).Infof("test %q", test.name)
base, err := ioutil.TempDir("", "bind-subpath-"+test.name+"-")
if err != nil {
t.Fatalf(err.Error())
@ -1647,7 +1651,7 @@ func TestSafeOpen(t *testing.T) {
}
for _, test := range tests {
glog.V(4).Infof("test %q", test.name)
klog.V(4).Infof("test %q", test.name)
base, err := ioutil.TempDir("", "safe-open-"+test.name+"-")
if err != nil {
t.Fatalf(err.Error())
@ -1660,7 +1664,7 @@ func TestSafeOpen(t *testing.T) {
t.Errorf("test %q: %s", test.name, err)
}
if err != nil {
glog.Infof("got error: %s", err)
klog.Infof("got error: %s", err)
}
if err == nil && test.expectError {
t.Errorf("test %q: expected error, got none", test.name)
@ -1794,7 +1798,7 @@ func TestFindExistingPrefix(t *testing.T) {
}
for _, test := range tests {
glog.V(4).Infof("test %q", test.name)
klog.V(4).Infof("test %q", test.name)
base, err := ioutil.TempDir("", "find-prefix-"+test.name+"-")
if err != nil {
t.Fatalf(err.Error())
@ -1806,7 +1810,7 @@ func TestFindExistingPrefix(t *testing.T) {
t.Errorf("test %q: %s", test.name, err)
}
if err != nil {
glog.Infof("got error: %s", err)
klog.Infof("got error: %s", err)
}
if err == nil && test.expectError {
t.Errorf("test %q: expected error, got none", test.name)

60
vendor/k8s.io/kubernetes/pkg/util/mount/mount_test.go generated vendored Normal file
View File

@ -0,0 +1,60 @@
/*
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 mount
import (
"reflect"
"testing"
)
func TestIsBind(t *testing.T) {
tests := []struct {
mountOption []string
isBind bool
expectedBindOpts []string
expectedRemountOpts []string
}{
{
[]string{"vers=2", "ro", "_netdev"},
false,
[]string{},
[]string{},
},
{
[]string{"bind", "vers=2", "ro", "_netdev"},
true,
[]string{"bind", "_netdev"},
[]string{"bind", "remount", "vers=2", "ro", "_netdev"},
},
}
for _, test := range tests {
bind, bindOpts, bindRemountOpts := isBind(test.mountOption)
if bind != test.isBind {
t.Errorf("Expected bind to be %v but got %v", test.isBind, bind)
}
if test.isBind {
if !reflect.DeepEqual(test.expectedBindOpts, bindOpts) {
t.Errorf("Expected bind mount options to be %+v got %+v", test.expectedBindOpts, bindOpts)
}
if !reflect.DeepEqual(test.expectedRemountOpts, bindRemountOpts) {
t.Errorf("Expected remount options to be %+v got %+v", test.expectedRemountOpts, bindRemountOpts)
}
}
}
}

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

@ -28,7 +28,7 @@ import (
"strings"
"syscall"
"github.com/golang/glog"
"k8s.io/klog"
utilfile "k8s.io/kubernetes/pkg/util/file"
)
@ -54,7 +54,7 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio
target = normalizeWindowsPath(target)
if source == "tmpfs" {
glog.V(3).Infof("azureMount: mounting source (%q), target (%q), with options (%q)", source, target, options)
klog.V(3).Infof("azureMount: mounting source (%q), target (%q), with options (%q)", source, target, options)
return os.MkdirAll(target, 0755)
}
@ -63,17 +63,17 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio
return err
}
glog.V(4).Infof("azureMount: mount options(%q) source:%q, target:%q, fstype:%q, begin to mount",
klog.V(4).Infof("azureMount: mount options(%q) source:%q, target:%q, fstype:%q, begin to mount",
options, source, target, fstype)
bindSource := ""
// tell it's going to mount azure disk or azure file according to options
if bind, _ := isBind(options); bind {
if bind, _, _ := isBind(options); bind {
// mount azure disk
bindSource = normalizeWindowsPath(source)
} else {
if len(options) < 2 {
glog.Warningf("azureMount: mount options(%q) command number(%d) less than 2, source:%q, target:%q, skip mounting",
klog.Warningf("azureMount: mount options(%q) command number(%d) less than 2, source:%q, target:%q, skip mounting",
options, len(options), source, target)
return nil
}
@ -83,20 +83,26 @@ 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))
}
}
if output, err := exec.Command("cmd", "/c", "mklink", "/D", target, bindSource).CombinedOutput(); err != nil {
glog.Errorf("mklink failed: %v, source(%q) target(%q) output: %q", err, bindSource, target, string(output))
klog.Errorf("mklink failed: %v, source(%q) target(%q) output: %q", err, bindSource, target, string(output))
return err
}
@ -105,25 +111,15 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio
// Unmount unmounts the target.
func (mounter *Mounter) Unmount(target string) error {
glog.V(4).Infof("azureMount: Unmount target (%q)", target)
klog.V(4).Infof("azureMount: Unmount target (%q)", target)
target = normalizeWindowsPath(target)
if output, err := exec.Command("cmd", "/c", "rmdir", target).CombinedOutput(); err != nil {
glog.Errorf("rmdir failed: %v, output: %q", err, string(output))
klog.Errorf("rmdir failed: %v, output: %q", err, string(output))
return err
}
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,9 +166,9 @@ 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)
klog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err)
return "", err
}
if len(refs) == 0 {
@ -183,7 +179,7 @@ func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (str
if strings.Contains(ref, basemountPath) {
volumeID, err := filepath.Rel(normalizeWindowsPath(basemountPath), ref)
if err != nil {
glog.Errorf("Failed to get volume id from mount %s - %v", mountPath, err)
klog.Errorf("Failed to get volume id from mount %s - %v", mountPath, err)
return "", err
}
return volumeID, nil
@ -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
}
@ -361,10 +362,10 @@ func (mounter *Mounter) CleanSubPaths(podDir string, volumeName string) error {
func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, fstype string, options []string) error {
// Try to mount the disk
glog.V(4).Infof("Attempting to formatAndMount disk: %s %s %s", fstype, source, target)
klog.V(4).Infof("Attempting to formatAndMount disk: %s %s %s", fstype, source, target)
if err := ValidateDiskNumber(source); err != nil {
glog.Errorf("diskMount: formatAndMount failed, err: %v", err)
klog.Errorf("diskMount: formatAndMount failed, err: %v", err)
return err
}
@ -379,7 +380,7 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
if output, err := mounter.Exec.Run("powershell", "/c", cmd); err != nil {
return fmt.Errorf("diskMount: format disk failed, error: %v, output: %q", err, string(output))
}
glog.V(4).Infof("diskMount: Disk successfully formatted, disk: %q, fstype: %q", source, fstype)
klog.V(4).Infof("diskMount: Disk successfully formatted, disk: %q, fstype: %q", source, fstype)
driveLetter, err := getDriveLetterByDiskNumber(source, mounter.Exec)
if err != nil {
@ -387,9 +388,9 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
}
driverPath := driveLetter + ":"
target = normalizeWindowsPath(target)
glog.V(4).Infof("Attempting to formatAndMount disk: %s %s %s", fstype, driverPath, target)
klog.V(4).Infof("Attempting to formatAndMount disk: %s %s %s", fstype, driverPath, target)
if output, err := mounter.Exec.Run("cmd", "/c", "mklink", "/D", target, driverPath); err != nil {
glog.Errorf("mklink failed: %v, output: %q", err, string(output))
klog.Errorf("mklink failed: %v, output: %q", err, string(output))
return err
}
return nil
@ -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
@ -496,9 +499,9 @@ 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)
klog.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)
}
@ -509,7 +512,7 @@ func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
if s.IsDir() {
// The directory already exists. It can be outside of the parent,
// but there is no race-proof check.
glog.V(4).Infof("Directory %s already exists", pathname)
klog.V(4).Infof("Directory %s already exists", pathname)
return nil
}
return &os.PathError{Op: "mkdir", Path: pathname, Err: syscall.ENOTDIR}
@ -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)
}
@ -544,13 +547,13 @@ func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
return err
}
glog.V(4).Infof("%q already exists, %q to create", fullExistingPath, filepath.Join(toCreate...))
klog.V(4).Infof("%q already exists, %q to create", fullExistingPath, filepath.Join(toCreate...))
currentPath := fullExistingPath
// create the directories one by one, making sure nobody can change
// created directory into symlink by lock that directory immediately
for _, dir := range toCreate {
currentPath = filepath.Join(currentPath, dir)
glog.V(4).Infof("Creating %s", dir)
klog.V(4).Infof("Creating %s", dir)
if err := os.Mkdir(currentPath, perm); err != nil {
return fmt.Errorf("cannot create directory %s: %s", currentPath, 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

@ -25,8 +25,8 @@ import (
"strings"
"syscall"
"github.com/golang/glog"
"golang.org/x/sys/unix"
"k8s.io/klog"
utilfile "k8s.io/kubernetes/pkg/util/file"
"k8s.io/kubernetes/pkg/util/nsenter"
)
@ -61,10 +61,10 @@ var _ = Interface(&NsenterMounter{})
// Mount runs mount(8) in the host's root mount namespace. Aside from this
// aspect, Mount has the same semantics as the mounter returned by mount.New()
func (n *NsenterMounter) Mount(source string, target string, fstype string, options []string) error {
bind, bindRemountOpts := isBind(options)
bind, bindOpts, bindRemountOpts := isBind(options)
if bind {
err := n.doNsenterMount(source, target, fstype, []string{"bind"})
err := n.doNsenterMount(source, target, fstype, bindOpts)
if err != nil {
return err
}
@ -77,11 +77,11 @@ func (n *NsenterMounter) Mount(source string, target string, fstype string, opti
// doNsenterMount nsenters the host's mount namespace and performs the
// requested mount.
func (n *NsenterMounter) doNsenterMount(source, target, fstype string, options []string) error {
glog.V(5).Infof("nsenter mount %s %s %s %v", source, target, fstype, options)
klog.V(5).Infof("nsenter mount %s %s %s %v", source, target, fstype, options)
cmd, args := n.makeNsenterArgs(source, target, fstype, options)
outputBytes, err := n.ne.Exec(cmd, args).CombinedOutput()
if len(outputBytes) != 0 {
glog.V(5).Infof("Output of mounting %s to %s: %v", source, target, string(outputBytes))
klog.V(5).Infof("Output of mounting %s to %s: %v", source, target, string(outputBytes))
}
return err
}
@ -131,10 +131,10 @@ func (n *NsenterMounter) Unmount(target string) error {
// No need to execute systemd-run here, it's enough that unmount is executed
// in the host's mount namespace. It will finish appropriate fuse daemon(s)
// running in any scope.
glog.V(5).Infof("nsenter unmount args: %v", args)
klog.V(5).Infof("nsenter unmount args: %v", args)
outputBytes, err := n.ne.Exec("umount", args).CombinedOutput()
if len(outputBytes) != 0 {
glog.V(5).Infof("Output of unmounting %s: %v", target, string(outputBytes))
klog.V(5).Infof("Output of unmounting %s: %v", target, string(outputBytes))
}
return err
}
@ -163,18 +163,25 @@ func (n *NsenterMounter) IsLikelyNotMountPoint(file string) (bool, error) {
// Check the directory exists
if _, err = os.Stat(file); os.IsNotExist(err) {
glog.V(5).Infof("findmnt: directory %s does not exist", file)
klog.V(5).Infof("findmnt: directory %s does not exist", file)
return true, err
}
// Resolve any symlinks in file, kernel would do the same and use the resolved path in /proc/mounts
resolvedFile, err := n.EvalHostSymlinks(file)
if err != nil {
return true, err
}
// Add --first-only option: since we are testing for the absence of a mountpoint, it is sufficient to get only
// the first of multiple possible mountpoints using --first-only.
// Also add fstype output to make sure that the output of target file will give the full path
// TODO: Need more refactoring for this function. Track the solution with issue #26996
args := []string{"-o", "target,fstype", "--noheadings", "--first-only", "--target", file}
glog.V(5).Infof("nsenter findmnt args: %v", args)
args := []string{"-o", "target,fstype", "--noheadings", "--first-only", "--target", resolvedFile}
klog.V(5).Infof("nsenter findmnt args: %v", args)
out, err := n.ne.Exec("findmnt", args).CombinedOutput()
if err != nil {
glog.V(2).Infof("Failed findmnt command for path %s: %s %v", file, out, err)
klog.V(2).Infof("Failed findmnt command for path %s: %s %v", resolvedFile, out, err)
// Different operating systems behave differently for paths which are not mount points.
// On older versions (e.g. 2.20.1) we'd get error, on newer ones (e.g. 2.26.2) we'd get "/".
// It's safer to assume that it's not a mount point.
@ -185,13 +192,13 @@ func (n *NsenterMounter) IsLikelyNotMountPoint(file string) (bool, error) {
return false, err
}
glog.V(5).Infof("IsLikelyNotMountPoint findmnt output for path %s: %v:", file, mountTarget)
klog.V(5).Infof("IsLikelyNotMountPoint findmnt output for path %s: %v:", resolvedFile, mountTarget)
if mountTarget == file {
glog.V(5).Infof("IsLikelyNotMountPoint: %s is a mount point", file)
if mountTarget == resolvedFile {
klog.V(5).Infof("IsLikelyNotMountPoint: %s is a mount point", resolvedFile)
return false, nil
}
glog.V(5).Infof("IsLikelyNotMountPoint: %s is not a mount point", file)
klog.V(5).Infof("IsLikelyNotMountPoint: %s is not a mount point", resolvedFile)
return true, nil
}
@ -287,6 +294,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 +327,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 +344,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
@ -357,7 +375,7 @@ func doNsEnterBindSubPath(mounter *NsenterMounter, subpath Subpath) (hostPath st
if err != nil {
return "", fmt.Errorf("error resolving symlinks in %q: %v", subpath.Path, err)
}
glog.V(5).Infof("doBindSubPath %q (%q) for volumepath %q", subpath.Path, evaluatedHostSubpath, subpath.VolumePath)
klog.V(5).Infof("doBindSubPath %q (%q) for volumepath %q", subpath.Path, evaluatedHostSubpath, subpath.VolumePath)
subpath.VolumePath = mounter.ne.KubeletPath(evaluatedHostVolumePath)
subpath.Path = mounter.ne.KubeletPath(evaluatedHostSubpath)
@ -380,9 +398,9 @@ func doNsEnterBindSubPath(mounter *NsenterMounter, subpath Subpath) (hostPath st
defer func() {
// Cleanup subpath on error
if !success {
glog.V(4).Infof("doNsEnterBindSubPath() failed for %q, cleaning up subpath", bindPathTarget)
klog.V(4).Infof("doNsEnterBindSubPath() failed for %q, cleaning up subpath", bindPathTarget)
if cleanErr := cleanSubPath(mounter, subpath); cleanErr != nil {
glog.Errorf("Failed to clean subpath %q: %v", bindPathTarget, cleanErr)
klog.Errorf("Failed to clean subpath %q: %v", bindPathTarget, cleanErr)
}
}
}()
@ -390,7 +408,7 @@ func doNsEnterBindSubPath(mounter *NsenterMounter, subpath Subpath) (hostPath st
// Leap of faith: optimistically expect that nobody has modified previously
// expanded evalSubPath with evil symlinks and bind-mount it.
// Mount is done on the host! don't use kubelet path!
glog.V(5).Infof("bind mounting %q at %q", evaluatedHostSubpath, bindPathTarget)
klog.V(5).Infof("bind mounting %q at %q", evaluatedHostSubpath, bindPathTarget)
if err = mounter.Mount(evaluatedHostSubpath, bindPathTarget, "" /*fstype*/, []string{"bind"}); err != nil {
return "", fmt.Errorf("error mounting %s: %s", evaluatedHostSubpath, err)
}
@ -403,7 +421,7 @@ func doNsEnterBindSubPath(mounter *NsenterMounter, subpath Subpath) (hostPath st
}
success = true
glog.V(3).Infof("Bound SubPath %s into %s", subpath.Path, bindPathTarget)
klog.V(3).Infof("Bound SubPath %s into %s", subpath.Path, bindPathTarget)
return bindPathTarget, nil
}

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

@ -14,7 +14,7 @@ go_library(
],
importpath = "k8s.io/kubernetes/pkg/util/netsh",
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
)

View File

@ -24,7 +24,7 @@ import (
"sync"
"time"
"github.com/golang/glog"
"k8s.io/klog"
utilexec "k8s.io/utils/exec"
)
@ -68,7 +68,7 @@ func New(exec utilexec.Interface) Interface {
// EnsurePortProxyRule checks if the specified redirect exists, if not creates it.
func (runner *runner) EnsurePortProxyRule(args []string) (bool, error) {
glog.V(4).Infof("running netsh interface portproxy add v4tov4 %v", args)
klog.V(4).Infof("running netsh interface portproxy add v4tov4 %v", args)
out, err := runner.exec.Command(cmdNetsh, args...).CombinedOutput()
if err == nil {
@ -87,7 +87,7 @@ func (runner *runner) EnsurePortProxyRule(args []string) (bool, error) {
// DeletePortProxyRule deletes the specified portproxy rule. If the rule did not exist, return error.
func (runner *runner) DeletePortProxyRule(args []string) error {
glog.V(4).Infof("running netsh interface portproxy delete v4tov4 %v", args)
klog.V(4).Infof("running netsh interface portproxy delete v4tov4 %v", args)
out, err := runner.exec.Command(cmdNetsh, args...).CombinedOutput()
if err == nil {
@ -116,12 +116,12 @@ func (runner *runner) EnsureIPAddress(args []string, ip net.IP) (bool, error) {
exists, _ := checkIPExists(ipToCheck, argsShowAddress, runner)
if exists == true {
glog.V(4).Infof("not adding IP address %q as it already exists", ipToCheck)
klog.V(4).Infof("not adding IP address %q as it already exists", ipToCheck)
return true, nil
}
// IP Address is not already added, add it now
glog.V(4).Infof("running netsh interface ipv4 add address %v", args)
klog.V(4).Infof("running netsh interface ipv4 add address %v", args)
out, err := runner.exec.Command(cmdNetsh, args...).CombinedOutput()
if err == nil {
@ -129,7 +129,7 @@ func (runner *runner) EnsureIPAddress(args []string, ip net.IP) (bool, error) {
// Query all the IP addresses and see if the one we added is present
// PS: We are using netsh interface ipv4 show address here to query all the IP addresses, instead of
// querying net.InterfaceAddrs() as it returns the IP address as soon as it is added even though it is uninitialized
glog.V(3).Infof("Waiting until IP: %v is added to the network adapter", ipToCheck)
klog.V(3).Infof("Waiting until IP: %v is added to the network adapter", ipToCheck)
for {
if exists, _ := checkIPExists(ipToCheck, argsShowAddress, runner); exists {
return true, nil
@ -149,7 +149,7 @@ func (runner *runner) EnsureIPAddress(args []string, ip net.IP) (bool, error) {
// DeleteIPAddress checks if the specified IP address is present and, if so, deletes it.
func (runner *runner) DeleteIPAddress(args []string) error {
glog.V(4).Infof("running netsh interface ipv4 delete address %v", args)
klog.V(4).Infof("running netsh interface ipv4 delete address %v", args)
out, err := runner.exec.Command(cmdNetsh, args...).CombinedOutput()
if err == nil {
@ -187,7 +187,7 @@ func checkIPExists(ipToCheck string, args []string, runner *runner) (bool, error
return false, err
}
ipAddressString := string(ipAddress[:])
glog.V(3).Infof("Searching for IP: %v in IP dump: %v", ipToCheck, ipAddressString)
klog.V(3).Infof("Searching for IP: %v in IP dump: %v", ipToCheck, ipAddressString)
showAddressArray := strings.Split(ipAddressString, "\n")
for _, showAddress := range showAddressArray {
if strings.Contains(showAddress, "IP") {

View File

@ -11,15 +11,14 @@ 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",
"//vendor/k8s.io/klog:go_default_library",
],
)
@ -29,8 +28,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,35 +24,44 @@ import (
"strings"
"time"
"github.com/golang/glog"
"k8s.io/klog"
"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"
)
const (
// The reason and message set on a pod when its state cannot be confirmed as kubelet is unresponsive
// NodeUnreachablePodReason is the reason on a pod when its state cannot be confirmed as kubelet is unresponsive
// on the node it is (was) running.
NodeUnreachablePodReason = "NodeLost"
// NodeUnreachablePodMessage is the message on a pod when its state cannot be confirmed as kubelet is unresponsive
// on the node it is (was) running.
NodeUnreachablePodReason = "NodeLost"
NodeUnreachablePodMessage = "Node %v which was running pod %v is unresponsive"
)
// 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 +73,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,22 +95,20 @@ 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])
// GetNodeIP returns the ip of node with the provided hostname
func GetNodeIP(client clientset.Interface, hostname string) net.IP {
var nodeIP net.IP
node, err := client.CoreV1().Nodes().Get(hostname, metav1.GetOptions{})
if err != nil {
klog.Warningf("Failed to retrieve node info: %v", err)
return nil
}
if addresses, ok := addressMap[api.NodeInternalIP]; ok {
return net.ParseIP(addresses[0].Address), nil
nodeIP, err = GetNodeHostIP(node)
if err != nil {
klog.Warningf("Failed to retrieve node IP: %v", err)
return 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)
return nodeIP
}
// GetZoneKey is a helper function that builds a string identifier that is unique per failure-zone;

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({
@ -54,7 +24,7 @@ go_library(
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:linux": [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:nacl": [
@ -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"
"k8s.io/klog"
"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...)...)
klog.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...)...)
klog.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

@ -28,7 +28,7 @@ import (
"k8s.io/utils/exec"
"github.com/golang/glog"
"k8s.io/klog"
)
const (
@ -127,7 +127,7 @@ func (ne *Nsenter) Exec(cmd string, args []string) exec.Cmd {
hostProcMountNsPath := filepath.Join(ne.hostRootFsPath, mountNsPath)
fullArgs := append([]string{fmt.Sprintf("--mount=%s", hostProcMountNsPath), "--"},
append([]string{ne.AbsHostPath(cmd)}, args...)...)
glog.V(5).Infof("Running nsenter command: %v %v", nsenterPath, fullArgs)
klog.V(5).Infof("Running nsenter command: %v %v", nsenterPath, fullArgs)
return ne.executor.Command(nsenterPath, fullArgs...)
}
@ -170,7 +170,7 @@ func (ne *Nsenter) EvalSymlinks(pathname string, mustExist bool) (string, error)
}
outBytes, err := ne.Exec("realpath", args).CombinedOutput()
if err != nil {
glog.Infof("failed to resolve symbolic links on %s: %v", pathname, err)
klog.Infof("failed to resolve symbolic links on %s: %v", pathname, err)
return "", err
}
return strings.TrimSpace(string(outBytes)), nil

View File

@ -12,47 +12,14 @@ 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": [
"//pkg/kubelet/cm/util:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/klog: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": [
"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

@ -29,7 +29,7 @@ import (
cmutil "k8s.io/kubernetes/pkg/kubelet/cm/util"
"github.com/golang/glog"
"k8s.io/klog"
)
func NewOOMAdjuster() *OOMAdjuster {
@ -62,24 +62,24 @@ func applyOOMScoreAdj(pid int, oomScoreAdj int) error {
maxTries := 2
oomScoreAdjPath := path.Join("/proc", pidStr, "oom_score_adj")
value := strconv.Itoa(oomScoreAdj)
glog.V(4).Infof("attempting to set %q to %q", oomScoreAdjPath, value)
klog.V(4).Infof("attempting to set %q to %q", oomScoreAdjPath, value)
var err error
for i := 0; i < maxTries; i++ {
err = ioutil.WriteFile(oomScoreAdjPath, []byte(value), 0700)
if err != nil {
if os.IsNotExist(err) {
glog.V(2).Infof("%q does not exist", oomScoreAdjPath)
klog.V(2).Infof("%q does not exist", oomScoreAdjPath)
return os.ErrNotExist
}
glog.V(3).Info(err)
klog.V(3).Info(err)
time.Sleep(100 * time.Millisecond)
continue
}
return nil
}
if err != nil {
glog.V(2).Infof("failed to set %q to %q: %v", oomScoreAdjPath, value, err)
klog.V(2).Infof("failed to set %q to %q: %v", oomScoreAdjPath, value, err)
}
return err
}
@ -97,20 +97,20 @@ func (oomAdjuster *OOMAdjuster) applyOOMScoreAdjContainer(cgroupName string, oom
return os.ErrNotExist
}
continueAdjusting = true
glog.V(10).Infof("Error getting process list for cgroup %s: %+v", cgroupName, err)
klog.V(10).Infof("Error getting process list for cgroup %s: %+v", cgroupName, err)
} else if len(pidList) == 0 {
glog.V(10).Infof("Pid list is empty")
klog.V(10).Infof("Pid list is empty")
continueAdjusting = true
} else {
for _, pid := range pidList {
if !adjustedProcessSet[pid] {
glog.V(10).Infof("pid %d needs to be set", pid)
klog.V(10).Infof("pid %d needs to be set", pid)
if err = oomAdjuster.ApplyOOMScoreAdj(pid, oomScoreAdj); err == nil {
adjustedProcessSet[pid] = true
} else if err == os.ErrNotExist {
continue
} else {
glog.V(10).Infof("cannot adjust oom score for pid %d - %v", pid, err)
klog.V(10).Infof("cannot adjust oom score for pid %d - %v", pid, err)
continueAdjusting = true
}
// Processes can come and go while we try to apply oom score adjust value. So ignore errors here.

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": [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/k8s.io/klog: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

@ -21,6 +21,7 @@ package procfs
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path"
@ -31,8 +32,8 @@ import (
"syscall"
"unicode"
"github.com/golang/glog"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/klog"
)
type ProcFS struct{}
@ -105,47 +106,60 @@ func PidOf(name string) ([]int, error) {
func getPids(re *regexp.Regexp) []int {
pids := []int{}
filepath.Walk("/proc", func(path string, info os.FileInfo, err error) error {
dirFD, err := os.Open("/proc")
if err != nil {
return nil
}
defer dirFD.Close()
for {
// Read a small number at a time in case there are many entries, we don't want to
// allocate a lot here.
ls, err := dirFD.Readdir(10)
if err == io.EOF {
break
}
if err != nil {
// We should continue processing other directories/files
return nil
}
base := filepath.Base(path)
// Traverse only the directories we are interested in
if info.IsDir() && path != "/proc" {
for _, entry := range ls {
if !entry.IsDir() {
continue
}
// If the directory is not a number (i.e. not a PID), skip it
if _, err := strconv.Atoi(base); err != nil {
return filepath.SkipDir
pid, err := strconv.Atoi(entry.Name())
if err != nil {
continue
}
cmdline, err := ioutil.ReadFile(filepath.Join("/proc", entry.Name(), "cmdline"))
if err != nil {
klog.V(4).Infof("Error reading file %s: %+v", filepath.Join("/proc", entry.Name(), "cmdline"), err)
continue
}
// The bytes we read have '\0' as a separator for the command line
parts := bytes.SplitN(cmdline, []byte{0}, 2)
if len(parts) == 0 {
continue
}
// Split the command line itself we are interested in just the first part
exe := strings.FieldsFunc(string(parts[0]), func(c rune) bool {
return unicode.IsSpace(c) || c == ':'
})
if len(exe) == 0 {
continue
}
// Check if the name of the executable is what we are looking for
if re.MatchString(exe[0]) {
// Grab the PID from the directory path
pids = append(pids, pid)
}
}
if base != "cmdline" {
return nil
}
cmdline, err := ioutil.ReadFile(path)
if err != nil {
glog.V(4).Infof("Error reading file %s: %+v", path, err)
return nil
}
// The bytes we read have '\0' as a separator for the command line
parts := bytes.SplitN(cmdline, []byte{0}, 2)
if len(parts) == 0 {
return nil
}
// Split the command line itself we are interested in just the first part
exe := strings.FieldsFunc(string(parts[0]), func(c rune) bool {
return unicode.IsSpace(c) || c == ':'
})
if len(exe) == 0 {
return nil
}
// Check if the name of the executable is what we are looking for
if re.MatchString(exe[0]) {
dirname := filepath.Base(filepath.Dir(path))
// Grab the PID from the directory path
pid, _ := strconv.Atoi(dirname)
pids = append(pids, pid)
}
return nil
})
}
return pids
}

View File

@ -23,6 +23,7 @@ import (
"os"
"os/signal"
"path/filepath"
"regexp"
"runtime"
"syscall"
"testing"
@ -95,3 +96,21 @@ func TestPKill(t *testing.T) {
t.Fatalf("timeout waiting for %v", sig)
}
}
func BenchmarkGetPids(b *testing.B) {
if runtime.GOOS == "darwin" || runtime.GOOS == "windows" {
b.Skipf("not supported on GOOS=%s", runtime.GOOS)
}
re, err := regexp.Compile("(^|/)" + filepath.Base(os.Args[0]) + "$")
assert.Empty(b, err)
for i := 0; i < b.N; i++ {
pids := getPids(re)
b.StopTimer()
assert.NotZero(b, pids)
assert.Contains(b, pids, os.Getpid())
b.StartTimer()
}
}

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({
@ -55,7 +23,7 @@ go_library(
],
"@io_bazel_rules_go//go/platform:linux": [
"//pkg/util/mount:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
"@io_bazel_rules_go//go/platform:nacl": [
"//pkg/util/mount:go_default_library",

View File

@ -21,7 +21,7 @@ package resizefs
import (
"fmt"
"github.com/golang/glog"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/util/mount"
)
@ -50,7 +50,7 @@ func (resizefs *ResizeFs) Resize(devicePath string, deviceMountPath string) (boo
return false, nil
}
glog.V(3).Infof("ResizeFS.Resize - Expanding mounted volume %s", devicePath)
klog.V(3).Infof("ResizeFS.Resize - Expanding mounted volume %s", devicePath)
switch format {
case "ext3", "ext4":
return resizefs.extResize(devicePath)
@ -63,7 +63,7 @@ func (resizefs *ResizeFs) Resize(devicePath string, deviceMountPath string) (boo
func (resizefs *ResizeFs) extResize(devicePath string) (bool, error) {
output, err := resizefs.mounter.Exec.Run("resize2fs", devicePath)
if err == nil {
glog.V(2).Infof("Device %s resized successfully", devicePath)
klog.V(2).Infof("Device %s resized successfully", devicePath)
return true, nil
}
@ -77,7 +77,7 @@ func (resizefs *ResizeFs) xfsResize(deviceMountPath string) (bool, error) {
output, err := resizefs.mounter.Exec.Run("xfs_growfs", args...)
if err == nil {
glog.V(2).Infof("Device %s resized successfully", deviceMountPath)
klog.V(2).Infof("Device %s resized successfully", deviceMountPath)
return true, nil
}

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

@ -25,7 +25,7 @@ import (
"github.com/opencontainers/runc/libcontainer/configs"
)
// Creates resource-only containerName if it does not already exist and moves
// RunInResourceContainer creates resource-only containerName if it does not already exist and moves
// the current process to it.
//
// containerName must be an absolute container name.

View File

@ -22,6 +22,7 @@ import (
"errors"
)
// RunInResourceContainer creates resource-only containerName unsupported.
func RunInResourceContainer(containerName string) error {
return errors.New("resource-only containers unsupported in this platform")
}

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": [

Some files were not shown because too many files have changed in this diff Show More