-
Notifications
You must be signed in to change notification settings - Fork 38.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Attacher/Detacher interfaces and support to kubelet #19503
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -111,23 +111,6 @@ func (vh *volumeHost) GetHostName() string { | |
return vh.kubelet.hostname | ||
} | ||
|
||
func (kl *Kubelet) newVolumeBuilderFromPlugins(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) { | ||
plugin, err := kl.volumePluginMgr.FindPluginBySpec(spec) | ||
if err != nil { | ||
return nil, fmt.Errorf("can't use volume plugins for %s: %v", spec.Name(), err) | ||
} | ||
if plugin == nil { | ||
// Not found but not an error | ||
return nil, nil | ||
} | ||
builder, err := plugin.NewBuilder(spec, pod, opts) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to instantiate volume plugin for %s: %v", spec.Name(), err) | ||
} | ||
glog.V(3).Infof("Used volume plugin %q for %s", plugin.Name(), spec.Name()) | ||
return builder, nil | ||
} | ||
|
||
func (kl *Kubelet) mountExternalVolumes(pod *api.Pod) (kubecontainer.VolumeMap, error) { | ||
podVolumes := make(kubecontainer.VolumeMap) | ||
for i := range pod.Spec.Volumes { | ||
|
@@ -152,6 +135,22 @@ func (kl *Kubelet) mountExternalVolumes(pod *api.Pod) (kubecontainer.VolumeMap, | |
if builder == nil { | ||
return nil, errUnsupportedVolumeType | ||
} | ||
|
||
// some volumes require attachment before builder's setup. | ||
// The plugin can be nil, but non-nil errors are legitimate errors. | ||
// For non-nil plugins, Attachment to a node is required before Builder's setup. | ||
attacher, err := kl.newVolumeAttacherFromPlugins(internal, pod, volume.VolumeOptions{RootContext: rootContext}) | ||
if err != nil { | ||
glog.Errorf("Could not create volume attacher for pod %s: %v", pod.UID, err) | ||
return nil, err | ||
} | ||
if attacher != nil { | ||
err = attacher.Attach() | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
err = builder.SetUp(fsGroup) | ||
if err != nil { | ||
return nil, err | ||
|
@@ -206,14 +205,22 @@ func (kl *Kubelet) getPodVolumes(podUID types.UID) ([]*volumeTuple, error) { | |
return volumes, nil | ||
} | ||
|
||
// cleanerTuple is a union struct to allow separating detaching from the cleaner. | ||
// some volumes require detachment but not all. Cleaner cannot be nil but Detacher is optional. | ||
type cleanerTuple struct { | ||
Cleaner volume.Cleaner | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if "tuple" is the right noun for this object. For clarity, how about calling this struct just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's rename Builder to Mounter and Cleaner to Unmounter to everywhere. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There's |
||
Detacher *volume.Detacher | ||
} | ||
|
||
// getPodVolumesFromDisk examines directory structure to determine volumes that | ||
// are presently active and mounted. Returns a map of volume.Cleaner types. | ||
func (kl *Kubelet) getPodVolumesFromDisk() map[string]volume.Cleaner { | ||
currentVolumes := make(map[string]volume.Cleaner) | ||
// are presently active and mounted. Returns a union struct containing a volume.Cleaner | ||
// and potentially a volume.Detacher. | ||
func (kl *Kubelet) getPodVolumesFromDisk() map[string]cleanerTuple { | ||
currentVolumes := make(map[string]cleanerTuple) | ||
podUIDs, err := kl.listPodsFromDisk() | ||
if err != nil { | ||
glog.Errorf("Could not get pods from disk: %v", err) | ||
return map[string]volume.Cleaner{} | ||
return map[string]cleanerTuple{} | ||
} | ||
// Find the volumes for each on-disk pod. | ||
for _, podUID := range podUIDs { | ||
|
@@ -239,12 +246,58 @@ func (kl *Kubelet) getPodVolumesFromDisk() map[string]volume.Cleaner { | |
glog.Errorf("Could not create volume cleaner for %s: %v", volume.Name, errUnsupportedVolumeType) | ||
continue | ||
} | ||
currentVolumes[identifier] = cleaner | ||
|
||
tuple := cleanerTuple{Cleaner: cleaner} | ||
detacher, err := kl.newVolumeDetacherFromPlugins(volume.Kind, volume.Name, podUID) | ||
// plugin can be nil but a non-nil error is a legitimate error | ||
if err != nil { | ||
glog.Errorf("Could not create volume detacher for %s: %v", volume.Name, err) | ||
continue | ||
} | ||
if detacher != nil { | ||
tuple.Detacher = &detacher | ||
} | ||
currentVolumes[identifier] = tuple | ||
} | ||
} | ||
return currentVolumes | ||
} | ||
|
||
func (kl *Kubelet) newVolumeBuilderFromPlugins(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) { | ||
plugin, err := kl.volumePluginMgr.FindPluginBySpec(spec) | ||
if err != nil { | ||
return nil, fmt.Errorf("can't use volume plugins for %s: %v", spec.Name(), err) | ||
} | ||
if plugin == nil { | ||
// Not found but not an error | ||
return nil, nil | ||
} | ||
builder, err := plugin.NewBuilder(spec, pod, opts) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to instantiate volume builder for %s: %v", spec.Name(), err) | ||
} | ||
glog.V(3).Infof("Used volume plugin %q to mount %s", plugin.Name(), spec.Name()) | ||
return builder, nil | ||
} | ||
|
||
func (kl *Kubelet) newVolumeAttacherFromPlugins(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Attacher, error) { | ||
plugin, err := kl.volumePluginMgr.FindAttachablePluginBySpec(spec) | ||
if err != nil { | ||
return nil, fmt.Errorf("can't use volume plugins for %s: %v", spec.Name(), err) | ||
} | ||
if plugin == nil { | ||
// Not found but not an error. | ||
return nil, nil | ||
} | ||
|
||
attacher, err := plugin.NewAttacher(spec) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to instantiate volume attacher for %s: %v", spec.Name(), err) | ||
} | ||
glog.V(3).Infof("Used volume plugin %q to attach %s/%s", plugin.Name(), spec.Name()) | ||
return attacher, nil | ||
} | ||
|
||
func (kl *Kubelet) newVolumeCleanerFromPlugins(kind string, name string, podUID types.UID) (volume.Cleaner, error) { | ||
plugName := strings.UnescapeQualifiedNameForDisk(kind) | ||
plugin, err := kl.volumePluginMgr.FindPluginByName(plugName) | ||
|
@@ -260,6 +313,25 @@ func (kl *Kubelet) newVolumeCleanerFromPlugins(kind string, name string, podUID | |
if err != nil { | ||
return nil, fmt.Errorf("failed to instantiate volume plugin for %s/%s: %v", podUID, kind, err) | ||
} | ||
glog.V(3).Infof("Used volume plugin %q for %s/%s", plugin.Name(), podUID, kind) | ||
glog.V(3).Infof("Used volume plugin %q to unmount %s/%s", plugin.Name(), podUID, kind) | ||
return cleaner, nil | ||
} | ||
|
||
func (kl *Kubelet) newVolumeDetacherFromPlugins(kind string, name string, podUID types.UID) (volume.Detacher, error) { | ||
plugName := strings.UnescapeQualifiedNameForDisk(kind) | ||
plugin, err := kl.volumePluginMgr.FindAttachablePluginByName(plugName) | ||
if err != nil { | ||
return nil, fmt.Errorf("can't use volume plugins for %s/%s: %v", podUID, kind, err) | ||
} | ||
if plugin == nil { | ||
// Not found but not an error. | ||
return nil, nil | ||
} | ||
|
||
detacher, err := plugin.NewDetacher(name, podUID) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to instantiate volume plugin for %s/%s: %v", podUID, kind, err) | ||
} | ||
glog.V(3).Infof("Used volume plugin %q to detach %s/%s", plugin.Name(), podUID, kind) | ||
return detacher, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -117,7 +117,7 @@ type Provisioner interface { | |
NewPersistentVolumeTemplate() (*api.PersistentVolume, error) | ||
} | ||
|
||
// Delete removes the resource from the underlying storage provider. Calls to this method should block until | ||
// Deleter removes the resource from the underlying storage provider. Calls to this method should block until | ||
// the deletion is complete. Any error returned indicates the volume has failed to be reclaimed. | ||
// A nil return indicates success. | ||
type Deleter interface { | ||
|
@@ -126,6 +126,17 @@ type Deleter interface { | |
Delete() error | ||
} | ||
|
||
// Attacher can attach a volume to a node. | ||
type Attacher interface { | ||
Volume | ||
Attach() error | ||
} | ||
|
||
// Detacher can detach a volume from a node. | ||
type Detacher interface { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this need to inline There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably? I'm not sure either really needs to inline Does any other volume interface that's not Builder/Cleaner (soon to be Mounter/Unmounter) need |
||
Detach() error | ||
} | ||
|
||
func RenameDirectory(oldPath, newName string) (string, error) { | ||
newPath, err := ioutil.TempDir(path.Dir(oldPath), newName) | ||
if err != nil { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor nit: why not move this block to after
internal
is declared, so builder declaration is near the call to setup.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any benefit to knowing you have a builder (for mounting) before an attempt to attach is made? Error handling would prevent an attachment for a non-existent builder.