mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-04 09:49:50 +00:00
Merge pull request #34611 from jsafrane/provision-pvc
Automatic merge from submit-queue Pass whole PVC to provisioner plugins Gluster provisioner is interested in namespace of PVCs that are being provisioned and I don't want to add at as a new field in `volume.VolumeOptions` - it would contain almost whole PVC. Let's rework `VolumeOptions` and pass direct reference to PVC there instead of some "interesting" fields and let the provisioner to pick information it is interested in. There was lot of refactoring in volume plugins to apply this change (too many plugins), however the logic is simple and it's all the same in all plugins. @rootfs @humblec
This commit is contained in:
commit
4e393fadf3
@ -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{},
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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 == "" {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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)),
|
||||||
}
|
}
|
||||||
|
@ -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{
|
||||||
|
@ -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)),
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user