Add Exec interface to VolumeHost

This exec should be used by volume plugins to execute mount utilities.
It will eventually execute things in mount containers.
pull/6/head
Jan Safranek 2017-08-14 12:16:25 +02:00
parent 4193357272
commit 282404cbc9
8 changed files with 82 additions and 0 deletions

View File

@ -571,6 +571,10 @@ func (adc *attachDetachController) GetConfigMapFunc() func(namespace, name strin
} }
} }
func (adc *attachDetachController) GetExec(pluginName string) mount.Exec {
return mount.NewOsExec()
}
func (adc *attachDetachController) addNodeToDswp(node *v1.Node, nodeName types.NodeName) { func (adc *attachDetachController) addNodeToDswp(node *v1.Node, nodeName types.NodeName) {
if _, exists := node.Annotations[volumehelper.ControllerManagedAttachAnnotation]; exists { if _, exists := node.Annotations[volumehelper.ControllerManagedAttachAnnotation]; exists {
keepTerminatedPodVolumes := false keepTerminatedPodVolumes := false

View File

@ -93,6 +93,10 @@ func (adc *PersistentVolumeController) GetConfigMapFunc() func(namespace, name s
} }
} }
func (adc *PersistentVolumeController) GetExec(pluginName string) mount.Exec {
return mount.NewOsExec()
}
func (ctrl *PersistentVolumeController) GetNodeLabels() (map[string]string, error) { func (ctrl *PersistentVolumeController) GetNodeLabels() (map[string]string, error) {
return nil, fmt.Errorf("GetNodeLabels() unsupported in PersistentVolumeController") return nil, fmt.Errorf("GetNodeLabels() unsupported in PersistentVolumeController")
} }

View File

@ -156,3 +156,7 @@ func (kvh *kubeletVolumeHost) GetNodeLabels() (map[string]string, error) {
} }
return node.Labels, nil return node.Labels, nil
} }
func (kvh *kubeletVolumeHost) GetExec(pluginName string) mount.Exec {
return mount.NewOsExec()
}

View File

@ -10,6 +10,7 @@ go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"doc.go", "doc.go",
"exec.go",
"fake.go", "fake.go",
"mount.go", "mount.go",
"mount_unsupported.go", "mount_unsupported.go",

50
pkg/util/mount/exec.go Normal file
View File

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

View File

@ -70,6 +70,16 @@ type Interface interface {
GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error)
} }
// Exec executes command where mount utilities are. This can be either the host,
// container where kubelet runs or even a remote pod with mount utilities.
// Usual pkg/util/exec interface is not used because kubelet.RunInContainer does
// not provide stdin/stdout/stderr streams.
type Exec interface {
// Run executes a command and returns its stdout + stderr combined in one
// stream.
Run(cmd string, args ...string) ([]byte, error)
}
// Compile-time check to ensure all Mounter implementations satisfy // Compile-time check to ensure all Mounter implementations satisfy
// the mount interface // the mount interface
var _ Interface = &Mounter{} var _ Interface = &Mounter{}

View File

@ -244,6 +244,9 @@ type VolumeHost interface {
// Returns a function that returns a configmap. // Returns a function that returns a configmap.
GetConfigMapFunc() func(namespace, name string) (*v1.ConfigMap, error) GetConfigMapFunc() func(namespace, name string) (*v1.ConfigMap, error)
// Returns an interface that should be used to execute any utilities in volume plugins
GetExec(pluginName string) mount.Exec
// Returns the labels on the node // Returns the labels on the node
GetNodeLabels() (map[string]string, error) GetNodeLabels() (map[string]string, error)
} }

View File

@ -49,6 +49,7 @@ type fakeVolumeHost struct {
pluginMgr VolumePluginMgr pluginMgr VolumePluginMgr
cloud cloudprovider.Interface cloud cloudprovider.Interface
mounter mount.Interface mounter mount.Interface
exec mount.Exec
writer io.Writer writer io.Writer
} }
@ -64,6 +65,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.FakeMounter{} host.mounter = &mount.FakeMounter{}
host.writer = &io.StdWriter{} host.writer = &io.StdWriter{}
host.exec = mount.NewFakeExec(nil)
host.pluginMgr.InitPlugins(plugins, host) host.pluginMgr.InitPlugins(plugins, host)
return host return host
} }
@ -142,6 +144,10 @@ func (f *fakeVolumeHost) GetSecretFunc() func(namespace, name string) (*v1.Secre
} }
} }
func (f *fakeVolumeHost) GetExec(pluginName string) mount.Exec {
return f.exec
}
func (f *fakeVolumeHost) GetConfigMapFunc() func(namespace, name string) (*v1.ConfigMap, error) { func (f *fakeVolumeHost) GetConfigMapFunc() func(namespace, name string) (*v1.ConfigMap, error) {
return func(namespace, name string) (*v1.ConfigMap, error) { return func(namespace, name string) (*v1.ConfigMap, error) {
return f.kubeClient.Core().ConfigMaps(namespace).Get(name, metav1.GetOptions{}) return f.kubeClient.Core().ConfigMaps(namespace).Get(name, metav1.GetOptions{})