func (plugin *awsElasticBlockStorePlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager ebsManager, mounter mount.Interface) (volume.Mounter, error) { // EBSs used directly in a pod have a ReadOnly flag set by the pod author. // EBSs used as a PersistentVolume gets the ReadOnly flag indirectly through the persistent-claim volume used to mount the PV ebs, readOnly, err := getVolumeSource(spec) if err != nil { return nil, err } volumeID := aws.KubernetesVolumeID(ebs.VolumeID) fsType := ebs.FSType partition := "" if ebs.Partition != 0 { partition = strconv.Itoa(int(ebs.Partition)) } return &awsElasticBlockStoreMounter{ awsElasticBlockStore: &awsElasticBlockStore{ podUID: podUID, volName: spec.Name(), volumeID: volumeID, partition: partition, manager: manager, mounter: mounter, plugin: plugin, MetricsProvider: volume.NewMetricsStatFS(getPath(podUID, spec.Name(), plugin.host)), }, fsType: fsType, readOnly: readOnly, diskMounter: &mount.SafeFormatAndMount{Interface: plugin.host.GetMounter(), Runner: exec.New()}}, nil }
func (attacher *awsElasticBlockStoreAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.NodeName) (map[*volume.Spec]bool, error) { volumesAttachedCheck := make(map[*volume.Spec]bool) volumeSpecMap := make(map[aws.KubernetesVolumeID]*volume.Spec) volumeIDList := []aws.KubernetesVolumeID{} for _, spec := range specs { volumeSource, _, err := getVolumeSource(spec) if err != nil { glog.Errorf("Error getting volume (%q) source : %v", spec.Name(), err) continue } name := aws.KubernetesVolumeID(volumeSource.VolumeID) volumeIDList = append(volumeIDList, name) volumesAttachedCheck[spec] = true volumeSpecMap[name] = spec } attachedResult, err := attacher.awsVolumes.DisksAreAttached(volumeIDList, nodeName) if err != nil { // Log error and continue with attach glog.Errorf( "Error checking if volumes (%v) is already attached to current node (%q). err=%v", volumeIDList, nodeName, err) return volumesAttachedCheck, err } for volumeID, attached := range attachedResult { if !attached { spec := volumeSpecMap[volumeID] volumesAttachedCheck[spec] = false glog.V(2).Infof("VolumesAreAttached: check volume %q (specName: %q) is no longer attached", volumeID, spec.Name()) } } return volumesAttachedCheck, nil }
func (attacher *awsElasticBlockStoreAttacher) GetDeviceMountPath( spec *volume.Spec) (string, error) { volumeSource, _, err := getVolumeSource(spec) if err != nil { return "", err } return makeGlobalPDPath(attacher.host, aws.KubernetesVolumeID(volumeSource.VolumeID)), nil }
func (plugin *awsElasticBlockStorePlugin) newDeleterInternal(spec *volume.Spec, manager ebsManager) (volume.Deleter, error) { if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.AWSElasticBlockStore == nil { glog.Errorf("spec.PersistentVolumeSource.AWSElasticBlockStore is nil") return nil, fmt.Errorf("spec.PersistentVolumeSource.AWSElasticBlockStore is nil") } return &awsElasticBlockStoreDeleter{ awsElasticBlockStore: &awsElasticBlockStore{ volName: spec.Name(), volumeID: aws.KubernetesVolumeID(spec.PersistentVolume.Spec.AWSElasticBlockStore.VolumeID), manager: manager, plugin: plugin, }}, nil }
func TestGetVolumeName_PersistentVolume(t *testing.T) { plugin := newPlugin() name := aws.KubernetesVolumeID("my-aws-pv") spec := createPVSpec(name, true) volumeName, err := plugin.GetVolumeName(spec) if err != nil { t.Errorf("GetVolumeName error: %v", err) } if volumeName != string(name) { t.Errorf("GetVolumeName error: expected %s, got %s", name, volumeName) } }
func (attacher *awsElasticBlockStoreAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string, error) { volumeSource, readOnly, err := getVolumeSource(spec) if err != nil { return "", err } volumeID := aws.KubernetesVolumeID(volumeSource.VolumeID) // awsCloud.AttachDisk checks if disk is already attached to node and // succeeds in that case, so no need to do that separately. devicePath, err := attacher.awsVolumes.AttachDisk(volumeID, nodeName, readOnly) if err != nil { glog.Errorf("Error attaching volume %q: %+v", volumeID, err) return "", err } return devicePath, nil }
func (detacher *awsElasticBlockStoreDetacher) Detach(deviceMountPath string, nodeName types.NodeName) error { volumeID := aws.KubernetesVolumeID(path.Base(deviceMountPath)) attached, err := detacher.awsVolumes.DiskIsAttached(volumeID, nodeName) if err != nil { // Log error and continue with detach glog.Errorf( "Error checking if volume (%q) is already attached to current node (%q). Will continue and try detach anyway. err=%v", volumeID, nodeName, err) } if err == nil && !attached { // Volume is already detached from node. glog.Infof("detach operation was successful. volume %q is already detached from node %q.", volumeID, nodeName) return nil } if _, err = detacher.awsVolumes.DetachDisk(volumeID, nodeName); err != nil { glog.Errorf("Error detaching volumeID %q: %v", volumeID, err) return err } return nil }
func (l *persistentVolumeLabel) findAWSEBSLabels(volume *api.PersistentVolume) (map[string]string, error) { // Ignore any volumes that are being provisioned if volume.Spec.AWSElasticBlockStore.VolumeID == vol.ProvisionedVolumeName { return nil, nil } ebsVolumes, err := l.getEBSVolumes() if err != nil { return nil, err } if ebsVolumes == nil { return nil, fmt.Errorf("unable to build AWS cloud provider for EBS") } // TODO: GetVolumeLabels is actually a method on the Volumes interface // If that gets standardized we can refactor to reduce code duplication spec := aws.KubernetesVolumeID(volume.Spec.AWSElasticBlockStore.VolumeID) labels, err := ebsVolumes.GetVolumeLabels(spec) if err != nil { return nil, err } return labels, err }
func TestAttachDetach(t *testing.T) { diskName := aws.KubernetesVolumeID("disk") nodeName := types.NodeName("instance") readOnly := false spec := createVolSpec(diskName, readOnly) attachError := errors.New("Fake attach error") detachError := errors.New("Fake detach error") diskCheckError := errors.New("Fake DiskIsAttached error") tests := []testcase{ // Successful Attach call { name: "Attach_Positive", attach: attachCall{diskName, nodeName, readOnly, "/dev/sda", nil}, test: func(testcase *testcase) (string, error) { attacher := newAttacher(testcase) return attacher.Attach(spec, nodeName) }, expectedDevice: "/dev/sda", }, // Attach call fails { name: "Attach_Negative", attach: attachCall{diskName, nodeName, readOnly, "", attachError}, test: func(testcase *testcase) (string, error) { attacher := newAttacher(testcase) return attacher.Attach(spec, nodeName) }, expectedError: attachError, }, // Detach succeeds { name: "Detach_Positive", diskIsAttached: diskIsAttachedCall{diskName, nodeName, true, nil}, detach: detachCall{diskName, nodeName, "/dev/sda", nil}, test: func(testcase *testcase) (string, error) { detacher := newDetacher(testcase) mountPath := "/mnt/" + string(diskName) return "", detacher.Detach(mountPath, nodeName) }, }, // Disk is already detached { name: "Detach_Positive_AlreadyDetached", diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, nil}, test: func(testcase *testcase) (string, error) { detacher := newDetacher(testcase) mountPath := "/mnt/" + string(diskName) return "", detacher.Detach(mountPath, nodeName) }, }, // Detach succeeds when DiskIsAttached fails { name: "Detach_Positive_CheckFails", diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, diskCheckError}, detach: detachCall{diskName, nodeName, "/dev/sda", nil}, test: func(testcase *testcase) (string, error) { detacher := newDetacher(testcase) mountPath := "/mnt/" + string(diskName) return "", detacher.Detach(mountPath, nodeName) }, }, // Detach fails { name: "Detach_Negative", diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, diskCheckError}, detach: detachCall{diskName, nodeName, "", detachError}, test: func(testcase *testcase) (string, error) { detacher := newDetacher(testcase) mountPath := "/mnt/" + string(diskName) return "", detacher.Detach(mountPath, nodeName) }, expectedError: detachError, }, } for _, testcase := range tests { testcase.t = t device, err := testcase.test(&testcase) if err != testcase.expectedError { t.Errorf("%s failed: expected err=%q, got %q", testcase.name, testcase.expectedError.Error(), err.Error()) } if device != testcase.expectedDevice { t.Errorf("%s failed: expected device=%q, got %q", testcase.name, testcase.expectedDevice, device) } t.Logf("Test %q succeeded", testcase.name) } }