Merge pull request #61816 from wackxu/rman

Automatic merge from submit-queue (batch tested with PRs 54997, 61869, 61816, 61909, 60525). 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>.

Remove alpha annotation for volume node affinity

**What this PR does / why we need it**:

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes # https://github.com/kubernetes/kubernetes/issues/61785

**Special notes for your reviewer**:
/assign @msau42 

**Release note**:

```release-note
ACTION REQUIRED: Alpha annotation for PersistentVolume node affinity has been removed.  Update your PersistentVolumes to use the beta PersistentVolume.nodeAffinity field before upgrading to this release
```
This commit is contained in:
Kubernetes Submit Queue 2018-03-30 20:13:09 -07:00 committed by GitHub
commit ac8a02f5ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 3 additions and 571 deletions

View File

@ -565,33 +565,3 @@ func PersistentVolumeClaimHasClass(claim *core.PersistentVolumeClaim) bool {
return false
}
// GetStorageNodeAffinityFromAnnotation gets the json serialized data from PersistentVolume.Annotations
// and converts it to the NodeAffinity type in core.
// TODO: update when storage node affinity graduates to beta
func GetStorageNodeAffinityFromAnnotation(annotations map[string]string) (*core.NodeAffinity, error) {
if len(annotations) > 0 && annotations[core.AlphaStorageNodeAffinityAnnotation] != "" {
var affinity core.NodeAffinity
err := json.Unmarshal([]byte(annotations[core.AlphaStorageNodeAffinityAnnotation]), &affinity)
if err != nil {
return nil, err
}
return &affinity, nil
}
return nil, nil
}
// Converts NodeAffinity type to Alpha annotation for use in PersistentVolumes
// TODO: update when storage node affinity graduates to beta
func StorageNodeAffinityToAlphaAnnotation(annotations map[string]string, affinity *core.NodeAffinity) error {
if affinity == nil {
return nil
}
json, err := json.Marshal(*affinity)
if err != nil {
return err
}
annotations[core.AlphaStorageNodeAffinityAnnotation] = string(json)
return nil
}

View File

@ -286,93 +286,6 @@ func TestSysctlsFromPodAnnotation(t *testing.T) {
}
}
// TODO: remove when alpha support for topology constraints is removed
func TestGetNodeAffinityFromAnnotations(t *testing.T) {
testCases := []struct {
annotations map[string]string
expectErr bool
}{
{
annotations: nil,
expectErr: false,
},
{
annotations: map[string]string{},
expectErr: false,
},
{
annotations: map[string]string{
core.AlphaStorageNodeAffinityAnnotation: `{
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [
{ "matchExpressions": [
{ "key": "test-key1",
"operator": "In",
"values": ["test-value1", "test-value2"]
},
{ "key": "test-key2",
"operator": "In",
"values": ["test-value1", "test-value2"]
}
]}
]}
}`,
},
expectErr: false,
},
{
annotations: map[string]string{
core.AlphaStorageNodeAffinityAnnotation: `[{
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [
{ "matchExpressions": [
{ "key": "test-key1",
"operator": "In",
"values": ["test-value1", "test-value2"]
},
{ "key": "test-key2",
"operator": "In",
"values": ["test-value1", "test-value2"]
}
]}
]}
}]`,
},
expectErr: true,
},
{
annotations: map[string]string{
core.AlphaStorageNodeAffinityAnnotation: `{
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms":
"matchExpressions": [
{ "key": "test-key1",
"operator": "In",
"values": ["test-value1", "test-value2"]
},
{ "key": "test-key2",
"operator": "In",
"values": ["test-value1", "test-value2"]
}
]}
}
}`,
},
expectErr: true,
},
}
for i, tc := range testCases {
_, err := GetStorageNodeAffinityFromAnnotation(tc.annotations)
if err == nil && tc.expectErr {
t.Errorf("[%v]expected error but got none.", i)
}
if err != nil && !tc.expectErr {
t.Errorf("[%v]did not expect error but got: %v", i, err)
}
}
}
func TestIsHugePageResourceName(t *testing.T) {
testCases := []struct {
name core.ResourceName

View File

@ -412,10 +412,6 @@ const (
// MountOptionAnnotation defines mount option annotation used in PVs
MountOptionAnnotation = "volume.beta.kubernetes.io/mount-options"
// AlphaStorageNodeAffinityAnnotation defines node affinity policies for a PersistentVolume.
// Value is a string of the json representation of type NodeAffinity
AlphaStorageNodeAffinityAnnotation = "volume.alpha.kubernetes.io/node-affinity"
)
// +genclient

View File

@ -418,33 +418,3 @@ func GetPersistentVolumeClaimClass(claim *v1.PersistentVolumeClaim) string {
return ""
}
// GetStorageNodeAffinityFromAnnotation gets the json serialized data from PersistentVolume.Annotations
// and converts it to the NodeAffinity type in api.
// TODO: update when storage node affinity graduates to beta
func GetStorageNodeAffinityFromAnnotation(annotations map[string]string) (*v1.NodeAffinity, error) {
if len(annotations) > 0 && annotations[v1.AlphaStorageNodeAffinityAnnotation] != "" {
var affinity v1.NodeAffinity
err := json.Unmarshal([]byte(annotations[v1.AlphaStorageNodeAffinityAnnotation]), &affinity)
if err != nil {
return nil, err
}
return &affinity, nil
}
return nil, nil
}
// Converts NodeAffinity type to Alpha annotation for use in PersistentVolumes
// TODO: update when storage node affinity graduates to beta
func StorageNodeAffinityToAlphaAnnotation(annotations map[string]string, affinity *v1.NodeAffinity) error {
if affinity == nil {
return nil
}
json, err := json.Marshal(*affinity)
if err != nil {
return err
}
annotations[v1.AlphaStorageNodeAffinityAnnotation] = string(json)
return nil
}

View File

@ -566,90 +566,3 @@ func TestSysctlsFromPodAnnotation(t *testing.T) {
}
}
}
// TODO: remove when alpha support for topology constraints is removed
func TestGetNodeAffinityFromAnnotations(t *testing.T) {
testCases := []struct {
annotations map[string]string
expectErr bool
}{
{
annotations: nil,
expectErr: false,
},
{
annotations: map[string]string{},
expectErr: false,
},
{
annotations: map[string]string{
v1.AlphaStorageNodeAffinityAnnotation: `{
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [
{ "matchExpressions": [
{ "key": "test-key1",
"operator": "In",
"values": ["test-value1", "test-value2"]
},
{ "key": "test-key2",
"operator": "In",
"values": ["test-value1", "test-value2"]
}
]}
]}
}`,
},
expectErr: false,
},
{
annotations: map[string]string{
v1.AlphaStorageNodeAffinityAnnotation: `[{
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [
{ "matchExpressions": [
{ "key": "test-key1",
"operator": "In",
"values": ["test-value1", "test-value2"]
},
{ "key": "test-key2",
"operator": "In",
"values": ["test-value1", "test-value2"]
}
]}
]}
}]`,
},
expectErr: true,
},
{
annotations: map[string]string{
v1.AlphaStorageNodeAffinityAnnotation: `{
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms":
"matchExpressions": [
{ "key": "test-key1",
"operator": "In",
"values": ["test-value1", "test-value2"]
},
{ "key": "test-key2",
"operator": "In",
"values": ["test-value1", "test-value2"]
}
]}
}
}`,
},
expectErr: true,
},
}
for i, tc := range testCases {
_, err := GetStorageNodeAffinityFromAnnotation(tc.annotations)
if err == nil && tc.expectErr {
t.Errorf("[%v]expected error but got none.", i)
}
if err != nil && !tc.expectErr {
t.Errorf("[%v]did not expect error but got: %v", i, err)
}
}
}

View File

@ -56,7 +56,6 @@ go_test(
"//pkg/api/legacyscheme:go_default_library",
"//pkg/api/testapi:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/helper:go_default_library",
"//pkg/capabilities:go_default_library",
"//pkg/features:go_default_library",
"//pkg/security/apparmor:go_default_library",

View File

@ -1536,18 +1536,9 @@ func ValidatePersistentVolume(pv *core.PersistentVolume) field.ErrorList {
}
}
nodeAffinitySpecified, errs := validateStorageNodeAffinityAnnotation(pv.ObjectMeta.Annotations, metaPath.Child("annotations"))
nodeAffinitySpecified, errs := validateVolumeNodeAffinity(pv.Spec.NodeAffinity, specPath.Child("nodeAffinity"))
allErrs = append(allErrs, errs...)
volumeNodeAffinitySpecified, errs := validateVolumeNodeAffinity(pv.Spec.NodeAffinity, specPath.Child("nodeAffinity"))
allErrs = append(allErrs, errs...)
if nodeAffinitySpecified && volumeNodeAffinitySpecified {
allErrs = append(allErrs, field.Forbidden(specPath.Child("nodeAffinity"), "may not specify both alpha nodeAffinity annotation and nodeAffinity field"))
}
nodeAffinitySpecified = nodeAffinitySpecified || volumeNodeAffinitySpecified
numVolumes := 0
if pv.Spec.HostPath != nil {
if numVolumes > 0 {
@ -5031,35 +5022,6 @@ func sysctlIntersection(a []core.Sysctl, b []core.Sysctl) []string {
return result
}
// validateStorageNodeAffinityAnnotation tests that the serialized TopologyConstraints in PersistentVolume.Annotations has valid data
func validateStorageNodeAffinityAnnotation(annotations map[string]string, fldPath *field.Path) (bool, field.ErrorList) {
allErrs := field.ErrorList{}
na, err := helper.GetStorageNodeAffinityFromAnnotation(annotations)
if err != nil {
allErrs = append(allErrs, field.Invalid(fldPath, core.AlphaStorageNodeAffinityAnnotation, err.Error()))
return false, allErrs
}
if na == nil {
return false, allErrs
}
if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) {
allErrs = append(allErrs, field.Forbidden(fldPath, "Storage node affinity is disabled by feature-gate"))
}
policySpecified := false
if na.RequiredDuringSchedulingIgnoredDuringExecution != nil {
allErrs = append(allErrs, ValidateNodeSelector(na.RequiredDuringSchedulingIgnoredDuringExecution, fldPath.Child("requiredDuringSchedulingIgnoredDuringExecution"))...)
policySpecified = true
}
if len(na.PreferredDuringSchedulingIgnoredDuringExecution) > 0 {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("preferredDuringSchedulingIgnoredDuringExection"), "Storage node affinity does not support preferredDuringSchedulingIgnoredDuringExecution"))
}
return policySpecified, allErrs
}
// validateVolumeNodeAffinity tests that the PersistentVolume.NodeAffinity has valid data
// returns:
// - true if volumeNodeAffinity is set

View File

@ -35,7 +35,6 @@ import (
"k8s.io/kubernetes/pkg/api/legacyscheme"
_ "k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/helper"
"k8s.io/kubernetes/pkg/capabilities"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/security/apparmor"
@ -65,24 +64,6 @@ func testVolume(name string, namespace string, spec core.PersistentVolumeSpec) *
}
}
func testVolumeWithAlphaNodeAffinity(t *testing.T, name string, namespace string, affinity *core.NodeAffinity, spec core.PersistentVolumeSpec) *core.PersistentVolume {
objMeta := metav1.ObjectMeta{Name: name}
if namespace != "" {
objMeta.Namespace = namespace
}
objMeta.Annotations = map[string]string{}
err := helper.StorageNodeAffinityToAlphaAnnotation(objMeta.Annotations, affinity)
if err != nil {
t.Fatalf("Failed to get node affinity annotation: %v", err)
}
return &core.PersistentVolume{
ObjectMeta: objMeta,
Spec: spec,
}
}
func TestValidatePersistentVolumes(t *testing.T) {
validMode := core.PersistentVolumeFilesystem
scenarios := map[string]struct {
@ -512,29 +493,6 @@ func TestValidateLocalVolumes(t *testing.T) {
isExpectedFailure bool
volume *core.PersistentVolume
}{
"alpha valid local volume": {
isExpectedFailure: false,
volume: testVolumeWithAlphaNodeAffinity(
t,
"valid-local-volume",
"",
&core.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{
NodeSelectorTerms: []core.NodeSelectorTerm{
{
MatchExpressions: []core.NodeSelectorRequirement{
{
Key: "test-label-key",
Operator: core.NodeSelectorOpIn,
Values: []string{"test-label-value"},
},
},
},
},
},
},
testLocalVolume("/foo", nil)),
},
"alpha invalid local volume nil annotations": {
isExpectedFailure: true,
volume: testVolume(
@ -542,75 +500,6 @@ func TestValidateLocalVolumes(t *testing.T) {
"",
testLocalVolume("/foo", nil)),
},
"alpha invalid local volume empty affinity": {
isExpectedFailure: true,
volume: testVolumeWithAlphaNodeAffinity(
t,
"invalid-local-volume-empty-affinity",
"",
&core.NodeAffinity{},
testLocalVolume("/foo", nil)),
},
"alpha invalid local volume preferred affinity": {
isExpectedFailure: true,
volume: testVolumeWithAlphaNodeAffinity(
t,
"invalid-local-volume-preferred-affinity",
"",
&core.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{
NodeSelectorTerms: []core.NodeSelectorTerm{
{
MatchExpressions: []core.NodeSelectorRequirement{
{
Key: "test-label-key",
Operator: core.NodeSelectorOpIn,
Values: []string{"test-label-value"},
},
},
},
},
},
PreferredDuringSchedulingIgnoredDuringExecution: []core.PreferredSchedulingTerm{
{
Weight: 10,
Preference: core.NodeSelectorTerm{
MatchExpressions: []core.NodeSelectorRequirement{
{
Key: "test-label-key",
Operator: core.NodeSelectorOpIn,
Values: []string{"test-label-value"},
},
},
},
},
},
},
testLocalVolume("/foo", nil)),
},
"alpha and beta local volume": {
isExpectedFailure: true,
volume: testVolumeWithAlphaNodeAffinity(
t,
"invalid-alpha-beta-local-volume",
"",
&core.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{
NodeSelectorTerms: []core.NodeSelectorTerm{
{
MatchExpressions: []core.NodeSelectorRequirement{
{
Key: "test-label-key",
Operator: core.NodeSelectorOpIn,
Values: []string{"test-label-value"},
},
},
},
},
},
},
testLocalVolume("/foo", simpleVolumeNodeAffinity("foo", "bar"))),
},
"valid local volume": {
isExpectedFailure: false,
volume: testVolume("valid-local-volume", "",
@ -654,29 +543,6 @@ func TestValidateLocalVolumesDisabled(t *testing.T) {
isExpectedFailure bool
volume *core.PersistentVolume
}{
"alpha disabled valid local volume": {
isExpectedFailure: true,
volume: testVolumeWithAlphaNodeAffinity(
t,
"valid-local-volume",
"",
&core.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{
NodeSelectorTerms: []core.NodeSelectorTerm{
{
MatchExpressions: []core.NodeSelectorRequirement{
{
Key: "test-label-key",
Operator: core.NodeSelectorOpIn,
Values: []string{"test-label-value"},
},
},
},
},
},
},
testLocalVolume("/foo", nil)),
},
"feature disabled valid local volume": {
isExpectedFailure: true,
volume: testVolume("valid-local-volume", "",

View File

@ -52,7 +52,6 @@ go_library(
deps = [
"//pkg/api/v1/pod:go_default_library",
"//pkg/apis/core/helper:go_default_library",
"//pkg/apis/core/v1/helper:go_default_library",
"//pkg/features:go_default_library",
"//pkg/kubelet/apis:go_default_library",
"//pkg/scheduler:go_default_library",

View File

@ -52,7 +52,6 @@ import (
"k8s.io/client-go/tools/cache"
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
"k8s.io/kubernetes/pkg/apis/core/helper"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
"k8s.io/kubernetes/pkg/features"
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
"k8s.io/kubernetes/pkg/scheduler"
@ -407,17 +406,8 @@ func (c *configFactory) invalidatePredicatesForPvUpdate(oldPV, newPV *v1.Persist
}
}
if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) {
oldAffinity, err := v1helper.GetStorageNodeAffinityFromAnnotation(oldPV.Annotations)
if err != nil {
glog.Errorf("cannot get node affinity fo *v1.PersistentVolume: %v", oldPV)
return
}
newAffinity, err := v1helper.GetStorageNodeAffinityFromAnnotation(newPV.Annotations)
if err != nil {
glog.Errorf("cannot get node affinity fo *v1.PersistentVolume: %v", newPV)
return
}
oldAffinity := oldPV.Spec.NodeAffinity
newAffinity := newPV.Spec.NodeAffinity
// If node affinity of PV is changed.
if !reflect.DeepEqual(oldAffinity, newAffinity) {
invalidPredicates.Insert(predicates.CheckVolumeBindingPred)

View File

@ -91,7 +91,6 @@ go_test(
embed = [":go_default_library"],
deps = [
"//pkg/apis/core/install:go_default_library",
"//pkg/apis/core/v1/helper:go_default_library",
"//pkg/util/mount:go_default_library",
"//pkg/util/slice:go_default_library",
"//pkg/volume:go_default_library",

View File

@ -266,37 +266,9 @@ func GetClassForVolume(kubeClient clientset.Interface, pv *v1.PersistentVolume)
// CheckNodeAffinity looks at the PV node affinity, and checks if the node has the same corresponding labels
// This ensures that we don't mount a volume that doesn't belong to this node
func CheckNodeAffinity(pv *v1.PersistentVolume, nodeLabels map[string]string) error {
if err := checkAlphaNodeAffinity(pv, nodeLabels); err != nil {
return err
}
return checkVolumeNodeAffinity(pv, nodeLabels)
}
func checkAlphaNodeAffinity(pv *v1.PersistentVolume, nodeLabels map[string]string) error {
affinity, err := v1helper.GetStorageNodeAffinityFromAnnotation(pv.Annotations)
if err != nil {
return fmt.Errorf("Error getting storage node affinity: %v", err)
}
if affinity == nil {
return nil
}
if affinity.RequiredDuringSchedulingIgnoredDuringExecution != nil {
terms := affinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms
glog.V(10).Infof("Match for RequiredDuringSchedulingIgnoredDuringExecution node selector terms %+v", terms)
for _, term := range terms {
selector, err := v1helper.NodeSelectorRequirementsAsSelector(term.MatchExpressions)
if err != nil {
return fmt.Errorf("Failed to parse MatchExpressions: %v", err)
}
if !selector.Matches(labels.Set(nodeLabels)) {
return fmt.Errorf("NodeSelectorTerm %+v does not match node labels", term.MatchExpressions)
}
}
}
return nil
}
func checkVolumeNodeAffinity(pv *v1.PersistentVolume, nodeLabels map[string]string) error {
if pv.Spec.NodeAffinity == nil {
return nil

View File

@ -29,7 +29,6 @@ import (
"hash/fnv"
_ "k8s.io/kubernetes/pkg/apis/core/install"
"k8s.io/kubernetes/pkg/apis/core/v1/helper"
"k8s.io/kubernetes/pkg/util/mount"
"reflect"
@ -47,105 +46,6 @@ var nodeLabels map[string]string = map[string]string{
"test-key2": "test-value2",
}
func TestCheckAlphaNodeAffinity(t *testing.T) {
type affinityTest struct {
name string
expectSuccess bool
pv *v1.PersistentVolume
}
cases := []affinityTest{
{
name: "valid-no-constraints",
expectSuccess: true,
pv: testVolumeWithAlphaNodeAffinity(t, &v1.NodeAffinity{}),
},
{
name: "valid-constraints",
expectSuccess: true,
pv: testVolumeWithAlphaNodeAffinity(t, &v1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: "test-key1",
Operator: v1.NodeSelectorOpIn,
Values: []string{"test-value1", "test-value3"},
},
{
Key: "test-key2",
Operator: v1.NodeSelectorOpIn,
Values: []string{"test-value0", "test-value2"},
},
},
},
},
},
}),
},
{
name: "invalid-key",
expectSuccess: false,
pv: testVolumeWithAlphaNodeAffinity(t, &v1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: "test-key1",
Operator: v1.NodeSelectorOpIn,
Values: []string{"test-value1", "test-value3"},
},
{
Key: "test-key3",
Operator: v1.NodeSelectorOpIn,
Values: []string{"test-value0", "test-value2"},
},
},
},
},
},
}),
},
{
name: "invalid-values",
expectSuccess: false,
pv: testVolumeWithAlphaNodeAffinity(t, &v1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: "test-key1",
Operator: v1.NodeSelectorOpIn,
Values: []string{"test-value3", "test-value4"},
},
{
Key: "test-key2",
Operator: v1.NodeSelectorOpIn,
Values: []string{"test-value0", "test-value2"},
},
},
},
},
},
}),
},
}
for _, c := range cases {
err := CheckNodeAffinity(c.pv, nodeLabels)
if err != nil && c.expectSuccess {
t.Errorf("CheckTopology %v returned error: %v", c.name, err)
}
if err == nil && !c.expectSuccess {
t.Errorf("CheckTopology %v returned success, expected error", c.name)
}
}
}
func TestCheckVolumeNodeAffinity(t *testing.T) {
type affinityTest struct {
name string
@ -250,19 +150,6 @@ func TestCheckVolumeNodeAffinity(t *testing.T) {
}
}
func testVolumeWithAlphaNodeAffinity(t *testing.T, affinity *v1.NodeAffinity) *v1.PersistentVolume {
objMeta := metav1.ObjectMeta{Name: "test-constraints"}
objMeta.Annotations = map[string]string{}
err := helper.StorageNodeAffinityToAlphaAnnotation(objMeta.Annotations, affinity)
if err != nil {
t.Fatalf("Failed to get node affinity annotation: %v", err)
}
return &v1.PersistentVolume{
ObjectMeta: objMeta,
}
}
func testVolumeWithNodeAffinity(t *testing.T, affinity *v1.VolumeNodeAffinity) *v1.PersistentVolume {
objMeta := metav1.ObjectMeta{Name: "test-constraints"}
return &v1.PersistentVolume{

View File

@ -458,10 +458,6 @@ const (
// MountOptionAnnotation defines mount option annotation used in PVs
MountOptionAnnotation = "volume.beta.kubernetes.io/mount-options"
// AlphaStorageNodeAffinityAnnotation defines node affinity policies for a PersistentVolume.
// Value is a string of the json representation of type NodeAffinity
AlphaStorageNodeAffinityAnnotation = "volume.alpha.kubernetes.io/node-affinity"
)
// +genclient