*: initial update to kube 1.8
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
parent
2453222695
commit
d6e819133d
1237 changed files with 84117 additions and 564982 deletions
20
vendor/k8s.io/kubernetes/pkg/util/doc.go
generated
vendored
20
vendor/k8s.io/kubernetes/pkg/util/doc.go
generated
vendored
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package util implements various utility functions used in both testing and implementation
|
||||
// of Kubernetes. Package util may not depend on any other package in the Kubernetes
|
||||
// package tree.
|
||||
package util // import "k8s.io/kubernetes/pkg/util"
|
18
vendor/k8s.io/kubernetes/pkg/util/exec/doc.go
generated
vendored
18
vendor/k8s.io/kubernetes/pkg/util/exec/doc.go
generated
vendored
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package exec provides an injectable interface and implementations for running commands.
|
||||
package exec // import "k8s.io/kubernetes/pkg/util/exec"
|
200
vendor/k8s.io/kubernetes/pkg/util/exec/exec.go
generated
vendored
200
vendor/k8s.io/kubernetes/pkg/util/exec/exec.go
generated
vendored
|
@ -1,200 +0,0 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package exec
|
||||
|
||||
import (
|
||||
"io"
|
||||
osexec "os/exec"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ErrExecutableNotFound is returned if the executable is not found.
|
||||
var ErrExecutableNotFound = osexec.ErrNotFound
|
||||
|
||||
// Interface is an interface that presents a subset of the os/exec API. Use this
|
||||
// when you want to inject fakeable/mockable exec behavior.
|
||||
type Interface interface {
|
||||
// Command returns a Cmd instance which can be used to run a single command.
|
||||
// This follows the pattern of package os/exec.
|
||||
Command(cmd string, args ...string) Cmd
|
||||
|
||||
// LookPath wraps os/exec.LookPath
|
||||
LookPath(file string) (string, error)
|
||||
}
|
||||
|
||||
// Cmd is an interface that presents an API that is very similar to Cmd from os/exec.
|
||||
// As more functionality is needed, this can grow. Since Cmd is a struct, we will have
|
||||
// to replace fields with get/set method pairs.
|
||||
type Cmd interface {
|
||||
// Run runs the command to the completion.
|
||||
Run() error
|
||||
// CombinedOutput runs the command and returns its combined standard output
|
||||
// and standard error. This follows the pattern of package os/exec.
|
||||
CombinedOutput() ([]byte, error)
|
||||
// Output runs the command and returns standard output, but not standard err
|
||||
Output() ([]byte, error)
|
||||
SetDir(dir string)
|
||||
SetStdin(in io.Reader)
|
||||
SetStdout(out io.Writer)
|
||||
SetStderr(out io.Writer)
|
||||
// Stops the command by sending SIGTERM. It is not guaranteed the
|
||||
// process will stop before this function returns. If the process is not
|
||||
// responding, an internal timer function will send a SIGKILL to force
|
||||
// terminate after 10 seconds.
|
||||
Stop()
|
||||
}
|
||||
|
||||
// ExitError is an interface that presents an API similar to os.ProcessState, which is
|
||||
// what ExitError from os/exec is. This is designed to make testing a bit easier and
|
||||
// probably loses some of the cross-platform properties of the underlying library.
|
||||
type ExitError interface {
|
||||
String() string
|
||||
Error() string
|
||||
Exited() bool
|
||||
ExitStatus() int
|
||||
}
|
||||
|
||||
// Implements Interface in terms of really exec()ing.
|
||||
type executor struct{}
|
||||
|
||||
// New returns a new Interface which will os/exec to run commands.
|
||||
func New() Interface {
|
||||
return &executor{}
|
||||
}
|
||||
|
||||
// Command is part of the Interface interface.
|
||||
func (executor *executor) Command(cmd string, args ...string) Cmd {
|
||||
return (*cmdWrapper)(osexec.Command(cmd, args...))
|
||||
}
|
||||
|
||||
// LookPath is part of the Interface interface
|
||||
func (executor *executor) LookPath(file string) (string, error) {
|
||||
return osexec.LookPath(file)
|
||||
}
|
||||
|
||||
// Wraps exec.Cmd so we can capture errors.
|
||||
type cmdWrapper osexec.Cmd
|
||||
|
||||
func (cmd *cmdWrapper) SetDir(dir string) {
|
||||
cmd.Dir = dir
|
||||
}
|
||||
|
||||
func (cmd *cmdWrapper) SetStdin(in io.Reader) {
|
||||
cmd.Stdin = in
|
||||
}
|
||||
|
||||
func (cmd *cmdWrapper) SetStdout(out io.Writer) {
|
||||
cmd.Stdout = out
|
||||
}
|
||||
|
||||
func (cmd *cmdWrapper) SetStderr(out io.Writer) {
|
||||
cmd.Stderr = out
|
||||
}
|
||||
|
||||
// Run is part of the Cmd interface.
|
||||
func (cmd *cmdWrapper) Run() error {
|
||||
return (*osexec.Cmd)(cmd).Run()
|
||||
}
|
||||
|
||||
// CombinedOutput is part of the Cmd interface.
|
||||
func (cmd *cmdWrapper) CombinedOutput() ([]byte, error) {
|
||||
out, err := (*osexec.Cmd)(cmd).CombinedOutput()
|
||||
if err != nil {
|
||||
return out, handleError(err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (cmd *cmdWrapper) Output() ([]byte, error) {
|
||||
out, err := (*osexec.Cmd)(cmd).Output()
|
||||
if err != nil {
|
||||
return out, handleError(err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Stop is part of the Cmd interface.
|
||||
func (cmd *cmdWrapper) Stop() {
|
||||
c := (*osexec.Cmd)(cmd)
|
||||
if c.ProcessState.Exited() {
|
||||
return
|
||||
}
|
||||
c.Process.Signal(syscall.SIGTERM)
|
||||
time.AfterFunc(10*time.Second, func() {
|
||||
if c.ProcessState.Exited() {
|
||||
return
|
||||
}
|
||||
c.Process.Signal(syscall.SIGKILL)
|
||||
})
|
||||
}
|
||||
|
||||
func handleError(err error) error {
|
||||
if ee, ok := err.(*osexec.ExitError); ok {
|
||||
// Force a compile fail if exitErrorWrapper can't convert to ExitError.
|
||||
var x ExitError = &ExitErrorWrapper{ee}
|
||||
return x
|
||||
}
|
||||
if ee, ok := err.(*osexec.Error); ok {
|
||||
if ee.Err == osexec.ErrNotFound {
|
||||
return ErrExecutableNotFound
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// ExitErrorWrapper is an implementation of ExitError in terms of os/exec ExitError.
|
||||
// Note: standard exec.ExitError is type *os.ProcessState, which already implements Exited().
|
||||
type ExitErrorWrapper struct {
|
||||
*osexec.ExitError
|
||||
}
|
||||
|
||||
var _ ExitError = ExitErrorWrapper{}
|
||||
|
||||
// ExitStatus is part of the ExitError interface.
|
||||
func (eew ExitErrorWrapper) ExitStatus() int {
|
||||
ws, ok := eew.Sys().(syscall.WaitStatus)
|
||||
if !ok {
|
||||
panic("can't call ExitStatus() on a non-WaitStatus exitErrorWrapper")
|
||||
}
|
||||
return ws.ExitStatus()
|
||||
}
|
||||
|
||||
// CodeExitError is an implementation of ExitError consisting of an error object
|
||||
// and an exit code (the upper bits of os.exec.ExitStatus).
|
||||
type CodeExitError struct {
|
||||
Err error
|
||||
Code int
|
||||
}
|
||||
|
||||
var _ ExitError = CodeExitError{}
|
||||
|
||||
func (e CodeExitError) Error() string {
|
||||
return e.Err.Error()
|
||||
}
|
||||
|
||||
func (e CodeExitError) String() string {
|
||||
return e.Err.Error()
|
||||
}
|
||||
|
||||
func (e CodeExitError) Exited() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (e CodeExitError) ExitStatus() int {
|
||||
return e.Code
|
||||
}
|
145
vendor/k8s.io/kubernetes/pkg/util/exec/fake_exec.go
generated
vendored
145
vendor/k8s.io/kubernetes/pkg/util/exec/fake_exec.go
generated
vendored
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package exec
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// A simple scripted Interface type.
|
||||
type FakeExec struct {
|
||||
CommandScript []FakeCommandAction
|
||||
CommandCalls int
|
||||
LookPathFunc func(string) (string, error)
|
||||
}
|
||||
|
||||
type FakeCommandAction func(cmd string, args ...string) Cmd
|
||||
|
||||
func (fake *FakeExec) Command(cmd string, args ...string) Cmd {
|
||||
if fake.CommandCalls > len(fake.CommandScript)-1 {
|
||||
panic(fmt.Sprintf("ran out of Command() actions. Could not handle command [%d]: %s args: %v", fake.CommandCalls, cmd, args))
|
||||
}
|
||||
i := fake.CommandCalls
|
||||
fake.CommandCalls++
|
||||
return fake.CommandScript[i](cmd, args...)
|
||||
}
|
||||
|
||||
func (fake *FakeExec) LookPath(file string) (string, error) {
|
||||
return fake.LookPathFunc(file)
|
||||
}
|
||||
|
||||
// A simple scripted Cmd type.
|
||||
type FakeCmd struct {
|
||||
Argv []string
|
||||
CombinedOutputScript []FakeCombinedOutputAction
|
||||
CombinedOutputCalls int
|
||||
CombinedOutputLog [][]string
|
||||
RunScript []FakeRunAction
|
||||
RunCalls int
|
||||
RunLog [][]string
|
||||
Dirs []string
|
||||
Stdin io.Reader
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
}
|
||||
|
||||
func InitFakeCmd(fake *FakeCmd, cmd string, args ...string) Cmd {
|
||||
fake.Argv = append([]string{cmd}, args...)
|
||||
return fake
|
||||
}
|
||||
|
||||
type FakeCombinedOutputAction func() ([]byte, error)
|
||||
type FakeRunAction func() ([]byte, []byte, error)
|
||||
|
||||
func (fake *FakeCmd) SetDir(dir string) {
|
||||
fake.Dirs = append(fake.Dirs, dir)
|
||||
}
|
||||
|
||||
func (fake *FakeCmd) SetStdin(in io.Reader) {
|
||||
fake.Stdin = in
|
||||
}
|
||||
|
||||
func (fake *FakeCmd) SetStdout(out io.Writer) {
|
||||
fake.Stdout = out
|
||||
}
|
||||
|
||||
func (fake *FakeCmd) SetStderr(out io.Writer) {
|
||||
fake.Stderr = out
|
||||
}
|
||||
|
||||
func (fake *FakeCmd) Run() error {
|
||||
if fake.RunCalls > len(fake.RunScript)-1 {
|
||||
panic("ran out of Run() actions")
|
||||
}
|
||||
if fake.RunLog == nil {
|
||||
fake.RunLog = [][]string{}
|
||||
}
|
||||
i := fake.RunCalls
|
||||
fake.RunLog = append(fake.RunLog, append([]string{}, fake.Argv...))
|
||||
fake.RunCalls++
|
||||
stdout, stderr, err := fake.RunScript[i]()
|
||||
if stdout != nil {
|
||||
fake.Stdout.Write(stdout)
|
||||
}
|
||||
if stderr != nil {
|
||||
fake.Stderr.Write(stderr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (fake *FakeCmd) CombinedOutput() ([]byte, error) {
|
||||
if fake.CombinedOutputCalls > len(fake.CombinedOutputScript)-1 {
|
||||
panic("ran out of CombinedOutput() actions")
|
||||
}
|
||||
if fake.CombinedOutputLog == nil {
|
||||
fake.CombinedOutputLog = [][]string{}
|
||||
}
|
||||
i := fake.CombinedOutputCalls
|
||||
fake.CombinedOutputLog = append(fake.CombinedOutputLog, append([]string{}, fake.Argv...))
|
||||
fake.CombinedOutputCalls++
|
||||
return fake.CombinedOutputScript[i]()
|
||||
}
|
||||
|
||||
func (fake *FakeCmd) Output() ([]byte, error) {
|
||||
return nil, fmt.Errorf("unimplemented")
|
||||
}
|
||||
|
||||
func (fake *FakeCmd) Stop() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
// A simple fake ExitError type.
|
||||
type FakeExitError struct {
|
||||
Status int
|
||||
}
|
||||
|
||||
func (fake *FakeExitError) String() string {
|
||||
return fmt.Sprintf("exit %d", fake.Status)
|
||||
}
|
||||
|
||||
func (fake *FakeExitError) Error() string {
|
||||
return fake.String()
|
||||
}
|
||||
|
||||
func (fake *FakeExitError) Exited() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (fake *FakeExitError) ExitStatus() int {
|
||||
return fake.Status
|
||||
}
|
57
vendor/k8s.io/kubernetes/pkg/util/file/file.go
generated
vendored
Normal file
57
vendor/k8s.io/kubernetes/pkg/util/file/file.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
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 file
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// FileExists checks if specified file exists.
|
||||
func FileExists(filename string) (bool, error) {
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
return false, nil
|
||||
} else if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// FileOrSymlinkExists checks if specified file or symlink exists.
|
||||
func FileOrSymlinkExists(filename string) (bool, error) {
|
||||
if _, err := os.Lstat(filename); os.IsNotExist(err) {
|
||||
return false, nil
|
||||
} else if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// ReadDirNoStat returns a string of files/directories contained
|
||||
// in dirname without calling lstat on them.
|
||||
func ReadDirNoStat(dirname string) ([]string, error) {
|
||||
if dirname == "" {
|
||||
dirname = "."
|
||||
}
|
||||
|
||||
f, err := os.Open(dirname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return f.Readdirnames(-1)
|
||||
}
|
104
vendor/k8s.io/kubernetes/pkg/util/interrupt/interrupt.go
generated
vendored
104
vendor/k8s.io/kubernetes/pkg/util/interrupt/interrupt.go
generated
vendored
|
@ -1,104 +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 interrupt
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// terminationSignals are signals that cause the program to exit in the
|
||||
// supported platforms (linux, darwin, windows).
|
||||
var terminationSignals = []os.Signal{syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT}
|
||||
|
||||
// Handler guarantees execution of notifications after a critical section (the function passed
|
||||
// to a Run method), even in the presence of process termination. It guarantees exactly once
|
||||
// invocation of the provided notify functions.
|
||||
type Handler struct {
|
||||
notify []func()
|
||||
final func(os.Signal)
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
// Chain creates a new handler that invokes all notify functions when the critical section exits
|
||||
// and then invokes the optional handler's notifications. This allows critical sections to be
|
||||
// nested without losing exactly once invocations. Notify functions can invoke any cleanup needed
|
||||
// but should not exit (which is the responsibility of the parent handler).
|
||||
func Chain(handler *Handler, notify ...func()) *Handler {
|
||||
if handler == nil {
|
||||
return New(nil, notify...)
|
||||
}
|
||||
return New(handler.Signal, append(notify, handler.Close)...)
|
||||
}
|
||||
|
||||
// New creates a new handler that guarantees all notify functions are run after the critical
|
||||
// section exits (or is interrupted by the OS), then invokes the final handler. If no final
|
||||
// handler is specified, the default final is `os.Exit(1)`. A handler can only be used for
|
||||
// one critical section.
|
||||
func New(final func(os.Signal), notify ...func()) *Handler {
|
||||
return &Handler{
|
||||
final: final,
|
||||
notify: notify,
|
||||
}
|
||||
}
|
||||
|
||||
// Close executes all the notification handlers if they have not yet been executed.
|
||||
func (h *Handler) Close() {
|
||||
h.once.Do(func() {
|
||||
for _, fn := range h.notify {
|
||||
fn()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Signal is called when an os.Signal is received, and guarantees that all notifications
|
||||
// are executed, then the final handler is executed. This function should only be called once
|
||||
// per Handler instance.
|
||||
func (h *Handler) Signal(s os.Signal) {
|
||||
h.once.Do(func() {
|
||||
for _, fn := range h.notify {
|
||||
fn()
|
||||
}
|
||||
if h.final == nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
h.final(s)
|
||||
})
|
||||
}
|
||||
|
||||
// Run ensures that any notifications are invoked after the provided fn exits (even if the
|
||||
// process is interrupted by an OS termination signal). Notifications are only invoked once
|
||||
// per Handler instance, so calling Run more than once will not behave as the user expects.
|
||||
func (h *Handler) Run(fn func() error) error {
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, terminationSignals...)
|
||||
defer func() {
|
||||
signal.Stop(ch)
|
||||
close(ch)
|
||||
}()
|
||||
go func() {
|
||||
sig, ok := <-ch
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
h.Signal(sig)
|
||||
}()
|
||||
defer h.Close()
|
||||
return fn()
|
||||
}
|
45
vendor/k8s.io/kubernetes/pkg/util/io/consistentread.go
generated
vendored
Normal file
45
vendor/k8s.io/kubernetes/pkg/util/io/consistentread.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
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 io
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// ConsistentRead repeatedly reads a file until it gets the same content twice.
|
||||
// This is useful when reading files in /proc that are larger than page size
|
||||
// and kernel may modify them between individual read() syscalls.
|
||||
func ConsistentRead(filename string, attempts int) ([]byte, error) {
|
||||
oldContent, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < attempts; i++ {
|
||||
newContent, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if bytes.Compare(oldContent, newContent) == 0 {
|
||||
return newContent, nil
|
||||
}
|
||||
// Files are different, continue reading
|
||||
oldContent = newContent
|
||||
}
|
||||
return nil, fmt.Errorf("could not get consistent content of %s after %d attempts", filename, attempts)
|
||||
}
|
61
vendor/k8s.io/kubernetes/pkg/util/io/io.go
generated
vendored
61
vendor/k8s.io/kubernetes/pkg/util/io/io.go
generated
vendored
|
@ -1,61 +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 (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
)
|
||||
|
||||
// LoadPodFromFile will read, decode, and return a Pod from a file.
|
||||
func LoadPodFromFile(filePath string) (*v1.Pod, error) {
|
||||
if filePath == "" {
|
||||
return nil, fmt.Errorf("file path not specified")
|
||||
}
|
||||
podDef, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read file path %s: %+v", filePath, err)
|
||||
}
|
||||
if len(podDef) == 0 {
|
||||
return nil, fmt.Errorf("file was empty: %s", filePath)
|
||||
}
|
||||
pod := &v1.Pod{}
|
||||
|
||||
codec := api.Codecs.LegacyCodec(api.Registry.GroupOrDie(v1.GroupName).GroupVersion)
|
||||
if err := runtime.DecodeInto(codec, podDef, pod); err != nil {
|
||||
return nil, fmt.Errorf("failed decoding file: %v", err)
|
||||
}
|
||||
return pod, nil
|
||||
}
|
||||
|
||||
// SavePodToFile will encode and save a pod to a given path & permissions
|
||||
func SavePodToFile(pod *v1.Pod, filePath string, perm os.FileMode) error {
|
||||
if filePath == "" {
|
||||
return fmt.Errorf("file path not specified")
|
||||
}
|
||||
codec := api.Codecs.LegacyCodec(api.Registry.GroupOrDie(v1.GroupName).GroupVersion)
|
||||
data, err := runtime.Encode(codec, pod)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed encoding pod: %v", err)
|
||||
}
|
||||
return ioutil.WriteFile(filePath, data, perm)
|
||||
}
|
30
vendor/k8s.io/kubernetes/pkg/util/io/writer.go
generated
vendored
30
vendor/k8s.io/kubernetes/pkg/util/io/writer.go
generated
vendored
|
@ -28,6 +28,7 @@ import (
|
|||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
@ -36,31 +37,32 @@ type Writer interface {
|
|||
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)
|
||||
}
|
||||
|
||||
// Alternative implementation of Writer interface that allows writing data to file
|
||||
// using nsenter command.
|
||||
// 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
|
||||
// limitaion one has to first enter hosts namespace (by using 'nsenter') and only
|
||||
// then write data.
|
||||
type NsenterWriter struct {
|
||||
}
|
||||
// limitation one has to first enter hosts namespace (by using 'nsenter') and
|
||||
// only then write data.
|
||||
type NsenterWriter struct{}
|
||||
|
||||
// TODO: should take a writer, not []byte
|
||||
// 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 {
|
||||
cmd := "nsenter"
|
||||
base_args := []string{
|
||||
baseArgs := []string{
|
||||
"--mount=/rootfs/proc/1/ns/mnt",
|
||||
"--",
|
||||
}
|
||||
|
||||
echo_args := append(base_args, "sh", "-c", fmt.Sprintf("cat > %s", filename))
|
||||
glog.V(5).Infof("Command to write data to file: %v %v", cmd, echo_args)
|
||||
command := exec.Command(cmd, echo_args...)
|
||||
echoArgs := append(baseArgs, "sh", "-c", fmt.Sprintf("cat > %s", filename))
|
||||
glog.V(5).Infof("Command to write data to file: %v %v", cmd, echoArgs)
|
||||
command := exec.Command(cmd, echoArgs...)
|
||||
command.Stdin = bytes.NewBuffer(data)
|
||||
outputBytes, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
|
@ -68,9 +70,9 @@ func (writer *NsenterWriter) WriteFile(filename string, data []byte, perm os.Fil
|
|||
return err
|
||||
}
|
||||
|
||||
chmod_args := append(base_args, "chmod", fmt.Sprintf("%o", perm), filename)
|
||||
glog.V(5).Infof("Command to change permissions to file: %v %v", cmd, chmod_args)
|
||||
outputBytes, err = exec.Command(cmd, chmod_args...).CombinedOutput()
|
||||
chmodArgs := append(baseArgs, "chmod", fmt.Sprintf("%o", perm), filename)
|
||||
glog.V(5).Infof("Command to change permissions to file: %v %v", cmd, chmodArgs)
|
||||
outputBytes, err = exec.Command(cmd, chmodArgs...).CombinedOutput()
|
||||
if err != nil {
|
||||
glog.Errorf("Output from chmod command: %v", string(outputBytes))
|
||||
return err
|
||||
|
|
10
vendor/k8s.io/kubernetes/pkg/util/iptables/iptables.go
generated
vendored
10
vendor/k8s.io/kubernetes/pkg/util/iptables/iptables.go
generated
vendored
|
@ -27,8 +27,8 @@ import (
|
|||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
utildbus "k8s.io/kubernetes/pkg/util/dbus"
|
||||
utilexec "k8s.io/kubernetes/pkg/util/exec"
|
||||
utilversion "k8s.io/kubernetes/pkg/util/version"
|
||||
utilexec "k8s.io/utils/exec"
|
||||
)
|
||||
|
||||
type RulePosition string
|
||||
|
@ -338,7 +338,7 @@ func (runner *runner) RestoreAll(data []byte, flush FlushFlag, counters RestoreC
|
|||
}
|
||||
|
||||
type iptablesLocker interface {
|
||||
Close()
|
||||
Close() error
|
||||
}
|
||||
|
||||
// restoreInternal is the shared part of Restore/RestoreAll
|
||||
|
@ -361,7 +361,11 @@ func (runner *runner) restoreInternal(args []string, data []byte, flush FlushFla
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer locker.Close()
|
||||
defer func(locker iptablesLocker) {
|
||||
if err := locker.Close(); err != nil {
|
||||
glog.Errorf("Failed to close iptables locks: %v", err)
|
||||
}
|
||||
}(locker)
|
||||
}
|
||||
|
||||
// run the command and return the output or an error including the output and error
|
||||
|
|
13
vendor/k8s.io/kubernetes/pkg/util/iptables/iptables_linux.go
generated
vendored
13
vendor/k8s.io/kubernetes/pkg/util/iptables/iptables_linux.go
generated
vendored
|
@ -25,6 +25,7 @@ import (
|
|||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
)
|
||||
|
||||
|
@ -33,13 +34,19 @@ type locker struct {
|
|||
lock14 *net.UnixListener
|
||||
}
|
||||
|
||||
func (l *locker) Close() {
|
||||
func (l *locker) Close() error {
|
||||
errList := []error{}
|
||||
if l.lock16 != nil {
|
||||
l.lock16.Close()
|
||||
if err := l.lock16.Close(); err != nil {
|
||||
errList = append(errList, err)
|
||||
}
|
||||
}
|
||||
if l.lock14 != nil {
|
||||
l.lock14.Close()
|
||||
if err := l.lock14.Close(); err != nil {
|
||||
errList = append(errList, err)
|
||||
}
|
||||
}
|
||||
return utilerrors.NewAggregate(errList)
|
||||
}
|
||||
|
||||
func grabIptablesLocks(lockfilePath string) (iptablesLocker, error) {
|
||||
|
|
50
vendor/k8s.io/kubernetes/pkg/util/mount/exec.go
generated
vendored
Normal file
50
vendor/k8s.io/kubernetes/pkg/util/mount/exec.go
generated
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
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 mount
|
||||
|
||||
import "k8s.io/utils/exec"
|
||||
|
||||
func NewOsExec() Exec {
|
||||
return &osExec{}
|
||||
}
|
||||
|
||||
// Real implementation of Exec interface that uses simple util.Exec
|
||||
type osExec struct{}
|
||||
|
||||
var _ Exec = &osExec{}
|
||||
|
||||
func (e *osExec) Run(cmd string, args ...string) ([]byte, error) {
|
||||
exe := exec.New()
|
||||
return exe.Command(cmd, args...).CombinedOutput()
|
||||
}
|
||||
|
||||
func NewFakeExec(run runHook) *FakeExec {
|
||||
return &FakeExec{runHook: run}
|
||||
}
|
||||
|
||||
// Fake for testing.
|
||||
type FakeExec struct {
|
||||
runHook runHook
|
||||
}
|
||||
type runHook func(cmd string, args ...string) ([]byte, error)
|
||||
|
||||
func (f *FakeExec) Run(cmd string, args ...string) ([]byte, error) {
|
||||
if f.runHook != nil {
|
||||
return f.runHook(cmd, args...)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
4
vendor/k8s.io/kubernetes/pkg/util/mount/fake.go
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/util/mount/fake.go
generated
vendored
|
@ -171,3 +171,7 @@ func (f *FakeMounter) PathIsDevice(pathname string) (bool, error) {
|
|||
func (f *FakeMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
return getDeviceNameFromMount(f, mountPath, pluginDir)
|
||||
}
|
||||
|
||||
func (f *FakeMounter) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
|
84
vendor/k8s.io/kubernetes/pkg/util/mount/mount.go
generated
vendored
84
vendor/k8s.io/kubernetes/pkg/util/mount/mount.go
generated
vendored
|
@ -25,7 +25,6 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/util/exec"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -68,6 +67,19 @@ type Interface interface {
|
|||
// GetDeviceNameFromMount finds the device name by checking the mount path
|
||||
// to get the global mount path which matches its plugin directory
|
||||
GetDeviceNameFromMount(mountPath, pluginDir string) (string, error)
|
||||
// MakeRShared checks that given path is on a mount with 'rshared' mount
|
||||
// propagation. If not, it bind-mounts the path as rshared.
|
||||
MakeRShared(path string) error
|
||||
}
|
||||
|
||||
// Exec executes command where mount utilities are. This can be either the host,
|
||||
// container where kubelet runs or even a remote pod with mount utilities.
|
||||
// Usual pkg/util/exec interface is not used because kubelet.RunInContainer does
|
||||
// not provide stdin/stdout/stderr streams.
|
||||
type Exec interface {
|
||||
// Run executes a command and returns its stdout + stderr combined in one
|
||||
// stream.
|
||||
Run(cmd string, args ...string) ([]byte, error)
|
||||
}
|
||||
|
||||
// Compile-time check to ensure all Mounter implementations satisfy
|
||||
|
@ -89,7 +101,7 @@ type MountPoint struct {
|
|||
// mounts it otherwise the device is formatted first then mounted.
|
||||
type SafeFormatAndMount struct {
|
||||
Interface
|
||||
Runner exec.Interface
|
||||
Exec
|
||||
}
|
||||
|
||||
// FormatAndMount formats the given disk, if needed, and mounts it.
|
||||
|
@ -107,15 +119,6 @@ func (mounter *SafeFormatAndMount) FormatAndMount(source string, target string,
|
|||
return mounter.formatAndMount(source, target, fstype, options)
|
||||
}
|
||||
|
||||
// New returns a mount.Interface for the current system.
|
||||
// It provides options to override the default mounter behavior.
|
||||
// mounterPath allows using an alternative to `/bin/mount` for mounting.
|
||||
func New(mounterPath string) Interface {
|
||||
return &Mounter{
|
||||
mounterPath: mounterPath,
|
||||
}
|
||||
}
|
||||
|
||||
// GetMountRefs finds all other references to the device referenced
|
||||
// by mountPath; returns a list of paths.
|
||||
func GetMountRefs(mounter Interface, mountPath string) ([]string, error) {
|
||||
|
@ -123,7 +126,6 @@ func GetMountRefs(mounter Interface, mountPath string) ([]string, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Find the device name.
|
||||
deviceName := ""
|
||||
// If mountPath is symlink, need get its target path.
|
||||
|
@ -152,6 +154,39 @@ func GetMountRefs(mounter Interface, mountPath string) ([]string, error) {
|
|||
return refs, nil
|
||||
}
|
||||
|
||||
// GetMountRefsByDev finds all references to the device provided
|
||||
// by mountPath; returns a list of paths.
|
||||
func GetMountRefsByDev(mounter Interface, mountPath string) ([]string, error) {
|
||||
mps, err := mounter.List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
slTarget, err := filepath.EvalSymlinks(mountPath)
|
||||
if err != nil {
|
||||
slTarget = mountPath
|
||||
}
|
||||
|
||||
// Finding the device mounted to mountPath
|
||||
diskDev := ""
|
||||
for i := range mps {
|
||||
if slTarget == mps[i].Path {
|
||||
diskDev = mps[i].Device
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Find all references to the device.
|
||||
var refs []string
|
||||
for i := range mps {
|
||||
if mps[i].Device == diskDev || mps[i].Device == slTarget {
|
||||
if mps[i].Path != slTarget {
|
||||
refs = append(refs, mps[i].Path)
|
||||
}
|
||||
}
|
||||
}
|
||||
return refs, nil
|
||||
}
|
||||
|
||||
// GetDeviceNameFromMount: given a mnt point, find the device from /proc/mounts
|
||||
// returns the device name, reference count, and error code
|
||||
func GetDeviceNameFromMount(mounter Interface, mountPath string) (string, int, error) {
|
||||
|
@ -243,3 +278,28 @@ func IsNotMountPoint(mounter Interface, file string) (bool, error) {
|
|||
}
|
||||
return notMnt, nil
|
||||
}
|
||||
|
||||
// isBind detects whether a bind mount is being requested and makes the remount options to
|
||||
// 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) {
|
||||
bindRemountOpts := []string{"remount"}
|
||||
bind := false
|
||||
|
||||
if len(options) != 0 {
|
||||
for _, option := range options {
|
||||
switch option {
|
||||
case "bind":
|
||||
bind = true
|
||||
break
|
||||
case "remount":
|
||||
break
|
||||
default:
|
||||
bindRemountOpts = append(bindRemountOpts, option)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bind, bindRemountOpts
|
||||
}
|
||||
|
|
325
vendor/k8s.io/kubernetes/pkg/util/mount/mount_linux.go
generated
vendored
325
vendor/k8s.io/kubernetes/pkg/util/mount/mount_linux.go
generated
vendored
|
@ -19,10 +19,7 @@ limitations under the License.
|
|||
package mount
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
|
@ -30,8 +27,10 @@ import (
|
|||
"syscall"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"golang.org/x/sys/unix"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
utilexec "k8s.io/kubernetes/pkg/util/exec"
|
||||
utilio "k8s.io/kubernetes/pkg/util/io"
|
||||
utilexec "k8s.io/utils/exec"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -41,6 +40,8 @@ const (
|
|||
expectedNumFieldsPerLine = 6
|
||||
// Location of the mount file to use
|
||||
procMountsPath = "/proc/mounts"
|
||||
// Location of the mountinfo file
|
||||
procMountInfoPath = "/proc/self/mountinfo"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -55,6 +56,17 @@ const (
|
|||
// kubelet is running in the host's root mount namespace.
|
||||
type Mounter struct {
|
||||
mounterPath string
|
||||
withSystemd bool
|
||||
}
|
||||
|
||||
// New returns a mount.Interface for the current system.
|
||||
// It provides options to override the default mounter behavior.
|
||||
// mounterPath allows using an alternative to `/bin/mount` for mounting.
|
||||
func New(mounterPath string) Interface {
|
||||
return &Mounter{
|
||||
mounterPath: mounterPath,
|
||||
withSystemd: detectSystemd(),
|
||||
}
|
||||
}
|
||||
|
||||
// Mount mounts source to target as fstype with given options. 'source' and 'fstype' must
|
||||
|
@ -68,64 +80,95 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio
|
|||
mounterPath := ""
|
||||
bind, bindRemountOpts := isBind(options)
|
||||
if bind {
|
||||
err := doMount(mounterPath, defaultMountCommand, source, target, fstype, []string{"bind"})
|
||||
err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, []string{"bind"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts)
|
||||
return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts)
|
||||
}
|
||||
// The list of filesystems that require containerized mounter on GCI image cluster
|
||||
fsTypesNeedMounter := sets.NewString("nfs", "glusterfs", "ceph", "cifs")
|
||||
if fsTypesNeedMounter.Has(fstype) {
|
||||
mounterPath = mounter.mounterPath
|
||||
}
|
||||
return doMount(mounterPath, defaultMountCommand, source, target, fstype, options)
|
||||
}
|
||||
|
||||
// isBind detects whether a bind mount is being requested and makes the remount options to
|
||||
// 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) {
|
||||
bindRemountOpts := []string{"remount"}
|
||||
bind := false
|
||||
|
||||
if len(options) != 0 {
|
||||
for _, option := range options {
|
||||
switch option {
|
||||
case "bind":
|
||||
bind = true
|
||||
break
|
||||
case "remount":
|
||||
break
|
||||
default:
|
||||
bindRemountOpts = append(bindRemountOpts, option)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bind, bindRemountOpts
|
||||
return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, options)
|
||||
}
|
||||
|
||||
// doMount runs the mount command. mounterPath is the path to mounter binary if containerized mounter is used.
|
||||
func doMount(mounterPath string, mountCmd string, source string, target string, fstype string, options []string) error {
|
||||
func (m *Mounter) doMount(mounterPath string, mountCmd string, source string, target string, fstype string, options []string) error {
|
||||
mountArgs := makeMountArgs(source, target, fstype, options)
|
||||
if len(mounterPath) > 0 {
|
||||
mountArgs = append([]string{mountCmd}, mountArgs...)
|
||||
mountCmd = mounterPath
|
||||
}
|
||||
|
||||
if m.withSystemd {
|
||||
// Try to run mount via systemd-run --scope. This will escape the
|
||||
// service where kubelet runs and any fuse daemons will be started in a
|
||||
// specific scope. kubelet service than can be restarted without killing
|
||||
// these fuse daemons.
|
||||
//
|
||||
// Complete command line (when mounterPath is not used):
|
||||
// systemd-run --description=... --scope -- mount -t <type> <what> <where>
|
||||
//
|
||||
// Expected flow:
|
||||
// * systemd-run creates a transient scope (=~ cgroup) and executes its
|
||||
// argument (/bin/mount) there.
|
||||
// * mount does its job, forks a fuse daemon if necessary and finishes.
|
||||
// (systemd-run --scope finishes at this point, returning mount's exit
|
||||
// code and stdout/stderr - thats one of --scope benefits).
|
||||
// * systemd keeps the fuse daemon running in the scope (i.e. in its own
|
||||
// cgroup) until the fuse daemon dies (another --scope benefit).
|
||||
// Kubelet service can be restarted and the fuse daemon survives.
|
||||
// * When the fuse daemon dies (e.g. during unmount) systemd removes the
|
||||
// scope automatically.
|
||||
//
|
||||
// systemd-mount is not used because it's too new for older distros
|
||||
// (CentOS 7, Debian Jessie).
|
||||
mountCmd, mountArgs = addSystemdScope("systemd-run", target, mountCmd, mountArgs)
|
||||
} else {
|
||||
// No systemd-run on the host (or we failed to check it), assume kubelet
|
||||
// does not run as a systemd service.
|
||||
// No code here, mountCmd and mountArgs are already populated.
|
||||
}
|
||||
|
||||
glog.V(4).Infof("Mounting cmd (%s) with arguments (%s)", mountCmd, mountArgs)
|
||||
command := exec.Command(mountCmd, mountArgs...)
|
||||
output, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
glog.Errorf("Mount failed: %v\nMounting command: %s\nMounting arguments: %s %s %s %v\nOutput: %s\n", err, mountCmd, source, target, fstype, options, string(output))
|
||||
return fmt.Errorf("mount failed: %v\nMounting command: %s\nMounting arguments: %s %s %s %v\nOutput: %s\n",
|
||||
err, mountCmd, source, target, fstype, options, string(output))
|
||||
args := strings.Join(mountArgs, " ")
|
||||
glog.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
|
||||
}
|
||||
|
||||
// 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")
|
||||
return false
|
||||
}
|
||||
// Try to run systemd-run --scope /bin/true, that should be enough
|
||||
// to make sure that systemd is really running and not just installed,
|
||||
// which happens when running in a container with a systemd-based image
|
||||
// but with different pid 1.
|
||||
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))
|
||||
return false
|
||||
}
|
||||
glog.V(2).Infof("Detected OS with systemd")
|
||||
return true
|
||||
}
|
||||
|
||||
// makeMountArgs makes the arguments to the mount(8) command.
|
||||
func makeMountArgs(source, target, fstype string, options []string) []string {
|
||||
// Build mount command as follows:
|
||||
|
@ -145,6 +188,13 @@ func makeMountArgs(source, target, fstype string, options []string) []string {
|
|||
return mountArgs
|
||||
}
|
||||
|
||||
// addSystemdScope adds "system-run --scope" to given command line
|
||||
func addSystemdScope(systemdRunPath, mountName, command string, args []string) (string, []string) {
|
||||
descriptionArg := fmt.Sprintf("--description=Kubernetes transient mount for %s", mountName)
|
||||
systemdRunArgs := []string{descriptionArg, "--scope", "--", command}
|
||||
return systemdRunPath, append(systemdRunArgs, args...)
|
||||
}
|
||||
|
||||
// Unmount unmounts the target.
|
||||
func (mounter *Mounter) Unmount(target string) error {
|
||||
glog.V(4).Infof("Unmounting %s", target)
|
||||
|
@ -220,14 +270,14 @@ func exclusiveOpenFailsOnDevice(pathname string) (bool, error) {
|
|||
glog.Errorf("Path %q is not refering to a device.", pathname)
|
||||
return false, nil
|
||||
}
|
||||
fd, errno := syscall.Open(pathname, syscall.O_RDONLY|syscall.O_EXCL, 0)
|
||||
fd, errno := unix.Open(pathname, unix.O_RDONLY|unix.O_EXCL, 0)
|
||||
// If the device is in use, open will return an invalid fd.
|
||||
// When this happens, it is expected that Close will fail and throw an error.
|
||||
defer syscall.Close(fd)
|
||||
defer unix.Close(fd)
|
||||
if errno == nil {
|
||||
// device not in use
|
||||
return false, nil
|
||||
} else if errno == syscall.EBUSY {
|
||||
} else if errno == unix.EBUSY {
|
||||
// device is in use
|
||||
return true, nil
|
||||
}
|
||||
|
@ -258,76 +308,54 @@ func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginDir string) (str
|
|||
}
|
||||
|
||||
func listProcMounts(mountFilePath string) ([]MountPoint, error) {
|
||||
hash1, err := readProcMounts(mountFilePath, nil)
|
||||
content, err := utilio.ConsistentRead(mountFilePath, maxListTries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < maxListTries; i++ {
|
||||
mps := []MountPoint{}
|
||||
hash2, err := readProcMounts(mountFilePath, &mps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if hash1 == hash2 {
|
||||
// Success
|
||||
return mps, nil
|
||||
}
|
||||
hash1 = hash2
|
||||
}
|
||||
return nil, fmt.Errorf("failed to get a consistent snapshot of %v after %d tries", mountFilePath, maxListTries)
|
||||
return parseProcMounts(content)
|
||||
}
|
||||
|
||||
// readProcMounts reads the given mountFilePath (normally /proc/mounts) and produces a hash
|
||||
// of the contents. If the out argument is not nil, this fills it with MountPoint structs.
|
||||
func readProcMounts(mountFilePath string, out *[]MountPoint) (uint32, error) {
|
||||
file, err := os.Open(mountFilePath)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer file.Close()
|
||||
return readProcMountsFrom(file, out)
|
||||
}
|
||||
|
||||
func readProcMountsFrom(file io.Reader, out *[]MountPoint) (uint32, error) {
|
||||
hash := fnv.New32a()
|
||||
scanner := bufio.NewReader(file)
|
||||
for {
|
||||
line, err := scanner.ReadString('\n')
|
||||
if err == io.EOF {
|
||||
break
|
||||
func parseProcMounts(content []byte) ([]MountPoint, error) {
|
||||
out := []MountPoint{}
|
||||
lines := strings.Split(string(content), "\n")
|
||||
for _, line := range lines {
|
||||
if line == "" {
|
||||
// the last split() item is empty string following the last \n
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) != expectedNumFieldsPerLine {
|
||||
return 0, fmt.Errorf("wrong number of fields (expected %d, got %d): %s", expectedNumFieldsPerLine, len(fields), line)
|
||||
return nil, fmt.Errorf("wrong number of fields (expected %d, got %d): %s", expectedNumFieldsPerLine, len(fields), line)
|
||||
}
|
||||
|
||||
fmt.Fprintf(hash, "%s", line)
|
||||
|
||||
if out != nil {
|
||||
mp := MountPoint{
|
||||
Device: fields[0],
|
||||
Path: fields[1],
|
||||
Type: fields[2],
|
||||
Opts: strings.Split(fields[3], ","),
|
||||
}
|
||||
|
||||
freq, err := strconv.Atoi(fields[4])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
mp.Freq = freq
|
||||
|
||||
pass, err := strconv.Atoi(fields[5])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
mp.Pass = pass
|
||||
|
||||
*out = append(*out, mp)
|
||||
mp := MountPoint{
|
||||
Device: fields[0],
|
||||
Path: fields[1],
|
||||
Type: fields[2],
|
||||
Opts: strings.Split(fields[3], ","),
|
||||
}
|
||||
|
||||
freq, err := strconv.Atoi(fields[4])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mp.Freq = freq
|
||||
|
||||
pass, err := strconv.Atoi(fields[5])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mp.Pass = pass
|
||||
|
||||
out = append(out, mp)
|
||||
}
|
||||
return hash.Sum32(), nil
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (mounter *Mounter) MakeRShared(path string) error {
|
||||
mountCmd := defaultMountCommand
|
||||
mountArgs := []string{}
|
||||
return doMakeRShared(path, procMountInfoPath, mountCmd, mountArgs)
|
||||
}
|
||||
|
||||
// formatAndMount uses unix utils to format and mount the given disk
|
||||
|
@ -337,8 +365,7 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
|
|||
// Run fsck on the disk to fix repairable issues
|
||||
glog.V(4).Infof("Checking for issues with fsck on disk: %s", source)
|
||||
args := []string{"-a", source}
|
||||
cmd := mounter.Runner.Command("fsck", args...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
out, err := mounter.Exec.Run("fsck", args...)
|
||||
if err != nil {
|
||||
ee, isExitError := err.(utilexec.ExitError)
|
||||
switch {
|
||||
|
@ -375,8 +402,7 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
|
|||
args = []string{"-F", source}
|
||||
}
|
||||
glog.Infof("Disk %q appears to be unformatted, attempting to format as type: %q with options: %v", source, fstype, args)
|
||||
cmd := mounter.Runner.Command("mkfs."+fstype, args...)
|
||||
_, err := cmd.CombinedOutput()
|
||||
_, 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)
|
||||
|
@ -401,9 +427,8 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
|
|||
// diskLooksUnformatted uses 'lsblk' to see if the given disk is unformated
|
||||
func (mounter *SafeFormatAndMount) getDiskFormat(disk string) (string, error) {
|
||||
args := []string{"-n", "-o", "FSTYPE", disk}
|
||||
cmd := mounter.Runner.Command("lsblk", args...)
|
||||
glog.V(4).Infof("Attempting to determine if disk %q is formatted using lsblk with args: (%v)", disk, args)
|
||||
dataOut, err := cmd.CombinedOutput()
|
||||
dataOut, err := mounter.Exec.Run("lsblk", args...)
|
||||
output := string(dataOut)
|
||||
glog.V(4).Infof("Output: %q", output)
|
||||
|
||||
|
@ -430,3 +455,97 @@ func (mounter *SafeFormatAndMount) getDiskFormat(disk string) (string, error) {
|
|||
// and MD RAID are reported as FSTYPE and caught above).
|
||||
return "unknown data, probably partitions", nil
|
||||
}
|
||||
|
||||
// isShared returns true, if given path is on a mount point that has shared
|
||||
// mount propagation.
|
||||
func isShared(path string, filename string) (bool, error) {
|
||||
infos, err := parseMountInfo(filename)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// process /proc/xxx/mountinfo in backward order and find the first mount
|
||||
// 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 strings.HasPrefix(path, infos[i].mountPoint) {
|
||||
info = &infos[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
if info == nil {
|
||||
return false, fmt.Errorf("cannot find mount point for %q", path)
|
||||
}
|
||||
|
||||
// parse optional parameters
|
||||
for _, opt := range info.optional {
|
||||
if strings.HasPrefix(opt, "shared:") {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
type mountInfo struct {
|
||||
mountPoint string
|
||||
// list of "optional parameters", mount propagation is one of them
|
||||
optional []string
|
||||
}
|
||||
|
||||
// parseMountInfo parses /proc/xxx/mountinfo.
|
||||
func parseMountInfo(filename string) ([]mountInfo, error) {
|
||||
content, err := utilio.ConsistentRead(filename, maxListTries)
|
||||
if err != nil {
|
||||
return []mountInfo{}, err
|
||||
}
|
||||
contentStr := string(content)
|
||||
infos := []mountInfo{}
|
||||
|
||||
for _, line := range strings.Split(contentStr, "\n") {
|
||||
if line == "" {
|
||||
// the last split() item is empty string following the last \n
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 7 {
|
||||
return nil, fmt.Errorf("wrong number of fields in (expected %d, got %d): %s", 8, len(fields), line)
|
||||
}
|
||||
info := mountInfo{
|
||||
mountPoint: fields[4],
|
||||
optional: []string{},
|
||||
}
|
||||
for i := 6; i < len(fields) && fields[i] != "-"; i++ {
|
||||
info.optional = append(info.optional, fields[i])
|
||||
}
|
||||
infos = append(infos, info)
|
||||
}
|
||||
return infos, nil
|
||||
}
|
||||
|
||||
// doMakeRShared is common implementation of MakeRShared on Linux. It checks if
|
||||
// path is shared and bind-mounts it as rshared if needed. mountCmd and
|
||||
// mountArgs are expected to contain mount-like command, doMakeRShared will add
|
||||
// '--bind <path> <path>' and '--make-rshared <path>' to mountArgs.
|
||||
func doMakeRShared(path string, mountInfoFilename string, mountCmd string, mountArgs []string) error {
|
||||
shared, err := isShared(path, mountInfoFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if shared {
|
||||
glog.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)
|
||||
// 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)
|
||||
}
|
||||
|
||||
// mount --make-rshared /var/lib/kubelet
|
||||
if err := syscall.Mount(path, path, "" /*fstype*/, syscall.MS_SHARED|syscall.MS_REC, "" /*data*/); err != nil {
|
||||
return fmt.Errorf("failed to make %s rshared: %v", path, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
15
vendor/k8s.io/kubernetes/pkg/util/mount/mount_unsupported.go
generated
vendored
15
vendor/k8s.io/kubernetes/pkg/util/mount/mount_unsupported.go
generated
vendored
|
@ -1,4 +1,4 @@
|
|||
// +build !linux
|
||||
// +build !linux,!windows
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
@ -22,6 +22,15 @@ type Mounter struct {
|
|||
mounterPath string
|
||||
}
|
||||
|
||||
// New returns a mount.Interface for the current system.
|
||||
// It provides options to override the default mounter behavior.
|
||||
// mounterPath allows using an alternative to `/bin/mount` for mounting.
|
||||
func New(mounterPath string) Interface {
|
||||
return &Mounter{
|
||||
mounterPath: mounterPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (mounter *Mounter) Mount(source string, target string, fstype string, options []string) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -58,6 +67,10 @@ func (mounter *Mounter) PathIsDevice(pathname string) (bool, error) {
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func (mounter *Mounter) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, fstype string, options []string) error {
|
||||
return nil
|
||||
}
|
||||
|
|
206
vendor/k8s.io/kubernetes/pkg/util/mount/mount_windows.go
generated
vendored
Normal file
206
vendor/k8s.io/kubernetes/pkg/util/mount/mount_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,206 @@
|
|||
// +build windows
|
||||
|
||||
/*
|
||||
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 mount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// Mounter provides the default implementation of mount.Interface
|
||||
// for the windows platform. This implementation assumes that the
|
||||
// kubelet is running in the host's root mount namespace.
|
||||
type Mounter struct {
|
||||
mounterPath string
|
||||
}
|
||||
|
||||
// New returns a mount.Interface for the current system.
|
||||
// It provides options to override the default mounter behavior.
|
||||
// mounterPath allows using an alternative to `/bin/mount` for mounting.
|
||||
func New(mounterPath string) Interface {
|
||||
return &Mounter{
|
||||
mounterPath: mounterPath,
|
||||
}
|
||||
}
|
||||
|
||||
// Mount : mounts source to target as NTFS with given options.
|
||||
func (mounter *Mounter) Mount(source string, target string, fstype string, options []string) error {
|
||||
target = normalizeWindowsPath(target)
|
||||
|
||||
if source == "tmpfs" {
|
||||
glog.V(3).Infof("azureMount: mounting source (%q), target (%q), with options (%q)", source, target, options)
|
||||
return os.MkdirAll(target, 0755)
|
||||
}
|
||||
|
||||
parentDir := filepath.Dir(target)
|
||||
if err := os.MkdirAll(parentDir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
glog.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 {
|
||||
// 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",
|
||||
options, len(options), source, target)
|
||||
return nil
|
||||
}
|
||||
|
||||
// empty implementation for mounting azure file
|
||||
return os.MkdirAll(target, 0755)
|
||||
}
|
||||
|
||||
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))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unmount unmounts the target.
|
||||
func (mounter *Mounter) Unmount(target string) error {
|
||||
glog.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))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// List returns a list of all mounted filesystems. todo
|
||||
func (mounter *Mounter) List() ([]MountPoint, error) {
|
||||
return []MountPoint{}, nil
|
||||
}
|
||||
|
||||
// IsMountPointMatch determines if the mountpoint matches the dir
|
||||
func (mounter *Mounter) IsMountPointMatch(mp MountPoint, dir string) bool {
|
||||
return mp.Path == dir
|
||||
}
|
||||
|
||||
// IsNotMountPoint determines if a directory is a mountpoint.
|
||||
func (mounter *Mounter) IsNotMountPoint(dir string) (bool, error) {
|
||||
return IsNotMountPoint(mounter, dir)
|
||||
}
|
||||
|
||||
// IsLikelyNotMountPoint determines if a directory is not a mountpoint.
|
||||
func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
stat, err := os.Lstat(file)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
// If current file is a symlink, then it is a mountpoint.
|
||||
if stat.Mode()&os.ModeSymlink != 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// GetDeviceNameFromMount given a mnt point, find the device
|
||||
func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
return getDeviceNameFromMount(mounter, mountPath, pluginDir)
|
||||
}
|
||||
|
||||
// DeviceOpened determines if the device is in use elsewhere
|
||||
func (mounter *Mounter) DeviceOpened(pathname string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// PathIsDevice determines if a path is a device.
|
||||
func (mounter *Mounter) PathIsDevice(pathname string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// MakeRShared checks that given path is on a mount with 'rshared' mount
|
||||
// propagation. Empty implementation here.
|
||||
func (mounter *Mounter) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if err := ValidateDiskNumber(source); err != nil {
|
||||
glog.Errorf("azureMount: formatAndMount failed, err: %v\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
driveLetter, err := getDriveLetterByDiskNumber(source, mounter.Exec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
driverPath := driveLetter + ":"
|
||||
target = normalizeWindowsPath(target)
|
||||
glog.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))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizeWindowsPath(path string) string {
|
||||
normalizedPath := strings.Replace(path, "/", "\\", -1)
|
||||
if strings.HasPrefix(normalizedPath, "\\") {
|
||||
normalizedPath = "c:" + normalizedPath
|
||||
}
|
||||
return normalizedPath
|
||||
}
|
||||
|
||||
// ValidateDiskNumber : disk number should be a number in [0, 99]
|
||||
func ValidateDiskNumber(disk string) error {
|
||||
diskNum, err := strconv.Atoi(disk)
|
||||
if err != nil {
|
||||
return fmt.Errorf("wrong disk number format: %q, err:%v", disk, err)
|
||||
}
|
||||
|
||||
if diskNum < 0 || diskNum > 99 {
|
||||
return fmt.Errorf("disk number out of range: %q", disk)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get drive letter according to windows disk number
|
||||
func getDriveLetterByDiskNumber(diskNum string, exec Exec) (string, error) {
|
||||
cmd := fmt.Sprintf("(Get-Partition -DiskNumber %s).DriveLetter", diskNum)
|
||||
output, err := exec.Run("powershell", "/c", cmd)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("azureMount: Get Drive Letter failed: %v, output: %q", err, string(output))
|
||||
}
|
||||
if len(string(output)) < 1 {
|
||||
return "", fmt.Errorf("azureMount: Get Drive Letter failed, output is empty")
|
||||
}
|
||||
return string(output)[:1], nil
|
||||
}
|
101
vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount.go
generated
vendored
101
vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount.go
generated
vendored
|
@ -25,7 +25,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/util/exec"
|
||||
"k8s.io/utils/exec"
|
||||
)
|
||||
|
||||
// NsenterMounter is part of experimental support for running the kubelet
|
||||
|
@ -51,7 +51,7 @@ import (
|
|||
// contents. TODO: remove this requirement.
|
||||
// 6. The host image must have mount, findmnt, and umount binaries in /bin,
|
||||
// /usr/sbin, or /usr/bin
|
||||
//
|
||||
// 7. The host image should have systemd-run in /bin, /usr/sbin, or /usr/bin
|
||||
// For more information about mount propagation modes, see:
|
||||
// https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt
|
||||
type NsenterMounter struct {
|
||||
|
@ -62,9 +62,10 @@ type NsenterMounter struct {
|
|||
func NewNsenterMounter() *NsenterMounter {
|
||||
m := &NsenterMounter{
|
||||
paths: map[string]string{
|
||||
"mount": "",
|
||||
"findmnt": "",
|
||||
"umount": "",
|
||||
"mount": "",
|
||||
"findmnt": "",
|
||||
"umount": "",
|
||||
"systemd-run": "",
|
||||
},
|
||||
}
|
||||
// search for the mount command in other locations besides /usr/bin
|
||||
|
@ -80,6 +81,7 @@ func NewNsenterMounter() *NsenterMounter {
|
|||
break
|
||||
}
|
||||
// TODO: error, so that the kubelet can stop if the mounts don't exist
|
||||
// (don't forget that systemd-run is optional)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
@ -88,9 +90,11 @@ func NewNsenterMounter() *NsenterMounter {
|
|||
var _ = Interface(&NsenterMounter{})
|
||||
|
||||
const (
|
||||
hostRootFsPath = "/rootfs"
|
||||
hostProcMountsPath = "/rootfs/proc/1/mounts"
|
||||
nsenterPath = "nsenter"
|
||||
hostRootFsPath = "/rootfs"
|
||||
hostProcMountsPath = "/rootfs/proc/1/mounts"
|
||||
hostProcMountinfoPath = "/rootfs/proc/1/mountinfo"
|
||||
hostMountNamespacePath = "/rootfs/proc/1/ns/mnt"
|
||||
nsenterPath = "nsenter"
|
||||
)
|
||||
|
||||
// Mount runs mount(8) in the host's root mount namespace. Aside from this
|
||||
|
@ -128,26 +132,60 @@ func (n *NsenterMounter) doNsenterMount(source, target, fstype string, options [
|
|||
// makeNsenterArgs makes a list of argument to nsenter in order to do the
|
||||
// requested mount.
|
||||
func (n *NsenterMounter) makeNsenterArgs(source, target, fstype string, options []string) []string {
|
||||
nsenterArgs := []string{
|
||||
"--mount=/rootfs/proc/1/ns/mnt",
|
||||
"--",
|
||||
n.absHostPath("mount"),
|
||||
mountCmd := n.absHostPath("mount")
|
||||
mountArgs := makeMountArgs(source, target, fstype, options)
|
||||
|
||||
if systemdRunPath, hasSystemd := n.paths["systemd-run"]; hasSystemd {
|
||||
// Complete command line:
|
||||
// nsenter --mount=/rootfs/proc/1/ns/mnt -- /bin/systemd-run --description=... --scope -- /bin/mount -t <type> <what> <where>
|
||||
// Expected flow is:
|
||||
// * nsenter breaks out of container's mount namespace and executes
|
||||
// host's systemd-run.
|
||||
// * systemd-run creates a transient scope (=~ cgroup) and executes its
|
||||
// argument (/bin/mount) there.
|
||||
// * mount does its job, forks a fuse daemon if necessary and finishes.
|
||||
// (systemd-run --scope finishes at this point, returning mount's exit
|
||||
// code and stdout/stderr - thats one of --scope benefits).
|
||||
// * systemd keeps the fuse daemon running in the scope (i.e. in its own
|
||||
// cgroup) until the fuse daemon dies (another --scope benefit).
|
||||
// Kubelet container can be restarted and the fuse daemon survives.
|
||||
// * When the daemon dies (e.g. during unmount) systemd removes the
|
||||
// scope automatically.
|
||||
mountCmd, mountArgs = addSystemdScope(systemdRunPath, target, mountCmd, mountArgs)
|
||||
} else {
|
||||
// Fall back to simple mount when the host has no systemd.
|
||||
// Complete command line:
|
||||
// nsenter --mount=/rootfs/proc/1/ns/mnt -- /bin/mount -t <type> <what> <where>
|
||||
// Expected flow is:
|
||||
// * nsenter breaks out of container's mount namespace and executes host's /bin/mount.
|
||||
// * mount does its job, forks a fuse daemon if necessary and finishes.
|
||||
// * Any fuse daemon runs in cgroup of kubelet docker container,
|
||||
// restart of kubelet container will kill it!
|
||||
|
||||
// No code here, mountCmd and mountArgs use /bin/mount
|
||||
}
|
||||
|
||||
args := makeMountArgs(source, target, fstype, options)
|
||||
nsenterArgs := []string{
|
||||
"--mount=" + hostMountNamespacePath,
|
||||
"--",
|
||||
mountCmd,
|
||||
}
|
||||
nsenterArgs = append(nsenterArgs, mountArgs...)
|
||||
|
||||
return append(nsenterArgs, args...)
|
||||
return nsenterArgs
|
||||
}
|
||||
|
||||
// Unmount runs umount(8) in the host's mount namespace.
|
||||
func (n *NsenterMounter) Unmount(target string) error {
|
||||
args := []string{
|
||||
"--mount=/rootfs/proc/1/ns/mnt",
|
||||
"--mount=" + hostMountNamespacePath,
|
||||
"--",
|
||||
n.absHostPath("umount"),
|
||||
target,
|
||||
}
|
||||
|
||||
// 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("Unmount command: %v %v", nsenterPath, args)
|
||||
exec := exec.New()
|
||||
outputBytes, err := exec.Command(nsenterPath, args...).CombinedOutput()
|
||||
|
@ -189,7 +227,7 @@ func (n *NsenterMounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
|||
// 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{"--mount=/rootfs/proc/1/ns/mnt", "--", n.absHostPath("findmnt"), "-o", "target,fstype", "--noheadings", "--first-only", "--target", file}
|
||||
args := []string{"--mount=" + hostMountNamespacePath, "--", n.absHostPath("findmnt"), "-o", "target,fstype", "--noheadings", "--first-only", "--target", file}
|
||||
glog.V(5).Infof("findmnt command: %v %v", nsenterPath, args)
|
||||
|
||||
exec := exec.New()
|
||||
|
@ -201,8 +239,11 @@ func (n *NsenterMounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
|||
// It's safer to assume that it's not a mount point.
|
||||
return true, nil
|
||||
}
|
||||
mountTarget := strings.Split(string(out), " ")[0]
|
||||
mountTarget = strings.TrimSuffix(mountTarget, "\n")
|
||||
mountTarget, err := parseFindMnt(string(out))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
glog.V(5).Infof("IsLikelyNotMountPoint findmnt output for path %s: %v:", file, mountTarget)
|
||||
|
||||
if mountTarget == file {
|
||||
|
@ -213,6 +254,18 @@ func (n *NsenterMounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
|||
return true, nil
|
||||
}
|
||||
|
||||
// parse output of "findmnt -o target,fstype" and return just the target
|
||||
func parseFindMnt(out string) (string, error) {
|
||||
// cut trailing newline
|
||||
out = strings.TrimSuffix(out, "\n")
|
||||
// cut everything after the last space - it's the filesystem type
|
||||
i := strings.LastIndex(out, " ")
|
||||
if i == -1 {
|
||||
return "", fmt.Errorf("error parsing findmnt output, expected at least one space: %q", out)
|
||||
}
|
||||
return out[:i], nil
|
||||
}
|
||||
|
||||
// DeviceOpened checks if block device in use by calling Open with O_EXCL flag.
|
||||
// Returns true if open returns errno EBUSY, and false if errno is nil.
|
||||
// Returns an error if errno is any error other than EBUSY.
|
||||
|
@ -239,3 +292,13 @@ func (n *NsenterMounter) absHostPath(command string) string {
|
|||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func (n *NsenterMounter) MakeRShared(path string) error {
|
||||
nsenterCmd := nsenterPath
|
||||
nsenterArgs := []string{
|
||||
"--mount=" + hostMountNamespacePath,
|
||||
"--",
|
||||
n.absHostPath("mount"),
|
||||
}
|
||||
return doMakeRShared(path, hostProcMountinfoPath, nsenterCmd, nsenterArgs)
|
||||
}
|
||||
|
|
4
vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount_unsupported.go
generated
vendored
4
vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount_unsupported.go
generated
vendored
|
@ -61,3 +61,7 @@ func (*NsenterMounter) PathIsDevice(pathname string) (bool, error) {
|
|||
func (*NsenterMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (*NsenterMounter) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
|
10
vendor/k8s.io/kubernetes/pkg/util/net/sets/ipnet.go
generated
vendored
10
vendor/k8s.io/kubernetes/pkg/util/net/sets/ipnet.go
generated
vendored
|
@ -21,8 +21,10 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// IPNet maps string to net.IPNet.
|
||||
type IPNet map[string]*net.IPNet
|
||||
|
||||
// ParseIPNets parses string slice to IPNet.
|
||||
func ParseIPNets(specs ...string) (IPNet, error) {
|
||||
ipnetset := make(IPNet)
|
||||
for _, spec := range specs {
|
||||
|
@ -96,9 +98,9 @@ func (s IPNet) StringSlice() []string {
|
|||
}
|
||||
|
||||
// IsSuperset returns true if and only if s1 is a superset of s2.
|
||||
func (s1 IPNet) IsSuperset(s2 IPNet) bool {
|
||||
func (s IPNet) IsSuperset(s2 IPNet) bool {
|
||||
for k := range s2 {
|
||||
_, found := s1[k]
|
||||
_, found := s[k]
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
|
@ -109,8 +111,8 @@ func (s1 IPNet) IsSuperset(s2 IPNet) bool {
|
|||
// Equal returns true if and only if s1 is equal (as a set) to s2.
|
||||
// Two sets are equal if their membership is identical.
|
||||
// (In practice, this means same elements, order doesn't matter)
|
||||
func (s1 IPNet) Equal(s2 IPNet) bool {
|
||||
return len(s1) == len(s2) && s1.IsSuperset(s2)
|
||||
func (s IPNet) Equal(s2 IPNet) bool {
|
||||
return len(s) == len(s2) && s.IsSuperset(s2)
|
||||
}
|
||||
|
||||
// Len returns the size of the set.
|
||||
|
|
6
vendor/k8s.io/kubernetes/pkg/util/parsers/parsers.go
generated
vendored
6
vendor/k8s.io/kubernetes/pkg/util/parsers/parsers.go
generated
vendored
|
@ -18,6 +18,10 @@ package parsers
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
// Import the crypto sha256 algorithm for the docker image parser to work
|
||||
_ "crypto/sha256"
|
||||
// Import the crypto/sha512 algorithm for the docker image parser to work with 384 and 512 sha hashes
|
||||
_ "crypto/sha512"
|
||||
|
||||
dockerref "github.com/docker/distribution/reference"
|
||||
)
|
||||
|
@ -29,7 +33,7 @@ const (
|
|||
// ParseImageName parses a docker image string into three parts: repo, tag and digest.
|
||||
// If both tag and digest are empty, a default image tag will be returned.
|
||||
func ParseImageName(image string) (string, string, string, error) {
|
||||
named, err := dockerref.ParseNamed(image)
|
||||
named, err := dockerref.ParseNormalizedNamed(image)
|
||||
if err != nil {
|
||||
return "", "", "", fmt.Errorf("couldn't parse image name: %v", err)
|
||||
}
|
||||
|
|
62
vendor/k8s.io/kubernetes/pkg/util/pointer/pointer.go
generated
vendored
Normal file
62
vendor/k8s.io/kubernetes/pkg/util/pointer/pointer.go
generated
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
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 {
|
||||
o := i
|
||||
return &o
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
331
vendor/k8s.io/kubernetes/pkg/util/taints/taints.go
generated
vendored
Normal file
331
vendor/k8s.io/kubernetes/pkg/util/taints/taints.go
generated
vendored
Normal file
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
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 taints implements utilites for working with taints
|
||||
package taints
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/helper"
|
||||
)
|
||||
|
||||
const (
|
||||
MODIFIED = "modified"
|
||||
TAINTED = "tainted"
|
||||
UNTAINTED = "untainted"
|
||||
)
|
||||
|
||||
// parseTaint parses a taint from a string. Taint must be off the format '<key>=<value>:<effect>'.
|
||||
func parseTaint(st string) (v1.Taint, error) {
|
||||
var taint v1.Taint
|
||||
parts := strings.Split(st, "=")
|
||||
if len(parts) != 2 || len(parts[1]) == 0 || len(validation.IsQualifiedName(parts[0])) > 0 {
|
||||
return taint, fmt.Errorf("invalid taint spec: %v", st)
|
||||
}
|
||||
|
||||
parts2 := strings.Split(parts[1], ":")
|
||||
|
||||
effect := v1.TaintEffect(parts2[1])
|
||||
|
||||
errs := validation.IsValidLabelValue(parts2[0])
|
||||
if len(parts2) != 2 || len(errs) != 0 {
|
||||
return taint, fmt.Errorf("invalid taint spec: %v, %s", st, strings.Join(errs, "; "))
|
||||
}
|
||||
|
||||
if effect != v1.TaintEffectNoSchedule && effect != v1.TaintEffectPreferNoSchedule && effect != v1.TaintEffectNoExecute {
|
||||
return taint, fmt.Errorf("invalid taint spec: %v, unsupported taint effect", st)
|
||||
}
|
||||
|
||||
taint.Key = parts[0]
|
||||
taint.Value = parts2[0]
|
||||
taint.Effect = effect
|
||||
|
||||
return taint, nil
|
||||
}
|
||||
|
||||
// NewTaintsVar wraps []api.Taint in a struct that implements flag.Value to allow taints to be
|
||||
// bound to command line flags.
|
||||
func NewTaintsVar(ptr *[]api.Taint) taintsVar {
|
||||
return taintsVar{
|
||||
ptr: ptr,
|
||||
}
|
||||
}
|
||||
|
||||
type taintsVar struct {
|
||||
ptr *[]api.Taint
|
||||
}
|
||||
|
||||
func (t taintsVar) Set(s string) error {
|
||||
sts := strings.Split(s, ",")
|
||||
var taints []api.Taint
|
||||
for _, st := range sts {
|
||||
taint, err := parseTaint(st)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
taints = append(taints, api.Taint{Key: taint.Key, Value: taint.Value, Effect: api.TaintEffect(taint.Effect)})
|
||||
}
|
||||
*t.ptr = taints
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t taintsVar) String() string {
|
||||
if len(*t.ptr) == 0 {
|
||||
return "<nil>"
|
||||
}
|
||||
var taints []string
|
||||
for _, taint := range *t.ptr {
|
||||
taints = append(taints, fmt.Sprintf("%s=%s:%s", taint.Key, taint.Value, taint.Effect))
|
||||
}
|
||||
return strings.Join(taints, ",")
|
||||
}
|
||||
|
||||
func (t taintsVar) Type() string {
|
||||
return "[]api.Taint"
|
||||
}
|
||||
|
||||
// ParseTaints takes a spec which is an array and creates slices for new taints to be added, taints to be deleted.
|
||||
func ParseTaints(spec []string) ([]v1.Taint, []v1.Taint, error) {
|
||||
var taints, taintsToRemove []v1.Taint
|
||||
uniqueTaints := map[v1.TaintEffect]sets.String{}
|
||||
|
||||
for _, taintSpec := range spec {
|
||||
if strings.Index(taintSpec, "=") != -1 && strings.Index(taintSpec, ":") != -1 {
|
||||
newTaint, err := parseTaint(taintSpec)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// validate if taint is unique by <key, effect>
|
||||
if len(uniqueTaints[newTaint.Effect]) > 0 && uniqueTaints[newTaint.Effect].Has(newTaint.Key) {
|
||||
return nil, nil, fmt.Errorf("duplicated taints with the same key and effect: %v", newTaint)
|
||||
}
|
||||
// add taint to existingTaints for uniqueness check
|
||||
if len(uniqueTaints[newTaint.Effect]) == 0 {
|
||||
uniqueTaints[newTaint.Effect] = sets.String{}
|
||||
}
|
||||
uniqueTaints[newTaint.Effect].Insert(newTaint.Key)
|
||||
|
||||
taints = append(taints, newTaint)
|
||||
} else if strings.HasSuffix(taintSpec, "-") {
|
||||
taintKey := taintSpec[:len(taintSpec)-1]
|
||||
var effect v1.TaintEffect
|
||||
if strings.Index(taintKey, ":") != -1 {
|
||||
parts := strings.Split(taintKey, ":")
|
||||
taintKey = parts[0]
|
||||
effect = v1.TaintEffect(parts[1])
|
||||
}
|
||||
taintsToRemove = append(taintsToRemove, v1.Taint{Key: taintKey, Effect: effect})
|
||||
} else {
|
||||
return nil, nil, fmt.Errorf("unknown taint spec: %v", taintSpec)
|
||||
}
|
||||
}
|
||||
return taints, taintsToRemove, nil
|
||||
}
|
||||
|
||||
// ReorganizeTaints returns the updated set of taints, taking into account old taints that were not updated,
|
||||
// old taints that were updated, old taints that were deleted, and new taints.
|
||||
func ReorganizeTaints(node *v1.Node, overwrite bool, taintsToAdd []v1.Taint, taintsToRemove []v1.Taint) (string, []v1.Taint, error) {
|
||||
newTaints := append([]v1.Taint{}, taintsToAdd...)
|
||||
oldTaints := node.Spec.Taints
|
||||
// add taints that already existing but not updated to newTaints
|
||||
added := addTaints(oldTaints, &newTaints)
|
||||
allErrs, deleted := deleteTaints(taintsToRemove, &newTaints)
|
||||
if (added && deleted) || overwrite {
|
||||
return MODIFIED, newTaints, utilerrors.NewAggregate(allErrs)
|
||||
} else if added {
|
||||
return TAINTED, newTaints, utilerrors.NewAggregate(allErrs)
|
||||
}
|
||||
return UNTAINTED, newTaints, utilerrors.NewAggregate(allErrs)
|
||||
}
|
||||
|
||||
// deleteTaints deletes the given taints from the node's taintlist.
|
||||
func deleteTaints(taintsToRemove []v1.Taint, newTaints *[]v1.Taint) ([]error, bool) {
|
||||
allErrs := []error{}
|
||||
var removed bool
|
||||
for _, taintToRemove := range taintsToRemove {
|
||||
removed = false
|
||||
if len(taintToRemove.Effect) > 0 {
|
||||
*newTaints, removed = DeleteTaint(*newTaints, &taintToRemove)
|
||||
} else {
|
||||
*newTaints, removed = DeleteTaintsByKey(*newTaints, taintToRemove.Key)
|
||||
}
|
||||
if !removed {
|
||||
allErrs = append(allErrs, fmt.Errorf("taint %q not found", taintToRemove.ToString()))
|
||||
}
|
||||
}
|
||||
return allErrs, removed
|
||||
}
|
||||
|
||||
// addTaints adds the newTaints list to existing ones and updates the newTaints List.
|
||||
// TODO: This needs a rewrite to take only the new values instead of appended newTaints list to be consistent.
|
||||
func addTaints(oldTaints []v1.Taint, newTaints *[]v1.Taint) bool {
|
||||
for _, oldTaint := range oldTaints {
|
||||
existsInNew := false
|
||||
for _, taint := range *newTaints {
|
||||
if taint.MatchTaint(&oldTaint) {
|
||||
existsInNew = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !existsInNew {
|
||||
*newTaints = append(*newTaints, oldTaint)
|
||||
}
|
||||
}
|
||||
return len(oldTaints) != len(*newTaints)
|
||||
}
|
||||
|
||||
// CheckIfTaintsAlreadyExists checks if the node already has taints that we want to add and returns a string with taint keys.
|
||||
func CheckIfTaintsAlreadyExists(oldTaints []v1.Taint, taints []v1.Taint) string {
|
||||
var existingTaintList = make([]string, 0)
|
||||
for _, taint := range taints {
|
||||
for _, oldTaint := range oldTaints {
|
||||
if taint.Key == oldTaint.Key && taint.Effect == oldTaint.Effect {
|
||||
existingTaintList = append(existingTaintList, taint.Key)
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.Join(existingTaintList, ",")
|
||||
}
|
||||
|
||||
// DeleteTaintsByKey removes all the taints that have the same key to given taintKey
|
||||
func DeleteTaintsByKey(taints []v1.Taint, taintKey string) ([]v1.Taint, bool) {
|
||||
newTaints := []v1.Taint{}
|
||||
deleted := false
|
||||
for i := range taints {
|
||||
if taintKey == taints[i].Key {
|
||||
deleted = true
|
||||
continue
|
||||
}
|
||||
newTaints = append(newTaints, taints[i])
|
||||
}
|
||||
return newTaints, deleted
|
||||
}
|
||||
|
||||
// DeleteTaint removes all the the taints that have the same key and effect to given taintToDelete.
|
||||
func DeleteTaint(taints []v1.Taint, taintToDelete *v1.Taint) ([]v1.Taint, bool) {
|
||||
newTaints := []v1.Taint{}
|
||||
deleted := false
|
||||
for i := range taints {
|
||||
if taintToDelete.MatchTaint(&taints[i]) {
|
||||
deleted = true
|
||||
continue
|
||||
}
|
||||
newTaints = append(newTaints, taints[i])
|
||||
}
|
||||
return newTaints, deleted
|
||||
}
|
||||
|
||||
// RemoveTaint tries to remove a taint from annotations list. Returns a new copy of updated Node and true if something was updated
|
||||
// false otherwise.
|
||||
func RemoveTaint(node *v1.Node, taint *v1.Taint) (*v1.Node, bool, error) {
|
||||
objCopy, err := api.Scheme.DeepCopy(node)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
newNode := objCopy.(*v1.Node)
|
||||
nodeTaints := newNode.Spec.Taints
|
||||
if len(nodeTaints) == 0 {
|
||||
return newNode, false, nil
|
||||
}
|
||||
|
||||
if !TaintExists(nodeTaints, taint) {
|
||||
return newNode, false, nil
|
||||
}
|
||||
|
||||
newTaints, _ := DeleteTaint(nodeTaints, taint)
|
||||
newNode.Spec.Taints = newTaints
|
||||
return newNode, true, nil
|
||||
}
|
||||
|
||||
// AddOrUpdateTaint tries to add a taint to annotations list. Returns a new copy of updated Node and true if something was updated
|
||||
// false otherwise.
|
||||
func AddOrUpdateTaint(node *v1.Node, taint *v1.Taint) (*v1.Node, bool, error) {
|
||||
objCopy, err := api.Scheme.DeepCopy(node)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
newNode := objCopy.(*v1.Node)
|
||||
nodeTaints := newNode.Spec.Taints
|
||||
|
||||
var newTaints []v1.Taint
|
||||
updated := false
|
||||
for i := range nodeTaints {
|
||||
if taint.MatchTaint(&nodeTaints[i]) {
|
||||
if helper.Semantic.DeepEqual(*taint, nodeTaints[i]) {
|
||||
return newNode, false, nil
|
||||
}
|
||||
newTaints = append(newTaints, *taint)
|
||||
updated = true
|
||||
continue
|
||||
}
|
||||
|
||||
newTaints = append(newTaints, nodeTaints[i])
|
||||
}
|
||||
|
||||
if !updated {
|
||||
newTaints = append(newTaints, *taint)
|
||||
}
|
||||
|
||||
newNode.Spec.Taints = newTaints
|
||||
return newNode, true, nil
|
||||
}
|
||||
|
||||
// TaintExists checks if the given taint exists in list of taints. Returns true if exists false otherwise.
|
||||
func TaintExists(taints []v1.Taint, taintToFind *v1.Taint) bool {
|
||||
for _, taint := range taints {
|
||||
if taint.MatchTaint(taintToFind) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TaintSetDiff(t1, t2 []v1.Taint) (taintsToAdd []*v1.Taint, taintsToRemove []*v1.Taint) {
|
||||
for _, taint := range t1 {
|
||||
if !TaintExists(t2, &taint) {
|
||||
t := taint
|
||||
taintsToAdd = append(taintsToAdd, &t)
|
||||
}
|
||||
}
|
||||
|
||||
for _, taint := range t2 {
|
||||
if !TaintExists(t1, &taint) {
|
||||
t := taint
|
||||
taintsToRemove = append(taintsToRemove, &t)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func TaintSetFilter(taints []v1.Taint, fn func(*v1.Taint) bool) []v1.Taint {
|
||||
res := []v1.Taint{}
|
||||
|
||||
for _, taint := range taints {
|
||||
if fn(&taint) {
|
||||
res = append(res, taint)
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
48
vendor/k8s.io/kubernetes/pkg/util/template.go
generated
vendored
48
vendor/k8s.io/kubernetes/pkg/util/template.go
generated
vendored
|
@ -1,48 +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 util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"go/doc"
|
||||
"io"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func wrap(indent string, s string) string {
|
||||
var buf bytes.Buffer
|
||||
doc.ToText(&buf, s, indent, indent+" ", 80-len(indent))
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// ExecuteTemplate executes templateText with data and output written to w.
|
||||
func ExecuteTemplate(w io.Writer, templateText string, data interface{}) error {
|
||||
t := template.New("top")
|
||||
t.Funcs(template.FuncMap{
|
||||
"trim": strings.TrimSpace,
|
||||
"wrap": wrap,
|
||||
})
|
||||
template.Must(t.Parse(templateText))
|
||||
return t.Execute(w, data)
|
||||
}
|
||||
|
||||
func ExecuteTemplateToString(templateText string, data interface{}) (string, error) {
|
||||
b := bytes.Buffer{}
|
||||
err := ExecuteTemplate(&b, templateText, data)
|
||||
return b.String(), err
|
||||
}
|
132
vendor/k8s.io/kubernetes/pkg/util/term/resize.go
generated
vendored
132
vendor/k8s.io/kubernetes/pkg/util/term/resize.go
generated
vendored
|
@ -1,132 +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 term
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/docker/pkg/term"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
)
|
||||
|
||||
// GetSize returns the current size of the user's terminal. If it isn't a terminal,
|
||||
// nil is returned.
|
||||
func (t TTY) GetSize() *remotecommand.TerminalSize {
|
||||
outFd, isTerminal := term.GetFdInfo(t.Out)
|
||||
if !isTerminal {
|
||||
return nil
|
||||
}
|
||||
return GetSize(outFd)
|
||||
}
|
||||
|
||||
// GetSize returns the current size of the terminal associated with fd.
|
||||
func GetSize(fd uintptr) *remotecommand.TerminalSize {
|
||||
winsize, err := term.GetWinsize(fd)
|
||||
if err != nil {
|
||||
runtime.HandleError(fmt.Errorf("unable to get terminal size: %v", err))
|
||||
return nil
|
||||
}
|
||||
|
||||
return &remotecommand.TerminalSize{Width: winsize.Width, Height: winsize.Height}
|
||||
}
|
||||
|
||||
// MonitorSize monitors the terminal's size. It returns a TerminalSizeQueue primed with
|
||||
// initialSizes, or nil if there's no TTY present.
|
||||
func (t *TTY) MonitorSize(initialSizes ...*remotecommand.TerminalSize) remotecommand.TerminalSizeQueue {
|
||||
outFd, isTerminal := term.GetFdInfo(t.Out)
|
||||
if !isTerminal {
|
||||
return nil
|
||||
}
|
||||
|
||||
t.sizeQueue = &sizeQueue{
|
||||
t: *t,
|
||||
// make it buffered so we can send the initial terminal sizes without blocking, prior to starting
|
||||
// the streaming below
|
||||
resizeChan: make(chan remotecommand.TerminalSize, len(initialSizes)),
|
||||
stopResizing: make(chan struct{}),
|
||||
}
|
||||
|
||||
t.sizeQueue.monitorSize(outFd, initialSizes...)
|
||||
|
||||
return t.sizeQueue
|
||||
}
|
||||
|
||||
// sizeQueue implements remotecommand.TerminalSizeQueue
|
||||
type sizeQueue struct {
|
||||
t TTY
|
||||
// resizeChan receives a Size each time the user's terminal is resized.
|
||||
resizeChan chan remotecommand.TerminalSize
|
||||
stopResizing chan struct{}
|
||||
}
|
||||
|
||||
// make sure sizeQueue implements the resize.TerminalSizeQueue interface
|
||||
var _ remotecommand.TerminalSizeQueue = &sizeQueue{}
|
||||
|
||||
// monitorSize primes resizeChan with initialSizes and then monitors for resize events. With each
|
||||
// new event, it sends the current terminal size to resizeChan.
|
||||
func (s *sizeQueue) monitorSize(outFd uintptr, initialSizes ...*remotecommand.TerminalSize) {
|
||||
// send the initial sizes
|
||||
for i := range initialSizes {
|
||||
if initialSizes[i] != nil {
|
||||
s.resizeChan <- *initialSizes[i]
|
||||
}
|
||||
}
|
||||
|
||||
resizeEvents := make(chan remotecommand.TerminalSize, 1)
|
||||
|
||||
monitorResizeEvents(outFd, resizeEvents, s.stopResizing)
|
||||
|
||||
// listen for resize events in the background
|
||||
go func() {
|
||||
defer runtime.HandleCrash()
|
||||
|
||||
for {
|
||||
select {
|
||||
case size, ok := <-resizeEvents:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
// try to send the size to resizeChan, but don't block
|
||||
case s.resizeChan <- size:
|
||||
// send successful
|
||||
default:
|
||||
// unable to send / no-op
|
||||
}
|
||||
case <-s.stopResizing:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Next returns the new terminal size after the terminal has been resized. It returns nil when
|
||||
// monitoring has been stopped.
|
||||
func (s *sizeQueue) Next() *remotecommand.TerminalSize {
|
||||
size, ok := <-s.resizeChan
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return &size
|
||||
}
|
||||
|
||||
// stop stops the background goroutine that is monitoring for terminal resizes.
|
||||
func (s *sizeQueue) stop() {
|
||||
close(s.stopResizing)
|
||||
}
|
61
vendor/k8s.io/kubernetes/pkg/util/term/resizeevents.go
generated
vendored
61
vendor/k8s.io/kubernetes/pkg/util/term/resizeevents.go
generated
vendored
|
@ -1,61 +0,0 @@
|
|||
// +build !windows
|
||||
|
||||
/*
|
||||
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 term
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
)
|
||||
|
||||
// monitorResizeEvents spawns a goroutine that waits for SIGWINCH signals (these indicate the
|
||||
// terminal has resized). After receiving a SIGWINCH, this gets the terminal size and tries to send
|
||||
// it to the resizeEvents channel. The goroutine stops when the stop channel is closed.
|
||||
func monitorResizeEvents(fd uintptr, resizeEvents chan<- remotecommand.TerminalSize, stop chan struct{}) {
|
||||
go func() {
|
||||
defer runtime.HandleCrash()
|
||||
|
||||
winch := make(chan os.Signal, 1)
|
||||
signal.Notify(winch, syscall.SIGWINCH)
|
||||
defer signal.Stop(winch)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-winch:
|
||||
size := GetSize(fd)
|
||||
if size == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// try to send size
|
||||
select {
|
||||
case resizeEvents <- *size:
|
||||
// success
|
||||
default:
|
||||
// not sent
|
||||
}
|
||||
case <-stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
62
vendor/k8s.io/kubernetes/pkg/util/term/resizeevents_windows.go
generated
vendored
62
vendor/k8s.io/kubernetes/pkg/util/term/resizeevents_windows.go
generated
vendored
|
@ -1,62 +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 term
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
)
|
||||
|
||||
// monitorResizeEvents spawns a goroutine that periodically gets the terminal size and tries to send
|
||||
// it to the resizeEvents channel if the size has changed. The goroutine stops when the stop channel
|
||||
// is closed.
|
||||
func monitorResizeEvents(fd uintptr, resizeEvents chan<- remotecommand.TerminalSize, stop chan struct{}) {
|
||||
go func() {
|
||||
defer runtime.HandleCrash()
|
||||
|
||||
size := GetSize(fd)
|
||||
if size == nil {
|
||||
return
|
||||
}
|
||||
lastSize := *size
|
||||
|
||||
for {
|
||||
// see if we need to stop running
|
||||
select {
|
||||
case <-stop:
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
size := GetSize(fd)
|
||||
if size == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if size.Height != lastSize.Height || size.Width != lastSize.Width {
|
||||
lastSize.Height = size.Height
|
||||
lastSize.Width = size.Width
|
||||
resizeEvents <- *size
|
||||
}
|
||||
|
||||
// sleep to avoid hot looping
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
}
|
110
vendor/k8s.io/kubernetes/pkg/util/term/term.go
generated
vendored
110
vendor/k8s.io/kubernetes/pkg/util/term/term.go
generated
vendored
|
@ -1,110 +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 term
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/docker/docker/pkg/term"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/interrupt"
|
||||
)
|
||||
|
||||
// SafeFunc is a function to be invoked by TTY.
|
||||
type SafeFunc func() error
|
||||
|
||||
// TTY helps invoke a function and preserve the state of the terminal, even if the process is
|
||||
// terminated during execution. It also provides support for terminal resizing for remote command
|
||||
// execution/attachment.
|
||||
type TTY struct {
|
||||
// In is a reader representing stdin. It is a required field.
|
||||
In io.Reader
|
||||
// Out is a writer representing stdout. It must be set to support terminal resizing. It is an
|
||||
// optional field.
|
||||
Out io.Writer
|
||||
// Raw is true if the terminal should be set raw.
|
||||
Raw bool
|
||||
// TryDev indicates the TTY should try to open /dev/tty if the provided input
|
||||
// is not a file descriptor.
|
||||
TryDev bool
|
||||
// Parent is an optional interrupt handler provided to this function - if provided
|
||||
// it will be invoked after the terminal state is restored. If it is not provided,
|
||||
// a signal received during the TTY will result in os.Exit(0) being invoked.
|
||||
Parent *interrupt.Handler
|
||||
|
||||
// sizeQueue is set after a call to MonitorSize() and is used to monitor SIGWINCH signals when the
|
||||
// user's terminal resizes.
|
||||
sizeQueue *sizeQueue
|
||||
}
|
||||
|
||||
// IsTerminalIn returns true if t.In is a terminal. Does not check /dev/tty
|
||||
// even if TryDev is set.
|
||||
func (t TTY) IsTerminalIn() bool {
|
||||
return IsTerminal(t.In)
|
||||
}
|
||||
|
||||
// IsTerminalOut returns true if t.Out is a terminal. Does not check /dev/tty
|
||||
// even if TryDev is set.
|
||||
func (t TTY) IsTerminalOut() bool {
|
||||
return IsTerminal(t.Out)
|
||||
}
|
||||
|
||||
// IsTerminal returns whether the passed object is a terminal or not
|
||||
func IsTerminal(i interface{}) bool {
|
||||
_, terminal := term.GetFdInfo(i)
|
||||
return terminal
|
||||
}
|
||||
|
||||
// Safe invokes the provided function and will attempt to ensure that when the
|
||||
// function returns (or a termination signal is sent) that the terminal state
|
||||
// is reset to the condition it was in prior to the function being invoked. If
|
||||
// t.Raw is true the terminal will be put into raw mode prior to calling the function.
|
||||
// If the input file descriptor is not a TTY and TryDev is true, the /dev/tty file
|
||||
// will be opened (if available).
|
||||
func (t TTY) Safe(fn SafeFunc) error {
|
||||
inFd, isTerminal := term.GetFdInfo(t.In)
|
||||
|
||||
if !isTerminal && t.TryDev {
|
||||
if f, err := os.Open("/dev/tty"); err == nil {
|
||||
defer f.Close()
|
||||
inFd = f.Fd()
|
||||
isTerminal = term.IsTerminal(inFd)
|
||||
}
|
||||
}
|
||||
if !isTerminal {
|
||||
return fn()
|
||||
}
|
||||
|
||||
var state *term.State
|
||||
var err error
|
||||
if t.Raw {
|
||||
state, err = term.MakeRaw(inFd)
|
||||
} else {
|
||||
state, err = term.SaveState(inFd)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return interrupt.Chain(t.Parent, func() {
|
||||
if t.sizeQueue != nil {
|
||||
t.sizeQueue.stop()
|
||||
}
|
||||
|
||||
term.RestoreTerminal(inFd, state)
|
||||
}).Run(fn)
|
||||
}
|
124
vendor/k8s.io/kubernetes/pkg/util/term/term_writer.go
generated
vendored
124
vendor/k8s.io/kubernetes/pkg/util/term/term_writer.go
generated
vendored
|
@ -1,124 +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 term
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/docker/docker/pkg/term"
|
||||
wordwrap "github.com/mitchellh/go-wordwrap"
|
||||
)
|
||||
|
||||
type wordWrapWriter struct {
|
||||
limit uint
|
||||
writer io.Writer
|
||||
}
|
||||
|
||||
// NewResponsiveWriter creates a Writer that detects the column width of the
|
||||
// terminal we are in, and adjusts every line width to fit and use recommended
|
||||
// terminal sizes for better readability. Does proper word wrapping automatically.
|
||||
// if terminal width >= 120 columns use 120 columns
|
||||
// if terminal width >= 100 columns use 100 columns
|
||||
// if terminal width >= 80 columns use 80 columns
|
||||
// In case we're not in a terminal or if it's smaller than 80 columns width,
|
||||
// doesn't do any wrapping.
|
||||
func NewResponsiveWriter(w io.Writer) io.Writer {
|
||||
file, ok := w.(*os.File)
|
||||
if !ok {
|
||||
return w
|
||||
}
|
||||
fd := file.Fd()
|
||||
if !term.IsTerminal(fd) {
|
||||
return w
|
||||
}
|
||||
|
||||
terminalSize := GetSize(fd)
|
||||
if terminalSize == nil {
|
||||
return w
|
||||
}
|
||||
|
||||
var limit uint
|
||||
switch {
|
||||
case terminalSize.Width >= 120:
|
||||
limit = 120
|
||||
case terminalSize.Width >= 100:
|
||||
limit = 100
|
||||
case terminalSize.Width >= 80:
|
||||
limit = 80
|
||||
}
|
||||
|
||||
return NewWordWrapWriter(w, limit)
|
||||
}
|
||||
|
||||
// NewWordWrapWriter is a Writer that supports a limit of characters on every line
|
||||
// and does auto word wrapping that respects that limit.
|
||||
func NewWordWrapWriter(w io.Writer, limit uint) io.Writer {
|
||||
return &wordWrapWriter{
|
||||
limit: limit,
|
||||
writer: w,
|
||||
}
|
||||
}
|
||||
|
||||
func (w wordWrapWriter) Write(p []byte) (nn int, err error) {
|
||||
if w.limit == 0 {
|
||||
return w.writer.Write(p)
|
||||
}
|
||||
original := string(p)
|
||||
wrapped := wordwrap.WrapString(original, w.limit)
|
||||
return w.writer.Write([]byte(wrapped))
|
||||
}
|
||||
|
||||
// NewPunchCardWriter is a NewWordWrapWriter that limits the line width to 80 columns.
|
||||
func NewPunchCardWriter(w io.Writer) io.Writer {
|
||||
return NewWordWrapWriter(w, 80)
|
||||
}
|
||||
|
||||
type maxWidthWriter struct {
|
||||
maxWidth uint
|
||||
currentWidth uint
|
||||
written uint
|
||||
writer io.Writer
|
||||
}
|
||||
|
||||
// NewMaxWidthWriter is a Writer that supports a limit of characters on every
|
||||
// line, but doesn't do any word wrapping automatically.
|
||||
func NewMaxWidthWriter(w io.Writer, maxWidth uint) io.Writer {
|
||||
return &maxWidthWriter{
|
||||
maxWidth: maxWidth,
|
||||
writer: w,
|
||||
}
|
||||
}
|
||||
|
||||
func (m maxWidthWriter) Write(p []byte) (nn int, err error) {
|
||||
for _, b := range p {
|
||||
if m.currentWidth == m.maxWidth {
|
||||
m.writer.Write([]byte{'\n'})
|
||||
m.currentWidth = 0
|
||||
}
|
||||
if b == '\n' {
|
||||
m.currentWidth = 0
|
||||
}
|
||||
_, err := m.writer.Write([]byte{b})
|
||||
if err != nil {
|
||||
return int(m.written), err
|
||||
}
|
||||
m.written++
|
||||
m.currentWidth++
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
27
vendor/k8s.io/kubernetes/pkg/util/umask.go
generated
vendored
27
vendor/k8s.io/kubernetes/pkg/util/umask.go
generated
vendored
|
@ -1,27 +0,0 @@
|
|||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func Umask(mask int) (old int, err error) {
|
||||
return syscall.Umask(mask), nil
|
||||
}
|
27
vendor/k8s.io/kubernetes/pkg/util/umask_windows.go
generated
vendored
27
vendor/k8s.io/kubernetes/pkg/util/umask_windows.go
generated
vendored
|
@ -1,27 +0,0 @@
|
|||
// +build windows
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
func Umask(mask int) (int, error) {
|
||||
return 0, errors.New("platform and architecture is not supported")
|
||||
}
|
140
vendor/k8s.io/kubernetes/pkg/util/util.go
generated
vendored
140
vendor/k8s.io/kubernetes/pkg/util/util.go
generated
vendored
|
@ -1,140 +0,0 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// Takes a list of strings and compiles them into a list of regular expressions
|
||||
func CompileRegexps(regexpStrings []string) ([]*regexp.Regexp, error) {
|
||||
regexps := []*regexp.Regexp{}
|
||||
for _, regexpStr := range regexpStrings {
|
||||
r, err := regexp.Compile(regexpStr)
|
||||
if err != nil {
|
||||
return []*regexp.Regexp{}, err
|
||||
}
|
||||
regexps = append(regexps, r)
|
||||
}
|
||||
return regexps, nil
|
||||
}
|
||||
|
||||
// Detects if using systemd as the init system
|
||||
// Please note that simply reading /proc/1/cmdline can be misleading because
|
||||
// some installation of various init programs can automatically make /sbin/init
|
||||
// a symlink or even a renamed version of their main program.
|
||||
// TODO(dchen1107): realiably detects the init system using on the system:
|
||||
// systemd, upstart, initd, etc.
|
||||
func UsingSystemdInitSystem() bool {
|
||||
if _, err := os.Stat("/run/systemd/system"); err == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func FileExists(filename string) (bool, error) {
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
return false, nil
|
||||
} else if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func FileOrSymlinkExists(filename string) (bool, error) {
|
||||
if _, err := os.Lstat(filename); os.IsNotExist(err) {
|
||||
return false, nil
|
||||
} else if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// ReadDirNoStat returns a string of files/directories contained
|
||||
// in dirname without calling lstat on them.
|
||||
func ReadDirNoStat(dirname string) ([]string, error) {
|
||||
if dirname == "" {
|
||||
dirname = "."
|
||||
}
|
||||
|
||||
f, err := os.Open(dirname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return f.Readdirnames(-1)
|
||||
}
|
||||
|
||||
// IntPtr returns a pointer to an int
|
||||
func IntPtr(i int) *int {
|
||||
o := i
|
||||
return &o
|
||||
}
|
||||
|
||||
// Int32Ptr returns a pointer to an int32
|
||||
func Int32Ptr(i int32) *int32 {
|
||||
o := i
|
||||
return &o
|
||||
}
|
||||
|
||||
// IntPtrDerefOr dereference the int ptr and returns it i not nil,
|
||||
// else returns def.
|
||||
func IntPtrDerefOr(ptr *int, def int) int {
|
||||
if ptr != nil {
|
||||
return *ptr
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
28
vendor/k8s.io/kubernetes/pkg/util/version/version.go
generated
vendored
28
vendor/k8s.io/kubernetes/pkg/util/version/version.go
generated
vendored
|
@ -121,11 +121,39 @@ func MustParseSemantic(str string) *Version {
|
|||
return v
|
||||
}
|
||||
|
||||
// Major returns the major release number
|
||||
func (v *Version) Major() uint {
|
||||
return v.components[0]
|
||||
}
|
||||
|
||||
// Minor returns the minor release number
|
||||
func (v *Version) Minor() uint {
|
||||
return v.components[1]
|
||||
}
|
||||
|
||||
// Patch returns the patch release number if v is a Semantic Version, or 0
|
||||
func (v *Version) Patch() uint {
|
||||
if len(v.components) < 3 {
|
||||
return 0
|
||||
}
|
||||
return v.components[2]
|
||||
}
|
||||
|
||||
// BuildMetadata returns the build metadata, if v is a Semantic Version, or ""
|
||||
func (v *Version) BuildMetadata() string {
|
||||
return v.buildMetadata
|
||||
}
|
||||
|
||||
// PreRelease returns the prerelease metadata, if v is a Semantic Version, or ""
|
||||
func (v *Version) PreRelease() string {
|
||||
return v.preRelease
|
||||
}
|
||||
|
||||
// Components returns the version number components
|
||||
func (v *Version) Components() []uint {
|
||||
return v.components
|
||||
}
|
||||
|
||||
// String converts a Version back to a string; note that for versions parsed with
|
||||
// ParseGeneric, this will not include the trailing uninterpreted portion of the version
|
||||
// number.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue