diff --git a/Gopkg.lock b/Gopkg.lock index 65acde4b..755c07c0 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -375,6 +375,15 @@ revision = "fc32d2f3698e36b93322a3465f63a14e9f0eaead" version = "v1.10.0" +[[projects]] + branch = "master" + name = "k8s.io/utils" + packages = [ + "exec", + "exec/testing" + ] + revision = "258e2a2fa64568210fbd6267cf1d8fd87c3cb86e" + [solve-meta] analyzer-name = "dep" analyzer-version = 1 diff --git a/vendor/k8s.io/utils/.travis.yml b/vendor/k8s.io/utils/.travis.yml new file mode 100644 index 00000000..d39066cc --- /dev/null +++ b/vendor/k8s.io/utils/.travis.yml @@ -0,0 +1,9 @@ +language: go +go: + - 1.8.x + - 1.9.x +go_import_path: k8s.io/utils +script: + - diff -u <(echo -n) <(gofmt -d .) + - go tool vet . + - go test -v -race ./... diff --git a/vendor/k8s.io/utils/HOWTOMOVE.md b/vendor/k8s.io/utils/HOWTOMOVE.md new file mode 100644 index 00000000..49028998 --- /dev/null +++ b/vendor/k8s.io/utils/HOWTOMOVE.md @@ -0,0 +1,31 @@ +# How to move a utility pkg from other kubernetes repos + +It has 2 steps to move a pkg from other Kubernetes repos to `k8s.io/utils` repo: +- copy the pkg to `k8s.io/utils` repo +- update the import paths and `vendor/` in the repos that refer this pkg + +## Copy the pkg to `k8s.io/utils` repo + +Copying should preserve all the git history associated with it. +[Here](http://gbayer.com/development/moving-files-from-one-git-repository-to-another-preserving-history/) is a working approach. +Note: You may need to use `--allow-unrelated-histories` if you get error when running `git pull` following the post above. + +Then, you may need to restructure the package to make sure it has the following structure. + + . + ├── doc.go # Description for this package + ├── .go # utility go file + ├── _test.go # go unit tests + └── testing # All the testing framework + └── fake_.go # Testing framework go file + +[#5](https://github.com/kubernetes/utils/pull/5) is an example for this step. + +## Update the repos that refer the pkg + +You should update the import paths. +Then follow [this doc](https://github.com/kubernetes/community/blob/master/contributors/devel/godep.md) to update `vendor/` and `Godeps/`. + +You may want to run `make bazel-test` to make sure all new references work. + +[kubernetes/kubernetes#49234](https://github.com/kubernetes/kubernetes/pull/49234) is an example for this step. diff --git a/vendor/k8s.io/utils/LICENSE b/vendor/k8s.io/utils/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/vendor/k8s.io/utils/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/k8s.io/utils/README.md b/vendor/k8s.io/utils/README.md new file mode 100644 index 00000000..3765eed2 --- /dev/null +++ b/vendor/k8s.io/utils/README.md @@ -0,0 +1,57 @@ +# Utils + +[![Build Status]](https://travis-ci.org/kubernetes/utils) [![GoDoc](https://godoc.org/k8s.io/utils?status.svg)](https://godoc.org/k8s.io/utils) + +A set of Go libraries that provide low-level, +kubernetes-independent packages supplementing the [Go +standard libs]. + +## Purpose + +As Kubernetes grows and spins functionality out of its +[core] and into cooperating repositories like +[apiserver], [kubectl], [kubeadm], etc., the need +arises for leaf repositories to house shared code and +avoid cycles in repository relationships. + +This repository is intended to hold shared utilities +with no Kubernetes dependence that may be of interest +to any Go project. See these [instructions for moving] +an existing package to this repository. + + +## Criteria for adding code here + +- Used by multiple Kubernetes repositories. + +- Full unit test coverage. + +- Go tools compliant (`go get`, `go test`, etc.). + +- Complex enough to be worth vendoring, rather than copying. + +- Stable, or backward compatible, API. + +- _No dependence on any Kubernetes repository_. + +## Libraries + +- [Exec](/exec) provides an interface for `os/exec`. It makes it easier + to mock and replace in tests, especially with + the [FakeExec](exec/testing/fake_exec.go) struct. + +- [Temp](/temp) provides an interface to create temporary directories. It also + provides a [FakeDir](temp/temptest) implementation to replace in tests. + +- [Clock](/clock) provides an interface for time-based operations. It allows + mocking time for testing. + +[Build Status]: https://travis-ci.org/kubernetes/utils.svg?branch=master +[Go standard libs]: https://golang.org/pkg/#stdlib +[api]: https://github.com/kubernetes/api +[apiserver]: https://github.com/kubernetes/apiserver +[core]: https://github.com/kubernetes/kubernetes +[ingress]: https://github.com/kubernetes/ingress +[kubeadm]: https://github.com/kubernetes/kubeadm +[kubectl]: https://github.com/kubernetes/kubectl +[instructions for moving]: ./HOWTOMOVE.md diff --git a/vendor/k8s.io/utils/code-of-conduct.md b/vendor/k8s.io/utils/code-of-conduct.md new file mode 100644 index 00000000..0d15c00c --- /dev/null +++ b/vendor/k8s.io/utils/code-of-conduct.md @@ -0,0 +1,3 @@ +# Kubernetes Community Code of Conduct + +Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) diff --git a/vendor/k8s.io/utils/exec/doc.go b/vendor/k8s.io/utils/exec/doc.go new file mode 100644 index 00000000..cbb44bdb --- /dev/null +++ b/vendor/k8s.io/utils/exec/doc.go @@ -0,0 +1,18 @@ +/* +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 exec provides an injectable interface and implementations for running commands. +package exec // import "k8s.io/utils/exec" diff --git a/vendor/k8s.io/utils/exec/exec.go b/vendor/k8s.io/utils/exec/exec.go new file mode 100644 index 00000000..07735d88 --- /dev/null +++ b/vendor/k8s.io/utils/exec/exec.go @@ -0,0 +1,215 @@ +/* +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 exec + +import ( + "context" + "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 + + // CommandContext returns a Cmd instance which can be used to run a single command. + // + // The provided context is used to kill the process if the context becomes done + // before the command completes on its own. For example, a timeout can be set in + // the context. + CommandContext(ctx context.Context, 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...)) +} + +// CommandContext is part of the Interface interface. +func (executor *executor) CommandContext(ctx context.Context, cmd string, args ...string) Cmd { + return (*cmdWrapper)(osexec.CommandContext(ctx, 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 + +var _ Cmd = &cmdWrapper{} + +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 { + err := (*osexec.Cmd)(cmd).Run() + return handleError(err) +} + +// CombinedOutput is part of the Cmd interface. +func (cmd *cmdWrapper) CombinedOutput() ([]byte, error) { + out, err := (*osexec.Cmd)(cmd).CombinedOutput() + return out, handleError(err) +} + +func (cmd *cmdWrapper) Output() ([]byte, error) { + out, err := (*osexec.Cmd)(cmd).Output() + return out, handleError(err) +} + +// Stop is part of the Cmd interface. +func (cmd *cmdWrapper) Stop() { + c := (*osexec.Cmd)(cmd) + + if c.Process == nil { + return + } + + c.Process.Signal(syscall.SIGTERM) + + time.AfterFunc(10*time.Second, func() { + if !c.ProcessState.Exited() { + c.Process.Signal(syscall.SIGKILL) + } + }) +} + +func handleError(err error) error { + if err == nil { + return nil + } + + switch e := err.(type) { + case *osexec.ExitError: + return &ExitErrorWrapper{e} + case *osexec.Error: + if e.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 +} diff --git a/vendor/k8s.io/utils/exec/exec_test.go b/vendor/k8s.io/utils/exec/exec_test.go new file mode 100644 index 00000000..99ff44df --- /dev/null +++ b/vendor/k8s.io/utils/exec/exec_test.go @@ -0,0 +1,141 @@ +/* +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 exec + +import ( + "context" + osexec "os/exec" + "testing" + "time" +) + +func TestExecutorNoArgs(t *testing.T) { + ex := New() + + cmd := ex.Command("true") + out, err := cmd.CombinedOutput() + if err != nil { + t.Errorf("expected success, got %v", err) + } + if len(out) != 0 { + t.Errorf("expected no output, got %q", string(out)) + } + + cmd = ex.Command("false") + out, err = cmd.CombinedOutput() + if err == nil { + t.Errorf("expected failure, got nil error") + } + if len(out) != 0 { + t.Errorf("expected no output, got %q", string(out)) + } + ee, ok := err.(ExitError) + if !ok { + t.Errorf("expected an ExitError, got %+v", err) + } + if ee.Exited() { + if code := ee.ExitStatus(); code != 1 { + t.Errorf("expected exit status 1, got %d", code) + } + } + + cmd = ex.Command("/does/not/exist") + out, err = cmd.CombinedOutput() + if err == nil { + t.Errorf("expected failure, got nil error") + } + if ee, ok := err.(ExitError); ok { + t.Errorf("expected non-ExitError, got %+v", ee) + } +} + +func TestExecutorWithArgs(t *testing.T) { + ex := New() + + cmd := ex.Command("echo", "stdout") + out, err := cmd.CombinedOutput() + if err != nil { + t.Errorf("expected success, got %+v", err) + } + if string(out) != "stdout\n" { + t.Errorf("unexpected output: %q", string(out)) + } + + cmd = ex.Command("/bin/sh", "-c", "echo stderr > /dev/stderr") + out, err = cmd.CombinedOutput() + if err != nil { + t.Errorf("expected success, got %+v", err) + } + if string(out) != "stderr\n" { + t.Errorf("unexpected output: %q", string(out)) + } +} + +func TestLookPath(t *testing.T) { + ex := New() + + shExpected, _ := osexec.LookPath("sh") + sh, _ := ex.LookPath("sh") + if sh != shExpected { + t.Errorf("unexpected result for LookPath: got %s, expected %s", sh, shExpected) + } +} + +func TestExecutableNotFound(t *testing.T) { + exec := New() + + cmd := exec.Command("fake_executable_name") + _, err := cmd.CombinedOutput() + if err != ErrExecutableNotFound { + t.Errorf("cmd.CombinedOutput(): Expected error ErrExecutableNotFound but got %v", err) + } + + cmd = exec.Command("fake_executable_name") + _, err = cmd.Output() + if err != ErrExecutableNotFound { + t.Errorf("cmd.Output(): Expected error ErrExecutableNotFound but got %v", err) + } + + cmd = exec.Command("fake_executable_name") + err = cmd.Run() + if err != ErrExecutableNotFound { + t.Errorf("cmd.Run(): Expected error ErrExecutableNotFound but got %v", err) + } +} + +func TestStopBeforeStart(t *testing.T) { + cmd := New().Command("echo", "hello") + + // no panic calling Stop before calling Run + cmd.Stop() + + cmd.Run() + + // no panic calling Stop after command is done + cmd.Stop() +} + +func TestTimeout(t *testing.T) { + exec := New() + ctx, cancel := context.WithTimeout(context.Background(), time.Nanosecond) + defer cancel() + + err := exec.CommandContext(ctx, "sleep", "2").Run() + if err != context.DeadlineExceeded { + t.Errorf("expected %v but got %v", context.DeadlineExceeded, err) + } +} diff --git a/vendor/k8s.io/utils/exec/new_test.go b/vendor/k8s.io/utils/exec/new_test.go new file mode 100644 index 00000000..dba9bb35 --- /dev/null +++ b/vendor/k8s.io/utils/exec/new_test.go @@ -0,0 +1,37 @@ +/* +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 exec_test + +import ( + "bytes" + "fmt" + + "k8s.io/utils/exec" +) + +func ExampleNew() { + exec := exec.New() + + cmd := exec.Command("echo", "Bonjour!") + buff := bytes.Buffer{} + cmd.SetStdout(&buff) + if err := cmd.Run(); err != nil { + panic(err) + } + fmt.Println(buff.String()) + // Output: Bonjour! +} diff --git a/vendor/k8s.io/utils/exec/testing/fake_exec.go b/vendor/k8s.io/utils/exec/testing/fake_exec.go new file mode 100644 index 00000000..32cbae25 --- /dev/null +++ b/vendor/k8s.io/utils/exec/testing/fake_exec.go @@ -0,0 +1,158 @@ +/* +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 testingexec + +import ( + "context" + "fmt" + "io" + + "k8s.io/utils/exec" +) + +// A simple scripted Interface type. +type FakeExec struct { + CommandScript []FakeCommandAction + CommandCalls int + LookPathFunc func(string) (string, error) +} + +var _ exec.Interface = &FakeExec{} + +type FakeCommandAction func(cmd string, args ...string) exec.Cmd + +func (fake *FakeExec) Command(cmd string, args ...string) exec.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) CommandContext(ctx context.Context, cmd string, args ...string) exec.Cmd { + return fake.Command(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 +} + +var _ exec.Cmd = &FakeCmd{} + +func InitFakeCmd(fake *FakeCmd, cmd string, args ...string) exec.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 +} + +var _ exec.ExitError = FakeExitError{} + +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 +}