Pass whole PVC to provisioner plugin

Gluster provisioner is interested in pvc.Namespace and I don't want to add
at as a new field in VolumeOptions - it would contain almost whole PVC.

Let's pass direct reference to PVC instead and let the provisioner to pick
information it is interested in.
This commit is contained in:
Jan Safranek 2016-10-12 12:22:01 +02:00
parent 4747e1cc1d
commit 101602ab11
28 changed files with 135 additions and 133 deletions

View File

@ -1148,15 +1148,17 @@ func (plugin *mockVolumePlugin) Provision() (*api.PersistentVolume, error) {
} }
if call.ret == nil { if call.ret == nil {
// Create a fake PV with known GCE volume (to match expected volume) // Create a fake PV with known GCE volume (to match expected volume)
capacity := plugin.provisionOptions.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)]
accessModes := plugin.provisionOptions.PVC.Spec.AccessModes
pv = &api.PersistentVolume{ pv = &api.PersistentVolume{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: plugin.provisionOptions.PVName, Name: plugin.provisionOptions.PVName,
}, },
Spec: api.PersistentVolumeSpec{ Spec: api.PersistentVolumeSpec{
Capacity: api.ResourceList{ Capacity: api.ResourceList{
api.ResourceName(api.ResourceStorage): plugin.provisionOptions.Capacity, api.ResourceName(api.ResourceStorage): capacity,
}, },
AccessModes: plugin.provisionOptions.AccessModes, AccessModes: accessModes,
PersistentVolumeReclaimPolicy: plugin.provisionOptions.PersistentVolumeReclaimPolicy, PersistentVolumeReclaimPolicy: plugin.provisionOptions.PersistentVolumeReclaimPolicy,
PersistentVolumeSource: api.PersistentVolumeSource{ PersistentVolumeSource: api.PersistentVolumeSource{
GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{}, GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{},

View File

@ -1260,15 +1260,12 @@ func (ctrl *PersistentVolumeController) provisionClaimOperation(claimObj interfa
tags[cloudVolumeCreatedForVolumeNameTag] = pvName tags[cloudVolumeCreatedForVolumeNameTag] = pvName
options := vol.VolumeOptions{ options := vol.VolumeOptions{
Capacity: claim.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)],
AccessModes: claim.Spec.AccessModes,
PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete, PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete,
CloudTags: &tags, CloudTags: &tags,
ClusterName: ctrl.clusterName, ClusterName: ctrl.clusterName,
PVName: pvName, PVName: pvName,
PVCName: claim.Name, PVC: claim,
Parameters: storageClass.Parameters, Parameters: storageClass.Parameters,
Selector: claim.Spec.Selector,
} }
// Provision the volume // Provision the volume

View File

@ -160,9 +160,6 @@ func (plugin *awsElasticBlockStorePlugin) newDeleterInternal(spec *volume.Spec,
} }
func (plugin *awsElasticBlockStorePlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) { func (plugin *awsElasticBlockStorePlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) {
if len(options.AccessModes) == 0 {
options.AccessModes = plugin.GetAccessModes()
}
return plugin.newProvisionerInternal(options, &AWSDiskUtil{}) return plugin.newProvisionerInternal(options, &AWSDiskUtil{})
} }
@ -429,7 +426,7 @@ func (c *awsElasticBlockStoreProvisioner) Provision() (*api.PersistentVolume, er
}, },
Spec: api.PersistentVolumeSpec{ Spec: api.PersistentVolumeSpec{
PersistentVolumeReclaimPolicy: c.options.PersistentVolumeReclaimPolicy, PersistentVolumeReclaimPolicy: c.options.PersistentVolumeReclaimPolicy,
AccessModes: c.options.AccessModes, AccessModes: c.options.PVC.Spec.AccessModes,
Capacity: api.ResourceList{ Capacity: api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)), api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)),
}, },
@ -444,6 +441,10 @@ func (c *awsElasticBlockStoreProvisioner) Provision() (*api.PersistentVolume, er
}, },
} }
if len(c.options.PVC.Spec.AccessModes) == 0 {
pv.Spec.AccessModes = c.plugin.GetAccessModes()
}
if len(labels) != 0 { if len(labels) != 0 {
if pv.Labels == nil { if pv.Labels == nil {
pv.Labels = make(map[string]string) pv.Labels = make(map[string]string)

View File

@ -23,7 +23,6 @@ import (
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/types" "k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/util/mount"
@ -180,12 +179,8 @@ func TestPlugin(t *testing.T) {
} }
// Test Provisioner // Test Provisioner
cap := resource.MustParse("100Mi")
options := volume.VolumeOptions{ options := volume.VolumeOptions{
Capacity: cap, PVC: volumetest.CreateTestPVC("100Mi", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}),
AccessModes: []api.PersistentVolumeAccessMode{
api.ReadWriteOnce,
},
PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete, PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete,
} }
provisioner, err := plug.(*awsElasticBlockStorePlugin).newProvisionerInternal(options, &fakePDManager{}) provisioner, err := plug.(*awsElasticBlockStorePlugin).newProvisionerInternal(options, &fakePDManager{})
@ -197,7 +192,7 @@ func TestPlugin(t *testing.T) {
if persistentSpec.Spec.PersistentVolumeSource.AWSElasticBlockStore.VolumeID != "test-aws-volume-name" { if persistentSpec.Spec.PersistentVolumeSource.AWSElasticBlockStore.VolumeID != "test-aws-volume-name" {
t.Errorf("Provision() returned unexpected volume ID: %s", persistentSpec.Spec.PersistentVolumeSource.AWSElasticBlockStore.VolumeID) t.Errorf("Provision() returned unexpected volume ID: %s", persistentSpec.Spec.PersistentVolumeSource.AWSElasticBlockStore.VolumeID)
} }
cap = persistentSpec.Spec.Capacity[api.ResourceStorage] cap := persistentSpec.Spec.Capacity[api.ResourceStorage]
size := cap.Value() size := cap.Value()
if size != 100*1024*1024*1024 { if size != 100*1024*1024*1024 {
t.Errorf("Provision() returned unexpected volume size: %v", size) t.Errorf("Provision() returned unexpected volume size: %v", size)

View File

@ -23,6 +23,7 @@ import (
"time" "time"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/cloudprovider" "k8s.io/kubernetes/pkg/cloudprovider"
"k8s.io/kubernetes/pkg/cloudprovider/providers/aws" "k8s.io/kubernetes/pkg/cloudprovider/providers/aws"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
@ -79,13 +80,14 @@ func (util *AWSDiskUtil) CreateVolume(c *awsElasticBlockStoreProvisioner) (strin
} }
tags["Name"] = volume.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 255) // AWS tags can have 255 characters tags["Name"] = volume.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 255) // AWS tags can have 255 characters
requestBytes := c.options.Capacity.Value() capacity := c.options.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)]
requestBytes := capacity.Value()
// AWS works with gigabytes, convert to GiB with rounding up // AWS works with gigabytes, convert to GiB with rounding up
requestGB := int(volume.RoundUpSize(requestBytes, 1024*1024*1024)) requestGB := int(volume.RoundUpSize(requestBytes, 1024*1024*1024))
volumeOptions := &aws.VolumeOptions{ volumeOptions := &aws.VolumeOptions{
CapacityGB: requestGB, CapacityGB: requestGB,
Tags: tags, Tags: tags,
PVCName: c.options.PVCName, PVCName: c.options.PVC.Name,
} }
// Apply Parameters (case-insensitive). We leave validation of // Apply Parameters (case-insensitive). We leave validation of
// the values to the cloud provider. // the values to the cloud provider.
@ -112,8 +114,8 @@ func (util *AWSDiskUtil) CreateVolume(c *awsElasticBlockStoreProvisioner) (strin
} }
} }
// TODO: implement c.options.ProvisionerSelector parsing // TODO: implement PVC.Selector parsing
if c.options.Selector != nil { if c.options.PVC.Spec.Selector != nil {
return "", 0, nil, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on AWS") return "", 0, nil, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on AWS")
} }

View File

@ -161,9 +161,6 @@ func (plugin *cinderPlugin) newDeleterInternal(spec *volume.Spec, manager cdMana
} }
func (plugin *cinderPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) { func (plugin *cinderPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) {
if len(options.AccessModes) == 0 {
options.AccessModes = plugin.GetAccessModes()
}
return plugin.newProvisionerInternal(options, &CinderDiskUtil{}) return plugin.newProvisionerInternal(options, &CinderDiskUtil{})
} }
@ -474,7 +471,7 @@ func (c *cinderVolumeProvisioner) Provision() (*api.PersistentVolume, error) {
}, },
Spec: api.PersistentVolumeSpec{ Spec: api.PersistentVolumeSpec{
PersistentVolumeReclaimPolicy: c.options.PersistentVolumeReclaimPolicy, PersistentVolumeReclaimPolicy: c.options.PersistentVolumeReclaimPolicy,
AccessModes: c.options.AccessModes, AccessModes: c.options.PVC.Spec.AccessModes,
Capacity: api.ResourceList{ Capacity: api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)), api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)),
}, },
@ -487,6 +484,10 @@ func (c *cinderVolumeProvisioner) Provision() (*api.PersistentVolume, error) {
}, },
}, },
} }
if len(c.options.PVC.Spec.AccessModes) == 0 {
pv.Spec.AccessModes = c.plugin.GetAccessModes()
}
return pv, nil return pv, nil
} }

View File

@ -24,7 +24,6 @@ import (
"time" "time"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/types" "k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/util/mount"
utiltesting "k8s.io/kubernetes/pkg/util/testing" utiltesting "k8s.io/kubernetes/pkg/util/testing"
@ -199,12 +198,8 @@ func TestPlugin(t *testing.T) {
} }
// Test Provisioner // Test Provisioner
cap := resource.MustParse("100Mi")
options := volume.VolumeOptions{ options := volume.VolumeOptions{
Capacity: cap, PVC: volumetest.CreateTestPVC("100Mi", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}),
AccessModes: []api.PersistentVolumeAccessMode{
api.ReadWriteOnce,
},
PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete, PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete,
} }
provisioner, err := plug.(*cinderPlugin).newProvisionerInternal(options, &fakePDManager{0}) provisioner, err := plug.(*cinderPlugin).newProvisionerInternal(options, &fakePDManager{0})
@ -216,7 +211,7 @@ func TestPlugin(t *testing.T) {
if persistentSpec.Spec.PersistentVolumeSource.Cinder.VolumeID != "test-volume-name" { if persistentSpec.Spec.PersistentVolumeSource.Cinder.VolumeID != "test-volume-name" {
t.Errorf("Provision() returned unexpected volume ID: %s", persistentSpec.Spec.PersistentVolumeSource.Cinder.VolumeID) t.Errorf("Provision() returned unexpected volume ID: %s", persistentSpec.Spec.PersistentVolumeSource.Cinder.VolumeID)
} }
cap = persistentSpec.Spec.Capacity[api.ResourceStorage] cap := persistentSpec.Spec.Capacity[api.ResourceStorage]
size := cap.Value() size := cap.Value()
if size != 1024*1024*1024 { if size != 1024*1024*1024 {
t.Errorf("Provision() returned unexpected volume size: %v", size) t.Errorf("Provision() returned unexpected volume size: %v", size)

View File

@ -24,6 +24,7 @@ import (
"time" "time"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/util/exec" "k8s.io/kubernetes/pkg/util/exec"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
) )
@ -139,7 +140,8 @@ func (util *CinderDiskUtil) CreateVolume(c *cinderVolumeProvisioner) (volumeID s
return "", 0, err return "", 0, err
} }
volSizeBytes := c.options.Capacity.Value() capacity := c.options.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)]
volSizeBytes := capacity.Value()
// Cinder works with gigabytes, convert to GiB with rounding up // Cinder works with gigabytes, convert to GiB with rounding up
volSizeGB := int(volume.RoundUpSize(volSizeBytes, 1024*1024*1024)) 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 name := volume.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 255) // Cinder volume name can have up to 255 characters
@ -157,8 +159,8 @@ func (util *CinderDiskUtil) CreateVolume(c *cinderVolumeProvisioner) (volumeID s
return "", 0, fmt.Errorf("invalid option %q for volume plugin %s", k, c.plugin.GetPluginName()) return "", 0, fmt.Errorf("invalid option %q for volume plugin %s", k, c.plugin.GetPluginName())
} }
} }
// TODO: implement c.options.ProvisionerSelector parsing // TODO: implement PVC.Selector parsing
if c.options.Selector != nil { if c.options.PVC.Spec.Selector != nil {
return "", 0, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on Cinder") return "", 0, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on Cinder")
} }

View File

@ -452,9 +452,6 @@ func (plugin *flockerPlugin) newDeleterInternal(spec *volume.Spec, manager volum
} }
func (plugin *flockerPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) { func (plugin *flockerPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) {
if len(options.AccessModes) == 0 {
options.AccessModes = plugin.GetAccessModes()
}
return plugin.newProvisionerInternal(options, &FlockerUtil{}) return plugin.newProvisionerInternal(options, &FlockerUtil{})
} }

View File

@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"time" "time"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/util/rand" "k8s.io/kubernetes/pkg/util/rand"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
@ -70,14 +71,15 @@ func (util *FlockerUtil) CreateVolume(c *flockerVolumeProvisioner) (datasetUUID
node := nodes[rand.Intn(len(nodes))] node := nodes[rand.Intn(len(nodes))]
glog.V(2).Infof("selected flocker node with UUID '%s' to provision dataset", node.UUID) glog.V(2).Infof("selected flocker node with UUID '%s' to provision dataset", node.UUID)
requestBytes := c.options.Capacity.Value() capacity := c.options.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)]
requestBytes := capacity.Value()
volumeSizeGB = int(volume.RoundUpSize(requestBytes, 1024*1024*1024)) volumeSizeGB = int(volume.RoundUpSize(requestBytes, 1024*1024*1024))
createOptions := &flockerApi.CreateDatasetOptions{ createOptions := &flockerApi.CreateDatasetOptions{
MaximumSize: requestBytes, MaximumSize: requestBytes,
Metadata: map[string]string{ Metadata: map[string]string{
"type": "k8s-dynamic-prov", "type": "k8s-dynamic-prov",
"pvc": c.options.PVCName, "pvc": c.options.PVC.Name,
}, },
Primary: node.UUID, Primary: node.UUID,
} }

View File

@ -21,8 +21,8 @@ import (
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -31,11 +31,9 @@ func TestFlockerUtil_CreateVolume(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
// test CreateVolume happy path // test CreateVolume happy path
pvc := volumetest.CreateTestPVC("3Gi", []api.PersistentVolumeAccessMode{api.ReadWriteOnce})
options := volume.VolumeOptions{ options := volume.VolumeOptions{
Capacity: resource.MustParse("3Gi"), PVC: pvc,
AccessModes: []api.PersistentVolumeAccessMode{
api.ReadWriteOnce,
},
PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete, PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete,
} }

View File

@ -58,7 +58,7 @@ func (c *flockerVolumeProvisioner) Provision() (*api.PersistentVolume, error) {
return nil, fmt.Errorf("Provisioning failed: Specified at least one unsupported parameter") return nil, fmt.Errorf("Provisioning failed: Specified at least one unsupported parameter")
} }
if c.options.Selector != nil { if c.options.PVC.Spec.Selector != nil {
return nil, fmt.Errorf("Provisioning failed: Specified unsupported selector") return nil, fmt.Errorf("Provisioning failed: Specified unsupported selector")
} }
@ -77,7 +77,7 @@ func (c *flockerVolumeProvisioner) Provision() (*api.PersistentVolume, error) {
}, },
Spec: api.PersistentVolumeSpec{ Spec: api.PersistentVolumeSpec{
PersistentVolumeReclaimPolicy: c.options.PersistentVolumeReclaimPolicy, PersistentVolumeReclaimPolicy: c.options.PersistentVolumeReclaimPolicy,
AccessModes: c.options.AccessModes, AccessModes: c.options.PVC.Spec.AccessModes,
Capacity: api.ResourceList{ Capacity: api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)), api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)),
}, },
@ -88,6 +88,9 @@ func (c *flockerVolumeProvisioner) Provision() (*api.PersistentVolume, error) {
}, },
}, },
} }
if len(c.options.PVC.Spec.AccessModes) == 0 {
pv.Spec.AccessModes = c.plugin.GetAccessModes()
}
if len(labels) != 0 { if len(labels) != 0 {
if pv.Labels == nil { if pv.Labels == nil {

View File

@ -21,7 +21,6 @@ import (
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
utiltesting "k8s.io/kubernetes/pkg/util/testing" utiltesting "k8s.io/kubernetes/pkg/util/testing"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
@ -48,12 +47,9 @@ func newTestableProvisioner(assert *assert.Assertions, options volume.VolumeOpti
func TestProvision(t *testing.T) { func TestProvision(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
cap := resource.MustParse("3Gi") pvc := volumetest.CreateTestPVC("3Gi", []api.PersistentVolumeAccessMode{api.ReadWriteOnce})
options := volume.VolumeOptions{ options := volume.VolumeOptions{
Capacity: cap, PVC: pvc,
AccessModes: []api.PersistentVolumeAccessMode{
api.ReadWriteOnce,
},
PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete, PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete,
} }
@ -62,7 +58,7 @@ func TestProvision(t *testing.T) {
persistentSpec, err := provisioner.Provision() persistentSpec, err := provisioner.Provision()
assert.NoError(err, "Provision() failed: ", err) assert.NoError(err, "Provision() failed: ", err)
cap = persistentSpec.Spec.Capacity[api.ResourceStorage] cap := persistentSpec.Spec.Capacity[api.ResourceStorage]
assert.Equal(int64(3*1024*1024*1024), cap.Value()) assert.Equal(int64(3*1024*1024*1024), cap.Value())
@ -78,10 +74,7 @@ func TestProvision(t *testing.T) {
// parameters are not supported // parameters are not supported
options = volume.VolumeOptions{ options = volume.VolumeOptions{
Capacity: cap, PVC: pvc,
AccessModes: []api.PersistentVolumeAccessMode{
api.ReadWriteOnce,
},
PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete, PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete,
Parameters: map[string]string{ Parameters: map[string]string{
"not-supported-params": "test123", "not-supported-params": "test123",
@ -93,13 +86,10 @@ func TestProvision(t *testing.T) {
assert.Error(err, "Provision() did not fail with Parameters specified") assert.Error(err, "Provision() did not fail with Parameters specified")
// selectors are not supported // selectors are not supported
pvc.Spec.Selector = &unversioned.LabelSelector{MatchLabels: map[string]string{"key": "value"}}
options = volume.VolumeOptions{ options = volume.VolumeOptions{
Capacity: cap, PVC: pvc,
AccessModes: []api.PersistentVolumeAccessMode{
api.ReadWriteOnce,
},
PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete, PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete,
Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"key": "value"}},
} }
provisioner = newTestableProvisioner(assert, options) provisioner = newTestableProvisioner(assert, options)

View File

@ -166,9 +166,6 @@ func (plugin *gcePersistentDiskPlugin) newDeleterInternal(spec *volume.Spec, man
} }
func (plugin *gcePersistentDiskPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) { func (plugin *gcePersistentDiskPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) {
if len(options.AccessModes) == 0 {
options.AccessModes = plugin.GetAccessModes()
}
return plugin.newProvisionerInternal(options, &GCEDiskUtil{}) return plugin.newProvisionerInternal(options, &GCEDiskUtil{})
} }
@ -393,7 +390,7 @@ func (c *gcePersistentDiskProvisioner) Provision() (*api.PersistentVolume, error
}, },
Spec: api.PersistentVolumeSpec{ Spec: api.PersistentVolumeSpec{
PersistentVolumeReclaimPolicy: c.options.PersistentVolumeReclaimPolicy, PersistentVolumeReclaimPolicy: c.options.PersistentVolumeReclaimPolicy,
AccessModes: c.options.AccessModes, AccessModes: c.options.PVC.Spec.AccessModes,
Capacity: api.ResourceList{ Capacity: api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)), api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)),
}, },
@ -406,6 +403,9 @@ func (c *gcePersistentDiskProvisioner) Provision() (*api.PersistentVolume, error
}, },
}, },
} }
if len(c.options.PVC.Spec.AccessModes) == 0 {
pv.Spec.AccessModes = c.plugin.GetAccessModes()
}
if len(labels) != 0 { if len(labels) != 0 {
if pv.Labels == nil { if pv.Labels == nil {

View File

@ -23,7 +23,6 @@ import (
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/types" "k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/util/mount"
@ -174,12 +173,8 @@ func TestPlugin(t *testing.T) {
} }
// Test Provisioner // Test Provisioner
cap := resource.MustParse("100Mi")
options := volume.VolumeOptions{ options := volume.VolumeOptions{
Capacity: cap, PVC: volumetest.CreateTestPVC("100Mi", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}),
AccessModes: []api.PersistentVolumeAccessMode{
api.ReadWriteOnce,
},
PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete, PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete,
} }
provisioner, err := plug.(*gcePersistentDiskPlugin).newProvisionerInternal(options, &fakePDManager{}) provisioner, err := plug.(*gcePersistentDiskPlugin).newProvisionerInternal(options, &fakePDManager{})
@ -191,7 +186,7 @@ func TestPlugin(t *testing.T) {
if persistentSpec.Spec.PersistentVolumeSource.GCEPersistentDisk.PDName != "test-gce-volume-name" { if persistentSpec.Spec.PersistentVolumeSource.GCEPersistentDisk.PDName != "test-gce-volume-name" {
t.Errorf("Provision() returned unexpected volume ID: %s", persistentSpec.Spec.PersistentVolumeSource.GCEPersistentDisk.PDName) t.Errorf("Provision() returned unexpected volume ID: %s", persistentSpec.Spec.PersistentVolumeSource.GCEPersistentDisk.PDName)
} }
cap = persistentSpec.Spec.Capacity[api.ResourceStorage] cap := persistentSpec.Spec.Capacity[api.ResourceStorage]
size := cap.Value() size := cap.Value()
if size != 100*1024*1024*1024 { if size != 100*1024*1024*1024 {
t.Errorf("Provision() returned unexpected volume size: %v", size) t.Errorf("Provision() returned unexpected volume size: %v", size)

View File

@ -24,6 +24,7 @@ import (
"time" "time"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/cloudprovider" "k8s.io/kubernetes/pkg/cloudprovider"
gcecloud "k8s.io/kubernetes/pkg/cloudprovider/providers/gce" gcecloud "k8s.io/kubernetes/pkg/cloudprovider/providers/gce"
"k8s.io/kubernetes/pkg/util/exec" "k8s.io/kubernetes/pkg/util/exec"
@ -77,7 +78,8 @@ func (gceutil *GCEDiskUtil) CreateVolume(c *gcePersistentDiskProvisioner) (strin
} }
name := volume.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 63) // GCE PD name can have up to 63 characters name := volume.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 63) // GCE PD name can have up to 63 characters
requestBytes := c.options.Capacity.Value() capacity := c.options.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)]
requestBytes := capacity.Value()
// GCE works with gigabytes, convert to GiB with rounding up // GCE works with gigabytes, convert to GiB with rounding up
requestGB := volume.RoundUpSize(requestBytes, 1024*1024*1024) requestGB := volume.RoundUpSize(requestBytes, 1024*1024*1024)
@ -96,8 +98,8 @@ func (gceutil *GCEDiskUtil) CreateVolume(c *gcePersistentDiskProvisioner) (strin
} }
} }
// TODO: implement c.options.ProvisionerSelector parsing // TODO: implement PVC.Selector parsing
if c.options.Selector != nil { if c.options.PVC.Spec.Selector != nil {
return "", 0, nil, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on GCE") return "", 0, nil, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on GCE")
} }
@ -109,7 +111,7 @@ func (gceutil *GCEDiskUtil) CreateVolume(c *gcePersistentDiskProvisioner) (strin
glog.V(2).Infof("error getting zone information from GCE: %v", err) glog.V(2).Infof("error getting zone information from GCE: %v", err)
return "", 0, nil, err return "", 0, nil, err
} }
zone = volume.ChooseZoneForVolume(zones, c.options.PVCName) zone = volume.ChooseZoneForVolume(zones, c.options.PVC.Name)
} }
err = cloud.CreateDisk(name, diskType, zone, int64(requestGB), *c.options.CloudTags) err = cloud.CreateDisk(name, diskType, zone, int64(requestGB), *c.options.CloudTags)

View File

@ -336,9 +336,6 @@ func getVolumeSource(
} }
func (plugin *glusterfsPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) { func (plugin *glusterfsPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) {
if len(options.AccessModes) == 0 {
options.AccessModes = plugin.GetAccessModes()
}
return plugin.newProvisionerInternal(options) return plugin.newProvisionerInternal(options)
} }
@ -441,7 +438,7 @@ func (d *glusterfsVolumeDeleter) Delete() error {
func (r *glusterfsVolumeProvisioner) Provision() (*api.PersistentVolume, error) { func (r *glusterfsVolumeProvisioner) Provision() (*api.PersistentVolume, error) {
var err error var err error
if r.options.Selector != nil { if r.options.PVC.Spec.Selector != nil {
glog.V(4).Infof("glusterfs: not able to parse your claim Selector") glog.V(4).Infof("glusterfs: not able to parse your claim Selector")
return nil, fmt.Errorf("glusterfs: not able to parse your claim Selector") return nil, fmt.Errorf("glusterfs: not able to parse your claim Selector")
} }
@ -507,7 +504,10 @@ func (r *glusterfsVolumeProvisioner) Provision() (*api.PersistentVolume, error)
pv := new(api.PersistentVolume) pv := new(api.PersistentVolume)
pv.Spec.PersistentVolumeSource.Glusterfs = glusterfs pv.Spec.PersistentVolumeSource.Glusterfs = glusterfs
pv.Spec.PersistentVolumeReclaimPolicy = r.options.PersistentVolumeReclaimPolicy pv.Spec.PersistentVolumeReclaimPolicy = r.options.PersistentVolumeReclaimPolicy
pv.Spec.AccessModes = r.options.AccessModes pv.Spec.AccessModes = r.options.PVC.Spec.AccessModes
if len(pv.Spec.AccessModes) == 0 {
pv.Spec.AccessModes = r.plugin.GetAccessModes()
}
pv.Spec.Capacity = api.ResourceList{ pv.Spec.Capacity = api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)), api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)),
} }
@ -516,7 +516,8 @@ func (r *glusterfsVolumeProvisioner) Provision() (*api.PersistentVolume, error)
} }
func (p *glusterfsVolumeProvisioner) CreateVolume() (r *api.GlusterfsVolumeSource, size int, err error) { func (p *glusterfsVolumeProvisioner) CreateVolume() (r *api.GlusterfsVolumeSource, size int, err error) {
volSizeBytes := p.options.Capacity.Value() capacity := p.options.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)]
volSizeBytes := capacity.Value()
sz := int(volume.RoundUpSize(volSizeBytes, 1024*1024*1024)) sz := int(volume.RoundUpSize(volSizeBytes, 1024*1024*1024))
glog.V(2).Infof("glusterfs: create volume of size: %d bytes and configuration %+v", volSizeBytes, p.provisioningConfig) glog.V(2).Infof("glusterfs: create volume of size: %d bytes and configuration %+v", volSizeBytes, p.provisioningConfig)
if p.url == "" { if p.url == "" {

View File

@ -48,7 +48,7 @@ type hostPathPlugin struct {
// decouple creating Recyclers/Deleters/Provisioners by deferring to a function. Allows for easier testing. // decouple creating Recyclers/Deleters/Provisioners by deferring to a function. Allows for easier testing.
newRecyclerFunc func(pvName string, spec *volume.Spec, eventRecorder volume.RecycleEventRecorder, host volume.VolumeHost, volumeConfig volume.VolumeConfig) (volume.Recycler, error) newRecyclerFunc func(pvName string, spec *volume.Spec, eventRecorder volume.RecycleEventRecorder, host volume.VolumeHost, volumeConfig volume.VolumeConfig) (volume.Recycler, error)
newDeleterFunc func(spec *volume.Spec, host volume.VolumeHost) (volume.Deleter, error) newDeleterFunc func(spec *volume.Spec, host volume.VolumeHost) (volume.Deleter, error)
newProvisionerFunc func(options volume.VolumeOptions, host volume.VolumeHost) (volume.Provisioner, error) newProvisionerFunc func(options volume.VolumeOptions, host volume.VolumeHost, plugin *hostPathPlugin) (volume.Provisioner, error)
config volume.VolumeConfig config volume.VolumeConfig
} }
@ -124,10 +124,7 @@ func (plugin *hostPathPlugin) NewProvisioner(options volume.VolumeOptions) (volu
if !plugin.config.ProvisioningEnabled { if !plugin.config.ProvisioningEnabled {
return nil, fmt.Errorf("Provisioning in volume plugin %q is disabled", plugin.GetPluginName()) return nil, fmt.Errorf("Provisioning in volume plugin %q is disabled", plugin.GetPluginName())
} }
if len(options.AccessModes) == 0 { return plugin.newProvisionerFunc(options, plugin.host, plugin)
options.AccessModes = plugin.GetAccessModes()
}
return plugin.newProvisionerFunc(options, plugin.host)
} }
func (plugin *hostPathPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *hostPathPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
@ -166,8 +163,8 @@ func newDeleter(spec *volume.Spec, host volume.VolumeHost) (volume.Deleter, erro
return &hostPathDeleter{name: spec.Name(), path: path, host: host}, nil return &hostPathDeleter{name: spec.Name(), path: path, host: host}, nil
} }
func newProvisioner(options volume.VolumeOptions, host volume.VolumeHost) (volume.Provisioner, error) { func newProvisioner(options volume.VolumeOptions, host volume.VolumeHost, plugin *hostPathPlugin) (volume.Provisioner, error) {
return &hostPathProvisioner{options: options, host: host}, nil return &hostPathProvisioner{options: options, host: host, plugin: plugin}, nil
} }
// HostPath volumes represent a bare host file or directory mount. // HostPath volumes represent a bare host file or directory mount.
@ -263,6 +260,7 @@ func (r *hostPathRecycler) Recycle() error {
type hostPathProvisioner struct { type hostPathProvisioner struct {
host volume.VolumeHost host volume.VolumeHost
options volume.VolumeOptions options volume.VolumeOptions
plugin *hostPathPlugin
} }
// Create for hostPath simply creates a local /tmp/hostpath_pv/%s directory as a new PersistentVolume. // Create for hostPath simply creates a local /tmp/hostpath_pv/%s directory as a new PersistentVolume.
@ -270,6 +268,7 @@ type hostPathProvisioner struct {
func (r *hostPathProvisioner) Provision() (*api.PersistentVolume, error) { func (r *hostPathProvisioner) Provision() (*api.PersistentVolume, error) {
fullpath := fmt.Sprintf("/tmp/hostpath_pv/%s", uuid.NewUUID()) fullpath := fmt.Sprintf("/tmp/hostpath_pv/%s", uuid.NewUUID())
capacity := r.options.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)]
pv := &api.PersistentVolume{ pv := &api.PersistentVolume{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: r.options.PVName, Name: r.options.PVName,
@ -279,9 +278,9 @@ func (r *hostPathProvisioner) Provision() (*api.PersistentVolume, error) {
}, },
Spec: api.PersistentVolumeSpec{ Spec: api.PersistentVolumeSpec{
PersistentVolumeReclaimPolicy: r.options.PersistentVolumeReclaimPolicy, PersistentVolumeReclaimPolicy: r.options.PersistentVolumeReclaimPolicy,
AccessModes: r.options.AccessModes, AccessModes: r.options.PVC.Spec.AccessModes,
Capacity: api.ResourceList{ Capacity: api.ResourceList{
api.ResourceName(api.ResourceStorage): r.options.Capacity, api.ResourceName(api.ResourceStorage): capacity,
}, },
PersistentVolumeSource: api.PersistentVolumeSource{ PersistentVolumeSource: api.PersistentVolumeSource{
HostPath: &api.HostPathVolumeSource{ HostPath: &api.HostPathVolumeSource{
@ -290,6 +289,9 @@ func (r *hostPathProvisioner) Provision() (*api.PersistentVolume, error) {
}, },
}, },
} }
if len(r.options.PVC.Spec.AccessModes) == 0 {
pv.Spec.AccessModes = r.plugin.GetAccessModes()
}
return pv, os.MkdirAll(pv.Spec.HostPath.Path, 0750) return pv, os.MkdirAll(pv.Spec.HostPath.Path, 0750)
} }

View File

@ -161,7 +161,11 @@ func TestProvisioner(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Can't find the plugin by name") t.Errorf("Can't find the plugin by name")
} }
creater, err := plug.NewProvisioner(volume.VolumeOptions{Capacity: resource.MustParse("1Gi"), PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete}) options := volume.VolumeOptions{
PVC: volumetest.CreateTestPVC("1Gi", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}),
PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete,
}
creater, err := plug.NewProvisioner(options)
if err != nil { if err != nil {
t.Errorf("Failed to make a new Provisioner: %v", err) t.Errorf("Failed to make a new Provisioner: %v", err)
} }

View File

@ -24,8 +24,6 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/unversioned"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/cloudprovider" "k8s.io/kubernetes/pkg/cloudprovider"
"k8s.io/kubernetes/pkg/types" "k8s.io/kubernetes/pkg/types"
@ -41,25 +39,22 @@ type VolumeOptions struct {
// TODO: refactor all of this out of volumes when an admin can configure // TODO: refactor all of this out of volumes when an admin can configure
// many kinds of provisioners. // many kinds of provisioners.
// Capacity is the size of a volume.
Capacity resource.Quantity
// AccessModes of a volume
AccessModes []api.PersistentVolumeAccessMode
// Reclamation policy for a persistent volume // Reclamation policy for a persistent volume
PersistentVolumeReclaimPolicy api.PersistentVolumeReclaimPolicy PersistentVolumeReclaimPolicy api.PersistentVolumeReclaimPolicy
// PV.Name of the appropriate PersistentVolume. Used to generate cloud // PV.Name of the appropriate PersistentVolume. Used to generate cloud
// volume name. // volume name.
PVName string PVName string
// PVC.Name of the PersistentVolumeClaim; only set during dynamic provisioning. // PVC is reference to the claim that lead to provisioning of a new PV.
PVCName string // Provisioners *must* create a PV that would be matched by this PVC,
// i.e. with required capacity, accessMode, labels matching PVC.Selector and
// so on.
PVC *api.PersistentVolumeClaim
// Unique name of Kubernetes cluster. // Unique name of Kubernetes cluster.
ClusterName string ClusterName string
// Tags to attach to the real volume in the cloud provider - e.g. AWS EBS // Tags to attach to the real volume in the cloud provider - e.g. AWS EBS
CloudTags *map[string]string CloudTags *map[string]string
// Volume provisioning parameters from StorageClass // Volume provisioning parameters from StorageClass
Parameters map[string]string Parameters map[string]string
// Volume selector from PersistentVolumeClaim
Selector *unversioned.LabelSelector
} }
// VolumePlugin is an interface to volume plugins that can be used on a // VolumePlugin is an interface to volume plugins that can be used on a

View File

@ -320,10 +320,6 @@ func (plugin *quobytePlugin) newDeleterInternal(spec *volume.Spec) (volume.Delet
} }
func (plugin *quobytePlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) { func (plugin *quobytePlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) {
if len(options.AccessModes) == 0 {
options.AccessModes = plugin.GetAccessModes()
}
return plugin.newProvisionerInternal(options) return plugin.newProvisionerInternal(options)
} }
@ -344,7 +340,7 @@ type quobyteVolumeProvisioner struct {
} }
func (provisioner *quobyteVolumeProvisioner) Provision() (*api.PersistentVolume, error) { func (provisioner *quobyteVolumeProvisioner) Provision() (*api.PersistentVolume, error) {
if provisioner.options.Selector != nil { if provisioner.options.PVC.Spec.Selector != nil {
return nil, fmt.Errorf("claim Selector is not supported") return nil, fmt.Errorf("claim Selector is not supported")
} }
var apiServer, adminSecretName, quobyteUser, quobytePassword string var apiServer, adminSecretName, quobyteUser, quobytePassword string
@ -416,7 +412,10 @@ func (provisioner *quobyteVolumeProvisioner) Provision() (*api.PersistentVolume,
pv := new(api.PersistentVolume) pv := new(api.PersistentVolume)
pv.Spec.PersistentVolumeSource.Quobyte = vol pv.Spec.PersistentVolumeSource.Quobyte = vol
pv.Spec.PersistentVolumeReclaimPolicy = provisioner.options.PersistentVolumeReclaimPolicy pv.Spec.PersistentVolumeReclaimPolicy = provisioner.options.PersistentVolumeReclaimPolicy
pv.Spec.AccessModes = provisioner.options.AccessModes pv.Spec.AccessModes = provisioner.options.PVC.Spec.AccessModes
if len(pv.Spec.AccessModes) == 0 {
pv.Spec.AccessModes = provisioner.plugin.GetAccessModes()
}
pv.Spec.Capacity = api.ResourceList{ pv.Spec.Capacity = api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)), api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)),
} }

View File

@ -33,7 +33,8 @@ type quobyteVolumeManager struct {
} }
func (manager *quobyteVolumeManager) createVolume(provisioner *quobyteVolumeProvisioner) (quobyte *api.QuobyteVolumeSource, size int, err error) { func (manager *quobyteVolumeManager) createVolume(provisioner *quobyteVolumeProvisioner) (quobyte *api.QuobyteVolumeSource, size int, err error) {
volumeSize := int(volume.RoundUpSize(provisioner.options.Capacity.Value(), 1024*1024*1024)) capacity := provisioner.options.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)]
volumeSize := int(volume.RoundUpSize(capacity.Value(), 1024*1024*1024))
// Quobyte has the concept of Volumes which doen't have a specific size (they can grow unlimited) // Quobyte has the concept of Volumes which doen't have a specific size (they can grow unlimited)
// to simulate a size constraint we could set here a Quota // to simulate a size constraint we could set here a Quota
volumeRequest := &quobyte_api.CreateVolumeRequest{ volumeRequest := &quobyte_api.CreateVolumeRequest{

View File

@ -213,9 +213,6 @@ func (plugin *rbdPlugin) newDeleterInternal(spec *volume.Spec, admin, secret str
} }
func (plugin *rbdPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) { func (plugin *rbdPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) {
if len(options.AccessModes) == 0 {
options.AccessModes = plugin.GetAccessModes()
}
return plugin.newProvisionerInternal(options, &RBDUtil{}) return plugin.newProvisionerInternal(options, &RBDUtil{})
} }
@ -237,7 +234,7 @@ type rbdVolumeProvisioner struct {
} }
func (r *rbdVolumeProvisioner) Provision() (*api.PersistentVolume, error) { func (r *rbdVolumeProvisioner) Provision() (*api.PersistentVolume, error) {
if r.options.Selector != nil { if r.options.PVC.Spec.Selector != nil {
return nil, fmt.Errorf("claim Selector is not supported") return nil, fmt.Errorf("claim Selector is not supported")
} }
var err error var err error
@ -309,7 +306,10 @@ func (r *rbdVolumeProvisioner) Provision() (*api.PersistentVolume, error) {
rbd.RadosUser = r.Id rbd.RadosUser = r.Id
pv.Spec.PersistentVolumeSource.RBD = rbd pv.Spec.PersistentVolumeSource.RBD = rbd
pv.Spec.PersistentVolumeReclaimPolicy = r.options.PersistentVolumeReclaimPolicy pv.Spec.PersistentVolumeReclaimPolicy = r.options.PersistentVolumeReclaimPolicy
pv.Spec.AccessModes = r.options.AccessModes pv.Spec.AccessModes = r.options.PVC.Spec.AccessModes
if len(pv.Spec.AccessModes) == 0 {
pv.Spec.AccessModes = r.plugin.GetAccessModes()
}
pv.Spec.Capacity = api.ResourceList{ pv.Spec.Capacity = api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dMi", sizeMB)), api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dMi", sizeMB)),
} }

View File

@ -314,7 +314,8 @@ func (util *RBDUtil) DetachDisk(c rbdUnmounter, mntPath string) error {
} }
func (util *RBDUtil) CreateImage(p *rbdVolumeProvisioner) (r *api.RBDVolumeSource, size int, err error) { func (util *RBDUtil) CreateImage(p *rbdVolumeProvisioner) (r *api.RBDVolumeSource, size int, err error) {
volSizeBytes := p.options.Capacity.Value() capacity := p.options.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)]
volSizeBytes := capacity.Value()
// convert to MB that rbd defaults on // convert to MB that rbd defaults on
sz := int(volume.RoundUpSize(volSizeBytes, 1024*1024)) sz := int(volume.RoundUpSize(volSizeBytes, 1024*1024))
volSz := fmt.Sprintf("%d", sz) volSz := fmt.Sprintf("%d", sz)

View File

@ -497,9 +497,9 @@ func (fc *FakeProvisioner) Provision() (*api.PersistentVolume, error) {
}, },
Spec: api.PersistentVolumeSpec{ Spec: api.PersistentVolumeSpec{
PersistentVolumeReclaimPolicy: fc.Options.PersistentVolumeReclaimPolicy, PersistentVolumeReclaimPolicy: fc.Options.PersistentVolumeReclaimPolicy,
AccessModes: fc.Options.AccessModes, AccessModes: fc.Options.PVC.Spec.AccessModes,
Capacity: api.ResourceList{ Capacity: api.ResourceList{
api.ResourceName(api.ResourceStorage): fc.Options.Capacity, api.ResourceName(api.ResourceStorage): fc.Options.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)],
}, },
PersistentVolumeSource: api.PersistentVolumeSource{ PersistentVolumeSource: api.PersistentVolumeSource{
HostPath: &api.HostPathVolumeSource{ HostPath: &api.HostPathVolumeSource{
@ -746,3 +746,22 @@ func GetTestVolumePluginMgr(
return &v.pluginMgr, plugins[0].(*FakeVolumePlugin) return &v.pluginMgr, plugins[0].(*FakeVolumePlugin)
} }
// CreateTestPVC returns a provisionable PVC for tests
func CreateTestPVC(capacity string, accessModes []api.PersistentVolumeAccessMode) *api.PersistentVolumeClaim {
claim := api.PersistentVolumeClaim{
ObjectMeta: api.ObjectMeta{
Name: "dummy",
Namespace: "default",
},
Spec: api.PersistentVolumeClaimSpec{
AccessModes: accessModes,
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse(capacity),
},
},
},
}
return &claim
}

View File

@ -321,9 +321,6 @@ type vsphereVolumeProvisioner struct {
var _ volume.Provisioner = &vsphereVolumeProvisioner{} var _ volume.Provisioner = &vsphereVolumeProvisioner{}
func (plugin *vsphereVolumePlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) { func (plugin *vsphereVolumePlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) {
if len(options.AccessModes) == 0 {
options.AccessModes = plugin.GetAccessModes()
}
return plugin.newProvisionerInternal(options, &VsphereDiskUtil{}) return plugin.newProvisionerInternal(options, &VsphereDiskUtil{})
} }
@ -353,7 +350,7 @@ func (v *vsphereVolumeProvisioner) Provision() (*api.PersistentVolume, error) {
}, },
Spec: api.PersistentVolumeSpec{ Spec: api.PersistentVolumeSpec{
PersistentVolumeReclaimPolicy: v.options.PersistentVolumeReclaimPolicy, PersistentVolumeReclaimPolicy: v.options.PersistentVolumeReclaimPolicy,
AccessModes: v.options.AccessModes, AccessModes: v.options.PVC.Spec.AccessModes,
Capacity: api.ResourceList{ Capacity: api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dKi", sizeKB)), api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dKi", sizeKB)),
}, },
@ -365,6 +362,10 @@ func (v *vsphereVolumeProvisioner) Provision() (*api.PersistentVolume, error) {
}, },
}, },
} }
if len(v.options.PVC.Spec.AccessModes) == 0 {
pv.Spec.AccessModes = v.plugin.GetAccessModes()
}
return pv, nil return pv, nil
} }

View File

@ -23,7 +23,6 @@ import (
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/types" "k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/util/mount"
utiltesting "k8s.io/kubernetes/pkg/util/testing" utiltesting "k8s.io/kubernetes/pkg/util/testing"
@ -142,12 +141,8 @@ func TestPlugin(t *testing.T) {
} }
// Test Provisioner // Test Provisioner
cap := resource.MustParse("100Mi")
options := volume.VolumeOptions{ options := volume.VolumeOptions{
Capacity: cap, PVC: volumetest.CreateTestPVC("100Mi", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}),
AccessModes: []api.PersistentVolumeAccessMode{
api.ReadWriteOnce,
},
PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete, PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete,
} }
provisioner, err := plug.(*vsphereVolumePlugin).newProvisionerInternal(options, &fakePDManager{}) provisioner, err := plug.(*vsphereVolumePlugin).newProvisionerInternal(options, &fakePDManager{})
@ -160,7 +155,7 @@ func TestPlugin(t *testing.T) {
t.Errorf("Provision() returned unexpected path %s", persistentSpec.Spec.PersistentVolumeSource.VsphereVolume.VolumePath) t.Errorf("Provision() returned unexpected path %s", persistentSpec.Spec.PersistentVolumeSource.VsphereVolume.VolumePath)
} }
cap = persistentSpec.Spec.Capacity[api.ResourceStorage] cap := persistentSpec.Spec.Capacity[api.ResourceStorage]
size := cap.Value() size := cap.Value()
if size != 100*1024 { if size != 100*1024 {
t.Errorf("Provision() returned unexpected volume size: %v", size) t.Errorf("Provision() returned unexpected volume size: %v", size)

View File

@ -23,6 +23,7 @@ import (
"time" "time"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/cloudprovider" "k8s.io/kubernetes/pkg/cloudprovider"
"k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere" "k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
@ -57,7 +58,8 @@ func (util *VsphereDiskUtil) CreateVolume(v *vsphereVolumeProvisioner) (vmDiskPa
return "", 0, err return "", 0, err
} }
volSizeBytes := v.options.Capacity.Value() capacity := v.options.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)]
volSizeBytes := capacity.Value()
// vSphere works with kilobytes, convert to KiB with rounding up // vSphere works with kilobytes, convert to KiB with rounding up
volSizeKB := int(volume.RoundUpSize(volSizeBytes, 1024)) volSizeKB := int(volume.RoundUpSize(volSizeBytes, 1024))
name := volume.GenerateVolumeName(v.options.ClusterName, v.options.PVName, 255) name := volume.GenerateVolumeName(v.options.ClusterName, v.options.PVName, 255)
@ -78,8 +80,8 @@ func (util *VsphereDiskUtil) CreateVolume(v *vsphereVolumeProvisioner) (vmDiskPa
} }
} }
// TODO: implement v.options.ProvisionerSelector parsing // TODO: implement PVC.Selector parsing
if v.options.Selector != nil { if v.options.PVC.Spec.Selector != nil {
return "", 0, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on vSphere") return "", 0, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on vSphere")
} }