vendor updates

This commit is contained in:
Serguei Bezverkhi
2018-03-06 17:33:18 -05:00
parent 4b3ebc171b
commit e9033989a0
5854 changed files with 248382 additions and 119809 deletions

View File

@ -24,7 +24,6 @@ go_library(
"//pkg/util/strings:go_default_library",
"//pkg/volume:go_default_library",
"//pkg/volume/util:go_default_library",
"//pkg/volume/util/volumehelper:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
@ -43,8 +42,7 @@ go_test(
"attacher_test.go",
"cinder_test.go",
],
importpath = "k8s.io/kubernetes/pkg/volume/cinder",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//pkg/cloudprovider:go_default_library",
"//pkg/util/mount:go_default_library",

View File

@ -2,7 +2,7 @@ approvers:
- jsafrane
- anguslees
- dims
- FengyunPan
- FengyunPan2
reviewers:
- anguslees
- rootfs
@ -10,4 +10,4 @@ reviewers:
- jsafrane
- jingxu97
- msau42
- FengyunPan
- FengyunPan2

View File

@ -17,6 +17,7 @@ limitations under the License.
package cinder
import (
"context"
"fmt"
"os"
"path"
@ -27,16 +28,14 @@ import (
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/kubernetes/pkg/cloudprovider"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
volumeutil "k8s.io/kubernetes/pkg/volume/util"
"k8s.io/kubernetes/pkg/volume/util/volumehelper"
)
type cinderDiskAttacher struct {
host volume.VolumeHost
cinderProvider CinderProvider
cinderProvider BlockStorageProvider
}
var _ volume.Attacher = &cinderDiskAttacher{}
@ -44,20 +43,21 @@ var _ volume.Attacher = &cinderDiskAttacher{}
var _ volume.AttachableVolumePlugin = &cinderPlugin{}
const (
checkSleepDuration = 1 * time.Second
operationFinishInitDealy = 1 * time.Second
probeVolumeInitDelay = 1 * time.Second
probeVolumeFactor = 2.0
operationFinishInitDelay = 1 * time.Second
operationFinishFactor = 1.1
operationFinishSteps = 10
diskAttachInitDealy = 1 * time.Second
diskAttachInitDelay = 1 * time.Second
diskAttachFactor = 1.2
diskAttachSteps = 15
diskDetachInitDealy = 1 * time.Second
diskDetachInitDelay = 1 * time.Second
diskDetachFactor = 1.2
diskDetachSteps = 13
)
func (plugin *cinderPlugin) NewAttacher() (volume.Attacher, error) {
cinder, err := getCloudProvider(plugin.host.GetCloudProvider())
cinder, err := plugin.getCloudProvider()
if err != nil {
return nil, err
}
@ -74,7 +74,7 @@ func (plugin *cinderPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string
func (attacher *cinderDiskAttacher) waitOperationFinished(volumeID string) error {
backoff := wait.Backoff{
Duration: operationFinishInitDealy,
Duration: operationFinishInitDelay,
Factor: operationFinishFactor,
Steps: operationFinishSteps,
}
@ -99,7 +99,7 @@ func (attacher *cinderDiskAttacher) waitOperationFinished(volumeID string) error
func (attacher *cinderDiskAttacher) waitDiskAttached(instanceID, volumeID string) error {
backoff := wait.Backoff{
Duration: diskAttachInitDealy,
Duration: diskAttachInitDelay,
Factor: diskAttachFactor,
Steps: diskAttachSteps,
}
@ -186,23 +186,7 @@ func (attacher *cinderDiskAttacher) VolumesAreAttached(specs []*volume.Spec, nod
volumeSpecMap[volumeSource.VolumeID] = spec
}
instanceID, err := attacher.nodeInstanceID(nodeName)
if err != nil {
if err == cloudprovider.InstanceNotFound {
// If node doesn't exist, OpenStack Nova will assume the volumes are not attached to it.
// Mark the volumes as detached and return false without error.
glog.Warningf("VolumesAreAttached: node %q does not exist.", nodeName)
for spec := range volumesAttachedCheck {
volumesAttachedCheck[spec] = false
}
return volumesAttachedCheck, nil
}
return volumesAttachedCheck, err
}
attachedResult, err := attacher.cinderProvider.DisksAreAttached(instanceID, volumeIDList)
attachedResult, err := attacher.cinderProvider.DisksAreAttachedByName(nodeName, volumeIDList)
if err != nil {
// Log error and continue with attach
glog.Errorf(
@ -231,14 +215,15 @@ func (attacher *cinderDiskAttacher) WaitForAttach(spec *volume.Spec, devicePath
volumeID := volumeSource.VolumeID
if devicePath == "" {
return "", fmt.Errorf("WaitForAttach failed for Cinder disk %q: devicePath is empty.", volumeID)
return "", fmt.Errorf("WaitForAttach failed for Cinder disk %q: devicePath is empty", volumeID)
}
ticker := time.NewTicker(checkSleepDuration)
ticker := time.NewTicker(probeVolumeInitDelay)
defer ticker.Stop()
timer := time.NewTimer(timeout)
defer timer.Stop()
duration := probeVolumeInitDelay
for {
select {
case <-ticker.C:
@ -252,12 +237,15 @@ func (attacher *cinderDiskAttacher) WaitForAttach(spec *volume.Spec, devicePath
if exists && err == nil {
glog.Infof("Successfully found attached Cinder disk %q at %v.", volumeID, devicePath)
return devicePath, nil
} else {
// Log an error, and continue checking periodically
glog.Errorf("Error: could not find attached Cinder disk %q (path: %q): %v", volumeID, devicePath, err)
}
// Log an error, and continue checking periodically
glog.Errorf("Error: could not find attached Cinder disk %q (path: %q): %v", volumeID, devicePath, err)
// Using exponential backoff instead of linear
ticker.Stop()
duration = time.Duration(float64(duration) * probeVolumeFactor)
ticker = time.NewTicker(duration)
case <-timer.C:
return "", fmt.Errorf("Could not find attached Cinder disk %q. Timeout waiting for mount paths to be created.", volumeID)
return "", fmt.Errorf("could not find attached Cinder disk %q. Timeout waiting for mount paths to be created", volumeID)
}
}
}
@ -297,8 +285,8 @@ func (attacher *cinderDiskAttacher) MountDevice(spec *volume.Spec, devicePath st
options = append(options, "ro")
}
if notMnt {
diskMounter := volumehelper.NewSafeFormatAndMountFromHost(cinderVolumePluginName, attacher.host)
mountOptions := volume.MountOptionFromSpec(spec, options...)
diskMounter := volumeutil.NewSafeFormatAndMountFromHost(cinderVolumePluginName, attacher.host)
mountOptions := volumeutil.MountOptionFromSpec(spec, options...)
err = diskMounter.FormatAndMount(devicePath, deviceMountPath, volumeSource.FSType, mountOptions)
if err != nil {
os.Remove(deviceMountPath)
@ -310,13 +298,13 @@ func (attacher *cinderDiskAttacher) MountDevice(spec *volume.Spec, devicePath st
type cinderDiskDetacher struct {
mounter mount.Interface
cinderProvider CinderProvider
cinderProvider BlockStorageProvider
}
var _ volume.Detacher = &cinderDiskDetacher{}
func (plugin *cinderPlugin) NewDetacher() (volume.Detacher, error) {
cinder, err := getCloudProvider(plugin.host.GetCloudProvider())
cinder, err := plugin.getCloudProvider()
if err != nil {
return nil, err
}
@ -328,7 +316,7 @@ func (plugin *cinderPlugin) NewDetacher() (volume.Detacher, error) {
func (detacher *cinderDiskDetacher) waitOperationFinished(volumeID string) error {
backoff := wait.Backoff{
Duration: operationFinishInitDealy,
Duration: operationFinishInitDelay,
Factor: operationFinishFactor,
Steps: operationFinishSteps,
}
@ -353,7 +341,7 @@ func (detacher *cinderDiskDetacher) waitOperationFinished(volumeID string) error
func (detacher *cinderDiskDetacher) waitDiskDetached(instanceID, volumeID string) error {
backoff := wait.Backoff{
Duration: diskDetachInitDealy,
Duration: diskDetachInitDelay,
Factor: diskDetachFactor,
Steps: diskDetachSteps,
}
@ -375,20 +363,10 @@ func (detacher *cinderDiskDetacher) waitDiskDetached(instanceID, volumeID string
func (detacher *cinderDiskDetacher) Detach(volumeName string, nodeName types.NodeName) error {
volumeID := path.Base(volumeName)
instances, res := detacher.cinderProvider.Instances()
if !res {
return fmt.Errorf("failed to list openstack instances")
}
instanceID, err := instances.InstanceID(nodeName)
if ind := strings.LastIndex(instanceID, "/"); ind >= 0 {
instanceID = instanceID[(ind + 1):]
}
if err := detacher.waitOperationFinished(volumeID); err != nil {
return err
}
attached, err := detacher.cinderProvider.DiskIsAttached(instanceID, volumeID)
attached, instanceID, err := detacher.cinderProvider.DiskIsAttachedByName(nodeName, volumeID)
if err != nil {
// Log error and continue with detach
glog.Errorf(
@ -423,7 +401,7 @@ func (attacher *cinderDiskAttacher) nodeInstanceID(nodeName types.NodeName) (str
if !res {
return "", fmt.Errorf("failed to list openstack instances")
}
instanceID, err := instances.InstanceID(nodeName)
instanceID, err := instances.InstanceID(context.TODO(), nodeName)
if err != nil {
return "", err
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package cinder
import (
"context"
"errors"
"reflect"
"testing"
@ -132,7 +133,7 @@ func TestAttachDetach(t *testing.T) {
name: "Attach_Positive",
instanceID: instanceID,
operationPending: operationPendingCall{volumeID, false, done, nil},
diskIsAttached: diskIsAttachedCall{instanceID, volumeID, false, nil},
diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, nil},
attach: attachCall{instanceID, volumeID, "", nil},
diskPath: diskPathCall{instanceID, volumeID, "/dev/sda", nil},
test: func(testcase *testcase) (string, error) {
@ -147,7 +148,7 @@ func TestAttachDetach(t *testing.T) {
name: "Attach_Positive_AlreadyAttached",
instanceID: instanceID,
operationPending: operationPendingCall{volumeID, false, done, nil},
diskIsAttached: diskIsAttachedCall{instanceID, volumeID, true, nil},
diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, true, nil},
diskPath: diskPathCall{instanceID, volumeID, "/dev/sda", nil},
test: func(testcase *testcase) (string, error) {
attacher := newAttacher(testcase)
@ -173,7 +174,7 @@ func TestAttachDetach(t *testing.T) {
name: "Attach_Negative",
instanceID: instanceID,
operationPending: operationPendingCall{volumeID, false, done, nil},
diskIsAttached: diskIsAttachedCall{instanceID, volumeID, false, diskCheckError},
diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, diskCheckError},
attach: attachCall{instanceID, volumeID, "/dev/sda", attachError},
test: func(testcase *testcase) (string, error) {
attacher := newAttacher(testcase)
@ -187,7 +188,7 @@ func TestAttachDetach(t *testing.T) {
name: "Attach_Negative_DiskPatchFails",
instanceID: instanceID,
operationPending: operationPendingCall{volumeID, false, done, nil},
diskIsAttached: diskIsAttachedCall{instanceID, volumeID, false, nil},
diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, nil},
attach: attachCall{instanceID, volumeID, "", nil},
diskPath: diskPathCall{instanceID, volumeID, "", diskPathError},
test: func(testcase *testcase) (string, error) {
@ -201,7 +202,7 @@ func TestAttachDetach(t *testing.T) {
{
name: "VolumesAreAttached_Positive",
instanceID: instanceID,
disksAreAttached: disksAreAttachedCall{instanceID, []string{volumeID}, map[string]bool{volumeID: true}, nil},
disksAreAttached: disksAreAttachedCall{instanceID, nodeName, []string{volumeID}, map[string]bool{volumeID: true}, nil},
test: func(testcase *testcase) (string, error) {
attacher := newAttacher(testcase)
attachments, err := attacher.VolumesAreAttached([]*volume.Spec{spec}, nodeName)
@ -214,7 +215,7 @@ func TestAttachDetach(t *testing.T) {
{
name: "VolumesAreAttached_Negative",
instanceID: instanceID,
disksAreAttached: disksAreAttachedCall{instanceID, []string{volumeID}, map[string]bool{volumeID: false}, nil},
disksAreAttached: disksAreAttachedCall{instanceID, nodeName, []string{volumeID}, map[string]bool{volumeID: false}, nil},
test: func(testcase *testcase) (string, error) {
attacher := newAttacher(testcase)
attachments, err := attacher.VolumesAreAttached([]*volume.Spec{spec}, nodeName)
@ -227,7 +228,7 @@ func TestAttachDetach(t *testing.T) {
{
name: "VolumesAreAttached_CinderFailed",
instanceID: instanceID,
disksAreAttached: disksAreAttachedCall{instanceID, []string{volumeID}, nil, disksCheckError},
disksAreAttached: disksAreAttachedCall{instanceID, nodeName, []string{volumeID}, nil, disksCheckError},
test: func(testcase *testcase) (string, error) {
attacher := newAttacher(testcase)
attachments, err := attacher.VolumesAreAttached([]*volume.Spec{spec}, nodeName)
@ -242,7 +243,7 @@ func TestAttachDetach(t *testing.T) {
name: "Detach_Positive",
instanceID: instanceID,
operationPending: operationPendingCall{volumeID, false, done, nil},
diskIsAttached: diskIsAttachedCall{instanceID, volumeID, true, nil},
diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, true, nil},
detach: detachCall{instanceID, volumeID, nil},
test: func(testcase *testcase) (string, error) {
detacher := newDetacher(testcase)
@ -255,7 +256,7 @@ func TestAttachDetach(t *testing.T) {
name: "Detach_Positive_AlreadyDetached",
instanceID: instanceID,
operationPending: operationPendingCall{volumeID, false, done, nil},
diskIsAttached: diskIsAttachedCall{instanceID, volumeID, false, nil},
diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, nil},
test: func(testcase *testcase) (string, error) {
detacher := newDetacher(testcase)
return "", detacher.Detach(volumeID, nodeName)
@ -267,7 +268,7 @@ func TestAttachDetach(t *testing.T) {
name: "Detach_Positive_CheckFails",
instanceID: instanceID,
operationPending: operationPendingCall{volumeID, false, done, nil},
diskIsAttached: diskIsAttachedCall{instanceID, volumeID, false, diskCheckError},
diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, diskCheckError},
detach: detachCall{instanceID, volumeID, nil},
test: func(testcase *testcase) (string, error) {
detacher := newDetacher(testcase)
@ -280,7 +281,7 @@ func TestAttachDetach(t *testing.T) {
name: "Detach_Negative",
instanceID: instanceID,
operationPending: operationPendingCall{volumeID, false, done, nil},
diskIsAttached: diskIsAttachedCall{instanceID, volumeID, false, diskCheckError},
diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, diskCheckError},
detach: detachCall{instanceID, volumeID, detachError},
test: func(testcase *testcase) (string, error) {
detacher := newDetacher(testcase)
@ -426,6 +427,7 @@ type operationPendingCall struct {
type diskIsAttachedCall struct {
instanceID string
nodeName types.NodeName
volumeID string
isAttached bool
ret error
@ -440,6 +442,7 @@ type diskPathCall struct {
type disksAreAttachedCall struct {
instanceID string
nodeName types.NodeName
volumeIDs []string
areAttached map[string]bool
ret error
@ -451,18 +454,18 @@ func (testcase *testcase) AttachDisk(instanceID, volumeID string) (string, error
if expected.volumeID == "" && expected.instanceID == "" {
// testcase.attach looks uninitialized, test did not expect to call
// AttachDisk
testcase.t.Errorf("Unexpected AttachDisk call!")
return "", errors.New("Unexpected AttachDisk call!")
testcase.t.Errorf("unexpected AttachDisk call")
return "", errors.New("unexpected AttachDisk call")
}
if expected.volumeID != volumeID {
testcase.t.Errorf("Unexpected AttachDisk call: expected volumeID %s, got %s", expected.volumeID, volumeID)
return "", errors.New("Unexpected AttachDisk call: wrong volumeID")
testcase.t.Errorf("unexpected AttachDisk call: expected volumeID %s, got %s", expected.volumeID, volumeID)
return "", errors.New("unexpected AttachDisk call: wrong volumeID")
}
if expected.instanceID != instanceID {
testcase.t.Errorf("Unexpected AttachDisk call: expected instanceID %s, got %s", expected.instanceID, instanceID)
return "", errors.New("Unexpected AttachDisk call: wrong instanceID")
testcase.t.Errorf("unexpected AttachDisk call: expected instanceID %s, got %s", expected.instanceID, instanceID)
return "", errors.New("unexpected AttachDisk call: wrong instanceID")
}
glog.V(4).Infof("AttachDisk call: %s, %s, returning %q, %v", volumeID, instanceID, expected.retDeviceName, expected.ret)
@ -477,18 +480,18 @@ func (testcase *testcase) DetachDisk(instanceID, volumeID string) error {
if expected.devicePath == "" && expected.instanceID == "" {
// testcase.detach looks uninitialized, test did not expect to call
// DetachDisk
testcase.t.Errorf("Unexpected DetachDisk call!")
return errors.New("Unexpected DetachDisk call!")
testcase.t.Errorf("unexpected DetachDisk call")
return errors.New("unexpected DetachDisk call")
}
if expected.devicePath != volumeID {
testcase.t.Errorf("Unexpected DetachDisk call: expected volumeID %s, got %s", expected.devicePath, volumeID)
return errors.New("Unexpected DetachDisk call: wrong volumeID")
testcase.t.Errorf("unexpected DetachDisk call: expected volumeID %s, got %s", expected.devicePath, volumeID)
return errors.New("unexpected DetachDisk call: wrong volumeID")
}
if expected.instanceID != instanceID {
testcase.t.Errorf("Unexpected DetachDisk call: expected instanceID %s, got %s", expected.instanceID, instanceID)
return errors.New("Unexpected DetachDisk call: wrong instanceID")
testcase.t.Errorf("unexpected DetachDisk call: expected instanceID %s, got %s", expected.instanceID, instanceID)
return errors.New("unexpected DetachDisk call: wrong instanceID")
}
glog.V(4).Infof("DetachDisk call: %s, %s, returning %v", volumeID, instanceID, expected.ret)
@ -525,18 +528,18 @@ func (testcase *testcase) DiskIsAttached(instanceID, volumeID string) (bool, err
if expected.volumeID == "" && expected.instanceID == "" {
// testcase.diskIsAttached looks uninitialized, test did not expect to
// call DiskIsAttached
testcase.t.Errorf("Unexpected DiskIsAttached call!")
return false, errors.New("Unexpected DiskIsAttached call!")
testcase.t.Errorf("unexpected DiskIsAttached call")
return false, errors.New("unexpected DiskIsAttached call")
}
if expected.volumeID != volumeID {
testcase.t.Errorf("Unexpected DiskIsAttached call: expected volumeID %s, got %s", expected.volumeID, volumeID)
return false, errors.New("Unexpected DiskIsAttached call: wrong volumeID")
testcase.t.Errorf("unexpected DiskIsAttached call: expected volumeID %s, got %s", expected.volumeID, volumeID)
return false, errors.New("unexpected DiskIsAttached call: wrong volumeID")
}
if expected.instanceID != instanceID {
testcase.t.Errorf("Unexpected DiskIsAttached call: expected instanceID %s, got %s", expected.instanceID, instanceID)
return false, errors.New("Unexpected DiskIsAttached call: wrong instanceID")
testcase.t.Errorf("unexpected DiskIsAttached call: expected instanceID %s, got %s", expected.instanceID, instanceID)
return false, errors.New("unexpected DiskIsAttached call: wrong instanceID")
}
glog.V(4).Infof("DiskIsAttached call: %s, %s, returning %v, %v", volumeID, instanceID, expected.isAttached, expected.ret)
@ -549,18 +552,18 @@ func (testcase *testcase) GetAttachmentDiskPath(instanceID, volumeID string) (st
if expected.volumeID == "" && expected.instanceID == "" {
// testcase.diskPath looks uninitialized, test did not expect to
// call GetAttachmentDiskPath
testcase.t.Errorf("Unexpected GetAttachmentDiskPath call!")
return "", errors.New("Unexpected GetAttachmentDiskPath call!")
testcase.t.Errorf("unexpected GetAttachmentDiskPath call")
return "", errors.New("unexpected GetAttachmentDiskPath call")
}
if expected.volumeID != volumeID {
testcase.t.Errorf("Unexpected GetAttachmentDiskPath call: expected volumeID %s, got %s", expected.volumeID, volumeID)
return "", errors.New("Unexpected GetAttachmentDiskPath call: wrong volumeID")
testcase.t.Errorf("unexpected GetAttachmentDiskPath call: expected volumeID %s, got %s", expected.volumeID, volumeID)
return "", errors.New("unexpected GetAttachmentDiskPath call: wrong volumeID")
}
if expected.instanceID != instanceID {
testcase.t.Errorf("Unexpected GetAttachmentDiskPath call: expected instanceID %s, got %s", expected.instanceID, instanceID)
return "", errors.New("Unexpected GetAttachmentDiskPath call: wrong instanceID")
testcase.t.Errorf("unexpected GetAttachmentDiskPath call: expected instanceID %s, got %s", expected.instanceID, instanceID)
return "", errors.New("unexpected GetAttachmentDiskPath call: wrong instanceID")
}
glog.V(4).Infof("GetAttachmentDiskPath call: %s, %s, returning %v, %v", volumeID, instanceID, expected.retPath, expected.ret)
@ -572,6 +575,46 @@ func (testcase *testcase) ShouldTrustDevicePath() bool {
return true
}
func (testcase *testcase) DiskIsAttachedByName(nodeName types.NodeName, volumeID string) (bool, string, error) {
expected := &testcase.diskIsAttached
instanceID := expected.instanceID
// If testcase call DetachDisk*, return false
if *testcase.attachOrDetach == detachStatus {
return false, instanceID, nil
}
// If testcase call AttachDisk*, return true
if *testcase.attachOrDetach == attachStatus {
return true, instanceID, nil
}
if expected.nodeName != nodeName {
testcase.t.Errorf("unexpected DiskIsAttachedByName call: expected nodename %s, got %s", expected.nodeName, nodeName)
return false, instanceID, errors.New("unexpected DiskIsAttachedByName call: wrong nodename")
}
if expected.volumeID == "" && expected.instanceID == "" {
// testcase.diskIsAttached looks uninitialized, test did not expect to
// call DiskIsAttached
testcase.t.Errorf("unexpected DiskIsAttachedByName call")
return false, instanceID, errors.New("unexpected DiskIsAttachedByName call")
}
if expected.volumeID != volumeID {
testcase.t.Errorf("unexpected DiskIsAttachedByName call: expected volumeID %s, got %s", expected.volumeID, volumeID)
return false, instanceID, errors.New("unexpected DiskIsAttachedByName call: wrong volumeID")
}
if expected.instanceID != instanceID {
testcase.t.Errorf("unexpected DiskIsAttachedByName call: expected instanceID %s, got %s", expected.instanceID, instanceID)
return false, instanceID, errors.New("unexpected DiskIsAttachedByName call: wrong instanceID")
}
glog.V(4).Infof("DiskIsAttachedByName call: %s, %s, returning %v, %v", volumeID, nodeName, expected.isAttached, expected.instanceID, expected.ret)
return expected.isAttached, expected.instanceID, expected.ret
}
func (testcase *testcase) CreateVolume(name string, size int, vtype, availability string, tags *map[string]string) (string, string, bool, error) {
return "", "", false, errors.New("Not implemented")
}
@ -626,36 +669,66 @@ func (testcase *testcase) DisksAreAttached(instanceID string, volumeIDs []string
return expected.areAttached, expected.ret
}
func (testcase *testcase) DisksAreAttachedByName(nodeName types.NodeName, volumeIDs []string) (map[string]bool, error) {
expected := &testcase.disksAreAttached
areAttached := make(map[string]bool)
instanceID := expected.instanceID
if expected.nodeName != nodeName {
testcase.t.Errorf("Unexpected DisksAreAttachedByName call: expected nodeName %s, got %s", expected.nodeName, nodeName)
return areAttached, errors.New("Unexpected DisksAreAttachedByName call: wrong nodename")
}
if len(expected.volumeIDs) == 0 && expected.instanceID == "" {
// testcase.volumeIDs looks uninitialized, test did not expect to call DisksAreAttached
testcase.t.Errorf("Unexpected DisksAreAttachedByName call!")
return areAttached, errors.New("Unexpected DisksAreAttachedByName call")
}
if !reflect.DeepEqual(expected.volumeIDs, volumeIDs) {
testcase.t.Errorf("Unexpected DisksAreAttachedByName call: expected volumeIDs %v, got %v", expected.volumeIDs, volumeIDs)
return areAttached, errors.New("Unexpected DisksAreAttachedByName call: wrong volumeID")
}
if expected.instanceID != instanceID {
testcase.t.Errorf("Unexpected DisksAreAttachedByName call: expected instanceID %s, got %s", expected.instanceID, instanceID)
return areAttached, errors.New("Unexpected DisksAreAttachedByName call: wrong instanceID")
}
glog.V(4).Infof("DisksAreAttachedByName call: %v, %s, returning %v, %v", volumeIDs, nodeName, expected.areAttached, expected.ret)
return expected.areAttached, expected.ret
}
// Implementation of fake cloudprovider.Instances
type instances struct {
instanceID string
}
func (instances *instances) NodeAddresses(name types.NodeName) ([]v1.NodeAddress, error) {
func (instances *instances) NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.NodeAddress, error) {
return []v1.NodeAddress{}, errors.New("Not implemented")
}
func (instances *instances) NodeAddressesByProviderID(providerID string) ([]v1.NodeAddress, error) {
func (instances *instances) NodeAddressesByProviderID(ctx context.Context, providerID string) ([]v1.NodeAddress, error) {
return []v1.NodeAddress{}, errors.New("Not implemented")
}
func (instances *instances) ExternalID(name types.NodeName) (string, error) {
func (instances *instances) ExternalID(ctx context.Context, name types.NodeName) (string, error) {
return "", errors.New("Not implemented")
}
func (instances *instances) InstanceID(name types.NodeName) (string, error) {
func (instances *instances) InstanceID(ctx context.Context, name types.NodeName) (string, error) {
return instances.instanceID, nil
}
func (instances *instances) InstanceType(name types.NodeName) (string, error) {
func (instances *instances) InstanceType(ctx context.Context, name types.NodeName) (string, error) {
return "", errors.New("Not implemented")
}
func (instances *instances) InstanceTypeByProviderID(providerID string) (string, error) {
func (instances *instances) InstanceTypeByProviderID(ctx context.Context, providerID string) (string, error) {
return "", errors.New("Not implemented")
}
func (instances *instances) InstanceExistsByProviderID(providerID string) (bool, error) {
func (instances *instances) InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error) {
return false, errors.New("unimplemented")
}
@ -663,10 +736,10 @@ func (instances *instances) List(filter string) ([]types.NodeName, error) {
return []types.NodeName{}, errors.New("Not implemented")
}
func (instances *instances) AddSSHKeyToAllInstances(user string, keyData []byte) error {
func (instances *instances) AddSSHKeyToAllInstances(ctx context.Context, user string, keyData []byte) error {
return errors.New("Not implemented")
}
func (instances *instances) CurrentNodeName(hostname string) (types.NodeName, error) {
func (instances *instances) CurrentNodeName(ctx context.Context, hostname string) (types.NodeName, error) {
return "", errors.New("Not implemented")
}

View File

@ -34,15 +34,20 @@ import (
kstrings "k8s.io/kubernetes/pkg/util/strings"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util"
"k8s.io/kubernetes/pkg/volume/util/volumehelper"
)
// This is the primary entrypoint for volume plugins.
const (
// DefaultCloudConfigPath is the default path for cloud configuration
DefaultCloudConfigPath = "/etc/kubernetes/cloud-config"
)
// ProbeVolumePlugins is the primary entrypoint for volume plugins.
func ProbeVolumePlugins() []volume.VolumePlugin {
return []volume.VolumePlugin{&cinderPlugin{}}
}
type CinderProvider interface {
// BlockStorageProvider is the interface for accessing cinder functionality.
type BlockStorageProvider interface {
AttachDisk(instanceID, volumeID string) (string, error)
DetachDisk(instanceID, volumeID string) error
DeleteVolume(volumeID string) error
@ -52,7 +57,8 @@ type CinderProvider interface {
GetAttachmentDiskPath(instanceID, volumeID string) (string, error)
OperationPending(diskName string) (bool, string, error)
DiskIsAttached(instanceID, volumeID string) (bool, error)
DisksAreAttached(instanceID string, volumeIDs []string) (map[string]bool, error)
DiskIsAttachedByName(nodeName types.NodeName, volumeID string) (bool, string, error)
DisksAreAttachedByName(nodeName types.NodeName, volumeIDs []string) (map[string]bool, error)
ShouldTrustDevicePath() bool
Instances() (cloudprovider.Instances, bool)
ExpandVolume(volumeID string, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error)
@ -115,7 +121,7 @@ func (plugin *cinderPlugin) GetAccessModes() []v1.PersistentVolumeAccessMode {
}
func (plugin *cinderPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
return plugin.newMounterInternal(spec, pod.UID, &CinderDiskUtil{}, plugin.host.GetMounter(plugin.GetPluginName()))
return plugin.newMounterInternal(spec, pod.UID, &DiskUtil{}, plugin.host.GetMounter(plugin.GetPluginName()))
}
func (plugin *cinderPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager cdManager, mounter mount.Interface) (volume.Mounter, error) {
@ -138,11 +144,11 @@ func (plugin *cinderPlugin) newMounterInternal(spec *volume.Spec, podUID types.U
},
fsType: fsType,
readOnly: readOnly,
blockDeviceMounter: volumehelper.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host)}, nil
blockDeviceMounter: util.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host)}, nil
}
func (plugin *cinderPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
return plugin.newUnmounterInternal(volName, podUID, &CinderDiskUtil{}, plugin.host.GetMounter(plugin.GetPluginName()))
return plugin.newUnmounterInternal(volName, podUID, &DiskUtil{}, plugin.host.GetMounter(plugin.GetPluginName()))
}
func (plugin *cinderPlugin) newUnmounterInternal(volName string, podUID types.UID, manager cdManager, mounter mount.Interface) (volume.Unmounter, error) {
@ -157,7 +163,7 @@ func (plugin *cinderPlugin) newUnmounterInternal(volName string, podUID types.UI
}
func (plugin *cinderPlugin) NewDeleter(spec *volume.Spec) (volume.Deleter, error) {
return plugin.newDeleterInternal(spec, &CinderDiskUtil{})
return plugin.newDeleterInternal(spec, &DiskUtil{})
}
func (plugin *cinderPlugin) newDeleterInternal(spec *volume.Spec, manager cdManager) (volume.Deleter, error) {
@ -174,7 +180,7 @@ func (plugin *cinderPlugin) newDeleterInternal(spec *volume.Spec, manager cdMana
}
func (plugin *cinderPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) {
return plugin.newProvisionerInternal(options, &CinderDiskUtil{})
return plugin.newProvisionerInternal(options, &DiskUtil{})
}
func (plugin *cinderPlugin) newProvisionerInternal(options volume.VolumeOptions, manager cdManager) (volume.Provisioner, error) {
@ -187,25 +193,30 @@ func (plugin *cinderPlugin) newProvisionerInternal(options volume.VolumeOptions,
}, nil
}
func getCloudProvider(cloudProvider cloudprovider.Interface) (CinderProvider, error) {
if cloud, ok := cloudProvider.(*openstack.OpenStack); ok && cloud != nil {
return cloud, nil
}
return nil, fmt.Errorf("wrong cloud type")
}
func (plugin *cinderPlugin) getCloudProvider() (CinderProvider, error) {
func (plugin *cinderPlugin) getCloudProvider() (BlockStorageProvider, error) {
cloud := plugin.host.GetCloudProvider()
if cloud == nil {
glog.Errorf("Cloud provider not initialized properly")
return nil, errors.New("Cloud provider not initialized properly")
if _, err := os.Stat(DefaultCloudConfigPath); err == nil {
var config *os.File
config, err = os.Open(DefaultCloudConfigPath)
if err != nil {
return nil, fmt.Errorf("unable to load OpenStack configuration from default path : %v", err)
}
defer config.Close()
cloud, err = cloudprovider.GetCloudProvider(openstack.ProviderName, config)
if err != nil {
return nil, fmt.Errorf("unable to create OpenStack cloud provider from default path : %v", err)
}
} else {
return nil, fmt.Errorf("OpenStack cloud provider was not initialized properly : %v", err)
}
}
switch cloud := cloud.(type) {
case *openstack.OpenStack:
return cloud, nil
default:
return nil, errors.New("Invalid cloud provider: expected OpenStack.")
return nil, errors.New("invalid cloud provider: expected OpenStack")
}
}
@ -489,7 +500,7 @@ type cinderVolumeProvisioner struct {
var _ volume.Provisioner = &cinderVolumeProvisioner{}
func (c *cinderVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
if !volume.AccessModesContainedInAll(c.plugin.GetAccessModes(), c.options.PVC.Spec.AccessModes) {
if !util.AccessModesContainedInAll(c.plugin.GetAccessModes(), c.options.PVC.Spec.AccessModes) {
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", c.options.PVC.Spec.AccessModes, c.plugin.GetAccessModes())
}
@ -503,7 +514,7 @@ func (c *cinderVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
Name: c.options.PVName,
Labels: labels,
Annotations: map[string]string{
volumehelper.VolumeDynamicallyCreatedByKey: "cinder-dynamic-provisioner",
util.VolumeDynamicallyCreatedByKey: "cinder-dynamic-provisioner",
},
},
Spec: v1.PersistentVolumeSpec{

View File

@ -172,13 +172,6 @@ func TestPlugin(t *testing.T) {
t.Errorf("SetUp() failed: %v", err)
}
}
if _, err := os.Stat(path); err != nil {
if os.IsNotExist(err) {
t.Errorf("SetUp() failed, volume path not created: %s", path)
} else {
t.Errorf("SetUp() failed: %v", err)
}
}
unmounter, err := plug.(*cinderPlugin).newUnmounterInternal("vol1", types.UID("poduid"), &fakePDManager{0}, &mount.FakeMounter{})
if err != nil {

View File

@ -32,14 +32,16 @@ import (
clientset "k8s.io/client-go/kubernetes"
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
"k8s.io/kubernetes/pkg/volume"
volutil "k8s.io/kubernetes/pkg/volume/util"
"k8s.io/utils/exec"
)
type CinderDiskUtil struct{}
// DiskUtil has utility/helper methods
type DiskUtil struct{}
// Attaches a disk specified by a volume.CinderPersistenDisk to the current kubelet.
// AttachDisk attaches a disk specified by a volume.CinderPersistenDisk to the current kubelet.
// Mounts the disk to its global path.
func (util *CinderDiskUtil) AttachDisk(b *cinderVolumeMounter, globalPDPath string) error {
func (util *DiskUtil) AttachDisk(b *cinderVolumeMounter, globalPDPath string) error {
options := []string{}
if b.readOnly {
options = append(options, "ro")
@ -98,8 +100,8 @@ func (util *CinderDiskUtil) AttachDisk(b *cinderVolumeMounter, globalPDPath stri
return nil
}
// Unmounts the device and detaches the disk from the kubelet's host machine.
func (util *CinderDiskUtil) DetachDisk(cd *cinderVolumeUnmounter) error {
// DetachDisk unmounts the device and detaches the disk from the kubelet's host machine.
func (util *DiskUtil) DetachDisk(cd *cinderVolumeUnmounter) error {
globalPDPath := makeGlobalPDName(cd.plugin.host, cd.pdName)
if err := cd.mounter.Unmount(globalPDPath); err != nil {
return err
@ -124,7 +126,8 @@ func (util *CinderDiskUtil) DetachDisk(cd *cinderVolumeUnmounter) error {
return nil
}
func (util *CinderDiskUtil) DeleteVolume(cd *cinderVolumeDeleter) error {
// DeleteVolume uses the cloud entrypoint to delete specified volume
func (util *DiskUtil) DeleteVolume(cd *cinderVolumeDeleter) error {
cloud, err := cd.plugin.getCloudProvider()
if err != nil {
return err
@ -158,7 +161,8 @@ func getZonesFromNodes(kubeClient clientset.Interface) (sets.String, error) {
return zones, nil
}
func (util *CinderDiskUtil) CreateVolume(c *cinderVolumeProvisioner) (volumeID string, volumeSizeGB int, volumeLabels map[string]string, fstype string, err error) {
// CreateVolume uses the cloud provider entrypoint for creating a volume
func (util *DiskUtil) CreateVolume(c *cinderVolumeProvisioner) (volumeID string, volumeSizeGB int, volumeLabels map[string]string, fstype string, err error) {
cloud, err := c.plugin.getCloudProvider()
if err != nil {
return "", 0, nil, "", err
@ -167,8 +171,8 @@ func (util *CinderDiskUtil) CreateVolume(c *cinderVolumeProvisioner) (volumeID s
capacity := c.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
volSizeBytes := capacity.Value()
// Cinder works with gigabytes, convert to GiB with rounding up
volSizeGB := int(volume.RoundUpSize(volSizeBytes, 1024*1024*1024))
name := volume.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 255) // Cinder volume name can have up to 255 characters
volSizeGB := int(volutil.RoundUpSize(volSizeBytes, 1024*1024*1024))
name := volutil.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 255) // Cinder volume name can have up to 255 characters
vtype := ""
availability := ""
// Apply ProvisionerParameters (case-insensitive). We leave validation of
@ -200,7 +204,7 @@ func (util *CinderDiskUtil) CreateVolume(c *cinderVolumeProvisioner) (volumeID s
// if we did not get any zones, lets leave it blank and gophercloud will
// use zone "nova" as default
if len(zones) > 0 {
availability = volume.ChooseZoneForVolume(zones, c.options.PVC.Name)
availability = volutil.ChooseZoneForVolume(zones, c.options.PVC.Name)
}
}
@ -224,6 +228,17 @@ func probeAttachedVolume() error {
scsiHostRescan()
executor := exec.New()
// udevadm settle waits for udevd to process the device creation
// events for all hardware devices, thus ensuring that any device
// nodes have been created successfully before proceeding.
argsSettle := []string{"settle"}
cmdSettle := executor.Command("udevadm", argsSettle...)
_, errSettle := cmdSettle.CombinedOutput()
if errSettle != nil {
glog.Errorf("error running udevadm settle %v\n", errSettle)
}
args := []string{"trigger"}
cmd := executor.Command("udevadm", args...)
_, err := cmd.CombinedOutput()
@ -236,10 +251,10 @@ func probeAttachedVolume() error {
}
func scsiHostRescan() {
scsi_path := "/sys/class/scsi_host/"
if dirs, err := ioutil.ReadDir(scsi_path); err == nil {
scsiPath := "/sys/class/scsi_host/"
if dirs, err := ioutil.ReadDir(scsiPath); err == nil {
for _, f := range dirs {
name := scsi_path + f.Name() + "/scan"
name := scsiPath + f.Name() + "/scan"
data := []byte("- - -")
ioutil.WriteFile(name, data, 0666)
}