mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 20:24:09 +00:00
Merge pull request #64447 from jsafrane/block-provision
Automatic merge from submit-queue (batch tested with PRs 63348, 63839, 63143, 64447, 64567). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Add block volume support to internal provisioners. **What this PR does / why we need it**: Internal provisioners now create filesystem PVs when block PVs are requested. This leads to unbindable PVCs. In this PR, volume plugins that support block volumes provision block PVs when block is requested. All the other provisioners return clear error in `kubectl describe pvc`: ``` Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning ProvisioningFailed 7s (x2 over 18s) persistentvolume-controller Failed to provision volume with StorageClass "standard": kubernetes.io/cinder does not support block volume provisioning ``` ```release-note NONE ``` cc @kubernetes/vmware for vsphere changes cc @andyzhangx for Azure changes /assign @copejon @mtanino
This commit is contained in:
commit
38d2dc7068
@ -19,6 +19,7 @@ go_library(
|
||||
deps = [
|
||||
"//pkg/cloudprovider:go_default_library",
|
||||
"//pkg/cloudprovider/providers/aws:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//pkg/util/mount:go_default_library",
|
||||
"//pkg/util/strings:go_default_library",
|
||||
"//pkg/volume:go_default_library",
|
||||
@ -29,6 +30,7 @@ go_library(
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -28,7 +28,9 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/aws"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
kstrings "k8s.io/kubernetes/pkg/util/strings"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
@ -507,5 +509,9 @@ func (c *awsElasticBlockStoreProvisioner) Provision() (*v1.PersistentVolume, err
|
||||
}
|
||||
}
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
|
||||
pv.Spec.VolumeMode = c.options.PVC.Spec.VolumeMode
|
||||
}
|
||||
|
||||
return pv, nil
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ go_library(
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/cloudprovider:go_default_library",
|
||||
"//pkg/cloudprovider/providers/azure:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//pkg/util/keymutex:go_default_library",
|
||||
"//pkg/util/mount:go_default_library",
|
||||
"//pkg/util/strings:go_default_library",
|
||||
@ -71,6 +72,7 @@ go_library(
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -23,6 +23,8 @@ import (
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
"k8s.io/kubernetes/pkg/volume/util"
|
||||
)
|
||||
@ -187,5 +189,10 @@ func (p *azureDiskProvisioner) Provision() (*v1.PersistentVolume, error) {
|
||||
MountOptions: p.options.MountOptions,
|
||||
},
|
||||
}
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
|
||||
pv.Spec.VolumeMode = p.options.PVC.Spec.VolumeMode
|
||||
}
|
||||
|
||||
return pv, nil
|
||||
}
|
||||
|
@ -135,6 +135,9 @@ func (a *azureFileProvisioner) Provision() (*v1.PersistentVolume, error) {
|
||||
if !util.AccessModesContainedInAll(a.plugin.GetAccessModes(), a.options.PVC.Spec.AccessModes) {
|
||||
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", a.options.PVC.Spec.AccessModes, a.plugin.GetAccessModes())
|
||||
}
|
||||
if util.CheckPersistentVolumeClaimModeBlock(a.options.PVC) {
|
||||
return nil, fmt.Errorf("%s does not support block volume provisioning", a.plugin.GetPluginName())
|
||||
}
|
||||
|
||||
var sku, location, account string
|
||||
|
||||
|
@ -508,6 +508,10 @@ func (c *cinderVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
|
||||
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", c.options.PVC.Spec.AccessModes, c.plugin.GetAccessModes())
|
||||
}
|
||||
|
||||
if util.CheckPersistentVolumeClaimModeBlock(c.options.PVC) {
|
||||
return nil, fmt.Errorf("%s does not support block volume provisioning", c.plugin.GetPluginName())
|
||||
}
|
||||
|
||||
volumeID, sizeGB, labels, fstype, err := c.manager.CreateVolume(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -67,6 +67,10 @@ func (c *flockerVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
|
||||
return nil, fmt.Errorf("Provisioning failed: Specified unsupported selector")
|
||||
}
|
||||
|
||||
if util.CheckPersistentVolumeClaimModeBlock(c.options.PVC) {
|
||||
return nil, fmt.Errorf("%s does not support block volume provisioning", c.plugin.GetPluginName())
|
||||
}
|
||||
|
||||
datasetUUID, sizeGB, labels, err := c.manager.CreateVolume(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -27,6 +27,8 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
kstrings "k8s.io/kubernetes/pkg/util/strings"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
@ -448,5 +450,9 @@ func (c *gcePersistentDiskProvisioner) Provision() (*v1.PersistentVolume, error)
|
||||
}
|
||||
}
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
|
||||
pv.Spec.VolumeMode = c.options.PVC.Spec.VolumeMode
|
||||
}
|
||||
|
||||
return pv, nil
|
||||
}
|
||||
|
@ -673,6 +673,11 @@ func (p *glusterfsVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
|
||||
glog.V(4).Infof("not able to parse your claim Selector")
|
||||
return nil, fmt.Errorf("not able to parse your claim Selector")
|
||||
}
|
||||
|
||||
if volutil.CheckPersistentVolumeClaimModeBlock(p.options.PVC) {
|
||||
return nil, fmt.Errorf("%s does not support block volume provisioning", p.plugin.GetPluginName())
|
||||
}
|
||||
|
||||
glog.V(4).Infof("Provision VolumeOptions %v", p.options)
|
||||
scName := v1helper.GetPersistentVolumeClaimClass(p.options.PVC)
|
||||
cfg, err := parseClassParameters(p.options.Parameters, p.plugin.host.GetKubeClient())
|
||||
|
@ -266,6 +266,10 @@ type hostPathProvisioner struct {
|
||||
// Create for hostPath simply creates a local /tmp/hostpath_pv/%s directory as a new PersistentVolume.
|
||||
// This Provisioner is meant for development and testing only and WILL NOT WORK in a multi-node cluster.
|
||||
func (r *hostPathProvisioner) Provision() (*v1.PersistentVolume, error) {
|
||||
if util.CheckPersistentVolumeClaimModeBlock(r.options.PVC) {
|
||||
return nil, fmt.Errorf("%s does not support block volume provisioning", r.plugin.GetPluginName())
|
||||
}
|
||||
|
||||
fullpath := fmt.Sprintf("/tmp/hostpath_pv/%s", uuid.NewUUID())
|
||||
|
||||
capacity := r.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
|
||||
|
@ -345,6 +345,10 @@ func (p *photonPersistentDiskProvisioner) Provision() (*v1.PersistentVolume, err
|
||||
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", p.options.PVC.Spec.AccessModes, p.plugin.GetAccessModes())
|
||||
}
|
||||
|
||||
if util.CheckPersistentVolumeClaimModeBlock(p.options.PVC) {
|
||||
return nil, fmt.Errorf("%s does not support block volume provisioning", p.plugin.GetPluginName())
|
||||
}
|
||||
|
||||
pdID, sizeGB, fstype, err := p.manager.CreateVolume(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -383,6 +383,10 @@ func (c *portworxVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
|
||||
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", c.options.PVC.Spec.AccessModes, c.plugin.GetAccessModes())
|
||||
}
|
||||
|
||||
if util.CheckPersistentVolumeClaimModeBlock(c.options.PVC) {
|
||||
return nil, fmt.Errorf("%s does not support block volume provisioning", c.plugin.GetPluginName())
|
||||
}
|
||||
|
||||
volumeID, sizeGiB, labels, err := c.manager.CreateVolume(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -359,6 +359,10 @@ func (provisioner *quobyteVolumeProvisioner) Provision() (*v1.PersistentVolume,
|
||||
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", provisioner.options.PVC.Spec.AccessModes, provisioner.plugin.GetAccessModes())
|
||||
}
|
||||
|
||||
if util.CheckPersistentVolumeClaimModeBlock(provisioner.options.PVC) {
|
||||
return nil, fmt.Errorf("%s does not support block volume provisioning", provisioner.plugin.GetPluginName())
|
||||
}
|
||||
|
||||
if provisioner.options.PVC.Spec.Selector != nil {
|
||||
return nil, fmt.Errorf("claim Selector is not supported")
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ go_library(
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/volume/rbd",
|
||||
deps = [
|
||||
"//pkg/features:go_default_library",
|
||||
"//pkg/util/file:go_default_library",
|
||||
"//pkg/util/mount:go_default_library",
|
||||
"//pkg/util/node:go_default_library",
|
||||
@ -33,6 +34,7 @@ go_library(
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -30,7 +30,9 @@ import (
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
"k8s.io/kubernetes/pkg/util/strings"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
@ -698,6 +700,11 @@ func (r *rbdVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
|
||||
v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dMi", sizeMB)),
|
||||
}
|
||||
pv.Spec.MountOptions = r.options.MountOptions
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
|
||||
pv.Spec.VolumeMode = r.options.PVC.Spec.VolumeMode
|
||||
}
|
||||
|
||||
return pv, nil
|
||||
}
|
||||
|
||||
|
@ -259,6 +259,10 @@ func (v *sioVolume) Provision() (*api.PersistentVolume, error) {
|
||||
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", v.options.PVC.Spec.AccessModes, v.plugin.GetAccessModes())
|
||||
}
|
||||
|
||||
if util.CheckPersistentVolumeClaimModeBlock(v.options.PVC) {
|
||||
return nil, fmt.Errorf("%s does not support block volume provisioning", v.plugin.GetPluginName())
|
||||
}
|
||||
|
||||
// setup volume attrributes
|
||||
genName := v.generateName("k8svol", 11)
|
||||
var oneGig int64 = 1024 * 1024 * 1024
|
||||
|
@ -564,6 +564,9 @@ func (c *storageosProvisioner) Provision() (*v1.PersistentVolume, error) {
|
||||
if !util.AccessModesContainedInAll(c.plugin.GetAccessModes(), c.options.PVC.Spec.AccessModes) {
|
||||
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", c.options.PVC.Spec.AccessModes, c.plugin.GetAccessModes())
|
||||
}
|
||||
if util.CheckPersistentVolumeClaimModeBlock(c.options.PVC) {
|
||||
return nil, fmt.Errorf("%s does not support block volume provisioning", c.plugin.GetPluginName())
|
||||
}
|
||||
|
||||
var adminSecretName, adminSecretNamespace string
|
||||
|
||||
|
@ -718,6 +718,12 @@ func CheckVolumeModeFilesystem(volumeSpec *volume.Spec) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// CheckPersistentVolumeClaimModeBlock checks VolumeMode.
|
||||
// If the mode is Block, return true otherwise return false.
|
||||
func CheckPersistentVolumeClaimModeBlock(pvc *v1.PersistentVolumeClaim) bool {
|
||||
return utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) && pvc.Spec.VolumeMode != nil && *pvc.Spec.VolumeMode == v1.PersistentVolumeBlock
|
||||
}
|
||||
|
||||
// MakeAbsolutePath convert path to absolute path according to GOOS
|
||||
func MakeAbsolutePath(goos, path string) string {
|
||||
if goos != "windows" {
|
||||
|
@ -352,6 +352,9 @@ func (v *vsphereVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
|
||||
if !util.AccessModesContainedInAll(v.plugin.GetAccessModes(), v.options.PVC.Spec.AccessModes) {
|
||||
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", v.options.PVC.Spec.AccessModes, v.plugin.GetAccessModes())
|
||||
}
|
||||
if util.CheckPersistentVolumeClaimModeBlock(v.options.PVC) {
|
||||
return nil, fmt.Errorf("%s does not support block volume provisioning", v.plugin.GetPluginName())
|
||||
}
|
||||
|
||||
volSpec, err := v.manager.CreateVolume(v)
|
||||
if err != nil {
|
||||
|
@ -57,6 +57,7 @@ type storageClassTest struct {
|
||||
pvCheck func(volume *v1.PersistentVolume) error
|
||||
nodeName string
|
||||
attach bool
|
||||
volumeMode *v1.PersistentVolumeMode
|
||||
}
|
||||
|
||||
const (
|
||||
@ -120,6 +121,10 @@ func testDynamicProvisioning(t storageClassTest, client clientset.Interface, cla
|
||||
Expect(pv.Spec.PersistentVolumeReclaimPolicy).To(Equal(*class.ReclaimPolicy))
|
||||
Expect(pv.Spec.MountOptions).To(Equal(class.MountOptions))
|
||||
}
|
||||
if t.volumeMode != nil {
|
||||
Expect(pv.Spec.VolumeMode).NotTo(BeNil())
|
||||
Expect(*pv.Spec.VolumeMode).To(Equal(*t.volumeMode))
|
||||
}
|
||||
|
||||
// Run the checker
|
||||
if t.pvCheck != nil {
|
||||
@ -818,6 +823,34 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
|
||||
testDynamicProvisioning(test, c, claim, class)
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Block volume provisioning [Feature:BlockVolume]", func() {
|
||||
It("should create and delete block persistent volumes", func() {
|
||||
|
||||
// TODO: add openstack once Cinder volume plugin supports block volumes
|
||||
framework.SkipUnlessProviderIs("gce", "aws", "gke", "vsphere", "azure")
|
||||
|
||||
By("creating a claim with default class")
|
||||
block := v1.PersistentVolumeBlock
|
||||
test := storageClassTest{
|
||||
name: "default",
|
||||
claimSize: "2Gi",
|
||||
expectedSize: "2Gi",
|
||||
volumeMode: &block,
|
||||
}
|
||||
// gce or gke
|
||||
if getDefaultPluginName() == "kubernetes.io/gce-pd" {
|
||||
// using GB not GiB as e2e test unit since gce-pd returns GB,
|
||||
// or expectedSize may be greater than claimSize.
|
||||
test.claimSize = "2G"
|
||||
test.expectedSize = "2G"
|
||||
}
|
||||
|
||||
claim := newClaim(test, ns, "default")
|
||||
claim.Spec.VolumeMode = &block
|
||||
testDynamicProvisioning(test, c, claim, nil)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func getDefaultStorageClassName(c clientset.Interface) string {
|
||||
|
Loading…
Reference in New Issue
Block a user