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/client-go/util/workqueue:go_default_library",
"//staging/src/k8s.io/cloud-provider:go_default_library", "//staging/src/k8s.io/cloud-provider:go_default_library",
"//vendor/k8s.io/klog: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" "k8s.io/client-go/util/workqueue"
cloudprovider "k8s.io/cloud-provider" cloudprovider "k8s.io/cloud-provider"
"k8s.io/klog" "k8s.io/klog"
utilexec "k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache" "k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache"
"k8s.io/kubernetes/pkg/controller/volume/attachdetach/metrics" "k8s.io/kubernetes/pkg/controller/volume/attachdetach/metrics"
"k8s.io/kubernetes/pkg/controller/volume/attachdetach/populator" "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 { func (adc *attachDetachController) GetExec(pluginName string) utilexec.Interface {
return mount.NewOSExec() return utilexec.New()
} }
func (adc *attachDetachController) addNodeToDswp(node *v1.Node, nodeName types.NodeName) { 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/client-go/util/workqueue:go_default_library",
"//staging/src/k8s.io/cloud-provider:go_default_library", "//staging/src/k8s.io/cloud-provider:go_default_library",
"//vendor/k8s.io/klog: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/tools/record"
"k8s.io/client-go/util/workqueue" "k8s.io/client-go/util/workqueue"
cloudprovider "k8s.io/cloud-provider" cloudprovider "k8s.io/cloud-provider"
utilexec "k8s.io/utils/exec"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
"k8s.io/kubernetes/pkg/controller/volume/events" "k8s.io/kubernetes/pkg/controller/volume/events"
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/util/mount"
@ -380,8 +382,8 @@ func (expc *expandController) GetMounter(pluginName string) mount.Interface {
return nil return nil
} }
func (expc *expandController) GetExec(pluginName string) mount.Exec { func (expc *expandController) GetExec(pluginName string) utilexec.Interface {
return mount.NewOSExec() return utilexec.New()
} }
func (expc *expandController) GetHostName() string { 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/cloud-provider/volume/errors:go_default_library",
"//staging/src/k8s.io/csi-translation-lib:go_default_library", "//staging/src/k8s.io/csi-translation-lib:go_default_library",
"//vendor/k8s.io/klog: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" "k8s.io/client-go/tools/record"
cloudprovider "k8s.io/cloud-provider" cloudprovider "k8s.io/cloud-provider"
"k8s.io/klog" "k8s.io/klog"
utilexec "k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/util/mount"
vol "k8s.io/kubernetes/pkg/volume" vol "k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util/subpath" "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 { func (adc *PersistentVolumeController) GetExec(pluginName string) utilexec.Interface {
return mount.NewOSExec() return utilexec.New()
} }
func (ctrl *PersistentVolumeController) GetNodeLabels() (map[string]string, error) { 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/cache"
"k8s.io/client-go/tools/record" "k8s.io/client-go/tools/record"
cloudprovider "k8s.io/cloud-provider" cloudprovider "k8s.io/cloud-provider"
utilexec "k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/kubelet/configmap" "k8s.io/kubernetes/pkg/kubelet/configmap"
"k8s.io/kubernetes/pkg/kubelet/secret" "k8s.io/kubernetes/pkg/kubelet/secret"
@ -86,7 +88,7 @@ func NewInitializedVolumePluginMgr(
informerFactory: informerFactory, informerFactory: informerFactory,
csiDriverLister: csiDriverLister, csiDriverLister: csiDriverLister,
csiDriversSynced: csiDriversSynced, csiDriversSynced: csiDriversSynced,
exec: mount.NewOSExec(), exec: utilexec.New(),
} }
if err := kvh.volumePluginMgr.InitPlugins(plugins, prober, kvh); err != nil { if err := kvh.volumePluginMgr.InitPlugins(plugins, prober, kvh); err != nil {
@ -115,7 +117,7 @@ type kubeletVolumeHost struct {
informerFactory informers.SharedInformerFactory informerFactory informers.SharedInformerFactory
csiDriverLister storagelisters.CSIDriverLister csiDriverLister storagelisters.CSIDriverLister
csiDriversSynced cache.InformerSynced csiDriversSynced cache.InformerSynced
exec mount.Exec exec utilexec.Interface
} }
func (kvh *kubeletVolumeHost) SetKubeletError(err error) { func (kvh *kubeletVolumeHost) SetKubeletError(err error) {
@ -271,6 +273,6 @@ func (kvh *kubeletVolumeHost) GetEventRecorder() record.EventRecorder {
return kvh.kubelet.recorder return kvh.kubelet.recorder
} }
func (kvh *kubeletVolumeHost) GetExec(pluginName string) mount.Exec { func (kvh *kubeletVolumeHost) GetExec(pluginName string) utilexec.Interface {
return kvh.exec return kvh.exec
} }

View File

@ -4,7 +4,6 @@ go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"doc.go", "doc.go",
"exec.go",
"fake_exec.go", "fake_exec.go",
"fake_mounter.go", "fake_mounter.go",
"mount.go", "mount.go",
@ -75,6 +74,7 @@ go_test(
], ],
embed = [":go_default_library"], embed = [":go_default_library"],
deps = [ deps = [
"//vendor/k8s.io/utils/exec:go_default_library",
"//vendor/k8s.io/utils/exec/testing:go_default_library", "//vendor/k8s.io/utils/exec/testing:go_default_library",
] + select({ ] + select({
"@io_bazel_rules_go//go/platform:windows": [ "@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" "os"
"path/filepath" "path/filepath"
"strings" "strings"
utilexec "k8s.io/utils/exec"
) )
const ( const (
@ -53,13 +55,6 @@ type Interface interface {
GetMountRefs(pathname string) ([]string, error) 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 // Compile-time check to ensure all Mounter implementations satisfy
// the mount interface. // the mount interface.
var _ Interface = &Mounter{} var _ Interface = &Mounter{}
@ -79,7 +74,7 @@ type MountPoint struct {
// mounts it otherwise the device is formatted first then mounted. // mounts it otherwise the device is formatted first then mounted.
type SafeFormatAndMount struct { type SafeFormatAndMount struct {
Interface Interface
Exec Exec utilexec.Interface
} }
// FormatAndMount formats the given disk, if needed, and mounts it. // 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. // 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) klog.V(4).Infof("Checking for issues with fsck on disk: %s", source)
args := []string{"-a", source} args := []string{"-a", source}
out, err := mounter.Exec.Run("fsck", args...) out, err := mounter.Exec.Command("fsck", args...).CombinedOutput()
if err != nil { if err != nil {
ee, isExitError := err.(utilexec.ExitError) ee, isExitError := err.(utilexec.ExitError)
switch { 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) 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 { if err == nil {
// the disk has been formatted successfully try to mount it again. // the disk has been formatted successfully try to mount it again.
klog.Infof("Disk successfully formatted (mkfs): %s - %s %s", fstype, source, target) 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) { func (mounter *SafeFormatAndMount) GetDiskFormat(disk string) (string, error) {
args := []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", disk} 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) 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) output := string(dataOut)
klog.V(4).Infof("Output: %q, err: %v", output, err) klog.V(4).Infof("Output: %q, err: %v", output, err)

View File

@ -26,6 +26,7 @@ import (
"strings" "strings"
"k8s.io/klog" "k8s.io/klog"
utilexec "k8s.io/utils/exec"
"k8s.io/utils/keymutex" "k8s.io/utils/keymutex"
utilpath "k8s.io/utils/path" utilpath "k8s.io/utils/path"
) )
@ -219,7 +220,7 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
// format disk if it is unformatted(raw) // format disk if it is unformatted(raw)
cmd := fmt.Sprintf("Get-Disk -Number %s | Where partitionstyle -eq 'raw' | Initialize-Disk -PartitionStyle MBR -PassThru"+ 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) " | 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)) 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) 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 + ":" driverPath := driveLetter + ":"
target = NormalizeWindowsPath(target) target = NormalizeWindowsPath(target)
klog.V(4).Infof("Attempting to formatAndMount disk: %s %s %s", fstype, driverPath, target) klog.V(4).Infof("Attempting to formatAndMount disk: %s %s %s", fstype, driverPath, target)
if output, err := mounter.Exec.Run("cmd", "/c", "mklink", "/D", target, driverPath); err != nil { 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)) klog.Errorf("mklink failed: %v, output: %q", err, string(output))
return err return err
} }
@ -239,9 +240,9 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
} }
// Get drive letter according to windows disk number // 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) 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 { if err != nil {
return "", fmt.Errorf("azureMount: Get Drive Letter failed: %v, output: %q", err, string(output)) return "", fmt.Errorf("azureMount: Get Drive Letter failed: %v, output: %q", err, string(output))
} }

View File

@ -24,10 +24,10 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"k8s.io/utils/exec/testing"
) )
func makeLink(link, target string) error { func makeLink(link, target string) error {
@ -224,61 +224,61 @@ func TestIsLikelyNotMountPoint(t *testing.T) {
} }
func TestFormatAndMount(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 { tests := []struct {
device string device string
target string target string
fstype string fstype string
execScripts []ExecArgs
mountOptions []string mountOptions []string
expectError bool expectError bool
}{ }{
{ {
"0", device: "0",
"disk", target: "disk",
"NTFS", fstype: "NTFS",
[]string{}, execScripts: []ExecArgs{
false, {"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", device: "0",
"disk", target: "disk",
"", fstype: "",
[]string{}, execScripts: []ExecArgs{
false, {"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", device: "invalidDevice",
"disk", target: "disk",
"NTFS", fstype: "NTFS",
[]string{}, mountOptions: []string{},
true, expectError: true,
}, },
} }
for _, test := range tests { 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) base, err := ioutil.TempDir("", test.device)
if err != nil { if err != nil {
t.Fatalf(err.Error()) t.Fatalf(err.Error())

View File

@ -24,7 +24,8 @@ import (
"strings" "strings"
"testing" "testing"
fakeexec "k8s.io/utils/exec/testing" "k8s.io/utils/exec"
"k8s.io/utils/exec/testing"
) )
type ErrorMounter struct { type ErrorMounter struct {
@ -82,7 +83,7 @@ func TestSafeFormatAndMount(t *testing.T) {
description: "Test 'fsck' fails with exit status 4", description: "Test 'fsck' fails with exit status 4",
fstype: "ext4", fstype: "ext4",
execScripts: []ExecArgs{ 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"), 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)", description: "Test 'fsck' fails with exit status 1 (errors found and corrected)",
fstype: "ext4", fstype: "ext4",
execScripts: []ExecArgs{ 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)", description: "Test 'fsck' fails with exit status other than 1 and 4 (likely unformatted device)",
fstype: "ext4", fstype: "ext4",
execScripts: []ExecArgs{ 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)'")}, mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
execScripts: []ExecArgs{ execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil}, {"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")}, {"mkfs.ext4", []string{"-F", "-m0", "/dev/foo"}, "", fmt.Errorf("formatting failed")},
}, },
expectedError: 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")}, mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), fmt.Errorf("Still cannot mount")},
execScripts: []ExecArgs{ execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil}, {"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}, {"mkfs.ext4", []string{"-F", "-m0", "/dev/foo"}, "", nil},
}, },
expectedError: fmt.Errorf("Still cannot mount"), expectedError: fmt.Errorf("Still cannot mount"),
@ -138,7 +139,7 @@ func TestSafeFormatAndMount(t *testing.T) {
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil}, mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
execScripts: []ExecArgs{ execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil}, {"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}, {"mkfs.ext4", []string{"-F", "-m0", "/dev/foo"}, "", nil},
}, },
expectedError: nil, expectedError: nil,
@ -149,7 +150,7 @@ func TestSafeFormatAndMount(t *testing.T) {
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil}, mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
execScripts: []ExecArgs{ execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil}, {"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}, {"mkfs.ext3", []string{"-F", "-m0", "/dev/foo"}, "", nil},
}, },
expectedError: nil, expectedError: nil,
@ -160,7 +161,7 @@ func TestSafeFormatAndMount(t *testing.T) {
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil}, mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
execScripts: []ExecArgs{ execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil}, {"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}, {"mkfs.xfs", []string{"/dev/foo"}, "", nil},
}, },
expectedError: nil, expectedError: nil,
@ -181,7 +182,7 @@ func TestSafeFormatAndMount(t *testing.T) {
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil}, mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
execScripts: []ExecArgs{ execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil}, {"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}, {"mkfs.xfs", []string{"/dev/foo"}, "", nil},
}, },
expectedError: fmt.Errorf("exit 4"), expectedError: fmt.Errorf("exit 4"),
@ -189,27 +190,15 @@ func TestSafeFormatAndMount(t *testing.T) {
} }
for _, test := range tests { 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} 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{ mounter := SafeFormatAndMount{
Interface: &fakeMounter, Interface: &fakeMounter,
Exec: fakeExec, 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) { 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 { if err == nil {
klog.V(2).Infof("Device %s resized successfully", devicePath) klog.V(2).Infof("Device %s resized successfully", devicePath)
return true, nil return true, nil
@ -74,7 +74,7 @@ func (resizefs *ResizeFs) extResize(devicePath string) (bool, error) {
func (resizefs *ResizeFs) xfsResize(deviceMountPath string) (bool, error) { func (resizefs *ResizeFs) xfsResize(deviceMountPath string) (bool, error) {
args := []string{"-d", deviceMountPath} 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 { if err == nil {
klog.V(2).Infof("Device %s resized successfully", deviceMountPath) 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/client-go/tools/record:go_default_library",
"//staging/src/k8s.io/cloud-provider:go_default_library", "//staging/src/k8s.io/cloud-provider:go_default_library",
"//vendor/k8s.io/klog: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] volumeID = split[len(split)-1]
exec := attacher.host.GetExec(awsElasticBlockStorePluginName) exec := attacher.host.GetExec(awsElasticBlockStorePluginName)
output, err := exec.Run(ebsnvmeID) output, err := exec.Command(ebsnvmeID).CombinedOutput()
if err != nil { if err != nil {
return "", fmt.Errorf("error calling ebsnvme-id.exe: %v", err) 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/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/klog:go_default_library",
"//vendor/k8s.io/utils/strings: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( filegroup(
@ -70,7 +108,6 @@ go_test(
], ],
embed = [":go_default_library"], embed = [":go_default_library"],
deps = [ deps = [
"//pkg/util/mount:go_default_library",
"//pkg/volume:go_default_library", "//pkg/volume:go_default_library",
"//pkg/volume/testing:go_default_library", "//pkg/volume/testing:go_default_library",
"//staging/src/k8s.io/api/core/v1: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", "//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/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/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" libstrings "strings"
"k8s.io/klog" "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 // 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) 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/" scsi_path := "/sys/class/scsi_host/"
if dirs, err := io.ReadDir(scsi_path); err == nil { if dirs, err := io.ReadDir(scsi_path); err == nil {
for _, f := range dirs { 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) azureDisks := listAzureDiskPath(io)
return findDiskByLunWithConstraint(lun, io, azureDisks) 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/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/util/mount"
) )
type fakeFileInfo struct { type fakeFileInfo struct {
@ -126,7 +125,7 @@ func TestIoHandler(t *testing.T) {
if runtime.GOOS != "windows" && runtime.GOOS != "linux" { if runtime.GOOS != "windows" && runtime.GOOS != "linux" {
t.Skipf("TestIoHandler not supported on GOOS=%s", runtime.GOOS) 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 runtime.GOOS == "windows" {
if err != nil { if err != nil {
t.Errorf("no data disk found: disk %v err %v", disk, err) 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 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 return "", nil
} }

View File

@ -26,22 +26,23 @@ import (
"strings" "strings"
"k8s.io/klog" "k8s.io/klog"
utilexec "k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/util/mount"
) )
func scsiHostRescan(io ioHandler, exec mount.Exec) { func scsiHostRescan(io ioHandler, exec utilexec.Interface) {
cmd := "Update-HostStorageCache" cmd := "Update-HostStorageCache"
output, err := exec.Run("powershell", "/c", cmd) output, err := exec.Command("powershell", "/c", cmd).CombinedOutput()
if err != nil { if err != nil {
klog.Errorf("Update-HostStorageCache failed in scsiHostRescan, error: %v, output: %q", err, string(output)) klog.Errorf("Update-HostStorageCache failed in scsiHostRescan, error: %v, output: %q", err, string(output))
} }
} }
// search Windows disk number by LUN // 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` 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 { if err != nil {
klog.Errorf("Get-Disk failed in findDiskByLun, error: %v, output: %q", err, string(output)) klog.Errorf("Get-Disk failed in findDiskByLun, error: %v, output: %q", err, string(output))
return "", err return "", err
@ -98,7 +99,7 @@ func findDiskByLun(lun int, iohandler ioHandler, exec mount.Exec) (string, error
return "", nil 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 { if err := mount.ValidateDiskNumber(disk); err != nil {
klog.Errorf("azureDisk Mount: formatIfNotFormatted failed, err: %v\n", err) klog.Errorf("azureDisk Mount: formatIfNotFormatted failed, err: %v\n", err)
return 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("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) 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 { if err != nil {
klog.Errorf("azureDisk Mount: Get-Disk failed, error: %v, output: %q", err, string(output)) klog.Errorf("azureDisk Mount: Get-Disk failed, error: %v, output: %q", err, string(output))
} else { } else {

View File

@ -331,7 +331,7 @@ func (cephfsVolume *cephfsMounter) checkFuseMount() bool {
execute := cephfsVolume.plugin.host.GetExec(cephfsVolume.plugin.GetPluginName()) execute := cephfsVolume.plugin.host.GetExec(cephfsVolume.plugin.GetPluginName())
switch runtime.GOOS { switch runtime.GOOS {
case "linux": 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.") klog.V(4).Info("/sbin/mount.fuse.ceph exists, it should be fuse mount.")
return true return true
} }

View File

@ -27,6 +27,7 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//vendor/k8s.io/klog: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", "//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/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/fake: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", "//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" "k8s.io/apimachinery/pkg/types"
utilfeature "k8s.io/apiserver/pkg/util/feature" utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/klog" "k8s.io/klog"
utilexec "k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume" "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())) 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 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 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) 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())) 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) fc, readOnly, err := getVolumeSource(spec)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -29,6 +29,8 @@ import (
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/kubernetes/fake"
utiltesting "k8s.io/client-go/util/testing" utiltesting "k8s.io/client-go/util/testing"
"k8s.io/utils/exec/testing"
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing" volumetest "k8s.io/kubernetes/pkg/volume/testing"
@ -164,7 +166,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) {
fakeManager := newFakeDiskManager() fakeManager := newFakeDiskManager()
defer fakeManager.Cleanup() defer fakeManager.Cleanup()
fakeMounter := mount.NewFakeMounter(nil) fakeMounter := mount.NewFakeMounter(nil)
fakeExec := mount.NewFakeExec(nil) fakeExec := &testingexec.FakeExec{}
mounter, err := plug.(*fcPlugin).newMounterInternal(spec, types.UID("poduid"), fakeManager, fakeMounter, fakeExec) mounter, err := plug.(*fcPlugin).newMounterInternal(spec, types.UID("poduid"), fakeManager, fakeMounter, fakeExec)
if err != nil { if err != nil {
t.Errorf("Failed to make a new Mounter: %v", err) t.Errorf("Failed to make a new Mounter: %v", err)
@ -227,7 +229,7 @@ func doTestPluginNilMounter(t *testing.T, spec *volume.Spec) {
fakeManager := newFakeDiskManager() fakeManager := newFakeDiskManager()
defer fakeManager.Cleanup() defer fakeManager.Cleanup()
fakeMounter := mount.NewFakeMounter(nil) fakeMounter := mount.NewFakeMounter(nil)
fakeExec := mount.NewFakeExec(nil) fakeExec := &testingexec.FakeExec{}
mounter, err := plug.(*fcPlugin).newMounterInternal(spec, types.UID("poduid"), fakeManager, fakeMounter, fakeExec) mounter, err := plug.(*fcPlugin).newMounterInternal(spec, types.UID("poduid"), fakeManager, fakeMounter, fakeExec)
if err == nil { if err == nil {
t.Errorf("Error failed to make a new Mounter is expected: %v", err) 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" volumetesting "k8s.io/kubernetes/pkg/volume/testing"
"k8s.io/kubernetes/test/utils/harness" "k8s.io/kubernetes/test/utils/harness"
"k8s.io/utils/exec" "k8s.io/utils/exec"
fakeexec "k8s.io/utils/exec/testing" "k8s.io/utils/exec/testing"
) )
func testPlugin(h *harness.Harness) (*flexVolumeAttachablePlugin, string) { func testPlugin(h *harness.Harness) (*flexVolumeAttachablePlugin, string) {
@ -39,7 +39,7 @@ func testPlugin(h *harness.Harness) (*flexVolumeAttachablePlugin, string) {
}, rootDir }, 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 { return func(cmd string, args ...string) exec.Cmd {
if cmd != "/plugin/test" { if cmd != "/plugin/test" {
t.Errorf("Wrong executable called: got %v, expected %v", 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) { if !sameArgs(cmdArgs, expectedArgs) {
t.Errorf("Wrong args for %s: got %v, expected %v", args[0], cmdArgs, expectedArgs) t.Errorf("Wrong args for %s: got %v, expected %v", args[0], cmdArgs, expectedArgs)
} }
return &fakeexec.FakeCmd{ return &testingexec.FakeCmd{
Argv: args, Argv: args,
CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{output}, CombinedOutputScript: []testingexec.FakeCombinedOutputAction{output},
} }
} }
} }
func fakeRunner(fakeCommands ...fakeexec.FakeCommandAction) exec.Interface { func fakeRunner(fakeCommands ...testingexec.FakeCommandAction) exec.Interface {
return &fakeexec.FakeExec{ return &testingexec.FakeExec{
CommandScript: fakeCommands, CommandScript: fakeCommands,
} }
} }
func fakeResultOutput(result interface{}) fakeexec.FakeCombinedOutputAction { func fakeResultOutput(result interface{}) testingexec.FakeCombinedOutputAction {
return func() ([]byte, error) { return func() ([]byte, error) {
bytes, err := json.Marshal(result) bytes, err := json.Marshal(result)
if err != nil { 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}) return fakeResultOutput(&DriverStatus{StatusSuccess, "", "", "", true, nil, 0})
} }
func notSupportedOutput() fakeexec.FakeCombinedOutputAction { func notSupportedOutput() testingexec.FakeCombinedOutputAction {
return fakeResultOutput(&DriverStatus{StatusNotSupported, "", "", "", false, nil, 0}) return fakeResultOutput(&DriverStatus{StatusNotSupported, "", "", "", false, nil, 0})
} }

View File

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

View File

@ -33,6 +33,8 @@ import (
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/klog" "k8s.io/klog"
utilexec "k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
volumeutil "k8s.io/kubernetes/pkg/volume/util" volumeutil "k8s.io/kubernetes/pkg/volume/util"
@ -179,10 +181,10 @@ func (attacher *gcePersistentDiskAttacher) BulkVerifyVolumes(volumesByNode map[t
} }
// search Windows disk number by LUN // 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 // TODO: replace Get-GcePdName with native windows support of Get-Disk, see issue #74674
cmd := `Get-GcePdName | select Name, DeviceId | ConvertTo-Json` 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 { if err != nil {
klog.Errorf("Get-GcePdName failed, error: %v, output: %q", err, string(output)) klog.Errorf("Get-GcePdName failed, error: %v, output: %q", err, string(output))
err = errors.New(err.Error() + " " + 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()) exe := b.plugin.host.GetExec(b.plugin.GetPluginName())
switch runtime.GOOS { switch runtime.GOOS {
case "linux": 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) 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/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/fake: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", "//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" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/klog" "k8s.io/klog"
utilexec "k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
ioutil "k8s.io/kubernetes/pkg/volume/util" 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) 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) readOnly, fsType, err := getISCSIVolumeInfo(spec)
if err != nil { if err != nil {
return nil, err 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) 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) readOnly, _, err := getISCSIVolumeInfo(spec)
if err != nil { if err != nil {
return nil, err 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())) 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{ return &iscsiDiskUnmounter{
iscsiDisk: &iscsiDisk{ iscsiDisk: &iscsiDisk{
podUID: podUID, 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())) 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{ return &iscsiDiskUnmapper{
iscsiDisk: &iscsiDisk{ iscsiDisk: &iscsiDisk{
podUID: podUID, podUID: podUID,
@ -318,7 +320,7 @@ type iscsiDiskMounter struct {
fsType string fsType string
volumeMode v1.PersistentVolumeMode volumeMode v1.PersistentVolumeMode
mounter *mount.SafeFormatAndMount mounter *mount.SafeFormatAndMount
exec mount.Exec exec utilexec.Interface
deviceUtil ioutil.DeviceUtil deviceUtil ioutil.DeviceUtil
mountOptions []string mountOptions []string
} }
@ -356,7 +358,7 @@ func (b *iscsiDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) e
type iscsiDiskUnmounter struct { type iscsiDiskUnmounter struct {
*iscsiDisk *iscsiDisk
mounter mount.Interface mounter mount.Interface
exec mount.Exec exec utilexec.Interface
deviceUtil ioutil.DeviceUtil deviceUtil ioutil.DeviceUtil
} }
@ -376,7 +378,7 @@ func (c *iscsiDiskUnmounter) TearDownAt(dir string) error {
type iscsiDiskMapper struct { type iscsiDiskMapper struct {
*iscsiDisk *iscsiDisk
readOnly bool readOnly bool
exec mount.Exec exec utilexec.Interface
deviceUtil ioutil.DeviceUtil deviceUtil ioutil.DeviceUtil
} }
@ -392,7 +394,7 @@ func (b *iscsiDiskMapper) MapDevice(devicePath, globalMapPath, volumeMapPath, vo
type iscsiDiskUnmapper struct { type iscsiDiskUnmapper struct {
*iscsiDisk *iscsiDisk
exec mount.Exec exec utilexec.Interface
deviceUtil ioutil.DeviceUtil deviceUtil ioutil.DeviceUtil
} }

View File

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

View File

@ -24,6 +24,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"sort"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -96,7 +97,7 @@ func updateISCSIDiscoverydb(b iscsiDiskMounter, tp string) error {
v := b.secret[k] v := b.secret[k]
if len(v) > 0 { if len(v) > 0 {
// explicitly not using execWithLog so secrets are not logged // 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 { if err != nil {
return fmt.Errorf("iscsi: failed to update discoverydb key %q error: %v", k, string(out)) 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] v := b.secret[k]
if len(v) > 0 { if len(v) > 0 {
// explicitly not using execWithLog so secrets are not logged // 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 { if err != nil {
return fmt.Errorf("iscsi: failed to update node session key %q error: %v", k, string(out)) 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 // Flush any multipath device maps
for mpathDevice := range mpathDevices { for mpathDevice := range mpathDevices {
_, err = c.exec.Run("multipath", "-f", mpathDevice) _, err = c.exec.Command("multipath", "-f", mpathDevice).CombinedOutput()
if err != nil { if err != nil {
klog.Warningf("Warning: Failed to flush multipath device map: %s\nError: %v", mpathDevice, err) klog.Warningf("Warning: Failed to flush multipath device map: %s\nError: %v", mpathDevice, err)
// Fall through -- keep deleting the block devices // Fall through -- keep deleting the block devices
@ -722,7 +723,7 @@ func (util *ISCSIUtil) DetachBlockISCSIDisk(c iscsiDiskUnmapper, mapPath string)
return nil 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 { for _, portal := range portals {
logoutArgs := []string{"-m", "node", "-p", portal, "-T", iqn, "--logout"} logoutArgs := []string{"-m", "node", "-p", portal, "-T", iqn, "--logout"}
deleteArgs := []string{"-m", "node", "-p", portal, "-T", iqn, "-o", "delete"} 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}...) deleteArgs = append(deleteArgs, []string{"-I", iface}...)
} }
klog.Infof("iscsi: log out target %s iqn %s iface %s", portal, iqn, 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) err = ignoreExitCodes(err, exit_ISCSI_ERR_NO_OBJS_FOUND, exit_ISCSI_ERR_SESS_NOT_FOUND)
if err != nil { if err != nil {
klog.Errorf("iscsi: failed to detach disk Error: %s", string(out)) 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 // Delete the node record
klog.Infof("iscsi: delete node record target %s iqn %s", portal, iqn) 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) err = ignoreExitCodes(err, exit_ISCSI_ERR_NO_OBJS_FOUND, exit_ISCSI_ERR_SESS_NOT_FOUND)
if err != nil { if err != nil {
klog.Errorf("iscsi: failed to delete node record Error: %s", string(out)) 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 the iface is not created via iscsi plugin, skip to delete
if initiatorName != "" && found && iface == (portals[0]+":"+volName) { if initiatorName != "" && found && iface == (portals[0]+":"+volName) {
deleteArgs := []string{"-m", "iface", "-I", iface, "-o", "delete"} 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) err = ignoreExitCodes(err, exit_ISCSI_ERR_NO_OBJS_FOUND, exit_ISCSI_ERR_SESS_NOT_FOUND)
if err != nil { if err != nil {
klog.Errorf("iscsi: failed to delete iface Error: %s", string(out)) klog.Errorf("iscsi: failed to delete iface Error: %s", string(out))
@ -884,9 +885,15 @@ func cloneIface(b iscsiDiskMounter) error {
return lastErr 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 // update new iface records
for key, val := range params { for _, key := range keys {
_, err = execWithLog(b, "iscsiadm", "-m", "iface", "-I", b.Iface, "-o", "update", "-n", key, "-v", val) _, err = execWithLog(b, "iscsiadm", "-m", "iface", "-I", b.Iface, "-o", "update", "-n", key, "-v", params[key])
if err != nil { if err != nil {
execWithLog(b, "iscsiadm", "-m", "iface", "-I", b.Iface, "-o", "delete") 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) 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) { func execWithLog(b iscsiDiskMounter, cmd string, args ...string) (string, error) {
start := time.Now() start := time.Now()
out, err := b.exec.Run(cmd, args...) out, err := b.exec.Command(cmd, args...).CombinedOutput()
if klog.V(5) { if klog.V(5) {
d := time.Since(start) d := time.Since(start)
klog.V(5).Infof("Executed %s %v in %v, err: %v", cmd, args, d, err) 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 package iscsi
import ( import (
"errors"
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
"testing" "testing"
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/utils/exec/testing"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing"
)
const (
TestIface = "192.168.1.10:pv0001"
) )
func TestExtractDeviceAndPrefix(t *testing.T) { func TestExtractDeviceAndPrefix(t *testing.T) {
@ -216,28 +220,28 @@ func TestParseIscsiadmShow(t *testing.T) {
} }
func TestClonedIface(t *testing.T) { func TestClonedIface(t *testing.T) {
cmdCount := 0 fakeExec := &testingexec.FakeExec{}
fakeExec := mount.NewFakeExec(func(cmd string, args ...string) ([]byte, error) { scripts := []volumetest.CommandScript{
cmdCount++ {
if cmd != "iscsiadm" { Cmd: "iscsiadm",
t.Errorf("iscsiadm command expected, got %q", cmd) 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"},
},
} }
switch cmdCount { volumetest.ScriptCommands(fakeExec, scripts)
case 1: fakeExec.ExactOrder = true
// 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)
})
plugins := []volume.VolumePlugin{ plugins := []volume.VolumePlugin{
&iscsiPlugin{ &iscsiPlugin{
host: nil, host: nil,
@ -246,27 +250,32 @@ func TestClonedIface(t *testing.T) {
plugin := plugins[0] plugin := plugins[0]
fakeMounter := iscsiDiskMounter{ fakeMounter := iscsiDiskMounter{
iscsiDisk: &iscsiDisk{ iscsiDisk: &iscsiDisk{
Iface: "192.168.1.10:pv0001", Iface: TestIface,
plugin: plugin.(*iscsiPlugin)}, plugin: plugin.(*iscsiPlugin)},
exec: fakeExec, exec: fakeExec,
} }
cloneIface(fakeMounter) err := cloneIface(fakeMounter)
if cmdCount != 4 { if err != nil {
t.Errorf("expected 4 CombinedOutput() calls, got %d", cmdCount) 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) { func TestClonedIfaceShowError(t *testing.T) {
cmdCount := 0 fakeExec := &testingexec.FakeExec{}
fakeExec := mount.NewFakeExec(func(cmd string, args ...string) ([]byte, error) { scripts := []volumetest.CommandScript{
cmdCount++ {
if cmd != "iscsiadm" { Cmd: "iscsiadm",
t.Errorf("iscsiadm command expected, got %q", cmd) Args: []string{"-m", "iface", "-I", "", "-o", "show"},
Output: "test error",
ReturnCode: 1,
},
} }
// iscsiadm -m iface -I <iface> -o show, return test error volumetest.ScriptCommands(fakeExec, scripts)
return []byte(""), errors.New("test error") fakeExec.ExactOrder = true
})
plugins := []volume.VolumePlugin{ plugins := []volume.VolumePlugin{
&iscsiPlugin{ &iscsiPlugin{
host: nil, host: nil,
@ -275,43 +284,49 @@ func TestClonedIfaceShowError(t *testing.T) {
plugin := plugins[0] plugin := plugins[0]
fakeMounter := iscsiDiskMounter{ fakeMounter := iscsiDiskMounter{
iscsiDisk: &iscsiDisk{ iscsiDisk: &iscsiDisk{
Iface: "192.168.1.10:pv0001", Iface: TestIface,
plugin: plugin.(*iscsiPlugin)}, plugin: plugin.(*iscsiPlugin)},
exec: fakeExec, exec: fakeExec,
} }
cloneIface(fakeMounter) err := cloneIface(fakeMounter)
if cmdCount != 1 { if err == nil {
t.Errorf("expected 1 CombinedOutput() calls, got %d", cmdCount) 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) { func TestClonedIfaceUpdateError(t *testing.T) {
cmdCount := 0 fakeExec := &testingexec.FakeExec{}
fakeExec := mount.NewFakeExec(func(cmd string, args ...string) ([]byte, error) { scripts := []volumetest.CommandScript{
cmdCount++ {
if cmd != "iscsiadm" { Cmd: "iscsiadm",
t.Errorf("iscsiadm command expected, got %q", cmd) 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"},
},
} }
switch cmdCount { volumetest.ScriptCommands(fakeExec, scripts)
case 1: fakeExec.ExactOrder = true
// 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(""), 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{ plugins := []volume.VolumePlugin{
&iscsiPlugin{ &iscsiPlugin{
host: nil, host: nil,
@ -320,13 +335,16 @@ func TestClonedIfaceUpdateError(t *testing.T) {
plugin := plugins[0] plugin := plugins[0]
fakeMounter := iscsiDiskMounter{ fakeMounter := iscsiDiskMounter{
iscsiDisk: &iscsiDisk{ iscsiDisk: &iscsiDisk{
Iface: "192.168.1.10:pv0001", Iface: TestIface,
plugin: plugin.(*iscsiPlugin)}, plugin: plugin.(*iscsiPlugin)},
exec: fakeExec, exec: fakeExec,
} }
cloneIface(fakeMounter) err := cloneIface(fakeMounter)
if cmdCount != 5 { if err == nil {
t.Errorf("expected 5 CombinedOutput() calls, got %d", cmdCount) 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()) exec := nfsMounter.plugin.host.GetExec(nfsMounter.plugin.GetPluginName())
switch runtime.GOOS { switch runtime.GOOS {
case "linux": 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") 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 fmt.Errorf("Required binary /sbin/mount.nfs4 is missing")
} }
return nil return nil
case "darwin": 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") return fmt.Errorf("Required binary /sbin/mount_nfs is missing")
} }
} }

View File

@ -38,6 +38,8 @@ import (
"k8s.io/client-go/tools/record" "k8s.io/client-go/tools/record"
cloudprovider "k8s.io/cloud-provider" cloudprovider "k8s.io/cloud-provider"
"k8s.io/klog" "k8s.io/klog"
"k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume/util/hostutil" "k8s.io/kubernetes/pkg/volume/util/hostutil"
@ -437,7 +439,7 @@ type VolumeHost interface {
DeleteServiceAccountTokenFunc() func(podUID types.UID) DeleteServiceAccountTokenFunc() func(podUID types.UID)
// Returns an interface that should be used to execute any utilities in volume plugins // 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 // Returns the labels on the node
GetNodeLabels() (map[string]string, error) 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()) 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)) klog.V(4).Infof("quobyte: can support: %s", string(out))
return true return true
} }

View File

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

View File

@ -38,6 +38,7 @@ import (
"k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util"
volutil "k8s.io/kubernetes/pkg/volume/util" volutil "k8s.io/kubernetes/pkg/volume/util"
"k8s.io/kubernetes/pkg/volume/util/volumepathhandler" "k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
utilexec "k8s.io/utils/exec"
utilstrings "k8s.io/utils/strings" 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())) 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) mon, err := getVolumeSourceMonitors(spec)
if err != nil { if err != nil {
return nil, err return nil, err
@ -770,7 +771,7 @@ type rbd struct {
ReadOnly bool ReadOnly bool
plugin *rbdPlugin plugin *rbdPlugin
mounter *mount.SafeFormatAndMount mounter *mount.SafeFormatAndMount
exec mount.Exec exec utilexec.Interface
// Utility interface that provides API calls to the provider to attach/detach disks. // Utility interface that provides API calls to the provider to attach/detach disks.
manager diskManager manager diskManager
volume.MetricsProvider `json:"-"` volume.MetricsProvider `json:"-"`

View File

@ -32,7 +32,7 @@ import (
"strings" "strings"
"time" "time"
"k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
@ -42,6 +42,7 @@ import (
"k8s.io/kubernetes/pkg/util/node" "k8s.io/kubernetes/pkg/util/node"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
volutil "k8s.io/kubernetes/pkg/volume/util" volutil "k8s.io/kubernetes/pkg/volume/util"
utilexec "k8s.io/utils/exec"
utilpath "k8s.io/utils/path" 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. // do not change this format - some tools like rbd-nbd are strict about it.
imgPath := fmt.Sprintf("%s/%s", b.Pool, b.Image) imgPath := fmt.Sprintf("%s/%s", b.Pool, b.Image)
if b.Secret != "" { if b.Secret != "" {
return b.exec.Run(rbdCmd, return b.exec.Command(rbdCmd,
"map", imgPath, "--id", b.Id, "-m", mon, "--key="+b.Secret) "map", imgPath, "--id", b.Id, "-m", mon, "--key="+b.Secret).CombinedOutput()
} else { } else {
return b.exec.Run(rbdCmd, return b.exec.Command(rbdCmd,
"map", imgPath, "--id", b.Id, "-m", mon, "-k", b.Keyring) "map", imgPath, "--id", b.Id, "-m", mon, "-k", b.Keyring).CombinedOutput()
} }
} }
// Check if rbd-nbd tools are installed. // Check if rbd-nbd tools are installed.
func checkRbdNbdTools(e mount.Exec) bool { func checkRbdNbdTools(e utilexec.Interface) bool {
_, err := e.Run("modprobe", "nbd") _, err := e.Command("modprobe", "nbd").CombinedOutput()
if err != nil { if err != nil {
klog.V(5).Infof("rbd-nbd: nbd modprobe failed with error %v", err) klog.V(5).Infof("rbd-nbd: nbd modprobe failed with error %v", err)
return false 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) klog.V(5).Infof("rbd-nbd: getting rbd-nbd version failed with error %v", err)
return false return false
} }
@ -335,7 +336,7 @@ func (util *RBDUtil) rbdUnlock(b rbdMounter) error {
// Get the locker name, something like "client.1234". // Get the locker name, something like "client.1234".
args := []string{"lock", "list", b.Image, "--pool", b.Pool, "--id", b.Id, "-m", mon} args := []string{"lock", "list", b.Image, "--pool", b.Pool, "--id", b.Id, "-m", mon}
args = append(args, secret_opt...) args = append(args, secret_opt...)
cmd, err = b.exec.Run("rbd", args...) cmd, err = b.exec.Command("rbd", args...).CombinedOutput()
output = string(cmd) output = string(cmd)
klog.V(4).Infof("lock list output %q", output) klog.V(4).Infof("lock list output %q", output)
if err != nil { if err != nil {
@ -353,7 +354,7 @@ func (util *RBDUtil) rbdUnlock(b rbdMounter) error {
if len(locker) > 0 { if len(locker) > 0 {
args := []string{"lock", "remove", b.Image, lock_id, locker, "--pool", b.Pool, "--id", b.Id, "-m", mon} args := []string{"lock", "remove", b.Image, lock_id, locker, "--pool", b.Pool, "--id", b.Id, "-m", mon}
args = append(args, secret_opt...) args = append(args, secret_opt...)
cmd, err = b.exec.Run("rbd", args...) cmd, err = b.exec.Command("rbd", args...).CombinedOutput()
if err == nil { 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) 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 { } else {
@ -432,7 +433,7 @@ func (util *RBDUtil) AttachDisk(b rbdMounter) (string, error) {
mon := util.kernelRBDMonitorsOpt(b.Mon) mon := util.kernelRBDMonitorsOpt(b.Mon)
klog.V(1).Infof("rbd: map mon %s", 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 { if err != nil {
klog.Warningf("rbd: failed to load rbd kernel module:%v", err) 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 // rbd unmap
output, err := exec.Run(rbdCmd, "unmap", device) output, err := exec.Command(rbdCmd, "unmap", device).CombinedOutput()
if err != nil { if err != nil {
return rbdErrors(err, fmt.Errorf("rbd: failed to unmap device %s, error %v, rbd output: %v", device, err, output)) 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 // rbd unmap
output, err := exec.Run(rbdCmd, "unmap", device) output, err := exec.Command(rbdCmd, "unmap", device).CombinedOutput()
if err != nil { if err != nil {
return rbdErrors(err, fmt.Errorf("rbd: failed to unmap device %s, error %v, rbd output: %s", device, err, string(output))) 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, ",") features := strings.Join(p.rbdMounter.imageFeatures, ",")
args = append(args, "--image-feature", features) args = append(args, "--image-feature", features)
} }
output, err = p.exec.Run("rbd", args...) output, err = p.exec.Command("rbd", args...).CombinedOutput()
if err != nil { if err != nil {
klog.Warningf("failed to create rbd image, output %v", string(output)) klog.Warningf("failed to create rbd image, output %v", string(output))
@ -628,8 +629,8 @@ func (util *RBDUtil) DeleteImage(p *rbdVolumeDeleter) error {
// rbd rm. // rbd rm.
mon := util.kernelRBDMonitorsOpt(p.rbdMounter.Mon) 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) 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", output, err = p.exec.Command("rbd",
"rm", p.rbdMounter.Image, "--pool", p.rbdMounter.Pool, "--id", p.rbdMounter.adminId, "-m", mon, "--key="+p.rbdMounter.adminSecret) "rm", p.rbdMounter.Image, "--pool", p.rbdMounter.Pool, "--id", p.rbdMounter.adminId, "-m", mon, "--key="+p.rbdMounter.adminSecret).CombinedOutput()
if err == nil { if err == nil {
return nil return nil
} }
@ -660,8 +661,8 @@ func (util *RBDUtil) ExpandImage(rbdExpander *rbdVolumeExpander, oldSize resourc
// rbd resize. // rbd resize.
mon := util.kernelRBDMonitorsOpt(rbdExpander.rbdMounter.Mon) 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) 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", 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) "resize", rbdExpander.rbdMounter.Image, "--size", newVolSz, "--pool", rbdExpander.rbdMounter.Pool, "--id", rbdExpander.rbdMounter.adminId, "-m", mon, "--key="+rbdExpander.rbdMounter.adminSecret).CombinedOutput()
if err == nil { if err == nil {
return newSizeQuant, 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 // 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) 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", output, err = b.exec.Command("rbd",
"info", b.Image, "--pool", b.Pool, "-m", mon, "--id", id, "--key="+secret, "-k=/dev/null", "--format=json") "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, ok := err.(*exec.Error); ok {
if err.Err == exec.ErrNotFound { 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 // 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) 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", cmd, err = b.exec.Command("rbd",
"status", b.Image, "--pool", b.Pool, "-m", mon, "--id", id, "--key="+secret) "status", b.Image, "--pool", b.Pool, "-m", mon, "--id", id, "--key="+secret).CombinedOutput()
output = string(cmd) output = string(cmd)
if err, ok := err.(*exec.Error); ok { if err, ok := err.(*exec.Error); ok {

View File

@ -15,7 +15,6 @@ go_test(
], ],
embed = [":go_default_library"], embed = [":go_default_library"],
deps = [ deps = [
"//pkg/util/mount:go_default_library",
"//pkg/volume:go_default_library", "//pkg/volume:go_default_library",
"//pkg/volume/testing:go_default_library", "//pkg/volume/testing:go_default_library",
"//staging/src/k8s.io/api/core/v1: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", "//staging/src/k8s.io/client-go/util/testing:go_default_library",
"//vendor/github.com/thecodeteam/goscaleio/types/v1:go_default_library", "//vendor/github.com/thecodeteam/goscaleio/types/v1:go_default_library",
"//vendor/k8s.io/klog: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:go_default_library",
"//vendor/github.com/thecodeteam/goscaleio/types/v1:go_default_library", "//vendor/github.com/thecodeteam/goscaleio/types/v1:go_default_library",
"//vendor/k8s.io/klog: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/keymutex:go_default_library",
"//vendor/k8s.io/utils/strings:go_default_library", "//vendor/k8s.io/utils/strings:go_default_library",
], ],

View File

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

View File

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

View File

@ -21,9 +21,8 @@ import (
"testing" "testing"
"time" "time"
"k8s.io/kubernetes/pkg/util/mount"
siotypes "github.com/thecodeteam/goscaleio/types/v1" siotypes "github.com/thecodeteam/goscaleio/types/v1"
"k8s.io/utils/exec/testing"
) )
var ( var (
@ -44,7 +43,7 @@ var (
) )
func newTestMgr(t *testing.T) *sioMgr { func newTestMgr(t *testing.T) *sioMgr {
mgr, err := newSioMgr(fakeConfig, mount.NewFakeExec(nil)) mgr, err := newSioMgr(fakeConfig, &testingexec.FakeExec{})
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -53,7 +52,7 @@ func newTestMgr(t *testing.T) *sioMgr {
} }
func TestMgrNew(t *testing.T) { func TestMgrNew(t *testing.T) {
mgr, err := newSioMgr(fakeConfig, mount.NewFakeExec(nil)) mgr, err := newSioMgr(fakeConfig, &testingexec.FakeExec{})
if err != nil { if err != nil {
t.Fatal(err) 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:go_default_library",
"//vendor/github.com/storageos/go-api/types:go_default_library", "//vendor/github.com/storageos/go-api/types:go_default_library",
"//vendor/k8s.io/klog: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", "//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/kubernetes/fake:go_default_library",
"//staging/src/k8s.io/client-go/util/testing: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/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/util/mount"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util"
utilexec "k8s.io/utils/exec"
utilstrings "k8s.io/utils/strings" 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())) 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) volName, volNamespace, fsType, readOnly, err := getVolumeInfoFromSpec(spec)
if err != nil { 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())) 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 // Parse volume namespace & name from mountpoint if mounted
volNamespace, volName, err := getVolumeInfo(pvName, podUID, plugin.host) volNamespace, volName, err := getVolumeInfo(pvName, podUID, plugin.host)
@ -311,7 +312,7 @@ type storageos struct {
apiCfg *storageosAPIConfig apiCfg *storageosAPIConfig
manager storageosManager manager storageosManager
mounter mount.Interface mounter mount.Interface
exec mount.Exec exec utilexec.Interface
plugin *storageosPlugin plugin *storageosPlugin
volume.MetricsProvider volume.MetricsProvider
} }

View File

@ -30,6 +30,7 @@ import (
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing" volumetest "k8s.io/kubernetes/pkg/volume/testing"
"k8s.io/utils/exec/testing"
) )
func TestCanSupport(t *testing.T) { 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) 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 { if err != nil {
t.Fatalf("Failed to make a new Mounter: %v", err) t.Fatalf("Failed to make a new Mounter: %v", err)
} }
@ -231,7 +232,7 @@ func TestPlugin(t *testing.T) {
// Test Unmounter // Test Unmounter
fakeManager = &fakePDManager{} 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 { if err != nil {
t.Errorf("Failed to make a new Unmounter: %v", err) t.Errorf("Failed to make a new Unmounter: %v", err)
} }
@ -372,7 +373,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
fakeManager := &fakePDManager{} fakeManager := &fakePDManager{}
fakeConfig := &fakeConfig{} fakeConfig := &fakeConfig{}
apiCfg := fakeConfig.GetAPIConfig() 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 { if err != nil {
t.Fatalf("error creating a new internal mounter:%v", err) t.Fatalf("error creating a new internal mounter:%v", err)
} }

View File

@ -23,11 +23,10 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"k8s.io/kubernetes/pkg/util/mount"
storageosapi "github.com/storageos/go-api" storageosapi "github.com/storageos/go-api"
storageostypes "github.com/storageos/go-api/types" storageostypes "github.com/storageos/go-api/types"
"k8s.io/klog" "k8s.io/klog"
utilexec "k8s.io/utils/exec"
) )
const ( 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 // attachFileDevice takes a path to a regular file and makes it available as an
// attached block device. // 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) blockDevicePath, err := getLoopDevice(path, exec)
if err != nil && err.Error() != ErrDeviceNotFound { if err != nil && err.Error() != ErrDeviceNotFound {
return "", err 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. // 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) _, err := os.Stat(path)
if os.IsNotExist(err) { if os.IsNotExist(err) {
return "", errors.New(ErrNotAvailable) return "", errors.New(ErrNotAvailable)
@ -359,7 +358,7 @@ func getLoopDevice(path string, exec mount.Exec) (string, error) {
} }
args := []string{"-j", path} args := []string{"-j", path}
out, err := exec.Run(losetupPath, args...) out, err := exec.Command(losetupPath, args...).CombinedOutput()
if err != nil { if err != nil {
klog.V(2).Infof("Failed device discover command for path %s: %v", path, err) klog.V(2).Infof("Failed device discover command for path %s: %v", path, err)
return "", err return "", err
@ -367,9 +366,9 @@ func getLoopDevice(path string, exec mount.Exec) (string, error) {
return parseLosetupOutputForDevice(out) 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} args := []string{"-f", "-P", "--show", path}
out, err := exec.Run(losetupPath, args...) out, err := exec.Command(losetupPath, args...).CombinedOutput()
if err != nil { if err != nil {
klog.V(2).Infof("Failed device create command for path %s: %v", path, err) klog.V(2).Infof("Failed device create command for path %s: %v", path, err)
return "", err return "", err
@ -377,9 +376,9 @@ func makeLoopDevice(path string, exec mount.Exec) (string, error) {
return parseLosetupOutputForDevice(out) return parseLosetupOutputForDevice(out)
} }
func removeLoopDevice(device string, exec mount.Exec) error { func removeLoopDevice(device string, exec utilexec.Interface) error {
args := []string{"-d", device} args := []string{"-d", device}
out, err := exec.Run(losetupPath, args...) out, err := exec.Command(losetupPath, args...).CombinedOutput()
if err != nil { if err != nil {
if !strings.Contains(string(out), "No such device or address") { if !strings.Contains(string(out), "No such device or address") {
return err 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/client-go/util/testing:go_default_library",
"//staging/src/k8s.io/cloud-provider:go_default_library", "//staging/src/k8s.io/cloud-provider:go_default_library",
"//vendor/github.com/stretchr/testify/mock: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", "//vendor/k8s.io/utils/strings:go_default_library",
], ],
) )

View File

@ -20,7 +20,6 @@ import (
"fmt" "fmt"
"net" "net"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"strings" "strings"
"sync" "sync"
@ -41,6 +40,9 @@ import (
"k8s.io/client-go/tools/record" "k8s.io/client-go/tools/record"
utiltesting "k8s.io/client-go/util/testing" utiltesting "k8s.io/client-go/util/testing"
cloudprovider "k8s.io/cloud-provider" cloudprovider "k8s.io/cloud-provider"
"k8s.io/utils/exec"
"k8s.io/utils/exec/testing"
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/util/mount"
. "k8s.io/kubernetes/pkg/volume" . "k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util"
@ -73,7 +75,7 @@ type fakeVolumeHost struct {
cloud cloudprovider.Interface cloud cloudprovider.Interface
mounter mount.Interface mounter mount.Interface
hostUtil hostutil.HostUtils hostUtil hostutil.HostUtils
exec mount.Exec exec *testingexec.FakeExec
nodeLabels map[string]string nodeLabels map[string]string
nodeName string nodeName string
subpather subpath.Interface subpather subpath.Interface
@ -111,7 +113,7 @@ func newFakeVolumeHost(rootDir string, kubeClient clientset.Interface, plugins [
host := &fakeVolumeHost{rootDir: rootDir, kubeClient: kubeClient, cloud: cloud} host := &fakeVolumeHost{rootDir: rootDir, kubeClient: kubeClient, cloud: cloud}
host.mounter = mount.NewFakeMounter(nil) host.mounter = mount.NewFakeMounter(nil)
host.hostUtil = hostutil.NewFakeHostUtil(pathToTypeMap) host.hostUtil = hostutil.NewFakeHostUtil(pathToTypeMap)
host.exec = mount.NewFakeExec(nil) host.exec = &testingexec.FakeExec{DisableScripts: true}
host.pluginMgr.InitPlugins(plugins, nil /* prober */, host) host.pluginMgr.InitPlugins(plugins, nil /* prober */, host)
host.subpather = &subpath.FakeSubpath{} host.subpather = &subpath.FakeSubpath{}
host.informerFactory = informers.NewSharedInformerFactory(kubeClient, time.Minute) 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 return f.exec
} }
@ -248,6 +250,64 @@ func (f *fakeVolumeHost) GetEventRecorder() record.EventRecorder {
return nil 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 { func ProbeVolumePlugins(config VolumeConfig) []VolumePlugin {
if _, ok := config.OtherAttributes["fake-property"]; ok { if _, ok := config.OtherAttributes["fake-property"]; ok {
return []VolumePlugin{ return []VolumePlugin{
@ -1131,7 +1191,7 @@ func FindEmptyDirectoryUsageOnTmpfs() (*resource.Quantity, error) {
return nil, err return nil, err
} }
defer os.RemoveAll(tmpDir) 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 { if err != nil {
return nil, fmt.Errorf("failed command 'du' on %s with error %v", tmpDir, err) 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:go_default_library",
"//staging/src/k8s.io/component-base/metrics/legacyregistry:go_default_library", "//staging/src/k8s.io/component-base/metrics/legacyregistry:go_default_library",
"//vendor/k8s.io/klog: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", "//vendor/k8s.io/utils/strings:go_default_library",
], ],
) )

View File

@ -36,6 +36,7 @@ import (
utilfeature "k8s.io/apiserver/pkg/util/feature" utilfeature "k8s.io/apiserver/pkg/util/feature"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
"k8s.io/klog" "k8s.io/klog"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
podutil "k8s.io/kubernetes/pkg/api/v1/pod" podutil "k8s.io/kubernetes/pkg/api/v1/pod"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
@ -44,6 +45,7 @@ import (
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/kubernetes/pkg/volume/util/types"
"k8s.io/kubernetes/pkg/volume/util/volumepathhandler" "k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
utilexec "k8s.io/utils/exec"
utilstrings "k8s.io/utils/strings" 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 //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 os is windows, execute Write-VolumeCache powershell command on the disk
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
cmd := fmt.Sprintf("Get-Volume -FilePath %s | Write-Volumecache", deviceMountPath) 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)) klog.Infof("command (%q) execeuted: %v, output: %q", cmd, err, string(output))
if err != nil { if err != nil {
return fmt.Errorf("command (%q) failed: %v, output: %q", cmd, err, string(output)) return fmt.Errorf("command (%q) failed: %v, output: %q", cmd, err, string(output))