Merge pull request #43498 from aveshagarwal/master-issue-43228
Automatic merge from submit-queue Add validation for affinities and taints/tolerations annotations. It fixes annotations validation issues for pod/node affinities and taints/tolerations annotations for 1.5 to 1.6 upgrade tests as discussed in the issue https://github.com/kubernetes/kubernetes/issues/43228 . @davidopp @derekwaynecarr @kubernetes/sig-scheduling-pr-reviews
This commit is contained in:
		@@ -18,6 +18,7 @@ package api
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"crypto/md5"
 | 
						"crypto/md5"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@@ -429,6 +430,14 @@ func NodeSelectorRequirementsAsSelector(nsm []NodeSelectorRequirement) (labels.S
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
 | 
						// TolerationsAnnotationKey represents the key of tolerations data (json serialized)
 | 
				
			||||||
 | 
						// in the Annotations of a Pod.
 | 
				
			||||||
 | 
						TolerationsAnnotationKey string = "scheduler.alpha.kubernetes.io/tolerations"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TaintsAnnotationKey represents the key of taints data (json serialized)
 | 
				
			||||||
 | 
						// in the Annotations of a Node.
 | 
				
			||||||
 | 
						TaintsAnnotationKey string = "scheduler.alpha.kubernetes.io/taints"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// SeccompPodAnnotationKey represents the key of a seccomp profile applied
 | 
						// SeccompPodAnnotationKey represents the key of a seccomp profile applied
 | 
				
			||||||
	// to all containers of a pod.
 | 
						// to all containers of a pod.
 | 
				
			||||||
	SeccompPodAnnotationKey string = "seccomp.security.alpha.kubernetes.io/pod"
 | 
						SeccompPodAnnotationKey string = "seccomp.security.alpha.kubernetes.io/pod"
 | 
				
			||||||
@@ -463,8 +472,26 @@ const (
 | 
				
			|||||||
	// an object (e.g. secret, config map) before fetching it again from apiserver.
 | 
						// an object (e.g. secret, config map) before fetching it again from apiserver.
 | 
				
			||||||
	// This annotation can be attached to node.
 | 
						// This annotation can be attached to node.
 | 
				
			||||||
	ObjectTTLAnnotationKey string = "node.alpha.kubernetes.io/ttl"
 | 
						ObjectTTLAnnotationKey string = "node.alpha.kubernetes.io/ttl"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// AffinityAnnotationKey represents the key of affinity data (json serialized)
 | 
				
			||||||
 | 
						// in the Annotations of a Pod.
 | 
				
			||||||
 | 
						// TODO: remove when alpha support for affinity is removed
 | 
				
			||||||
 | 
						AffinityAnnotationKey string = "scheduler.alpha.kubernetes.io/affinity"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetTolerationsFromPodAnnotations gets the json serialized tolerations data from Pod.Annotations
 | 
				
			||||||
 | 
					// and converts it to the []Toleration type in api.
 | 
				
			||||||
 | 
					func GetTolerationsFromPodAnnotations(annotations map[string]string) ([]Toleration, error) {
 | 
				
			||||||
 | 
						var tolerations []Toleration
 | 
				
			||||||
 | 
						if len(annotations) > 0 && annotations[TolerationsAnnotationKey] != "" {
 | 
				
			||||||
 | 
							err := json.Unmarshal([]byte(annotations[TolerationsAnnotationKey]), &tolerations)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return tolerations, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return tolerations, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AddOrUpdateTolerationInPod tries to add a toleration to the pod's toleration list.
 | 
					// AddOrUpdateTolerationInPod tries to add a toleration to the pod's toleration list.
 | 
				
			||||||
// Returns true if something was updated, false otherwise.
 | 
					// Returns true if something was updated, false otherwise.
 | 
				
			||||||
func AddOrUpdateTolerationInPod(pod *Pod, toleration *Toleration) (bool, error) {
 | 
					func AddOrUpdateTolerationInPod(pod *Pod, toleration *Toleration) (bool, error) {
 | 
				
			||||||
@@ -548,6 +575,19 @@ func (t *Taint) ToString() string {
 | 
				
			|||||||
	return fmt.Sprintf("%v=%v:%v", t.Key, t.Value, t.Effect)
 | 
						return fmt.Sprintf("%v=%v:%v", t.Key, t.Value, t.Effect)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetTaintsFromNodeAnnotations gets the json serialized taints data from Pod.Annotations
 | 
				
			||||||
 | 
					// and converts it to the []Taint type in api.
 | 
				
			||||||
 | 
					func GetTaintsFromNodeAnnotations(annotations map[string]string) ([]Taint, error) {
 | 
				
			||||||
 | 
						var taints []Taint
 | 
				
			||||||
 | 
						if len(annotations) > 0 && annotations[TaintsAnnotationKey] != "" {
 | 
				
			||||||
 | 
							err := json.Unmarshal([]byte(annotations[TaintsAnnotationKey]), &taints)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return []Taint{}, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return taints, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SysctlsFromPodAnnotations parses the sysctl annotations into a slice of safe Sysctls
 | 
					// SysctlsFromPodAnnotations parses the sysctl annotations into a slice of safe Sysctls
 | 
				
			||||||
// and a slice of unsafe Sysctls. This is only a convenience wrapper around
 | 
					// and a slice of unsafe Sysctls. This is only a convenience wrapper around
 | 
				
			||||||
// SysctlsFromPodAnnotation.
 | 
					// SysctlsFromPodAnnotation.
 | 
				
			||||||
@@ -596,6 +636,21 @@ func PodAnnotationsFromSysctls(sysctls []Sysctl) string {
 | 
				
			|||||||
	return strings.Join(kvs, ",")
 | 
						return strings.Join(kvs, ",")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetAffinityFromPodAnnotations gets the json serialized affinity data from Pod.Annotations
 | 
				
			||||||
 | 
					// and converts it to the Affinity type in api.
 | 
				
			||||||
 | 
					// TODO: remove when alpha support for affinity is removed
 | 
				
			||||||
 | 
					func GetAffinityFromPodAnnotations(annotations map[string]string) (*Affinity, error) {
 | 
				
			||||||
 | 
						if len(annotations) > 0 && annotations[AffinityAnnotationKey] != "" {
 | 
				
			||||||
 | 
							var affinity Affinity
 | 
				
			||||||
 | 
							err := json.Unmarshal([]byte(annotations[AffinityAnnotationKey]), &affinity)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return &affinity, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetPersistentVolumeClass returns StorageClassName.
 | 
					// GetPersistentVolumeClass returns StorageClassName.
 | 
				
			||||||
func GetPersistentVolumeClass(volume *PersistentVolume) string {
 | 
					func GetPersistentVolumeClass(volume *PersistentVolume) string {
 | 
				
			||||||
	// Use beta annotation first
 | 
						// Use beta annotation first
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -105,6 +105,14 @@ func ValidateDNS1123Subdomain(value string, fldPath *field.Path) field.ErrorList
 | 
				
			|||||||
func ValidatePodSpecificAnnotations(annotations map[string]string, spec *api.PodSpec, fldPath *field.Path) field.ErrorList {
 | 
					func ValidatePodSpecificAnnotations(annotations map[string]string, spec *api.PodSpec, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
	allErrs := field.ErrorList{}
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if annotations[api.AffinityAnnotationKey] != "" {
 | 
				
			||||||
 | 
							allErrs = append(allErrs, ValidateAffinityInPodAnnotations(annotations, fldPath)...)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if annotations[api.TolerationsAnnotationKey] != "" {
 | 
				
			||||||
 | 
							allErrs = append(allErrs, ValidateTolerationsInPodAnnotations(annotations, fldPath)...)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO: remove these after we EOL the annotations.
 | 
						// TODO: remove these after we EOL the annotations.
 | 
				
			||||||
	if hostname, exists := annotations[utilpod.PodHostnameAnnotation]; exists {
 | 
						if hostname, exists := annotations[utilpod.PodHostnameAnnotation]; exists {
 | 
				
			||||||
		allErrs = append(allErrs, ValidateDNS1123Label(hostname, fldPath.Key(utilpod.PodHostnameAnnotation))...)
 | 
							allErrs = append(allErrs, ValidateDNS1123Label(hostname, fldPath.Key(utilpod.PodHostnameAnnotation))...)
 | 
				
			||||||
@@ -136,6 +144,40 @@ func ValidatePodSpecificAnnotations(annotations map[string]string, spec *api.Pod
 | 
				
			|||||||
	return allErrs
 | 
						return allErrs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ValidateTolerationsInPodAnnotations tests that the serialized tolerations in Pod.Annotations has valid data
 | 
				
			||||||
 | 
					func ValidateTolerationsInPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tolerations, err := api.GetTolerationsFromPodAnnotations(annotations)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							allErrs = append(allErrs, field.Invalid(fldPath, api.TolerationsAnnotationKey, err.Error()))
 | 
				
			||||||
 | 
							return allErrs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(tolerations) > 0 {
 | 
				
			||||||
 | 
							allErrs = append(allErrs, validateTolerations(tolerations, fldPath.Child(api.TolerationsAnnotationKey))...)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return allErrs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ValidateAffinityInPodAnnotations tests that the serialized Affinity in Pod.Annotations has valid data
 | 
				
			||||||
 | 
					func ValidateAffinityInPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						affinity, err := api.GetAffinityFromPodAnnotations(annotations)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							allErrs = append(allErrs, field.Invalid(fldPath, api.AffinityAnnotationKey, err.Error()))
 | 
				
			||||||
 | 
							return allErrs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if affinity == nil {
 | 
				
			||||||
 | 
							return allErrs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						allErrs = append(allErrs, validateAffinity(affinity, fldPath.Child("affinity"))...)
 | 
				
			||||||
 | 
						return allErrs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ValidatePodSpecificAnnotationUpdates(newPod, oldPod *api.Pod, fldPath *field.Path) field.ErrorList {
 | 
					func ValidatePodSpecificAnnotationUpdates(newPod, oldPod *api.Pod, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
	allErrs := field.ErrorList{}
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
	newAnnotations := newPod.Annotations
 | 
						newAnnotations := newPod.Annotations
 | 
				
			||||||
@@ -2907,6 +2949,23 @@ func ValidateReadOnlyPersistentDisks(volumes []api.Volume, fldPath *field.Path)
 | 
				
			|||||||
	return allErrs
 | 
						return allErrs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ValidateTaintsInNodeAnnotations tests that the serialized taints in Node.Annotations has valid data
 | 
				
			||||||
 | 
					func ValidateTaintsInNodeAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						taints, err := api.GetTaintsFromNodeAnnotations(annotations)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							allErrs = append(allErrs, field.Invalid(fldPath, api.TaintsAnnotationKey, err.Error()))
 | 
				
			||||||
 | 
							return allErrs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(taints) > 0 {
 | 
				
			||||||
 | 
							allErrs = append(allErrs, validateNodeTaints(taints, fldPath.Child(api.TaintsAnnotationKey))...)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return allErrs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// validateNodeTaints tests if given taints have valid data.
 | 
					// validateNodeTaints tests if given taints have valid data.
 | 
				
			||||||
func validateNodeTaints(taints []api.Taint, fldPath *field.Path) field.ErrorList {
 | 
					func validateNodeTaints(taints []api.Taint, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
	allErrors := field.ErrorList{}
 | 
						allErrors := field.ErrorList{}
 | 
				
			||||||
@@ -2943,6 +3002,11 @@ func validateNodeTaints(taints []api.Taint, fldPath *field.Path) field.ErrorList
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func ValidateNodeSpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
 | 
					func ValidateNodeSpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
	allErrs := field.ErrorList{}
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if annotations[api.TaintsAnnotationKey] != "" {
 | 
				
			||||||
 | 
							allErrs = append(allErrs, ValidateTaintsInNodeAnnotations(annotations, fldPath)...)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if annotations[api.PreferAvoidPodsAnnotationKey] != "" {
 | 
						if annotations[api.PreferAvoidPodsAnnotationKey] != "" {
 | 
				
			||||||
		allErrs = append(allErrs, ValidateAvoidPodsInNodeAnnotations(annotations, fldPath)...)
 | 
							allErrs = append(allErrs, ValidateAvoidPodsInNodeAnnotations(annotations, fldPath)...)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package api
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"crypto/md5"
 | 
						"crypto/md5"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@@ -429,6 +430,14 @@ func NodeSelectorRequirementsAsSelector(nsm []NodeSelectorRequirement) (labels.S
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
 | 
						// TolerationsAnnotationKey represents the key of tolerations data (json serialized)
 | 
				
			||||||
 | 
						// in the Annotations of a Pod.
 | 
				
			||||||
 | 
						TolerationsAnnotationKey string = "scheduler.alpha.kubernetes.io/tolerations"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TaintsAnnotationKey represents the key of taints data (json serialized)
 | 
				
			||||||
 | 
						// in the Annotations of a Node.
 | 
				
			||||||
 | 
						TaintsAnnotationKey string = "scheduler.alpha.kubernetes.io/taints"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// SeccompPodAnnotationKey represents the key of a seccomp profile applied
 | 
						// SeccompPodAnnotationKey represents the key of a seccomp profile applied
 | 
				
			||||||
	// to all containers of a pod.
 | 
						// to all containers of a pod.
 | 
				
			||||||
	SeccompPodAnnotationKey string = "seccomp.security.alpha.kubernetes.io/pod"
 | 
						SeccompPodAnnotationKey string = "seccomp.security.alpha.kubernetes.io/pod"
 | 
				
			||||||
@@ -463,8 +472,26 @@ const (
 | 
				
			|||||||
	// an object (e.g. secret, config map) before fetching it again from apiserver.
 | 
						// an object (e.g. secret, config map) before fetching it again from apiserver.
 | 
				
			||||||
	// This annotation can be attached to node.
 | 
						// This annotation can be attached to node.
 | 
				
			||||||
	ObjectTTLAnnotationKey string = "node.alpha.kubernetes.io/ttl"
 | 
						ObjectTTLAnnotationKey string = "node.alpha.kubernetes.io/ttl"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// AffinityAnnotationKey represents the key of affinity data (json serialized)
 | 
				
			||||||
 | 
						// in the Annotations of a Pod.
 | 
				
			||||||
 | 
						// TODO: remove when alpha support for affinity is removed
 | 
				
			||||||
 | 
						AffinityAnnotationKey string = "scheduler.alpha.kubernetes.io/affinity"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetTolerationsFromPodAnnotations gets the json serialized tolerations data from Pod.Annotations
 | 
				
			||||||
 | 
					// and converts it to the []Toleration type in api.
 | 
				
			||||||
 | 
					func GetTolerationsFromPodAnnotations(annotations map[string]string) ([]Toleration, error) {
 | 
				
			||||||
 | 
						var tolerations []Toleration
 | 
				
			||||||
 | 
						if len(annotations) > 0 && annotations[TolerationsAnnotationKey] != "" {
 | 
				
			||||||
 | 
							err := json.Unmarshal([]byte(annotations[TolerationsAnnotationKey]), &tolerations)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return tolerations, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return tolerations, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AddOrUpdateTolerationInPod tries to add a toleration to the pod's toleration list.
 | 
					// AddOrUpdateTolerationInPod tries to add a toleration to the pod's toleration list.
 | 
				
			||||||
// Returns true if something was updated, false otherwise.
 | 
					// Returns true if something was updated, false otherwise.
 | 
				
			||||||
func AddOrUpdateTolerationInPod(pod *Pod, toleration *Toleration) (bool, error) {
 | 
					func AddOrUpdateTolerationInPod(pod *Pod, toleration *Toleration) (bool, error) {
 | 
				
			||||||
@@ -548,6 +575,19 @@ func (t *Taint) ToString() string {
 | 
				
			|||||||
	return fmt.Sprintf("%v=%v:%v", t.Key, t.Value, t.Effect)
 | 
						return fmt.Sprintf("%v=%v:%v", t.Key, t.Value, t.Effect)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetTaintsFromNodeAnnotations gets the json serialized taints data from Pod.Annotations
 | 
				
			||||||
 | 
					// and converts it to the []Taint type in api.
 | 
				
			||||||
 | 
					func GetTaintsFromNodeAnnotations(annotations map[string]string) ([]Taint, error) {
 | 
				
			||||||
 | 
						var taints []Taint
 | 
				
			||||||
 | 
						if len(annotations) > 0 && annotations[TaintsAnnotationKey] != "" {
 | 
				
			||||||
 | 
							err := json.Unmarshal([]byte(annotations[TaintsAnnotationKey]), &taints)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return []Taint{}, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return taints, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SysctlsFromPodAnnotations parses the sysctl annotations into a slice of safe Sysctls
 | 
					// SysctlsFromPodAnnotations parses the sysctl annotations into a slice of safe Sysctls
 | 
				
			||||||
// and a slice of unsafe Sysctls. This is only a convenience wrapper around
 | 
					// and a slice of unsafe Sysctls. This is only a convenience wrapper around
 | 
				
			||||||
// SysctlsFromPodAnnotation.
 | 
					// SysctlsFromPodAnnotation.
 | 
				
			||||||
@@ -596,6 +636,21 @@ func PodAnnotationsFromSysctls(sysctls []Sysctl) string {
 | 
				
			|||||||
	return strings.Join(kvs, ",")
 | 
						return strings.Join(kvs, ",")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetAffinityFromPodAnnotations gets the json serialized affinity data from Pod.Annotations
 | 
				
			||||||
 | 
					// and converts it to the Affinity type in api.
 | 
				
			||||||
 | 
					// TODO: remove when alpha support for affinity is removed
 | 
				
			||||||
 | 
					func GetAffinityFromPodAnnotations(annotations map[string]string) (*Affinity, error) {
 | 
				
			||||||
 | 
						if len(annotations) > 0 && annotations[AffinityAnnotationKey] != "" {
 | 
				
			||||||
 | 
							var affinity Affinity
 | 
				
			||||||
 | 
							err := json.Unmarshal([]byte(annotations[AffinityAnnotationKey]), &affinity)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return &affinity, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetPersistentVolumeClass returns StorageClassName.
 | 
					// GetPersistentVolumeClass returns StorageClassName.
 | 
				
			||||||
func GetPersistentVolumeClass(volume *PersistentVolume) string {
 | 
					func GetPersistentVolumeClass(volume *PersistentVolume) string {
 | 
				
			||||||
	// Use beta annotation first
 | 
						// Use beta annotation first
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user