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
}
Example #4
0
// 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
}