Skip to content

Commit

Permalink
Introduce new kubelet volume manager
Browse files Browse the repository at this point in the history
This commit adds a new volume manager in kubelet that synchronizes
volume mount/unmount (and attach/detach, if attach/detach controller
is not enabled).

This eliminates the race conditions between the pod creation loop
and the orphaned volumes loops. It also removes the unmount/detach
from the `syncPod()` path so volume clean up never blocks the
`syncPod` loop.
  • Loading branch information
saad-ali committed Jun 15, 2016
1 parent 9b6a505 commit 542f2dc
Show file tree
Hide file tree
Showing 85 changed files with 5,521 additions and 2,067 deletions.
2 changes: 1 addition & 1 deletion api/swagger-spec/v1.json
Expand Up @@ -16767,7 +16767,7 @@
"items": {
"$ref": "v1.UniqueVolumeName"
},
"description": "List of attachable volume devices in use (mounted) by the node."
"description": "List of attachable volumes in use (mounted) by the node."
}
}
},
Expand Down
12 changes: 7 additions & 5 deletions docs/api-reference/v1/definitions.html
Expand Up @@ -2766,6 +2766,10 @@ <h3 id="_v1_persistentvolumeclaimstatus">v1.PersistentVolumeClaimStatus</h3>
</tbody>
</table>

</div>
<div class="sect2">
<h3 id="_v1_uniquevolumename">v1.UniqueVolumeName</h3>

</div>
<div class="sect2">
<h3 id="_unversioned_labelselector">unversioned.LabelSelector</h3>
Expand Down Expand Up @@ -2806,9 +2810,7 @@ <h3 id="_unversioned_labelselector">unversioned.LabelSelector</h3>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_uniquevolumename">v1.UniqueVolumeName</h3>

</div>
<div class="sect2">
<h3 id="_v1_endpointsubset">v1.EndpointSubset</h3>
Expand Down Expand Up @@ -4755,7 +4757,7 @@ <h3 id="_v1_nodestatus">v1.NodeStatus</h3>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">volumesInUse</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">List of attachable volume devices in use (mounted) by the node.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">List of attachable volumes in use (mounted) by the node.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_uniquevolumename">v1.UniqueVolumeName</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
Expand Down Expand Up @@ -8103,7 +8105,7 @@ <h3 id="_any">any</h3>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2016-06-06 17:05:06 UTC
Last updated 2016-06-08 04:10:38 UTC
</div>
</div>
</body>
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/v1/generated.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/api/v1/types.go
Expand Up @@ -2386,7 +2386,7 @@ type NodeStatus struct {
NodeInfo NodeSystemInfo `json:"nodeInfo,omitempty" protobuf:"bytes,7,opt,name=nodeInfo"`
// List of container images on this node
Images []ContainerImage `json:"images,omitempty" protobuf:"bytes,8,rep,name=images"`
// List of attachable volume devices in use (mounted) by the node.
// List of attachable volumes in use (mounted) by the node.
VolumesInUse []UniqueVolumeName `json:"volumesInUse,omitempty" protobuf:"bytes,9,rep,name=volumesInUse"`
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/api/v1/types_swagger_doc_generated.go
Expand Up @@ -880,7 +880,7 @@ var map_NodeStatus = map[string]string{
"daemonEndpoints": "Endpoints of daemons running on the Node.",
"nodeInfo": "Set of ids/uuids to uniquely identify the node. More info: http://releases.k8s.io/HEAD/docs/admin/node.md#node-info",
"images": "List of container images on this node",
"volumesInUse": "List of attachable volume devices in use (mounted) by the node.",
"volumesInUse": "List of attachable volumes in use (mounted) by the node.",
}

func (NodeStatus) SwaggerDoc() map[string]string {
Expand Down
10 changes: 9 additions & 1 deletion pkg/controller/persistentvolume/framework_test.go
Expand Up @@ -980,14 +980,22 @@ func (plugin *mockVolumePlugin) Init(host vol.VolumeHost) error {
return nil
}

func (plugin *mockVolumePlugin) Name() string {
func (plugin *mockVolumePlugin) GetPluginName() string {
return mockPluginName
}

func (plugin *mockVolumePlugin) GetVolumeName(spec *vol.Spec) (string, error) {
return spec.Name(), nil
}

func (plugin *mockVolumePlugin) CanSupport(spec *vol.Spec) bool {
return true
}

func (plugin *mockVolumePlugin) RequiresRemount() bool {
return false
}

func (plugin *mockVolumePlugin) NewMounter(spec *vol.Spec, podRef *api.Pod, opts vol.VolumeOptions) (vol.Mounter, error) {
return nil, fmt.Errorf("Mounter is not supported by this plugin")
}
Expand Down
9 changes: 9 additions & 0 deletions pkg/controller/persistentvolume/volume_host.go
Expand Up @@ -18,6 +18,7 @@ package persistentvolume

import (
"fmt"
"net"

"k8s.io/kubernetes/pkg/api"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
Expand Down Expand Up @@ -71,3 +72,11 @@ func (ctrl *PersistentVolumeController) GetWriter() io.Writer {
func (ctrl *PersistentVolumeController) GetHostName() string {
return ""
}

func (ctrl *PersistentVolumeController) GetHostIP() (net.IP, error) {
return nil, fmt.Errorf("PersistentVolumeController.GetHostIP() is not implemented")
}

func (ctrl *PersistentVolumeController) GetRootContext() string {
return ""
}
29 changes: 17 additions & 12 deletions pkg/controller/volume/attach_detach_controller.go
Expand Up @@ -20,26 +20,27 @@ package volume

import (
"fmt"
"net"
"time"

"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/cloudprovider"
"k8s.io/kubernetes/pkg/controller/framework"
"k8s.io/kubernetes/pkg/controller/volume/attacherdetacher"
"k8s.io/kubernetes/pkg/controller/volume/cache"
"k8s.io/kubernetes/pkg/controller/volume/reconciler"
"k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util/io"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/util/runtime"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util/operationexecutor"
"k8s.io/kubernetes/pkg/volume/util/volumehelper"
)

const (
// loopPeriod is the ammount of time the reconciler loop waits between
// loopPeriod is the amount of time the reconciler loop waits between
// successive executions
reconcilerLoopPeriod time.Duration = 100 * time.Millisecond

Expand Down Expand Up @@ -103,7 +104,8 @@ func NewAttachDetachController(

adc.desiredStateOfWorld = cache.NewDesiredStateOfWorld(&adc.volumePluginMgr)
adc.actualStateOfWorld = cache.NewActualStateOfWorld(&adc.volumePluginMgr)
adc.attacherDetacher = attacherdetacher.NewAttacherDetacher(&adc.volumePluginMgr)
adc.attacherDetacher =
operationexecutor.NewOperationExecutor(&adc.volumePluginMgr)
adc.reconciler = reconciler.NewReconciler(
reconcilerLoopPeriod,
reconcilerMaxWaitForUnmountDuration,
Expand Down Expand Up @@ -152,7 +154,7 @@ type attachDetachController struct {
actualStateOfWorld cache.ActualStateOfWorld

// attacherDetacher is used to start asynchronous attach and operations
attacherDetacher attacherdetacher.AttacherDetacher
attacherDetacher operationexecutor.OperationExecutor

// reconciler is used to run an asynchronous periodic loop to reconcile the
// desiredStateOfWorld with the actualStateOfWorld by triggering attach
Expand Down Expand Up @@ -205,7 +207,7 @@ func (adc *attachDetachController) nodeAdd(obj interface{}) {
}

nodeName := node.Name
if _, exists := node.Annotations[volumehelper.ControllerManagedAnnotation]; exists {
if _, exists := node.Annotations[volumehelper.ControllerManagedAttachAnnotation]; exists {
// Node specifies annotation indicating it should be managed by attach
// detach controller. Add it to desired state of world.
adc.desiredStateOfWorld.AddNode(nodeName)
Expand Down Expand Up @@ -284,7 +286,7 @@ func (adc *attachDetachController) processPodVolumes(
continue
}

uniquePodName := getUniquePodName(pod)
uniquePodName := volumehelper.GetUniquePodName(pod)
if addVolumes {
// Add volume to desired state of world
_, err := adc.desiredStateOfWorld.AddPod(
Expand All @@ -304,7 +306,7 @@ func (adc *attachDetachController) processPodVolumes(
attachableVolumePlugin, volumeSpec)
if err != nil {
glog.V(10).Infof(
"Failed to delete volume %q for pod %q/%q from desiredStateOfWorld. GenerateUniqueVolumeName failed with %v",
"Failed to delete volume %q for pod %q/%q from desiredStateOfWorld. GetUniqueVolumeNameFromSpec failed with %v",
podVolume.Name,
pod.Namespace,
pod.Name,
Expand Down Expand Up @@ -502,11 +504,6 @@ func (adc *attachDetachController) processVolumesInUse(
}
}

// getUniquePodName returns a unique name to reference pod by in memory caches
func getUniquePodName(pod *api.Pod) types.UniquePodName {
return types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}.UniquePodName()
}

// VolumeHost implementation
// This is an unfortunate requirement of the current factoring of volume plugin
// initializing code. It requires kubelet specific methods used by the mounting
Expand Down Expand Up @@ -552,3 +549,11 @@ func (adc *attachDetachController) GetWriter() io.Writer {
func (adc *attachDetachController) GetHostName() string {
return ""
}

func (adc *attachDetachController) GetHostIP() (net.IP, error) {
return nil, fmt.Errorf("GetHostIP() not supported by Attach/Detach controller's VolumeHost implementation")
}

func (adc *attachDetachController) GetRootContext() string {
return ""
}

0 comments on commit 542f2dc

Please sign in to comment.