func (dsw *desiredStateOfWorld) AddPod( podName string, volumeSpec *volume.Spec, nodeName string) (api.UniqueDeviceName, error) { dsw.Lock() defer dsw.Unlock() nodeObj, nodeExists := dsw.nodesManaged[nodeName] if !nodeExists { return "", fmt.Errorf( "no node with the name %q exists in the list of managed nodes", nodeName) } attachableVolumePlugin, err := dsw.volumePluginMgr.FindAttachablePluginBySpec(volumeSpec) if err != nil || attachableVolumePlugin == nil { return "", fmt.Errorf( "failed to get AttachablePlugin from volumeSpec for volume %q err=%v", volumeSpec.Name(), err) } volumeName, err := attachdetach.GetUniqueDeviceNameFromSpec( attachableVolumePlugin, volumeSpec) if err != nil { return "", fmt.Errorf( "failed to GenerateUniqueDeviceName for volumeSpec %q err=%v", volumeSpec.Name(), err) } volumeObj, volumeExists := nodeObj.volumesToAttach[volumeName] if !volumeExists { volumeObj = volumeToAttach{ volumeName: volumeName, spec: volumeSpec, scheduledPods: make(map[string]pod), } dsw.nodesManaged[nodeName].volumesToAttach[volumeName] = volumeObj } if _, podExists := volumeObj.scheduledPods[podName]; !podExists { dsw.nodesManaged[nodeName].volumesToAttach[volumeName].scheduledPods[podName] = pod{ podName: podName, } } return volumeName, nil }
func (asw *actualStateOfWorld) AddVolumeNode( volumeSpec *volume.Spec, nodeName string) (api.UniqueDeviceName, error) { asw.Lock() defer asw.Unlock() attachableVolumePlugin, err := asw.volumePluginMgr.FindAttachablePluginBySpec(volumeSpec) if err != nil || attachableVolumePlugin == nil { return "", fmt.Errorf( "failed to get AttachablePlugin from volumeSpec for volume %q err=%v", volumeSpec.Name(), err) } volumeName, err := attachdetach.GetUniqueDeviceNameFromSpec( attachableVolumePlugin, volumeSpec) if err != nil { return "", fmt.Errorf( "failed to GetUniqueDeviceNameFromSpec for volumeSpec %q err=%v", volumeSpec.Name(), err) } volumeObj, volumeExists := asw.attachedVolumes[volumeName] if !volumeExists { volumeObj = attachedVolume{ volumeName: volumeName, spec: volumeSpec, nodesAttachedTo: make(map[string]nodeAttachedTo), } asw.attachedVolumes[volumeName] = volumeObj } nodeObj, nodeExists := volumeObj.nodesAttachedTo[nodeName] if !nodeExists { // Create object if it doesn't exist. volumeObj.nodesAttachedTo[nodeName] = nodeAttachedTo{ nodeName: nodeName, mountedByNode: true, // Assume mounted, until proven otherwise mountedByNodeSetCount: 0, detachRequestedTime: time.Time{}, } } else if !nodeObj.detachRequestedTime.IsZero() { // Reset detachRequestedTime values if object exists and time is non-zero nodeObj.detachRequestedTime = time.Time{} volumeObj.nodesAttachedTo[nodeName] = nodeObj } return volumeName, nil }
// processPodVolumes processes the volumes in the given pod and adds them to the // desired state of the world if addVolumes is true, otherwise it removes them. func (adc *attachDetachController) processPodVolumes( pod *api.Pod, addVolumes bool) { if pod == nil { return } if len(pod.Spec.Volumes) <= 0 { return } if !adc.desiredStateOfWorld.NodeExists(pod.Spec.NodeName) { // If the node the pod is scheduled to does not exist in the desired // state of the world data structure, that indicates the node is not // yet managed by the controller. Therefore, ignore the pod. // If the node is added to the list of managed nodes in the future, // future adds and updates to the pod will be processed. glog.V(10).Infof( "Skipping processing of pod %q/%q: it is scheduled to node %q which is not managed by the controller.", pod.Namespace, pod.Name, pod.Spec.NodeName) return } // Process volume spec for each volume defined in pod for _, podVolume := range pod.Spec.Volumes { volumeSpec, err := adc.createVolumeSpec(podVolume, pod.Namespace) if err != nil { glog.V(10).Infof( "Error processing volume %q for pod %q/%q: %v", podVolume.Name, pod.Namespace, pod.Name, err) continue } attachableVolumePlugin, err := adc.volumePluginMgr.FindAttachablePluginBySpec(volumeSpec) if err != nil || attachableVolumePlugin == nil { glog.V(10).Infof( "Skipping volume %q for pod %q/%q: it does not implement attacher interface. err=%v", podVolume.Name, pod.Namespace, pod.Name, err) continue } if addVolumes { // Add volume to desired state of world _, err := adc.desiredStateOfWorld.AddPod( getUniquePodName(pod), volumeSpec, pod.Spec.NodeName) if err != nil { glog.V(10).Infof( "Failed to add volume %q for pod %q/%q to desiredStateOfWorld. %v", podVolume.Name, pod.Namespace, pod.Name, err) } } else { // Remove volume from desired state of world uniqueVolumeName, err := attachdetach.GetUniqueDeviceNameFromSpec( attachableVolumePlugin, volumeSpec) if err != nil { glog.V(10).Infof( "Failed to delete volume %q for pod %q/%q from desiredStateOfWorld. GenerateUniqueDeviceName failed with %v", podVolume.Name, pod.Namespace, pod.Name, err) continue } adc.desiredStateOfWorld.DeletePod( getUniquePodName(pod), uniqueVolumeName, pod.Spec.NodeName) } } return }
// mountExternalVolumes mounts the volumes declared in a pod, attaching them // to the host if necessary, and returns a map containing information about // the volumes for the pod or an error. This method is run multiple times, // and requires that implementations of Attach() and SetUp() be idempotent. // // Note, in the future, the attach-detach controller will handle attaching and // detaching volumes; this call site will be maintained for backward- // compatibility with current behavior of static pods and pods created via the // Kubelet's http API. func (kl *Kubelet) mountExternalVolumes(pod *api.Pod) (kubecontainer.VolumeMap, error) { podVolumes := make(kubecontainer.VolumeMap) for i := range pod.Spec.Volumes { var fsGroup *int64 if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.FSGroup != nil { fsGroup = pod.Spec.SecurityContext.FSGroup } rootContext, err := kl.getRootDirContext() if err != nil { return nil, err } var volSpec *volume.Spec if pod.Spec.Volumes[i].VolumeSource.PersistentVolumeClaim != nil { claimName := pod.Spec.Volumes[i].PersistentVolumeClaim.ClaimName pv, err := kl.getPersistentVolumeByClaimName(claimName, pod.Namespace) if err != nil { glog.Errorf("Could not find persistentVolume for claim %s err %v", claimName, err) return nil, err } kl.applyPersistentVolumeAnnotations(pv, pod) volSpec = volume.NewSpecFromPersistentVolume(pv, pod.Spec.Volumes[i].PersistentVolumeClaim.ReadOnly) } else { volSpec = volume.NewSpecFromVolume(&pod.Spec.Volumes[i]) } // Try to use a plugin for this volume. mounter, err := kl.newVolumeMounterFromPlugins(volSpec, pod, volume.VolumeOptions{RootContext: rootContext}) if err != nil { glog.Errorf("Could not create volume mounter for pod %s: %v", pod.UID, err) return nil, err } // some volumes require attachment before mounter'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 Mounter's setup. attacher, attachablePlugin, err := kl.newVolumeAttacherFromPlugins(volSpec, pod) if err != nil { glog.Errorf("Could not create volume attacher for pod %s: %v", pod.UID, err) return nil, err } if attacher != nil { // If the device path is already mounted, avoid an expensive call to the // cloud provider. deviceMountPath := attacher.GetDeviceMountPath(volSpec) notMountPoint, err := kl.mounter.IsLikelyNotMountPoint(deviceMountPath) if err != nil && !os.IsNotExist(err) { return nil, err } if notMountPoint { if !kl.enableControllerAttachDetach { err = attacher.Attach(volSpec, kl.hostname) if err != nil { return nil, err } } devicePath, err := attacher.WaitForAttach(volSpec, maxWaitForVolumeOps) if err != nil { return nil, err } if kl.enableControllerAttachDetach { // Attach/Detach controller is enabled and this volume type // implements an attacher uniqueDeviceName, err := attachdetach.GetUniqueDeviceNameFromSpec( attachablePlugin, volSpec) if err != nil { return nil, err } kl.volumeManager.AddVolumeInUse( api.UniqueDeviceName(uniqueDeviceName)) } if err = attacher.MountDevice(volSpec, devicePath, deviceMountPath, kl.mounter); err != nil { return nil, err } } } err = mounter.SetUp(fsGroup) if err != nil { return nil, err } podVolumes[pod.Spec.Volumes[i].Name] = kubecontainer.VolumeInfo{Mounter: mounter} } return podVolumes, nil }