Merge pull request #85153 from codenrhoden/mount-no-exec-int

Retire mount.Exec for k8s.io/utils/exec
This commit is contained in:
Kubernetes Prow Robot 2019-11-13 17:28:32 -08:00 committed by GitHub
commit 565566f4b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 449 additions and 324 deletions

View File

@ -46,6 +46,7 @@ go_library(
"//staging/src/k8s.io/client-go/util/workqueue:go_default_library",
"//staging/src/k8s.io/cloud-provider:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
)

View File

@ -45,6 +45,8 @@ import (
"k8s.io/client-go/util/workqueue"
cloudprovider "k8s.io/cloud-provider"
"k8s.io/klog"
utilexec "k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache"
"k8s.io/kubernetes/pkg/controller/volume/attachdetach/metrics"
"k8s.io/kubernetes/pkg/controller/volume/attachdetach/populator"
@ -768,8 +770,8 @@ func (adc *attachDetachController) DeleteServiceAccountTokenFunc() func(types.UI
}
}
func (adc *attachDetachController) GetExec(pluginName string) mount.Exec {
return mount.NewOSExec()
func (adc *attachDetachController) GetExec(pluginName string) utilexec.Interface {
return utilexec.New()
}
func (adc *attachDetachController) addNodeToDswp(node *v1.Node, nodeName types.NodeName) {

View File

@ -33,6 +33,7 @@ go_library(
"//staging/src/k8s.io/client-go/util/workqueue:go_default_library",
"//staging/src/k8s.io/cloud-provider:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
)

View File

@ -41,6 +41,8 @@ import (
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
cloudprovider "k8s.io/cloud-provider"
utilexec "k8s.io/utils/exec"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
"k8s.io/kubernetes/pkg/controller/volume/events"
"k8s.io/kubernetes/pkg/util/mount"
@ -380,8 +382,8 @@ func (expc *expandController) GetMounter(pluginName string) mount.Interface {
return nil
}
func (expc *expandController) GetExec(pluginName string) mount.Exec {
return mount.NewOSExec()
func (expc *expandController) GetExec(pluginName string) utilexec.Interface {
return utilexec.New()
}
func (expc *expandController) GetHostName() string {

View File

@ -56,6 +56,7 @@ go_library(
"//staging/src/k8s.io/cloud-provider/volume/errors:go_default_library",
"//staging/src/k8s.io/csi-translation-lib:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
)

View File

@ -27,6 +27,8 @@ import (
"k8s.io/client-go/tools/record"
cloudprovider "k8s.io/cloud-provider"
"k8s.io/klog"
utilexec "k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/util/mount"
vol "k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util/subpath"
@ -116,8 +118,8 @@ func (ctrl *PersistentVolumeController) DeleteServiceAccountTokenFunc() func(typ
}
}
func (adc *PersistentVolumeController) GetExec(pluginName string) mount.Exec {
return mount.NewOSExec()
func (adc *PersistentVolumeController) GetExec(pluginName string) utilexec.Interface {
return utilexec.New()
}
func (ctrl *PersistentVolumeController) GetNodeLabels() (map[string]string, error) {

View File

@ -34,6 +34,8 @@ import (
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
cloudprovider "k8s.io/cloud-provider"
utilexec "k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/kubelet/configmap"
"k8s.io/kubernetes/pkg/kubelet/secret"
@ -86,7 +88,7 @@ func NewInitializedVolumePluginMgr(
informerFactory: informerFactory,
csiDriverLister: csiDriverLister,
csiDriversSynced: csiDriversSynced,
exec: mount.NewOSExec(),
exec: utilexec.New(),
}
if err := kvh.volumePluginMgr.InitPlugins(plugins, prober, kvh); err != nil {
@ -115,7 +117,7 @@ type kubeletVolumeHost struct {
informerFactory informers.SharedInformerFactory
csiDriverLister storagelisters.CSIDriverLister
csiDriversSynced cache.InformerSynced
exec mount.Exec
exec utilexec.Interface
}
func (kvh *kubeletVolumeHost) SetKubeletError(err error) {
@ -271,6 +273,6 @@ func (kvh *kubeletVolumeHost) GetEventRecorder() record.EventRecorder {
return kvh.kubelet.recorder
}
func (kvh *kubeletVolumeHost) GetExec(pluginName string) mount.Exec {
func (kvh *kubeletVolumeHost) GetExec(pluginName string) utilexec.Interface {
return kvh.exec
}

View File

@ -4,7 +4,6 @@ go_library(
name = "go_default_library",
srcs = [
"doc.go",
"exec.go",
"fake_exec.go",
"fake_mounter.go",
"mount.go",
@ -75,6 +74,7 @@ go_test(
],
embed = [":go_default_library"],
deps = [
"//vendor/k8s.io/utils/exec:go_default_library",
"//vendor/k8s.io/utils/exec/testing:go_default_library",
] + select({
"@io_bazel_rules_go//go/platform:windows": [

View File

@ -1,36 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mount
import "k8s.io/utils/exec"
// NewOSExec returns a new Exec interface implementation based on exec()
func NewOSExec() *OSExec {
return &OSExec{}
}
// OSExec is an implementation of Exec interface that uses simple utils.Exec
type OSExec struct{}
var _ Exec = &OSExec{}
// Run exucutes the given cmd and arges and returns stdout and stderr as a
// combined byte stream
func (e *OSExec) Run(cmd string, args ...string) ([]byte, error) {
exe := exec.New()
return exe.Command(cmd, args...).CombinedOutput()
}

View File

@ -23,6 +23,8 @@ import (
"os"
"path/filepath"
"strings"
utilexec "k8s.io/utils/exec"
)
const (
@ -53,13 +55,6 @@ type Interface interface {
GetMountRefs(pathname string) ([]string, error)
}
// Exec is an interface for executing commands on systems.
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
// the mount interface.
var _ Interface = &Mounter{}
@ -79,7 +74,7 @@ type MountPoint struct {
// mounts it otherwise the device is formatted first then mounted.
type SafeFormatAndMount struct {
Interface
Exec
Exec utilexec.Interface
}
// FormatAndMount formats the given disk, if needed, and mounts it.

View File

@ -273,7 +273,7 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
// Run fsck on the disk to fix repairable issues, only do this for volumes requested as rw.
klog.V(4).Infof("Checking for issues with fsck on disk: %s", source)
args := []string{"-a", source}
out, err := mounter.Exec.Run("fsck", args...)
out, err := mounter.Exec.Command("fsck", args...).CombinedOutput()
if err != nil {
ee, isExitError := err.(utilexec.ExitError)
switch {
@ -320,7 +320,7 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
}
}
klog.Infof("Disk %q appears to be unformatted, attempting to format as type: %q with options: %v", source, fstype, args)
_, err := mounter.Exec.Run("mkfs."+fstype, args...)
_, err := mounter.Exec.Command("mkfs."+fstype, args...).CombinedOutput()
if err == nil {
// the disk has been formatted successfully try to mount it again.
klog.Infof("Disk successfully formatted (mkfs): %s - %s %s", fstype, source, target)
@ -344,7 +344,7 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
func (mounter *SafeFormatAndMount) GetDiskFormat(disk string) (string, error) {
args := []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", disk}
klog.V(4).Infof("Attempting to determine if disk %q is formatted using blkid with args: (%v)", disk, args)
dataOut, err := mounter.Exec.Run("blkid", args...)
dataOut, err := mounter.Exec.Command("blkid", args...).CombinedOutput()
output := string(dataOut)
klog.V(4).Infof("Output: %q, err: %v", output, err)

View File

@ -26,6 +26,7 @@ import (
"strings"
"k8s.io/klog"
utilexec "k8s.io/utils/exec"
"k8s.io/utils/keymutex"
utilpath "k8s.io/utils/path"
)
@ -219,7 +220,7 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
// format disk if it is unformatted(raw)
cmd := fmt.Sprintf("Get-Disk -Number %s | Where partitionstyle -eq 'raw' | Initialize-Disk -PartitionStyle MBR -PassThru"+
" | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -FileSystem %s -Confirm:$false", source, fstype)
if output, err := mounter.Exec.Run("powershell", "/c", cmd); err != nil {
if output, err := mounter.Exec.Command("powershell", "/c", cmd).CombinedOutput(); err != nil {
return fmt.Errorf("diskMount: format disk failed, error: %v, output: %q", err, string(output))
}
klog.V(4).Infof("diskMount: Disk successfully formatted, disk: %q, fstype: %q", source, fstype)
@ -231,7 +232,7 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
driverPath := driveLetter + ":"
target = NormalizeWindowsPath(target)
klog.V(4).Infof("Attempting to formatAndMount disk: %s %s %s", fstype, driverPath, target)
if output, err := mounter.Exec.Run("cmd", "/c", "mklink", "/D", target, driverPath); err != nil {
if output, err := mounter.Exec.Command("cmd", "/c", "mklink", "/D", target, driverPath).CombinedOutput(); err != nil {
klog.Errorf("mklink failed: %v, output: %q", err, string(output))
return err
}
@ -239,9 +240,9 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
}
// Get drive letter according to windows disk number
func getDriveLetterByDiskNumber(diskNum string, exec Exec) (string, error) {
func getDriveLetterByDiskNumber(diskNum string, exec utilexec.Interface) (string, error) {
cmd := fmt.Sprintf("(Get-Partition -DiskNumber %s).DriveLetter", diskNum)
output, err := exec.Run("powershell", "/c", cmd)
output, err := exec.Command("powershell", "/c", cmd).CombinedOutput()
if err != nil {
return "", fmt.Errorf("azureMount: Get Drive Letter failed: %v, output: %q", err, string(output))
}

View File

@ -24,10 +24,10 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"k8s.io/utils/exec/testing"
)
func makeLink(link, target string) error {
@ -224,61 +224,61 @@ func TestIsLikelyNotMountPoint(t *testing.T) {
}
func TestFormatAndMount(t *testing.T) {
fakeMounter := ErrorMounter{NewFakeMounter(nil), 0, nil}
execCallback := func(cmd string, args ...string) ([]byte, error) {
for j := range args {
if strings.Contains(args[j], "Get-Disk -Number") {
return []byte("0"), nil
}
if strings.Contains(args[j], "Get-Partition -DiskNumber") {
return []byte("0"), nil
}
if strings.Contains(args[j], "mklink") {
return nil, nil
}
}
return nil, fmt.Errorf("Unexpected cmd %s, args %v", cmd, args)
}
fakeExec := NewFakeExec(execCallback)
mounter := SafeFormatAndMount{
Interface: &fakeMounter,
Exec: fakeExec,
}
tests := []struct {
device string
target string
fstype string
execScripts []ExecArgs
mountOptions []string
expectError bool
}{
{
"0",
"disk",
"NTFS",
[]string{},
false,
device: "0",
target: "disk",
fstype: "NTFS",
execScripts: []ExecArgs{
{"powershell", []string{"/c", "Get-Disk", "-Number"}, "0", nil},
{"powershell", []string{"/c", "Get-Partition", "-DiskNumber"}, "0", nil},
{"cmd", []string{"/c", "mklink", "/D"}, "", nil},
},
mountOptions: []string{},
expectError: false,
},
{
"0",
"disk",
"",
[]string{},
false,
device: "0",
target: "disk",
fstype: "",
execScripts: []ExecArgs{
{"powershell", []string{"/c", "Get-Disk", "-Number"}, "0", nil},
{"powershell", []string{"/c", "Get-Partition", "-DiskNumber"}, "0", nil},
{"cmd", []string{"/c", "mklink", "/D"}, "", nil},
},
mountOptions: []string{},
expectError: false,
},
{
"invalidDevice",
"disk",
"NTFS",
[]string{},
true,
device: "invalidDevice",
target: "disk",
fstype: "NTFS",
mountOptions: []string{},
expectError: true,
},
}
for _, test := range tests {
fakeMounter := ErrorMounter{NewFakeMounter(nil), 0, nil}
fakeExec := &testingexec.FakeExec{}
for _, script := range test.execScripts {
fakeCmd := &testingexec.FakeCmd{}
cmdAction := makeFakeCmd(fakeCmd, script.command, script.args...)
outputAction := makeFakeOutput(script.output, script.err)
fakeCmd.CombinedOutputScript = append(fakeCmd.CombinedOutputScript, outputAction)
fakeExec.CommandScript = append(fakeExec.CommandScript, cmdAction)
}
mounter := SafeFormatAndMount{
Interface: &fakeMounter,
Exec: fakeExec,
}
base, err := ioutil.TempDir("", test.device)
if err != nil {
t.Fatalf(err.Error())

View File

@ -24,7 +24,8 @@ import (
"strings"
"testing"
fakeexec "k8s.io/utils/exec/testing"
"k8s.io/utils/exec"
"k8s.io/utils/exec/testing"
)
type ErrorMounter struct {
@ -82,7 +83,7 @@ func TestSafeFormatAndMount(t *testing.T) {
description: "Test 'fsck' fails with exit status 4",
fstype: "ext4",
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", &fakeexec.FakeExitError{Status: 4}},
{"fsck", []string{"-a", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 4}},
},
expectedError: fmt.Errorf("'fsck' found errors on device /dev/foo but could not correct them"),
},
@ -90,14 +91,14 @@ func TestSafeFormatAndMount(t *testing.T) {
description: "Test 'fsck' fails with exit status 1 (errors found and corrected)",
fstype: "ext4",
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", &fakeexec.FakeExitError{Status: 1}},
{"fsck", []string{"-a", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 1}},
},
},
{
description: "Test 'fsck' fails with exit status other than 1 and 4 (likely unformatted device)",
fstype: "ext4",
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", &fakeexec.FakeExitError{Status: 8}},
{"fsck", []string{"-a", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 8}},
},
},
{
@ -116,7 +117,7 @@ func TestSafeFormatAndMount(t *testing.T) {
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &fakeexec.FakeExitError{Status: 2}},
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 2}},
{"mkfs.ext4", []string{"-F", "-m0", "/dev/foo"}, "", fmt.Errorf("formatting failed")},
},
expectedError: fmt.Errorf("formatting failed"),
@ -127,7 +128,7 @@ func TestSafeFormatAndMount(t *testing.T) {
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), fmt.Errorf("Still cannot mount")},
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &fakeexec.FakeExitError{Status: 2}},
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 2}},
{"mkfs.ext4", []string{"-F", "-m0", "/dev/foo"}, "", nil},
},
expectedError: fmt.Errorf("Still cannot mount"),
@ -138,7 +139,7 @@ func TestSafeFormatAndMount(t *testing.T) {
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &fakeexec.FakeExitError{Status: 2}},
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 2}},
{"mkfs.ext4", []string{"-F", "-m0", "/dev/foo"}, "", nil},
},
expectedError: nil,
@ -149,7 +150,7 @@ func TestSafeFormatAndMount(t *testing.T) {
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &fakeexec.FakeExitError{Status: 2}},
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 2}},
{"mkfs.ext3", []string{"-F", "-m0", "/dev/foo"}, "", nil},
},
expectedError: nil,
@ -160,7 +161,7 @@ func TestSafeFormatAndMount(t *testing.T) {
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &fakeexec.FakeExitError{Status: 2}},
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 2}},
{"mkfs.xfs", []string{"/dev/foo"}, "", nil},
},
expectedError: nil,
@ -181,7 +182,7 @@ func TestSafeFormatAndMount(t *testing.T) {
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &fakeexec.FakeExitError{Status: 4}},
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 4}},
{"mkfs.xfs", []string{"/dev/foo"}, "", nil},
},
expectedError: fmt.Errorf("exit 4"),
@ -189,27 +190,15 @@ func TestSafeFormatAndMount(t *testing.T) {
}
for _, test := range tests {
execCallCount := 0
execCallback := func(cmd string, args ...string) ([]byte, error) {
if len(test.execScripts) <= execCallCount {
t.Errorf("Unexpected command: %s %v", cmd, args)
return nil, nil
}
script := test.execScripts[execCallCount]
execCallCount++
if script.command != cmd {
t.Errorf("Unexpected command %s. Expecting %s", cmd, script.command)
}
for j := range args {
if args[j] != script.args[j] {
t.Errorf("Unexpected args %v. Expecting %v", args, script.args)
}
}
return []byte(script.output), script.err
}
fakeMounter := ErrorMounter{NewFakeMounter(nil), 0, test.mountErrs}
fakeExec := NewFakeExec(execCallback)
fakeExec := &testingexec.FakeExec{ExactOrder: true}
for _, script := range test.execScripts {
fakeCmd := &testingexec.FakeCmd{}
cmdAction := makeFakeCmd(fakeCmd, script.command, script.args...)
outputAction := makeFakeOutput(script.output, script.err)
fakeCmd.CombinedOutputScript = append(fakeCmd.CombinedOutputScript, outputAction)
fakeExec.CommandScript = append(fakeExec.CommandScript, cmdAction)
}
mounter := SafeFormatAndMount{
Interface: &fakeMounter,
Exec: fakeExec,
@ -241,3 +230,19 @@ func TestSafeFormatAndMount(t *testing.T) {
}
}
}
func makeFakeCmd(fakeCmd *testingexec.FakeCmd, cmd string, args ...string) testingexec.FakeCommandAction {
c := cmd
a := args
return func(cmd string, args ...string) exec.Cmd {
command := testingexec.InitFakeCmd(fakeCmd, c, a...)
return command
}
}
func makeFakeOutput(output string, err error) testingexec.FakeCombinedOutputAction {
o := output
return func() ([]byte, error) {
return []byte(o), err
}
}

View File

@ -61,7 +61,7 @@ func (resizefs *ResizeFs) Resize(devicePath string, deviceMountPath string) (boo
}
func (resizefs *ResizeFs) extResize(devicePath string) (bool, error) {
output, err := resizefs.mounter.Exec.Run("resize2fs", devicePath)
output, err := resizefs.mounter.Exec.Command("resize2fs", devicePath).CombinedOutput()
if err == nil {
klog.V(2).Infof("Device %s resized successfully", devicePath)
return true, nil
@ -74,7 +74,7 @@ func (resizefs *ResizeFs) extResize(devicePath string) (bool, error) {
func (resizefs *ResizeFs) xfsResize(deviceMountPath string) (bool, error) {
args := []string{"-d", deviceMountPath}
output, err := resizefs.mounter.Exec.Run("xfs_growfs", args...)
output, err := resizefs.mounter.Exec.Command("xfs_growfs", args...).CombinedOutput()
if err == nil {
klog.V(2).Infof("Device %s resized successfully", deviceMountPath)

View File

@ -40,6 +40,7 @@ go_library(
"//staging/src/k8s.io/client-go/tools/record:go_default_library",
"//staging/src/k8s.io/cloud-provider:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
)

View File

@ -41,7 +41,7 @@ func (attacher *awsElasticBlockStoreAttacher) getDiskNumber(volumeID string) (st
volumeID = split[len(split)-1]
exec := attacher.host.GetExec(awsElasticBlockStorePluginName)
output, err := exec.Run(ebsnvmeID)
output, err := exec.Command(ebsnvmeID).CombinedOutput()
if err != nil {
return "", fmt.Errorf("error calling ebsnvme-id.exe: %v", err)
}

View File

@ -43,7 +43,45 @@ go_library(
"//vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-04-01/storage:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/strings:go_default_library",
],
] + select({
"@io_bazel_rules_go//go/platform:android": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:darwin": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:ios": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:linux": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:nacl": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:plan9": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:solaris": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"@io_bazel_rules_go//go/platform:windows": [
"//vendor/k8s.io/utils/exec:go_default_library",
],
"//conditions:default": [],
}),
)
filegroup(
@ -70,7 +108,6 @@ go_test(
],
embed = [":go_default_library"],
deps = [
"//pkg/util/mount:go_default_library",
"//pkg/volume:go_default_library",
"//pkg/volume/testing:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
@ -79,5 +116,6 @@ go_test(
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
"//vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
)

View File

@ -26,7 +26,7 @@ import (
libstrings "strings"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/util/mount"
utilexec "k8s.io/utils/exec"
)
// exclude those used by azure as resource and OS root in /dev/disk/azure
@ -69,7 +69,7 @@ func getDiskLinkByDevName(io ioHandler, devLinkPath, devName string) (string, er
return "", fmt.Errorf("read %s error: %v", devLinkPath, err)
}
func scsiHostRescan(io ioHandler, exec mount.Exec) {
func scsiHostRescan(io ioHandler, exec utilexec.Interface) {
scsi_path := "/sys/class/scsi_host/"
if dirs, err := io.ReadDir(scsi_path); err == nil {
for _, f := range dirs {
@ -84,7 +84,7 @@ func scsiHostRescan(io ioHandler, exec mount.Exec) {
}
}
func findDiskByLun(lun int, io ioHandler, exec mount.Exec) (string, error) {
func findDiskByLun(lun int, io ioHandler, exec utilexec.Interface) (string, error) {
azureDisks := listAzureDiskPath(io)
return findDiskByLunWithConstraint(lun, io, azureDisks)
}

View File

@ -28,8 +28,7 @@ import (
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/stretchr/testify/assert"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/utils/exec"
)
type fakeFileInfo struct {
@ -126,7 +125,7 @@ func TestIoHandler(t *testing.T) {
if runtime.GOOS != "windows" && runtime.GOOS != "linux" {
t.Skipf("TestIoHandler not supported on GOOS=%s", runtime.GOOS)
}
disk, err := findDiskByLun(lun, &fakeIOHandler{}, mount.NewOSExec())
disk, err := findDiskByLun(lun, &fakeIOHandler{}, exec.New())
if runtime.GOOS == "windows" {
if err != nil {
t.Errorf("no data disk found: disk %v err %v", disk, err)

View File

@ -19,11 +19,11 @@ limitations under the License.
package azure_dd
import "k8s.io/kubernetes/pkg/util/mount"
import "k8s.io/utils/exec"
func scsiHostRescan(io ioHandler, exec mount.Exec) {
func scsiHostRescan(io ioHandler, exec exec.Interface) {
}
func findDiskByLun(lun int, io ioHandler, exec mount.Exec) (string, error) {
func findDiskByLun(lun int, io ioHandler, exec exec.Interface) (string, error) {
return "", nil
}

View File

@ -26,22 +26,23 @@ import (
"strings"
"k8s.io/klog"
utilexec "k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/util/mount"
)
func scsiHostRescan(io ioHandler, exec mount.Exec) {
func scsiHostRescan(io ioHandler, exec utilexec.Interface) {
cmd := "Update-HostStorageCache"
output, err := exec.Run("powershell", "/c", cmd)
output, err := exec.Command("powershell", "/c", cmd).CombinedOutput()
if err != nil {
klog.Errorf("Update-HostStorageCache failed in scsiHostRescan, error: %v, output: %q", err, string(output))
}
}
// search Windows disk number by LUN
func findDiskByLun(lun int, iohandler ioHandler, exec mount.Exec) (string, error) {
func findDiskByLun(lun int, iohandler ioHandler, exec utilexec.Interface) (string, error) {
cmd := `Get-Disk | select number, location | ConvertTo-Json`
output, err := exec.Run("powershell", "/c", cmd)
output, err := exec.Command("powershell", "/c", cmd).CombinedOutput()
if err != nil {
klog.Errorf("Get-Disk failed in findDiskByLun, error: %v, output: %q", err, string(output))
return "", err
@ -98,7 +99,7 @@ func findDiskByLun(lun int, iohandler ioHandler, exec mount.Exec) (string, error
return "", nil
}
func formatIfNotFormatted(disk string, fstype string, exec mount.Exec) {
func formatIfNotFormatted(disk string, fstype string, exec utilexec.Interface) {
if err := mount.ValidateDiskNumber(disk); err != nil {
klog.Errorf("azureDisk Mount: formatIfNotFormatted failed, err: %v\n", err)
return
@ -110,7 +111,7 @@ func formatIfNotFormatted(disk string, fstype string, exec mount.Exec) {
}
cmd := fmt.Sprintf("Get-Disk -Number %s | Where partitionstyle -eq 'raw' | Initialize-Disk -PartitionStyle MBR -PassThru", disk)
cmd += fmt.Sprintf(" | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -FileSystem %s -Confirm:$false", fstype)
output, err := exec.Run("powershell", "/c", cmd)
output, err := exec.Command("powershell", "/c", cmd).CombinedOutput()
if err != nil {
klog.Errorf("azureDisk Mount: Get-Disk failed, error: %v, output: %q", err, string(output))
} else {

View File

@ -331,7 +331,7 @@ func (cephfsVolume *cephfsMounter) checkFuseMount() bool {
execute := cephfsVolume.plugin.host.GetExec(cephfsVolume.plugin.GetPluginName())
switch runtime.GOOS {
case "linux":
if _, err := execute.Run("/usr/bin/test", "-x", "/sbin/mount.fuse.ceph"); err == nil {
if _, err := execute.Command("/usr/bin/test", "-x", "/sbin/mount.fuse.ceph").CombinedOutput(); err == nil {
klog.V(4).Info("/sbin/mount.fuse.ceph exists, it should be fuse mount.")
return true
}

View File

@ -27,6 +27,7 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
"//vendor/k8s.io/utils/strings:go_default_library",
],
)
@ -48,6 +49,7 @@ go_test(
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
"//vendor/k8s.io/utils/exec/testing:go_default_library",
],
)

View File

@ -28,6 +28,8 @@ import (
"k8s.io/apimachinery/pkg/types"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/klog"
utilexec "k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
@ -114,7 +116,7 @@ func (plugin *fcPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.Volu
return plugin.newMounterInternal(spec, pod.UID, &fcUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()))
}
func (plugin *fcPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, exec mount.Exec) (volume.Mounter, error) {
func (plugin *fcPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, exec utilexec.Interface) (volume.Mounter, error) {
// fc volumes used directly in a pod have a ReadOnly flag set by the pod author.
// fc volumes used as a PersistentVolume gets the ReadOnly flag indirectly through the persistent-claim volume used to mount the PV
fc, readOnly, err := getVolumeSource(spec)
@ -174,7 +176,7 @@ func (plugin *fcPlugin) NewBlockVolumeMapper(spec *volume.Spec, pod *v1.Pod, _ v
return plugin.newBlockVolumeMapperInternal(spec, uid, &fcUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()))
}
func (plugin *fcPlugin) newBlockVolumeMapperInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, exec mount.Exec) (volume.BlockVolumeMapper, error) {
func (plugin *fcPlugin) newBlockVolumeMapperInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, exec utilexec.Interface) (volume.BlockVolumeMapper, error) {
fc, readOnly, err := getVolumeSource(spec)
if err != nil {
return nil, err

View File

@ -29,6 +29,8 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes/fake"
utiltesting "k8s.io/client-go/util/testing"
"k8s.io/utils/exec/testing"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing"
@ -164,7 +166,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) {
fakeManager := newFakeDiskManager()
defer fakeManager.Cleanup()
fakeMounter := mount.NewFakeMounter(nil)
fakeExec := mount.NewFakeExec(nil)
fakeExec := &testingexec.FakeExec{}
mounter, err := plug.(*fcPlugin).newMounterInternal(spec, types.UID("poduid"), fakeManager, fakeMounter, fakeExec)
if err != nil {
t.Errorf("Failed to make a new Mounter: %v", err)
@ -227,7 +229,7 @@ func doTestPluginNilMounter(t *testing.T, spec *volume.Spec) {
fakeManager := newFakeDiskManager()
defer fakeManager.Cleanup()
fakeMounter := mount.NewFakeMounter(nil)
fakeExec := mount.NewFakeExec(nil)
fakeExec := &testingexec.FakeExec{}
mounter, err := plug.(*fcPlugin).newMounterInternal(spec, types.UID("poduid"), fakeManager, fakeMounter, fakeExec)
if err == nil {
t.Errorf("Error failed to make a new Mounter is expected: %v", err)

View File

@ -24,7 +24,7 @@ import (
volumetesting "k8s.io/kubernetes/pkg/volume/testing"
"k8s.io/kubernetes/test/utils/harness"
"k8s.io/utils/exec"
fakeexec "k8s.io/utils/exec/testing"
"k8s.io/utils/exec/testing"
)
func testPlugin(h *harness.Harness) (*flexVolumeAttachablePlugin, string) {
@ -39,7 +39,7 @@ func testPlugin(h *harness.Harness) (*flexVolumeAttachablePlugin, string) {
}, rootDir
}
func assertDriverCall(t *harness.Harness, output fakeexec.FakeCombinedOutputAction, expectedCommand string, expectedArgs ...string) fakeexec.FakeCommandAction {
func assertDriverCall(t *harness.Harness, output testingexec.FakeCombinedOutputAction, expectedCommand string, expectedArgs ...string) testingexec.FakeCommandAction {
return func(cmd string, args ...string) exec.Cmd {
if cmd != "/plugin/test" {
t.Errorf("Wrong executable called: got %v, expected %v", cmd, "/plugin/test")
@ -51,20 +51,20 @@ func assertDriverCall(t *harness.Harness, output fakeexec.FakeCombinedOutputActi
if !sameArgs(cmdArgs, expectedArgs) {
t.Errorf("Wrong args for %s: got %v, expected %v", args[0], cmdArgs, expectedArgs)
}
return &fakeexec.FakeCmd{
return &testingexec.FakeCmd{
Argv: args,
CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{output},
CombinedOutputScript: []testingexec.FakeCombinedOutputAction{output},
}
}
}
func fakeRunner(fakeCommands ...fakeexec.FakeCommandAction) exec.Interface {
return &fakeexec.FakeExec{
func fakeRunner(fakeCommands ...testingexec.FakeCommandAction) exec.Interface {
return &testingexec.FakeExec{
CommandScript: fakeCommands,
}
}
func fakeResultOutput(result interface{}) fakeexec.FakeCombinedOutputAction {
func fakeResultOutput(result interface{}) testingexec.FakeCombinedOutputAction {
return func() ([]byte, error) {
bytes, err := json.Marshal(result)
if err != nil {
@ -74,11 +74,11 @@ func fakeResultOutput(result interface{}) fakeexec.FakeCombinedOutputAction {
}
}
func successOutput() fakeexec.FakeCombinedOutputAction {
func successOutput() testingexec.FakeCombinedOutputAction {
return fakeResultOutput(&DriverStatus{StatusSuccess, "", "", "", true, nil, 0})
}
func notSupportedOutput() fakeexec.FakeCombinedOutputAction {
func notSupportedOutput() testingexec.FakeCombinedOutputAction {
return fakeResultOutput(&DriverStatus{StatusNotSupported, "", "", "", false, nil, 0})
}

View File

@ -20,7 +20,7 @@ import (
"testing"
"k8s.io/kubernetes/test/utils/harness"
exec "k8s.io/utils/exec/testing"
"k8s.io/utils/exec/testing"
)
func TestInit(tt *testing.T) {
@ -34,7 +34,7 @@ func TestInit(tt *testing.T) {
plugin.Init(plugin.host)
}
func fakeVolumeNameOutput(name string) exec.FakeCombinedOutputAction {
func fakeVolumeNameOutput(name string) testingexec.FakeCombinedOutputAction {
return fakeResultOutput(&DriverStatus{
Status: StatusSuccess,
VolumeName: name,

View File

@ -33,6 +33,8 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/klog"
utilexec "k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
volumeutil "k8s.io/kubernetes/pkg/volume/util"
@ -179,10 +181,10 @@ func (attacher *gcePersistentDiskAttacher) BulkVerifyVolumes(volumesByNode map[t
}
// search Windows disk number by LUN
func getDiskID(pdName string, exec mount.Exec) (string, error) {
func getDiskID(pdName string, exec utilexec.Interface) (string, error) {
// TODO: replace Get-GcePdName with native windows support of Get-Disk, see issue #74674
cmd := `Get-GcePdName | select Name, DeviceId | ConvertTo-Json`
output, err := exec.Run("powershell", "/c", cmd)
output, err := exec.Command("powershell", "/c", cmd).CombinedOutput()
if err != nil {
klog.Errorf("Get-GcePdName failed, error: %v, output: %q", err, string(output))
err = errors.New(err.Error() + " " + string(output))

View File

@ -264,7 +264,7 @@ func (b *glusterfsMounter) CanMount() error {
exe := b.plugin.host.GetExec(b.plugin.GetPluginName())
switch runtime.GOOS {
case "linux":
if _, err := exe.Run("test", "-x", gciLinuxGlusterMountBinaryPath); err != nil {
if _, err := exe.Command("test", "-x", gciLinuxGlusterMountBinaryPath).CombinedOutput(); err != nil {
return fmt.Errorf("required binary %s is missing", gciLinuxGlusterMountBinaryPath)
}
}

View File

@ -50,6 +50,7 @@ go_test(
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
"//vendor/k8s.io/utils/exec/testing:go_default_library",
],
)

View File

@ -27,6 +27,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/klog"
utilexec "k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
ioutil "k8s.io/kubernetes/pkg/volume/util"
@ -110,7 +112,7 @@ func (plugin *iscsiPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.V
return plugin.newMounterInternal(spec, pod.UID, &ISCSIUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()), secret)
}
func (plugin *iscsiPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, exec mount.Exec, secret map[string]string) (volume.Mounter, error) {
func (plugin *iscsiPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, exec utilexec.Interface, secret map[string]string) (volume.Mounter, error) {
readOnly, fsType, err := getISCSIVolumeInfo(spec)
if err != nil {
return nil, err
@ -153,7 +155,7 @@ func (plugin *iscsiPlugin) NewBlockVolumeMapper(spec *volume.Spec, pod *v1.Pod,
return plugin.newBlockVolumeMapperInternal(spec, uid, &ISCSIUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()), secret)
}
func (plugin *iscsiPlugin) newBlockVolumeMapperInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, exec mount.Exec, secret map[string]string) (volume.BlockVolumeMapper, error) {
func (plugin *iscsiPlugin) newBlockVolumeMapperInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, exec utilexec.Interface, secret map[string]string) (volume.BlockVolumeMapper, error) {
readOnly, _, err := getISCSIVolumeInfo(spec)
if err != nil {
return nil, err
@ -174,7 +176,7 @@ func (plugin *iscsiPlugin) NewUnmounter(volName string, podUID types.UID) (volum
return plugin.newUnmounterInternal(volName, podUID, &ISCSIUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()))
}
func (plugin *iscsiPlugin) newUnmounterInternal(volName string, podUID types.UID, manager diskManager, mounter mount.Interface, exec mount.Exec) (volume.Unmounter, error) {
func (plugin *iscsiPlugin) newUnmounterInternal(volName string, podUID types.UID, manager diskManager, mounter mount.Interface, exec utilexec.Interface) (volume.Unmounter, error) {
return &iscsiDiskUnmounter{
iscsiDisk: &iscsiDisk{
podUID: podUID,
@ -194,7 +196,7 @@ func (plugin *iscsiPlugin) NewBlockVolumeUnmapper(volName string, podUID types.U
return plugin.newUnmapperInternal(volName, podUID, &ISCSIUtil{}, plugin.host.GetExec(plugin.GetPluginName()))
}
func (plugin *iscsiPlugin) newUnmapperInternal(volName string, podUID types.UID, manager diskManager, exec mount.Exec) (volume.BlockVolumeUnmapper, error) {
func (plugin *iscsiPlugin) newUnmapperInternal(volName string, podUID types.UID, manager diskManager, exec utilexec.Interface) (volume.BlockVolumeUnmapper, error) {
return &iscsiDiskUnmapper{
iscsiDisk: &iscsiDisk{
podUID: podUID,
@ -318,7 +320,7 @@ type iscsiDiskMounter struct {
fsType string
volumeMode v1.PersistentVolumeMode
mounter *mount.SafeFormatAndMount
exec mount.Exec
exec utilexec.Interface
deviceUtil ioutil.DeviceUtil
mountOptions []string
}
@ -356,7 +358,7 @@ func (b *iscsiDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) e
type iscsiDiskUnmounter struct {
*iscsiDisk
mounter mount.Interface
exec mount.Exec
exec utilexec.Interface
deviceUtil ioutil.DeviceUtil
}
@ -376,7 +378,7 @@ func (c *iscsiDiskUnmounter) TearDownAt(dir string) error {
type iscsiDiskMapper struct {
*iscsiDisk
readOnly bool
exec mount.Exec
exec utilexec.Interface
deviceUtil ioutil.DeviceUtil
}
@ -392,7 +394,7 @@ func (b *iscsiDiskMapper) MapDevice(devicePath, globalMapPath, volumeMapPath, vo
type iscsiDiskUnmapper struct {
*iscsiDisk
exec mount.Exec
exec utilexec.Interface
deviceUtil ioutil.DeviceUtil
}

View File

@ -27,6 +27,8 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes/fake"
utiltesting "k8s.io/client-go/util/testing"
"k8s.io/utils/exec/testing"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing"
@ -160,7 +162,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) {
fakeManager := NewFakeDiskManager()
defer fakeManager.Cleanup()
fakeMounter := mount.NewFakeMounter(nil)
fakeExec := mount.NewFakeExec(nil)
fakeExec := &testingexec.FakeExec{}
mounter, err := plug.(*iscsiPlugin).newMounterInternal(spec, types.UID("poduid"), fakeManager, fakeMounter, fakeExec, nil)
if err != nil {
t.Errorf("Failed to make a new Mounter: %v", err)

View File

@ -24,6 +24,7 @@ import (
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
"time"
@ -96,7 +97,7 @@ func updateISCSIDiscoverydb(b iscsiDiskMounter, tp string) error {
v := b.secret[k]
if len(v) > 0 {
// explicitly not using execWithLog so secrets are not logged
out, err := b.exec.Run("iscsiadm", "-m", "discoverydb", "-t", "sendtargets", "-p", tp, "-I", b.Iface, "-o", "update", "-n", k, "-v", v)
out, err := b.exec.Command("iscsiadm", "-m", "discoverydb", "-t", "sendtargets", "-p", tp, "-I", b.Iface, "-o", "update", "-n", k, "-v", v).CombinedOutput()
if err != nil {
return fmt.Errorf("iscsi: failed to update discoverydb key %q error: %v", k, string(out))
}
@ -119,7 +120,7 @@ func updateISCSINode(b iscsiDiskMounter, tp string) error {
v := b.secret[k]
if len(v) > 0 {
// explicitly not using execWithLog so secrets are not logged
out, err := b.exec.Run("iscsiadm", "-m", "node", "-p", tp, "-T", b.Iqn, "-I", b.Iface, "-o", "update", "-n", k, "-v", v)
out, err := b.exec.Command("iscsiadm", "-m", "node", "-p", tp, "-T", b.Iqn, "-I", b.Iface, "-o", "update", "-n", k, "-v", v).CombinedOutput()
if err != nil {
return fmt.Errorf("iscsi: failed to update node session key %q error: %v", k, string(out))
}
@ -561,7 +562,7 @@ func deleteDevices(c iscsiDiskUnmounter) error {
}
// Flush any multipath device maps
for mpathDevice := range mpathDevices {
_, err = c.exec.Run("multipath", "-f", mpathDevice)
_, err = c.exec.Command("multipath", "-f", mpathDevice).CombinedOutput()
if err != nil {
klog.Warningf("Warning: Failed to flush multipath device map: %s\nError: %v", mpathDevice, err)
// Fall through -- keep deleting the block devices
@ -722,7 +723,7 @@ func (util *ISCSIUtil) DetachBlockISCSIDisk(c iscsiDiskUnmapper, mapPath string)
return nil
}
func (util *ISCSIUtil) detachISCSIDisk(exec mount.Exec, portals []string, iqn, iface, volName, initiatorName string, found bool) error {
func (util *ISCSIUtil) detachISCSIDisk(exec utilexec.Interface, portals []string, iqn, iface, volName, initiatorName string, found bool) error {
for _, portal := range portals {
logoutArgs := []string{"-m", "node", "-p", portal, "-T", iqn, "--logout"}
deleteArgs := []string{"-m", "node", "-p", portal, "-T", iqn, "-o", "delete"}
@ -731,7 +732,7 @@ func (util *ISCSIUtil) detachISCSIDisk(exec mount.Exec, portals []string, iqn, i
deleteArgs = append(deleteArgs, []string{"-I", iface}...)
}
klog.Infof("iscsi: log out target %s iqn %s iface %s", portal, iqn, iface)
out, err := exec.Run("iscsiadm", logoutArgs...)
out, err := exec.Command("iscsiadm", logoutArgs...).CombinedOutput()
err = ignoreExitCodes(err, exit_ISCSI_ERR_NO_OBJS_FOUND, exit_ISCSI_ERR_SESS_NOT_FOUND)
if err != nil {
klog.Errorf("iscsi: failed to detach disk Error: %s", string(out))
@ -739,7 +740,7 @@ func (util *ISCSIUtil) detachISCSIDisk(exec mount.Exec, portals []string, iqn, i
}
// Delete the node record
klog.Infof("iscsi: delete node record target %s iqn %s", portal, iqn)
out, err = exec.Run("iscsiadm", deleteArgs...)
out, err = exec.Command("iscsiadm", deleteArgs...).CombinedOutput()
err = ignoreExitCodes(err, exit_ISCSI_ERR_NO_OBJS_FOUND, exit_ISCSI_ERR_SESS_NOT_FOUND)
if err != nil {
klog.Errorf("iscsi: failed to delete node record Error: %s", string(out))
@ -750,7 +751,7 @@ func (util *ISCSIUtil) detachISCSIDisk(exec mount.Exec, portals []string, iqn, i
// If the iface is not created via iscsi plugin, skip to delete
if initiatorName != "" && found && iface == (portals[0]+":"+volName) {
deleteArgs := []string{"-m", "iface", "-I", iface, "-o", "delete"}
out, err := exec.Run("iscsiadm", deleteArgs...)
out, err := exec.Command("iscsiadm", deleteArgs...).CombinedOutput()
err = ignoreExitCodes(err, exit_ISCSI_ERR_NO_OBJS_FOUND, exit_ISCSI_ERR_SESS_NOT_FOUND)
if err != nil {
klog.Errorf("iscsi: failed to delete iface Error: %s", string(out))
@ -884,9 +885,15 @@ func cloneIface(b iscsiDiskMounter) error {
return lastErr
}
}
// Get and sort keys to maintain a stable iteration order
var keys []string
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
// update new iface records
for key, val := range params {
_, err = execWithLog(b, "iscsiadm", "-m", "iface", "-I", b.Iface, "-o", "update", "-n", key, "-v", val)
for _, key := range keys {
_, err = execWithLog(b, "iscsiadm", "-m", "iface", "-I", b.Iface, "-o", "update", "-n", key, "-v", params[key])
if err != nil {
execWithLog(b, "iscsiadm", "-m", "iface", "-I", b.Iface, "-o", "delete")
lastErr = fmt.Errorf("iscsi: failed to update iface records: %s (%v). iface(%s) will be used", out, err, b.InitIface)
@ -965,7 +972,7 @@ func ignoreExitCodes(err error, ignoredExitCodes ...int) error {
func execWithLog(b iscsiDiskMounter, cmd string, args ...string) (string, error) {
start := time.Now()
out, err := b.exec.Run(cmd, args...)
out, err := b.exec.Command(cmd, args...).CombinedOutput()
if klog.V(5) {
d := time.Since(start)
klog.V(5).Infof("Executed %s %v in %v, err: %v", cmd, args, d, err)

View File

@ -17,16 +17,20 @@ limitations under the License.
package iscsi
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"testing"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/utils/exec/testing"
"k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing"
)
const (
TestIface = "192.168.1.10:pv0001"
)
func TestExtractDeviceAndPrefix(t *testing.T) {
@ -216,28 +220,28 @@ func TestParseIscsiadmShow(t *testing.T) {
}
func TestClonedIface(t *testing.T) {
cmdCount := 0
fakeExec := mount.NewFakeExec(func(cmd string, args ...string) ([]byte, error) {
cmdCount++
if cmd != "iscsiadm" {
t.Errorf("iscsiadm command expected, got %q", cmd)
}
switch cmdCount {
case 1:
// iscsiadm -m iface -I <iface> -o show
return []byte("iface.ipaddress = <empty>\niface.transport_name = tcp\niface.initiatorname = <empty>\n"), nil
case 2:
// iscsiadm -m iface -I <newIface> -o new
return []byte("New interface 192.168.1.10:pv0001 added"), nil
case 3:
// iscsiadm -m iface -I <newIface> -o update -n <key> -v <val>
return []byte(""), nil
case 4:
return []byte(""), nil
}
return nil, fmt.Errorf("Unexpected exec call nr %d: %s", cmdCount, cmd)
})
fakeExec := &testingexec.FakeExec{}
scripts := []volumetest.CommandScript{
{
Cmd: "iscsiadm",
Args: []string{"-m", "iface", "-I", "", "-o", "show"},
Output: "iface.ipaddress = <empty>\niface.transport_name = tcp\niface.initiatorname = <empty>\n",
},
{
Cmd: "iscsiadm",
Args: []string{"-m", "iface", "-I", TestIface, "-o", "new"},
},
{
Cmd: "iscsiadm",
Args: []string{"-m", "iface", "-I", TestIface, "-o", "update", "-n", "iface.initiatorname", "-v", ""},
},
{
Cmd: "iscsiadm",
Args: []string{"-m", "iface", "-I", TestIface, "-o", "update", "-n", "iface.transport_name", "-v", "tcp"},
},
}
volumetest.ScriptCommands(fakeExec, scripts)
fakeExec.ExactOrder = true
plugins := []volume.VolumePlugin{
&iscsiPlugin{
host: nil,
@ -246,27 +250,32 @@ func TestClonedIface(t *testing.T) {
plugin := plugins[0]
fakeMounter := iscsiDiskMounter{
iscsiDisk: &iscsiDisk{
Iface: "192.168.1.10:pv0001",
Iface: TestIface,
plugin: plugin.(*iscsiPlugin)},
exec: fakeExec,
}
cloneIface(fakeMounter)
if cmdCount != 4 {
t.Errorf("expected 4 CombinedOutput() calls, got %d", cmdCount)
err := cloneIface(fakeMounter)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if fakeExec.CommandCalls != len(scripts) {
t.Errorf("expected 4 CombinedOutput() calls, got %d", fakeExec.CommandCalls)
}
}
func TestClonedIfaceShowError(t *testing.T) {
cmdCount := 0
fakeExec := mount.NewFakeExec(func(cmd string, args ...string) ([]byte, error) {
cmdCount++
if cmd != "iscsiadm" {
t.Errorf("iscsiadm command expected, got %q", cmd)
}
// iscsiadm -m iface -I <iface> -o show, return test error
return []byte(""), errors.New("test error")
})
fakeExec := &testingexec.FakeExec{}
scripts := []volumetest.CommandScript{
{
Cmd: "iscsiadm",
Args: []string{"-m", "iface", "-I", "", "-o", "show"},
Output: "test error",
ReturnCode: 1,
},
}
volumetest.ScriptCommands(fakeExec, scripts)
fakeExec.ExactOrder = true
plugins := []volume.VolumePlugin{
&iscsiPlugin{
host: nil,
@ -275,43 +284,49 @@ func TestClonedIfaceShowError(t *testing.T) {
plugin := plugins[0]
fakeMounter := iscsiDiskMounter{
iscsiDisk: &iscsiDisk{
Iface: "192.168.1.10:pv0001",
Iface: TestIface,
plugin: plugin.(*iscsiPlugin)},
exec: fakeExec,
}
cloneIface(fakeMounter)
if cmdCount != 1 {
t.Errorf("expected 1 CombinedOutput() calls, got %d", cmdCount)
err := cloneIface(fakeMounter)
if err == nil {
t.Errorf("expect to receive error, nil received")
}
if fakeExec.CommandCalls != len(scripts) {
t.Errorf("expected 1 CombinedOutput() calls, got %d", fakeExec.CommandCalls)
}
}
func TestClonedIfaceUpdateError(t *testing.T) {
cmdCount := 0
fakeExec := mount.NewFakeExec(func(cmd string, args ...string) ([]byte, error) {
cmdCount++
if cmd != "iscsiadm" {
t.Errorf("iscsiadm command expected, got %q", cmd)
}
switch cmdCount {
case 1:
// iscsiadm -m iface -I <iface> -o show
return []byte("iface.ipaddress = <empty>\niface.transport_name = tcp\niface.initiatorname = <empty>\n"), nil
fakeExec := &testingexec.FakeExec{}
scripts := []volumetest.CommandScript{
{
Cmd: "iscsiadm",
Args: []string{"-m", "iface", "-I", "", "-o", "show"},
Output: "iface.ipaddress = <empty>\niface.transport_name = tcp\niface.initiatorname = <empty>\n",
},
{
Cmd: "iscsiadm",
Args: []string{"-m", "iface", "-I", TestIface, "-o", "new"},
},
{
Cmd: "iscsiadm",
Args: []string{"-m", "iface", "-I", TestIface, "-o", "update", "-n", "iface.initiatorname", "-v", ""},
},
{
Cmd: "iscsiadm",
Args: []string{"-m", "iface", "-I", TestIface, "-o", "update", "-n", "iface.transport_name", "-v", "tcp"},
ReturnCode: 1,
},
{
Cmd: "iscsiadm",
Args: []string{"-m", "iface", "-I", TestIface, "-o", "delete"},
},
}
volumetest.ScriptCommands(fakeExec, scripts)
fakeExec.ExactOrder = true
case 2:
// iscsiadm -m iface -I <newIface> -o new
return []byte("New interface 192.168.1.10:pv0001 added"), nil
case 3:
// iscsiadm -m iface -I <newIface> -o update -n <key> -v <val>
return []byte(""), nil
case 4:
return []byte(""), errors.New("test error")
case 5:
// iscsiadm -m iface -I <newIface> -o delete
return []byte(""), nil
}
return nil, fmt.Errorf("Unexpected exec call nr %d: %s", cmdCount, cmd)
})
plugins := []volume.VolumePlugin{
&iscsiPlugin{
host: nil,
@ -320,13 +335,16 @@ func TestClonedIfaceUpdateError(t *testing.T) {
plugin := plugins[0]
fakeMounter := iscsiDiskMounter{
iscsiDisk: &iscsiDisk{
Iface: "192.168.1.10:pv0001",
Iface: TestIface,
plugin: plugin.(*iscsiPlugin)},
exec: fakeExec,
}
cloneIface(fakeMounter)
if cmdCount != 5 {
t.Errorf("expected 5 CombinedOutput() calls, got %d", cmdCount)
err := cloneIface(fakeMounter)
if err == nil {
t.Errorf("expect to receive error, nil received")
}
if fakeExec.CommandCalls != len(scripts) {
t.Errorf("expected 5 CombinedOutput() calls, got %d", fakeExec.CommandCalls)
}
}

View File

@ -206,15 +206,15 @@ func (nfsMounter *nfsMounter) CanMount() error {
exec := nfsMounter.plugin.host.GetExec(nfsMounter.plugin.GetPluginName())
switch runtime.GOOS {
case "linux":
if _, err := exec.Run("test", "-x", "/sbin/mount.nfs"); err != nil {
if _, err := exec.Command("test", "-x", "/sbin/mount.nfs").CombinedOutput(); err != nil {
return fmt.Errorf("Required binary /sbin/mount.nfs is missing")
}
if _, err := exec.Run("test", "-x", "/sbin/mount.nfs4"); err != nil {
if _, err := exec.Command("test", "-x", "/sbin/mount.nfs4").CombinedOutput(); err != nil {
return fmt.Errorf("Required binary /sbin/mount.nfs4 is missing")
}
return nil
case "darwin":
if _, err := exec.Run("test", "-x", "/sbin/mount_nfs"); err != nil {
if _, err := exec.Command("test", "-x", "/sbin/mount_nfs").CombinedOutput(); err != nil {
return fmt.Errorf("Required binary /sbin/mount_nfs is missing")
}
}

View File

@ -38,6 +38,8 @@ import (
"k8s.io/client-go/tools/record"
cloudprovider "k8s.io/cloud-provider"
"k8s.io/klog"
"k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume/util/hostutil"
@ -437,7 +439,7 @@ type VolumeHost interface {
DeleteServiceAccountTokenFunc() func(podUID types.UID)
// Returns an interface that should be used to execute any utilities in volume plugins
GetExec(pluginName string) mount.Exec
GetExec(pluginName string) exec.Interface
// Returns the labels on the node
GetNodeLabels() (map[string]string, error)

View File

@ -102,7 +102,7 @@ func (plugin *quobytePlugin) CanSupport(spec *volume.Spec) bool {
}
exec := plugin.host.GetExec(plugin.GetPluginName())
if out, err := exec.Run("ls", "/sbin/mount.quobyte"); err == nil {
if out, err := exec.Command("ls", "/sbin/mount.quobyte").CombinedOutput(); err == nil {
klog.V(4).Infof("quobyte: can support: %s", string(out))
return true
}

View File

@ -35,6 +35,7 @@ go_library(
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/cloud-provider/volume/helpers:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
"//vendor/k8s.io/utils/path:go_default_library",
"//vendor/k8s.io/utils/strings:go_default_library",
],

View File

@ -38,6 +38,7 @@ import (
"k8s.io/kubernetes/pkg/volume/util"
volutil "k8s.io/kubernetes/pkg/volume/util"
"k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
utilexec "k8s.io/utils/exec"
utilstrings "k8s.io/utils/strings"
)
@ -502,7 +503,7 @@ func (plugin *rbdPlugin) NewBlockVolumeMapper(spec *volume.Spec, pod *v1.Pod, _
return plugin.newBlockVolumeMapperInternal(spec, uid, &RBDUtil{}, secret, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()))
}
func (plugin *rbdPlugin) newBlockVolumeMapperInternal(spec *volume.Spec, podUID types.UID, manager diskManager, secret string, mounter mount.Interface, exec mount.Exec) (volume.BlockVolumeMapper, error) {
func (plugin *rbdPlugin) newBlockVolumeMapperInternal(spec *volume.Spec, podUID types.UID, manager diskManager, secret string, mounter mount.Interface, exec utilexec.Interface) (volume.BlockVolumeMapper, error) {
mon, err := getVolumeSourceMonitors(spec)
if err != nil {
return nil, err
@ -770,7 +771,7 @@ type rbd struct {
ReadOnly bool
plugin *rbdPlugin
mounter *mount.SafeFormatAndMount
exec mount.Exec
exec utilexec.Interface
// Utility interface that provides API calls to the provider to attach/detach disks.
manager diskManager
volume.MetricsProvider `json:"-"`

View File

@ -32,7 +32,7 @@ import (
"strings"
"time"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/wait"
@ -42,6 +42,7 @@ import (
"k8s.io/kubernetes/pkg/util/node"
"k8s.io/kubernetes/pkg/volume"
volutil "k8s.io/kubernetes/pkg/volume/util"
utilexec "k8s.io/utils/exec"
utilpath "k8s.io/utils/path"
)
@ -227,22 +228,22 @@ func execRbdMap(b rbdMounter, rbdCmd string, mon string) ([]byte, error) {
// do not change this format - some tools like rbd-nbd are strict about it.
imgPath := fmt.Sprintf("%s/%s", b.Pool, b.Image)
if b.Secret != "" {
return b.exec.Run(rbdCmd,
"map", imgPath, "--id", b.Id, "-m", mon, "--key="+b.Secret)
return b.exec.Command(rbdCmd,
"map", imgPath, "--id", b.Id, "-m", mon, "--key="+b.Secret).CombinedOutput()
} else {
return b.exec.Run(rbdCmd,
"map", imgPath, "--id", b.Id, "-m", mon, "-k", b.Keyring)
return b.exec.Command(rbdCmd,
"map", imgPath, "--id", b.Id, "-m", mon, "-k", b.Keyring).CombinedOutput()
}
}
// Check if rbd-nbd tools are installed.
func checkRbdNbdTools(e mount.Exec) bool {
_, err := e.Run("modprobe", "nbd")
func checkRbdNbdTools(e utilexec.Interface) bool {
_, err := e.Command("modprobe", "nbd").CombinedOutput()
if err != nil {
klog.V(5).Infof("rbd-nbd: nbd modprobe failed with error %v", err)
return false
}
if _, err := e.Run("rbd-nbd", "--version"); err != nil {
if _, err := e.Command("rbd-nbd", "--version").CombinedOutput(); err != nil {
klog.V(5).Infof("rbd-nbd: getting rbd-nbd version failed with error %v", err)
return false
}
@ -335,7 +336,7 @@ func (util *RBDUtil) rbdUnlock(b rbdMounter) error {
// Get the locker name, something like "client.1234".
args := []string{"lock", "list", b.Image, "--pool", b.Pool, "--id", b.Id, "-m", mon}
args = append(args, secret_opt...)
cmd, err = b.exec.Run("rbd", args...)
cmd, err = b.exec.Command("rbd", args...).CombinedOutput()
output = string(cmd)
klog.V(4).Infof("lock list output %q", output)
if err != nil {
@ -353,7 +354,7 @@ func (util *RBDUtil) rbdUnlock(b rbdMounter) error {
if len(locker) > 0 {
args := []string{"lock", "remove", b.Image, lock_id, locker, "--pool", b.Pool, "--id", b.Id, "-m", mon}
args = append(args, secret_opt...)
cmd, err = b.exec.Run("rbd", args...)
cmd, err = b.exec.Command("rbd", args...).CombinedOutput()
if err == nil {
klog.V(4).Infof("rbd: successfully remove lock (locker_id: %s) on image: %s/%s with id %s mon %s", lock_id, b.Pool, b.Image, b.Id, mon)
} else {
@ -432,7 +433,7 @@ func (util *RBDUtil) AttachDisk(b rbdMounter) (string, error) {
mon := util.kernelRBDMonitorsOpt(b.Mon)
klog.V(1).Infof("rbd: map mon %s", mon)
_, err := b.exec.Run("modprobe", "rbd")
_, err := b.exec.Command("modprobe", "rbd").CombinedOutput()
if err != nil {
klog.Warningf("rbd: failed to load rbd kernel module:%v", err)
}
@ -483,7 +484,7 @@ func (util *RBDUtil) DetachDisk(plugin *rbdPlugin, deviceMountPath string, devic
}
// rbd unmap
output, err := exec.Run(rbdCmd, "unmap", device)
output, err := exec.Command(rbdCmd, "unmap", device).CombinedOutput()
if err != nil {
return rbdErrors(err, fmt.Errorf("rbd: failed to unmap device %s, error %v, rbd output: %v", device, err, output))
}
@ -542,7 +543,7 @@ func (util *RBDUtil) DetachBlockDisk(disk rbdDiskUnmapper, mapPath string) error
}
// rbd unmap
output, err := exec.Run(rbdCmd, "unmap", device)
output, err := exec.Command(rbdCmd, "unmap", device).CombinedOutput()
if err != nil {
return rbdErrors(err, fmt.Errorf("rbd: failed to unmap device %s, error %v, rbd output: %s", device, err, string(output)))
}
@ -601,7 +602,7 @@ func (util *RBDUtil) CreateImage(p *rbdVolumeProvisioner) (r *v1.RBDPersistentVo
features := strings.Join(p.rbdMounter.imageFeatures, ",")
args = append(args, "--image-feature", features)
}
output, err = p.exec.Run("rbd", args...)
output, err = p.exec.Command("rbd", args...).CombinedOutput()
if err != nil {
klog.Warningf("failed to create rbd image, output %v", string(output))
@ -628,8 +629,8 @@ func (util *RBDUtil) DeleteImage(p *rbdVolumeDeleter) error {
// rbd rm.
mon := util.kernelRBDMonitorsOpt(p.rbdMounter.Mon)
klog.V(4).Infof("rbd: rm %s using mon %s, pool %s id %s key %s", p.rbdMounter.Image, mon, p.rbdMounter.Pool, p.rbdMounter.adminId, p.rbdMounter.adminSecret)
output, err = p.exec.Run("rbd",
"rm", p.rbdMounter.Image, "--pool", p.rbdMounter.Pool, "--id", p.rbdMounter.adminId, "-m", mon, "--key="+p.rbdMounter.adminSecret)
output, err = p.exec.Command("rbd",
"rm", p.rbdMounter.Image, "--pool", p.rbdMounter.Pool, "--id", p.rbdMounter.adminId, "-m", mon, "--key="+p.rbdMounter.adminSecret).CombinedOutput()
if err == nil {
return nil
}
@ -660,8 +661,8 @@ func (util *RBDUtil) ExpandImage(rbdExpander *rbdVolumeExpander, oldSize resourc
// rbd resize.
mon := util.kernelRBDMonitorsOpt(rbdExpander.rbdMounter.Mon)
klog.V(4).Infof("rbd: resize %s using mon %s, pool %s id %s key %s", rbdExpander.rbdMounter.Image, mon, rbdExpander.rbdMounter.Pool, rbdExpander.rbdMounter.adminId, rbdExpander.rbdMounter.adminSecret)
output, err = rbdExpander.exec.Run("rbd",
"resize", rbdExpander.rbdMounter.Image, "--size", newVolSz, "--pool", rbdExpander.rbdMounter.Pool, "--id", rbdExpander.rbdMounter.adminId, "-m", mon, "--key="+rbdExpander.rbdMounter.adminSecret)
output, err = rbdExpander.exec.Command("rbd",
"resize", rbdExpander.rbdMounter.Image, "--size", newVolSz, "--pool", rbdExpander.rbdMounter.Pool, "--id", rbdExpander.rbdMounter.adminId, "-m", mon, "--key="+rbdExpander.rbdMounter.adminSecret).CombinedOutput()
if err == nil {
return newSizeQuant, nil
}
@ -702,8 +703,8 @@ func (util *RBDUtil) rbdInfo(b *rbdMounter) (int, error) {
// rbd: error opening image 1234: (2) No such file or directory
//
klog.V(4).Infof("rbd: info %s using mon %s, pool %s id %s key %s", b.Image, mon, b.Pool, id, secret)
output, err = b.exec.Run("rbd",
"info", b.Image, "--pool", b.Pool, "-m", mon, "--id", id, "--key="+secret, "-k=/dev/null", "--format=json")
output, err = b.exec.Command("rbd",
"info", b.Image, "--pool", b.Pool, "-m", mon, "--id", id, "--key="+secret, "-k=/dev/null", "--format=json").CombinedOutput()
if err, ok := err.(*exec.Error); ok {
if err.Err == exec.ErrNotFound {
@ -765,8 +766,8 @@ func (util *RBDUtil) rbdStatus(b *rbdMounter) (bool, string, error) {
// rbd: error opening image kubernetes-dynamic-pvc-<UUID>: (2) No such file or directory
//
klog.V(4).Infof("rbd: status %s using mon %s, pool %s id %s key %s", b.Image, mon, b.Pool, id, secret)
cmd, err = b.exec.Run("rbd",
"status", b.Image, "--pool", b.Pool, "-m", mon, "--id", id, "--key="+secret)
cmd, err = b.exec.Command("rbd",
"status", b.Image, "--pool", b.Pool, "-m", mon, "--id", id, "--key="+secret).CombinedOutput()
output = string(cmd)
if err, ok := err.(*exec.Error); ok {

View File

@ -15,7 +15,6 @@ go_test(
],
embed = [":go_default_library"],
deps = [
"//pkg/util/mount:go_default_library",
"//pkg/volume:go_default_library",
"//pkg/volume/testing:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
@ -26,6 +25,7 @@ go_test(
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
"//vendor/github.com/thecodeteam/goscaleio/types/v1:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec/testing:go_default_library",
],
)
@ -52,6 +52,7 @@ go_library(
"//vendor/github.com/thecodeteam/goscaleio:go_default_library",
"//vendor/github.com/thecodeteam/goscaleio/types/v1:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
"//vendor/k8s.io/utils/keymutex:go_default_library",
"//vendor/k8s.io/utils/strings:go_default_library",
],

View File

@ -28,7 +28,7 @@ import (
"sync"
"time"
"k8s.io/kubernetes/pkg/util/mount"
utilexec "k8s.io/utils/exec"
sio "github.com/thecodeteam/goscaleio"
siotypes "github.com/thecodeteam/goscaleio/types/v1"
@ -78,10 +78,10 @@ type sioClient struct {
inited bool
diskRegex *regexp.Regexp
mtx sync.Mutex
exec mount.Exec
exec utilexec.Interface
}
func newSioClient(gateway, username, password string, sslEnabled bool, exec mount.Exec) (*sioClient, error) {
func newSioClient(gateway, username, password string, sslEnabled bool, exec utilexec.Interface) (*sioClient, error) {
client := new(sioClient)
client.gateway = gateway
client.username = username
@ -321,7 +321,7 @@ func (c *sioClient) getGUID() (string, error) {
if c.sdcGUID == "" {
klog.V(4).Info(log("sdc guid label not set, falling back to using drv_cfg"))
cmd := c.getSdcCmd()
output, err := c.exec.Run(cmd, "--query_guid")
output, err := c.exec.Command(cmd, "--query_guid").CombinedOutput()
if err != nil {
klog.Error(log("drv_cfg --query_guid failed: %v", err))
return "", err

View File

@ -20,9 +20,8 @@ import (
"errors"
"strconv"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/klog"
utilexec "k8s.io/utils/exec"
siotypes "github.com/thecodeteam/goscaleio/types/v1"
)
@ -30,10 +29,10 @@ import (
type sioMgr struct {
client sioInterface
configData map[string]string
exec mount.Exec
exec utilexec.Interface
}
func newSioMgr(configs map[string]string, exec mount.Exec) (*sioMgr, error) {
func newSioMgr(configs map[string]string, exec utilexec.Interface) (*sioMgr, error) {
if configs == nil {
return nil, errors.New("missing configuration data")
}

View File

@ -21,9 +21,8 @@ import (
"testing"
"time"
"k8s.io/kubernetes/pkg/util/mount"
siotypes "github.com/thecodeteam/goscaleio/types/v1"
"k8s.io/utils/exec/testing"
)
var (
@ -44,7 +43,7 @@ var (
)
func newTestMgr(t *testing.T) *sioMgr {
mgr, err := newSioMgr(fakeConfig, mount.NewFakeExec(nil))
mgr, err := newSioMgr(fakeConfig, &testingexec.FakeExec{})
if err != nil {
t.Error(err)
}
@ -53,7 +52,7 @@ func newTestMgr(t *testing.T) *sioMgr {
}
func TestMgrNew(t *testing.T) {
mgr, err := newSioMgr(fakeConfig, mount.NewFakeExec(nil))
mgr, err := newSioMgr(fakeConfig, &testingexec.FakeExec{})
if err != nil {
t.Fatal(err)
}

View File

@ -27,6 +27,7 @@ go_library(
"//vendor/github.com/storageos/go-api:go_default_library",
"//vendor/github.com/storageos/go-api/types:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
"//vendor/k8s.io/utils/strings:go_default_library",
],
)
@ -48,6 +49,7 @@ go_test(
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
"//vendor/github.com/storageos/go-api/types:go_default_library",
"//vendor/k8s.io/utils/exec/testing:go_default_library",
],
)

View File

@ -33,6 +33,7 @@ import (
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util"
utilexec "k8s.io/utils/exec"
utilstrings "k8s.io/utils/strings"
)
@ -115,7 +116,7 @@ func (plugin *storageosPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volu
return plugin.newMounterInternal(spec, pod, apiCfg, &storageosUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()))
}
func (plugin *storageosPlugin) newMounterInternal(spec *volume.Spec, pod *v1.Pod, apiCfg *storageosAPIConfig, manager storageosManager, mounter mount.Interface, exec mount.Exec) (volume.Mounter, error) {
func (plugin *storageosPlugin) newMounterInternal(spec *volume.Spec, pod *v1.Pod, apiCfg *storageosAPIConfig, manager storageosManager, mounter mount.Interface, exec utilexec.Interface) (volume.Mounter, error) {
volName, volNamespace, fsType, readOnly, err := getVolumeInfoFromSpec(spec)
if err != nil {
@ -147,7 +148,7 @@ func (plugin *storageosPlugin) NewUnmounter(pvName string, podUID types.UID) (vo
return plugin.newUnmounterInternal(pvName, podUID, &storageosUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()))
}
func (plugin *storageosPlugin) newUnmounterInternal(pvName string, podUID types.UID, manager storageosManager, mounter mount.Interface, exec mount.Exec) (volume.Unmounter, error) {
func (plugin *storageosPlugin) newUnmounterInternal(pvName string, podUID types.UID, manager storageosManager, mounter mount.Interface, exec utilexec.Interface) (volume.Unmounter, error) {
// Parse volume namespace & name from mountpoint if mounted
volNamespace, volName, err := getVolumeInfo(pvName, podUID, plugin.host)
@ -311,7 +312,7 @@ type storageos struct {
apiCfg *storageosAPIConfig
manager storageosManager
mounter mount.Interface
exec mount.Exec
exec utilexec.Interface
plugin *storageosPlugin
volume.MetricsProvider
}

View File

@ -30,6 +30,7 @@ import (
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing"
"k8s.io/utils/exec/testing"
)
func TestCanSupport(t *testing.T) {
@ -194,7 +195,7 @@ func TestPlugin(t *testing.T) {
t.Errorf("Couldn't get secret from %v/%v", pod.Namespace, secretName)
}
mounter, err := plug.(*storageosPlugin).newMounterInternal(volume.NewSpecFromVolume(spec), pod, apiCfg, fakeManager, mount.NewFakeMounter(nil), mount.NewFakeExec(nil))
mounter, err := plug.(*storageosPlugin).newMounterInternal(volume.NewSpecFromVolume(spec), pod, apiCfg, fakeManager, mount.NewFakeMounter(nil), &testingexec.FakeExec{})
if err != nil {
t.Fatalf("Failed to make a new Mounter: %v", err)
}
@ -231,7 +232,7 @@ func TestPlugin(t *testing.T) {
// Test Unmounter
fakeManager = &fakePDManager{}
unmounter, err := plug.(*storageosPlugin).newUnmounterInternal("vol1-pvname", types.UID("poduid"), fakeManager, mount.NewFakeMounter(nil), mount.NewFakeExec(nil))
unmounter, err := plug.(*storageosPlugin).newUnmounterInternal("vol1-pvname", types.UID("poduid"), fakeManager, mount.NewFakeMounter(nil), &testingexec.FakeExec{})
if err != nil {
t.Errorf("Failed to make a new Unmounter: %v", err)
}
@ -372,7 +373,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
fakeManager := &fakePDManager{}
fakeConfig := &fakeConfig{}
apiCfg := fakeConfig.GetAPIConfig()
mounter, err := plug.(*storageosPlugin).newMounterInternal(spec, pod, apiCfg, fakeManager, mount.NewFakeMounter(nil), mount.NewFakeExec(nil))
mounter, err := plug.(*storageosPlugin).newMounterInternal(spec, pod, apiCfg, fakeManager, mount.NewFakeMounter(nil), &testingexec.FakeExec{})
if err != nil {
t.Fatalf("error creating a new internal mounter:%v", err)
}

View File

@ -23,11 +23,10 @@ import (
"path/filepath"
"strings"
"k8s.io/kubernetes/pkg/util/mount"
storageosapi "github.com/storageos/go-api"
storageostypes "github.com/storageos/go-api/types"
"k8s.io/klog"
utilexec "k8s.io/utils/exec"
)
const (
@ -331,7 +330,7 @@ func pathDeviceType(path string) (deviceType, error) {
// attachFileDevice takes a path to a regular file and makes it available as an
// attached block device.
func attachFileDevice(path string, exec mount.Exec) (string, error) {
func attachFileDevice(path string, exec utilexec.Interface) (string, error) {
blockDevicePath, err := getLoopDevice(path, exec)
if err != nil && err.Error() != ErrDeviceNotFound {
return "", err
@ -349,7 +348,7 @@ func attachFileDevice(path string, exec mount.Exec) (string, error) {
}
// Returns the full path to the loop device associated with the given path.
func getLoopDevice(path string, exec mount.Exec) (string, error) {
func getLoopDevice(path string, exec utilexec.Interface) (string, error) {
_, err := os.Stat(path)
if os.IsNotExist(err) {
return "", errors.New(ErrNotAvailable)
@ -359,7 +358,7 @@ func getLoopDevice(path string, exec mount.Exec) (string, error) {
}
args := []string{"-j", path}
out, err := exec.Run(losetupPath, args...)
out, err := exec.Command(losetupPath, args...).CombinedOutput()
if err != nil {
klog.V(2).Infof("Failed device discover command for path %s: %v", path, err)
return "", err
@ -367,9 +366,9 @@ func getLoopDevice(path string, exec mount.Exec) (string, error) {
return parseLosetupOutputForDevice(out)
}
func makeLoopDevice(path string, exec mount.Exec) (string, error) {
func makeLoopDevice(path string, exec utilexec.Interface) (string, error) {
args := []string{"-f", "-P", "--show", path}
out, err := exec.Run(losetupPath, args...)
out, err := exec.Command(losetupPath, args...).CombinedOutput()
if err != nil {
klog.V(2).Infof("Failed device create command for path %s: %v", path, err)
return "", err
@ -377,9 +376,9 @@ func makeLoopDevice(path string, exec mount.Exec) (string, error) {
return parseLosetupOutputForDevice(out)
}
func removeLoopDevice(device string, exec mount.Exec) error {
func removeLoopDevice(device string, exec utilexec.Interface) error {
args := []string{"-d", device}
out, err := exec.Run(losetupPath, args...)
out, err := exec.Command(losetupPath, args...).CombinedOutput()
if err != nil {
if !strings.Contains(string(out), "No such device or address") {
return err

View File

@ -35,6 +35,8 @@ go_library(
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
"//staging/src/k8s.io/cloud-provider:go_default_library",
"//vendor/github.com/stretchr/testify/mock:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
"//vendor/k8s.io/utils/exec/testing:go_default_library",
"//vendor/k8s.io/utils/strings:go_default_library",
],
)

View File

@ -20,7 +20,6 @@ import (
"fmt"
"net"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
@ -41,6 +40,9 @@ import (
"k8s.io/client-go/tools/record"
utiltesting "k8s.io/client-go/util/testing"
cloudprovider "k8s.io/cloud-provider"
"k8s.io/utils/exec"
"k8s.io/utils/exec/testing"
"k8s.io/kubernetes/pkg/util/mount"
. "k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util"
@ -73,7 +75,7 @@ type fakeVolumeHost struct {
cloud cloudprovider.Interface
mounter mount.Interface
hostUtil hostutil.HostUtils
exec mount.Exec
exec *testingexec.FakeExec
nodeLabels map[string]string
nodeName string
subpather subpath.Interface
@ -111,7 +113,7 @@ func newFakeVolumeHost(rootDir string, kubeClient clientset.Interface, plugins [
host := &fakeVolumeHost{rootDir: rootDir, kubeClient: kubeClient, cloud: cloud}
host.mounter = mount.NewFakeMounter(nil)
host.hostUtil = hostutil.NewFakeHostUtil(pathToTypeMap)
host.exec = mount.NewFakeExec(nil)
host.exec = &testingexec.FakeExec{DisableScripts: true}
host.pluginMgr.InitPlugins(plugins, nil /* prober */, host)
host.subpather = &subpath.FakeSubpath{}
host.informerFactory = informers.NewSharedInformerFactory(kubeClient, time.Minute)
@ -213,7 +215,7 @@ func (f *fakeVolumeHost) GetSecretFunc() func(namespace, name string) (*v1.Secre
}
}
func (f *fakeVolumeHost) GetExec(pluginName string) mount.Exec {
func (f *fakeVolumeHost) GetExec(pluginName string) exec.Interface {
return f.exec
}
@ -248,6 +250,64 @@ func (f *fakeVolumeHost) GetEventRecorder() record.EventRecorder {
return nil
}
func (f *fakeVolumeHost) ScriptCommands(scripts []CommandScript) {
ScriptCommands(f.exec, scripts)
}
// CommandScript is used to pre-configure a command that will be executed and
// optionally set it's output (stdout and stderr combined) and return code.
type CommandScript struct {
// Cmd is the command to execute, e.g. "ls"
Cmd string
// Args is a slice of arguments to pass to the command, e.g. "-a"
Args []string
// Output is the combined stdout and stderr of the command to return
Output string
// ReturnCode is the exit code for the command. Setting this to non-zero will
// cause the command to return an error with this exit code set.
ReturnCode int
}
// ScriptCommands configures fe, the FakeExec, to have a pre-configured list of
// commands to expect. Calling more commands using fe than those scripted will
// result in a panic. By default, the fe does not enforce command argument checking
// or order -- if you have given an Output to the command, the first command scripted
// will return its output on the first command call, even if the command called is
// different than the one scripted. This is mostly useful to make sure that the
// right number of commands were called. If you want to check the exact commands
// and arguments were called, set fe.ExectOrder to true.
func ScriptCommands(fe *testingexec.FakeExec, scripts []CommandScript) {
fe.DisableScripts = false
for _, script := range scripts {
fakeCmd := &testingexec.FakeCmd{}
cmdAction := makeFakeCmd(fakeCmd, script.Cmd, script.Args...)
outputAction := makeFakeOutput(script.Output, script.ReturnCode)
fakeCmd.CombinedOutputScript = append(fakeCmd.CombinedOutputScript, outputAction)
fe.CommandScript = append(fe.CommandScript, cmdAction)
}
}
func makeFakeCmd(fakeCmd *testingexec.FakeCmd, cmd string, args ...string) testingexec.FakeCommandAction {
fc := fakeCmd
c := cmd
a := args
return func(cmd string, args ...string) exec.Cmd {
command := testingexec.InitFakeCmd(fc, c, a...)
return command
}
}
func makeFakeOutput(output string, rc int) testingexec.FakeCombinedOutputAction {
o := output
var e error
if rc != 0 {
e = testingexec.FakeExitError{Status: rc}
}
return func() ([]byte, error) {
return []byte(o), e
}
}
func ProbeVolumePlugins(config VolumeConfig) []VolumePlugin {
if _, ok := config.OtherAttributes["fake-property"]; ok {
return []VolumePlugin{
@ -1131,7 +1191,7 @@ func FindEmptyDirectoryUsageOnTmpfs() (*resource.Quantity, error) {
return nil, err
}
defer os.RemoveAll(tmpDir)
out, err := exec.Command("nice", "-n", "19", "du", "-x", "-s", "-B", "1", tmpDir).CombinedOutput()
out, err := exec.New().Command("nice", "-n", "19", "du", "-x", "-s", "-B", "1", tmpDir).CombinedOutput()
if err != nil {
return nil, fmt.Errorf("failed command 'du' on %s with error %v", tmpDir, err)
}

View File

@ -44,6 +44,7 @@ go_library(
"//staging/src/k8s.io/component-base/metrics:go_default_library",
"//staging/src/k8s.io/component-base/metrics/legacyregistry:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
"//vendor/k8s.io/utils/strings:go_default_library",
],
)

View File

@ -36,6 +36,7 @@ import (
utilfeature "k8s.io/apiserver/pkg/util/feature"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/api/legacyscheme"
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
@ -44,6 +45,7 @@ import (
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util/types"
"k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
utilexec "k8s.io/utils/exec"
utilstrings "k8s.io/utils/strings"
)
@ -585,11 +587,11 @@ func HasMountRefs(mountPath string, mountRefs []string) bool {
}
//WriteVolumeCache flush disk data given the spcified mount path
func WriteVolumeCache(deviceMountPath string, exec mount.Exec) error {
func WriteVolumeCache(deviceMountPath string, exec utilexec.Interface) error {
// If runtime os is windows, execute Write-VolumeCache powershell command on the disk
if runtime.GOOS == "windows" {
cmd := fmt.Sprintf("Get-Volume -FilePath %s | Write-Volumecache", deviceMountPath)
output, err := exec.Run("powershell", "/c", cmd)
output, err := exec.Command("powershell", "/c", cmd).CombinedOutput()
klog.Infof("command (%q) execeuted: %v, output: %q", cmd, err, string(output))
if err != nil {
return fmt.Errorf("command (%q) failed: %v, output: %q", cmd, err, string(output))