Update go dependencies (#2234)

This commit is contained in:
Manuel Alejandro de Brito Fontes 2018-03-23 13:35:19 -03:00 committed by GitHub
parent 6e099c5f57
commit 93c72ef646
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
1236 changed files with 37226 additions and 49844 deletions

View file

@ -116,7 +116,8 @@ var (
// MetricSpec specifies how to scale based on a single metric
// (only `type` and one other matching field should be set at once).
type MetricSpec struct {
// Type is the type of metric source. It should match one of the fields below.
// Type is the type of metric source. It should be one of "Object",
// "Pods" or "Resource", each mapping to a matching field in the object.
Type MetricSourceType
// Object refers to a metric describing a single kubernetes object
@ -261,7 +262,8 @@ type HorizontalPodAutoscalerCondition struct {
// MetricStatus describes the last-read state of a single metric.
type MetricStatus struct {
// Type is the type of metric source. It will match one of the fields below.
// Type is the type of metric source. It will be one of "Object",
// "Pods" or "Resource", each corresponds to a matching field in the object.
Type MetricSourceType
// Object refers to a metric describing a single kubernetes object

View file

@ -32,9 +32,12 @@ go_library(
go_test(
name = "go_default_test",
srcs = ["taint_test.go"],
srcs = [
"taint_test.go",
"toleration_test.go",
],
embed = [":go_default_library"],
importpath = "k8s.io/kubernetes/pkg/apis/core",
library = ":go_default_library",
)
filegroup(

View file

@ -9,8 +9,8 @@ load(
go_test(
name = "go_default_test",
srcs = ["helpers_test.go"],
embed = [":go_default_library"],
importpath = "k8s.io/kubernetes/pkg/apis/core/helper",
library = ":go_default_library",
deps = [
"//pkg/apis/core:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",

View file

@ -254,46 +254,18 @@ func IsIntegerResourceName(str string) bool {
return integerResources.Has(str) || IsExtendedResourceName(core.ResourceName(str))
}
// Extended and HugePages resources
func IsScalarResourceName(name core.ResourceName) bool {
return IsExtendedResourceName(name) || IsHugePageResourceName(name)
}
// this function aims to check if the service's ClusterIP is set or not
// the objective is not to perform validation here
func IsServiceIPSet(service *core.Service) bool {
return service.Spec.ClusterIP != core.ClusterIPNone && service.Spec.ClusterIP != ""
}
// this function aims to check if the service's cluster IP is requested or not
func IsServiceIPRequested(service *core.Service) bool {
// ExternalName services are CNAME aliases to external ones. Ignore the IP.
if service.Spec.Type == core.ServiceTypeExternalName {
return false
}
return service.Spec.ClusterIP == ""
}
var standardFinalizers = sets.NewString(
string(core.FinalizerKubernetes),
metav1.FinalizerOrphanDependents,
metav1.FinalizerDeleteDependents,
)
// HasAnnotation returns a bool if passed in annotation exists
func HasAnnotation(obj core.ObjectMeta, ann string) bool {
_, found := obj.Annotations[ann]
return found
}
// SetMetaDataAnnotation sets the annotation and value
func SetMetaDataAnnotation(obj *core.ObjectMeta, ann string, value string) {
if obj.Annotations == nil {
obj.Annotations = make(map[string]string)
}
obj.Annotations[ann] = value
}
func IsStandardFinalizerName(str string) bool {
return standardFinalizers.Has(str)
}
@ -482,37 +454,6 @@ func AddOrUpdateTolerationInPod(pod *core.Pod, toleration *core.Toleration) bool
return true
}
// TolerationToleratesTaint checks if the toleration tolerates the taint.
func TolerationToleratesTaint(toleration *core.Toleration, taint *core.Taint) bool {
if len(toleration.Effect) != 0 && toleration.Effect != taint.Effect {
return false
}
if toleration.Key != taint.Key {
return false
}
// TODO: Use proper defaulting when Toleration becomes a field of PodSpec
if (len(toleration.Operator) == 0 || toleration.Operator == core.TolerationOpEqual) && toleration.Value == taint.Value {
return true
}
if toleration.Operator == core.TolerationOpExists {
return true
}
return false
}
// TaintToleratedByTolerations checks if taint is tolerated by any of the tolerations.
func TaintToleratedByTolerations(taint *core.Taint, tolerations []core.Toleration) bool {
tolerated := false
for i := range tolerations {
if TolerationToleratesTaint(&tolerations[i], taint) {
tolerated = true
break
}
}
return tolerated
}
// GetTaintsFromNodeAnnotations gets the json serialized taints data from Pod.Annotations
// and converts it to the []Taint type in core.
func GetTaintsFromNodeAnnotations(annotations map[string]string) ([]core.Taint, error) {

View file

@ -24,8 +24,8 @@ go_library(
go_test(
name = "go_default_test",
srcs = ["install_test.go"],
embed = [":go_default_library"],
importpath = "k8s.io/kubernetes/pkg/apis/core/install",
library = ":go_default_library",
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/core:go_default_library",

View file

@ -11,8 +11,8 @@ go_library(
go_test(
name = "go_default_test",
srcs = ["helpers_test.go"],
embed = [":go_default_library"],
importpath = "k8s.io/kubernetes/pkg/apis/core/pods",
library = ":go_default_library",
)
filegroup(

View file

@ -0,0 +1,136 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package core
import "testing"
func TestMatchToleration(t *testing.T) {
tolerationSeconds := int64(5)
tolerationToMatchSeconds := int64(3)
testCases := []struct {
description string
toleration *Toleration
tolerationToMatch *Toleration
expectMatch bool
}{
{
description: "two taints with the same key,operator,value,effect should match",
toleration: &Toleration{
Key: "foo",
Operator: "Exists",
Value: "bar",
Effect: TaintEffectNoSchedule,
},
tolerationToMatch: &Toleration{
Key: "foo",
Operator: "Exists",
Value: "bar",
Effect: TaintEffectNoSchedule,
},
expectMatch: true,
},
{
description: "two taints with the different key cannot match",
toleration: &Toleration{
Key: "foo",
Operator: "Exists",
Value: "bar",
Effect: TaintEffectNoSchedule,
},
tolerationToMatch: &Toleration{
Key: "different-key",
Operator: "Exists",
Value: "bar",
Effect: TaintEffectNoSchedule,
},
expectMatch: false,
},
{
description: "two taints with the different operator cannot match",
toleration: &Toleration{
Key: "foo",
Operator: "Exists",
Value: "bar",
Effect: TaintEffectNoSchedule,
},
tolerationToMatch: &Toleration{
Key: "foo",
Operator: "different-operator",
Value: "bar",
Effect: TaintEffectNoSchedule,
},
expectMatch: false,
},
{
description: "two taints with the different value cannot match",
toleration: &Toleration{
Key: "foo",
Operator: "Exists",
Value: "bar",
Effect: TaintEffectNoSchedule,
},
tolerationToMatch: &Toleration{
Key: "foo",
Operator: "Exists",
Value: "different-value",
Effect: TaintEffectNoSchedule,
},
expectMatch: false,
},
{
description: "two taints with the different effect cannot match",
toleration: &Toleration{
Key: "foo",
Operator: "Exists",
Value: "bar",
Effect: TaintEffectNoSchedule,
},
tolerationToMatch: &Toleration{
Key: "foo",
Operator: "Exists",
Value: "bar",
Effect: TaintEffectPreferNoSchedule,
},
expectMatch: false,
},
{
description: "two taints with the different tolerationSeconds should match",
toleration: &Toleration{
Key: "foo",
Operator: "Exists",
Value: "bar",
Effect: TaintEffectNoSchedule,
TolerationSeconds: &tolerationSeconds,
},
tolerationToMatch: &Toleration{
Key: "foo",
Operator: "Exists",
Value: "bar",
Effect: TaintEffectNoSchedule,
TolerationSeconds: &tolerationToMatchSeconds,
},
expectMatch: true,
},
}
for _, tc := range testCases {
if actual := tc.toleration.MatchToleration(tc.tolerationToMatch); actual != tc.expectMatch {
t.Errorf("[%s] expect: %v , got: %v", tc.description, tc.expectMatch, !tc.expectMatch)
}
}
}

View file

@ -354,7 +354,7 @@ type PersistentVolumeSource struct {
// FlexVolume represents a generic volume resource that is
// provisioned/attached using an exec based plugin.
// +optional
FlexVolume *FlexVolumeSource
FlexVolume *FlexPersistentVolumeSource
// Cinder represents a cinder volume attached and mounted on kubelets host machine
// +optional
Cinder *CinderVolumeSource
@ -867,6 +867,32 @@ type FCVolumeSource struct {
WWIDs []string
}
// FlexPersistentVolumeSource represents a generic persistent volume resource that is
// provisioned/attached using an exec based plugin.
type FlexPersistentVolumeSource struct {
// Driver is the name of the driver to use for this volume.
Driver string
// Filesystem type to mount.
// Must be a filesystem type supported by the host operating system.
// Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script.
// +optional
FSType string
// Optional: SecretRef is reference to the secret object containing
// sensitive information to pass to the plugin scripts. This may be
// empty if no secret object is specified. If the secret object
// contains more than one secret, all secrets are passed to the plugin
// scripts.
// +optional
SecretRef *SecretReference
// Optional: Defaults to false (read/write). ReadOnly here will force
// the ReadOnly setting in VolumeMounts.
// +optional
ReadOnly bool
// Optional: Extra driver options if any.
// +optional
Options map[string]string
}
// FlexVolume represents a generic volume resource that is
// provisioned/attached using an exec based plugin.
type FlexVolumeSource struct {
@ -2338,13 +2364,13 @@ type PodAffinityTerm struct {
LabelSelector *metav1.LabelSelector
// namespaces specifies which namespaces the labelSelector applies to (matches against);
// null or empty list means "this pod's namespace"
// +optional
Namespaces []string
// This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
// the labelSelector in the specified namespaces, where co-located is defined as running on a node
// whose value of the label with key topologyKey matches that of any node on which any of the
// selected pods is running.
// Empty topologyKey is not allowed.
// +optional
TopologyKey string
}

View file

@ -9,8 +9,8 @@ load(
go_test(
name = "go_default_test",
srcs = ["helpers_test.go"],
embed = [":go_default_library"],
importpath = "k8s.io/kubernetes/pkg/apis/core/v1/helper",
library = ":go_default_library",
deps = [
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",

View file

@ -89,15 +89,6 @@ func IsServiceIPSet(service *v1.Service) bool {
return service.Spec.ClusterIP != v1.ClusterIPNone && service.Spec.ClusterIP != ""
}
// this function aims to check if the service's cluster IP is requested or not
func IsServiceIPRequested(service *v1.Service) bool {
// ExternalName services are CNAME aliases to external ones. Ignore the IP.
if service.Spec.Type == v1.ServiceTypeExternalName {
return false
}
return service.Spec.ClusterIP == ""
}
// AddToNodeAddresses appends the NodeAddresses to the passed-by-pointer slice,
// only if they do not already exist
func AddToNodeAddresses(addresses *[]v1.NodeAddress, addAddresses ...v1.NodeAddress) {
@ -416,20 +407,6 @@ func GetPersistentVolumeClaimClass(claim *v1.PersistentVolumeClaim) string {
return ""
}
// PersistentVolumeClaimHasClass returns true if given claim has set StorageClassName field.
func PersistentVolumeClaimHasClass(claim *v1.PersistentVolumeClaim) bool {
// Use beta annotation first
if _, found := claim.Annotations[v1.BetaStorageClassAnnotation]; found {
return true
}
if claim.Spec.StorageClassName != nil {
return true
}
return false
}
// 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

View file

@ -21,6 +21,8 @@ limitations under the License.
package v1
import (
unsafe "unsafe"
v1 "k8s.io/api/core/v1"
resource "k8s.io/apimachinery/pkg/api/resource"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -28,7 +30,6 @@ import (
runtime "k8s.io/apimachinery/pkg/runtime"
types "k8s.io/apimachinery/pkg/types"
core "k8s.io/kubernetes/pkg/apis/core"
unsafe "unsafe"
)
func init() {
@ -141,6 +142,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
Convert_core_ExecAction_To_v1_ExecAction,
Convert_v1_FCVolumeSource_To_core_FCVolumeSource,
Convert_core_FCVolumeSource_To_v1_FCVolumeSource,
Convert_v1_FlexPersistentVolumeSource_To_core_FlexPersistentVolumeSource,
Convert_core_FlexPersistentVolumeSource_To_v1_FlexPersistentVolumeSource,
Convert_v1_FlexVolumeSource_To_core_FlexVolumeSource,
Convert_core_FlexVolumeSource_To_v1_FlexVolumeSource,
Convert_v1_FlockerVolumeSource_To_core_FlockerVolumeSource,
@ -1758,6 +1761,34 @@ func Convert_core_FCVolumeSource_To_v1_FCVolumeSource(in *core.FCVolumeSource, o
return autoConvert_core_FCVolumeSource_To_v1_FCVolumeSource(in, out, s)
}
func autoConvert_v1_FlexPersistentVolumeSource_To_core_FlexPersistentVolumeSource(in *v1.FlexPersistentVolumeSource, out *core.FlexPersistentVolumeSource, s conversion.Scope) error {
out.Driver = in.Driver
out.FSType = in.FSType
out.SecretRef = (*core.SecretReference)(unsafe.Pointer(in.SecretRef))
out.ReadOnly = in.ReadOnly
out.Options = *(*map[string]string)(unsafe.Pointer(&in.Options))
return nil
}
// Convert_v1_FlexPersistentVolumeSource_To_core_FlexPersistentVolumeSource is an autogenerated conversion function.
func Convert_v1_FlexPersistentVolumeSource_To_core_FlexPersistentVolumeSource(in *v1.FlexPersistentVolumeSource, out *core.FlexPersistentVolumeSource, s conversion.Scope) error {
return autoConvert_v1_FlexPersistentVolumeSource_To_core_FlexPersistentVolumeSource(in, out, s)
}
func autoConvert_core_FlexPersistentVolumeSource_To_v1_FlexPersistentVolumeSource(in *core.FlexPersistentVolumeSource, out *v1.FlexPersistentVolumeSource, s conversion.Scope) error {
out.Driver = in.Driver
out.FSType = in.FSType
out.SecretRef = (*v1.SecretReference)(unsafe.Pointer(in.SecretRef))
out.ReadOnly = in.ReadOnly
out.Options = *(*map[string]string)(unsafe.Pointer(&in.Options))
return nil
}
// Convert_core_FlexPersistentVolumeSource_To_v1_FlexPersistentVolumeSource is an autogenerated conversion function.
func Convert_core_FlexPersistentVolumeSource_To_v1_FlexPersistentVolumeSource(in *core.FlexPersistentVolumeSource, out *v1.FlexPersistentVolumeSource, s conversion.Scope) error {
return autoConvert_core_FlexPersistentVolumeSource_To_v1_FlexPersistentVolumeSource(in, out, s)
}
func autoConvert_v1_FlexVolumeSource_To_core_FlexVolumeSource(in *v1.FlexVolumeSource, out *core.FlexVolumeSource, s conversion.Scope) error {
out.Driver = in.Driver
out.FSType = in.FSType
@ -3250,7 +3281,7 @@ func autoConvert_v1_PersistentVolumeSource_To_core_PersistentVolumeSource(in *v1
out.CephFS = (*core.CephFSPersistentVolumeSource)(unsafe.Pointer(in.CephFS))
out.FC = (*core.FCVolumeSource)(unsafe.Pointer(in.FC))
out.Flocker = (*core.FlockerVolumeSource)(unsafe.Pointer(in.Flocker))
out.FlexVolume = (*core.FlexVolumeSource)(unsafe.Pointer(in.FlexVolume))
out.FlexVolume = (*core.FlexPersistentVolumeSource)(unsafe.Pointer(in.FlexVolume))
out.AzureFile = (*core.AzureFilePersistentVolumeSource)(unsafe.Pointer(in.AzureFile))
out.VsphereVolume = (*core.VsphereVirtualDiskVolumeSource)(unsafe.Pointer(in.VsphereVolume))
out.Quobyte = (*core.QuobyteVolumeSource)(unsafe.Pointer(in.Quobyte))
@ -3278,7 +3309,7 @@ func autoConvert_core_PersistentVolumeSource_To_v1_PersistentVolumeSource(in *co
out.RBD = (*v1.RBDPersistentVolumeSource)(unsafe.Pointer(in.RBD))
out.Quobyte = (*v1.QuobyteVolumeSource)(unsafe.Pointer(in.Quobyte))
out.ISCSI = (*v1.ISCSIPersistentVolumeSource)(unsafe.Pointer(in.ISCSI))
out.FlexVolume = (*v1.FlexVolumeSource)(unsafe.Pointer(in.FlexVolume))
out.FlexVolume = (*v1.FlexPersistentVolumeSource)(unsafe.Pointer(in.FlexVolume))
out.Cinder = (*v1.CinderVolumeSource)(unsafe.Pointer(in.Cinder))
out.CephFS = (*v1.CephFSPersistentVolumeSource)(unsafe.Pointer(in.CephFS))
out.FC = (*v1.FCVolumeSource)(unsafe.Pointer(in.FC))

View file

@ -24,6 +24,7 @@ go_library(
"//pkg/capabilities:go_default_library",
"//pkg/features:go_default_library",
"//pkg/fieldpath:go_default_library",
"//pkg/master/ports:go_default_library",
"//pkg/security/apparmor:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
@ -50,8 +51,8 @@ go_test(
"events_test.go",
"validation_test.go",
],
embed = [":go_default_library"],
importpath = "k8s.io/kubernetes/pkg/apis/core/validation",
library = ":go_default_library",
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/api/testapi:go_default_library",

View file

@ -51,6 +51,7 @@ import (
"k8s.io/kubernetes/pkg/capabilities"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/fieldpath"
"k8s.io/kubernetes/pkg/master/ports"
"k8s.io/kubernetes/pkg/security/apparmor"
)
@ -212,15 +213,6 @@ func ValidateOwnerReferences(ownerReferences []metav1.OwnerReference, fldPath *f
// value that were not valid. Otherwise this returns an empty list or nil.
type ValidateNameFunc apimachineryvalidation.ValidateNameFunc
// maskTrailingDash replaces the final character of a string with a subdomain safe
// value if is a dash.
func maskTrailingDash(name string) string {
if strings.HasSuffix(name, "-") {
return name[:len(name)-2] + "a"
}
return name
}
// ValidatePodName can be used to check whether the given pod name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
@ -1257,6 +1249,27 @@ func validateFlexVolumeSource(fv *core.FlexVolumeSource, fldPath *field.Path) fi
return allErrs
}
func validateFlexPersistentVolumeSource(fv *core.FlexPersistentVolumeSource, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if len(fv.Driver) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("driver"), ""))
}
// Make sure user-specified options don't use kubernetes namespaces
for k := range fv.Options {
namespace := k
if parts := strings.SplitN(k, "/", 2); len(parts) == 2 {
namespace = parts[0]
}
normalized := "." + strings.ToLower(namespace)
if strings.HasSuffix(normalized, ".kubernetes.io") || strings.HasSuffix(normalized, ".k8s.io") {
allErrs = append(allErrs, field.Invalid(fldPath.Child("options").Key(k), k, "kubernetes.io and k8s.io namespaces are reserved"))
}
}
return allErrs
}
func validateAzureFile(azure *core.AzureFileVolumeSource, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if azure.SecretName == "" {
@ -1588,7 +1601,7 @@ func ValidatePersistentVolume(pv *core.PersistentVolume) field.ErrorList {
}
if pv.Spec.FlexVolume != nil {
numVolumes++
allErrs = append(allErrs, validateFlexVolumeSource(pv.Spec.FlexVolume, specPath.Child("flexVolume"))...)
allErrs = append(allErrs, validateFlexPersistentVolumeSource(pv.Spec.FlexVolume, specPath.Child("flexVolume"))...)
}
if pv.Spec.AzureFile != nil {
if numVolumes > 0 {
@ -1773,27 +1786,26 @@ func ValidatePersistentVolumeClaimSpec(spec *core.PersistentVolumeClaimSpec, fld
func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *core.PersistentVolumeClaim) field.ErrorList {
allErrs := ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, ValidatePersistentVolumeClaim(newPvc)...)
newPvcClone := newPvc.DeepCopy()
oldPvcClone := oldPvc.DeepCopy()
// PVController needs to update PVC.Spec w/ VolumeName.
// Claims are immutable in order to enforce quota, range limits, etc. without gaming the system.
if len(oldPvc.Spec.VolumeName) == 0 {
// volumeName changes are allowed once.
// Reset back to empty string after equality check
oldPvc.Spec.VolumeName = newPvc.Spec.VolumeName
defer func() { oldPvc.Spec.VolumeName = "" }()
oldPvcClone.Spec.VolumeName = newPvcClone.Spec.VolumeName
}
if utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) {
newPVCSpecCopy := newPvc.Spec.DeepCopy()
// lets make sure storage values are same.
if newPvc.Status.Phase == core.ClaimBound && newPVCSpecCopy.Resources.Requests != nil {
newPVCSpecCopy.Resources.Requests["storage"] = oldPvc.Spec.Resources.Requests["storage"]
if newPvc.Status.Phase == core.ClaimBound && newPvcClone.Spec.Resources.Requests != nil {
newPvcClone.Spec.Resources.Requests["storage"] = oldPvc.Spec.Resources.Requests["storage"]
}
oldSize := oldPvc.Spec.Resources.Requests["storage"]
newSize := newPvc.Spec.Resources.Requests["storage"]
if !apiequality.Semantic.DeepEqual(*newPVCSpecCopy, oldPvc.Spec) {
if !apiequality.Semantic.DeepEqual(newPvcClone.Spec, oldPvcClone.Spec) {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "is immutable after creation except resources.requests for bound claims"))
}
if newSize.Cmp(oldSize) < 0 {
@ -1803,7 +1815,7 @@ func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *core.PersistentVolumeCl
} else {
// changes to Spec are not allowed, but updates to label/and some annotations are OK.
// no-op updates pass validation.
if !apiequality.Semantic.DeepEqual(newPvc.Spec, oldPvc.Spec) {
if !apiequality.Semantic.DeepEqual(newPvcClone.Spec, oldPvcClone.Spec) {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "field is immutable after creation"))
}
}
@ -1815,8 +1827,6 @@ func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *core.PersistentVolumeCl
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
allErrs = append(allErrs, ValidateImmutableField(newPvc.Spec.VolumeMode, oldPvc.Spec.VolumeMode, field.NewPath("volumeMode"))...)
}
newPvc.Status = oldPvc.Status
return allErrs
}
@ -3322,6 +3332,31 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod) field.ErrorList {
return allErrs
}
// ValidateContainerStateTransition test to if any illegal container state transitions are being attempted
func ValidateContainerStateTransition(newStatuses, oldStatuses []core.ContainerStatus, fldpath *field.Path, restartPolicy core.RestartPolicy) field.ErrorList {
allErrs := field.ErrorList{}
// If we should always restart, containers are allowed to leave the terminated state
if restartPolicy == core.RestartPolicyAlways {
return allErrs
}
for i, oldStatus := range oldStatuses {
// Skip any container that is not terminated
if oldStatus.State.Terminated == nil {
continue
}
// Skip any container that failed but is allowed to restart
if oldStatus.State.Terminated.ExitCode != 0 && restartPolicy == core.RestartPolicyOnFailure {
continue
}
for _, newStatus := range newStatuses {
if oldStatus.Name == newStatus.Name && newStatus.State.Terminated == nil {
allErrs = append(allErrs, field.Forbidden(fldpath.Index(i).Child("state"), "may not be transitioned to non-terminated state"))
}
}
}
return allErrs
}
// ValidatePodStatusUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
// that cannot be changed.
func ValidatePodStatusUpdate(newPod, oldPod *core.Pod) field.ErrorList {
@ -3329,10 +3364,16 @@ func ValidatePodStatusUpdate(newPod, oldPod *core.Pod) field.ErrorList {
allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, fldPath)
allErrs = append(allErrs, ValidatePodSpecificAnnotationUpdates(newPod, oldPod, fldPath.Child("annotations"))...)
fldPath = field.NewPath("status")
if newPod.Spec.NodeName != oldPod.Spec.NodeName {
allErrs = append(allErrs, field.Forbidden(field.NewPath("status", "nodeName"), "may not be changed directly"))
allErrs = append(allErrs, field.Forbidden(fldPath.Child("nodeName"), "may not be changed directly"))
}
// If pod should not restart, make sure the status update does not transition
// any terminated containers to a non-terminated state.
allErrs = append(allErrs, ValidateContainerStateTransition(newPod.Status.ContainerStatuses, oldPod.Status.ContainerStatuses, fldPath.Child("containerStatuses"), oldPod.Spec.RestartPolicy)...)
allErrs = append(allErrs, ValidateContainerStateTransition(newPod.Status.InitContainerStatuses, oldPod.Status.InitContainerStatuses, fldPath.Child("initContainerStatuses"), oldPod.Spec.RestartPolicy)...)
// For status update we ignore changes to pod spec.
newPod.Spec = oldPod.Spec
@ -3390,9 +3431,9 @@ func ValidateService(service *core.Service) field.ErrorList {
// This is a workaround for broken cloud environments that
// over-open firewalls. Hopefully it can go away when more clouds
// understand containers better.
if port.Port == 10250 {
if port.Port == ports.KubeletPort {
portPath := specPath.Child("ports").Index(ix)
allErrs = append(allErrs, field.Invalid(portPath, port.Port, "may not expose port 10250 externally since it is used by kubelet"))
allErrs = append(allErrs, field.Invalid(portPath, port.Port, fmt.Sprintf("may not expose port %v externally since it is used by kubelet", ports.KubeletPort)))
}
}
if service.Spec.ClusterIP == "None" {
@ -3404,7 +3445,7 @@ func ValidateService(service *core.Service) field.ErrorList {
}
case core.ServiceTypeExternalName:
if service.Spec.ClusterIP != "" {
allErrs = append(allErrs, field.Invalid(specPath.Child("clusterIP"), service.Spec.ClusterIP, "must be empty for ExternalName services"))
allErrs = append(allErrs, field.Forbidden(specPath.Child("clusterIP"), "must be empty for ExternalName services"))
}
if len(service.Spec.ExternalName) > 0 {
allErrs = append(allErrs, ValidateDNS1123Subdomain(service.Spec.ExternalName, specPath.Child("externalName"))...)
@ -3483,7 +3524,7 @@ func ValidateService(service *core.Service) field.ErrorList {
for i := range service.Spec.Ports {
portPath := portsPath.Index(i)
if service.Spec.Ports[i].NodePort != 0 {
allErrs = append(allErrs, field.Invalid(portPath.Child("nodePort"), service.Spec.Ports[i].NodePort, "may not be used when `type` is 'ClusterIP'"))
allErrs = append(allErrs, field.Forbidden(portPath.Child("nodePort"), "may not be used when `type` is 'ClusterIP'"))
}
}
}
@ -3533,7 +3574,7 @@ func ValidateService(service *core.Service) field.ErrorList {
val = service.Annotations[core.AnnotationLoadBalancerSourceRangesKey]
}
if service.Spec.Type != core.ServiceTypeLoadBalancer {
allErrs = append(allErrs, field.Invalid(fieldPath, "", "may only be used when `type` is 'LoadBalancer'"))
allErrs = append(allErrs, field.Forbidden(fieldPath, "may only be used when `type` is 'LoadBalancer'"))
}
_, err := apiservice.GetLoadBalancerSourceRanges(service)
if err != nil {
@ -4340,7 +4381,13 @@ func ValidateResourceRequirements(requirements *core.ResourceRequirements, fldPa
allErrs := field.ErrorList{}
limPath := fldPath.Child("limits")
reqPath := fldPath.Child("requests")
limContainsCpuOrMemory := false
reqContainsCpuOrMemory := false
limContainsHugePages := false
reqContainsHugePages := false
supportedQoSComputeResources := sets.NewString(string(core.ResourceCPU), string(core.ResourceMemory))
for resourceName, quantity := range requirements.Limits {
fldPath := limPath.Key(string(resourceName))
// Validate resource name.
allErrs = append(allErrs, validateContainerResourceName(string(resourceName), fldPath)...)
@ -4351,10 +4398,17 @@ func ValidateResourceRequirements(requirements *core.ResourceRequirements, fldPa
if resourceName == core.ResourceEphemeralStorage && !utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) {
allErrs = append(allErrs, field.Forbidden(limPath, "ResourceEphemeralStorage field disabled by feature-gate for ResourceRequirements"))
}
if helper.IsHugePageResourceName(resourceName) && !utilfeature.DefaultFeatureGate.Enabled(features.HugePages) {
allErrs = append(allErrs, field.Forbidden(limPath, fmt.Sprintf("%s field disabled by feature-gate for ResourceRequirements", resourceName)))
if helper.IsHugePageResourceName(resourceName) {
if !utilfeature.DefaultFeatureGate.Enabled(features.HugePages) {
allErrs = append(allErrs, field.Forbidden(limPath, fmt.Sprintf("%s field disabled by feature-gate for ResourceRequirements", resourceName)))
} else {
limContainsHugePages = true
}
}
if supportedQoSComputeResources.Has(string(resourceName)) {
limContainsCpuOrMemory = true
}
}
for resourceName, quantity := range requirements.Requests {
fldPath := reqPath.Key(string(resourceName))
@ -4366,15 +4420,25 @@ func ValidateResourceRequirements(requirements *core.ResourceRequirements, fldPa
// Check that request <= limit.
limitQuantity, exists := requirements.Limits[resourceName]
if exists {
// For GPUs, not only requests can't exceed limits, they also can't be lower, i.e. must be equal.
// For non overcommitable resources, not only requests can't exceed limits, they also can't be lower, i.e. must be equal.
if quantity.Cmp(limitQuantity) != 0 && !helper.IsOvercommitAllowed(resourceName) {
allErrs = append(allErrs, field.Invalid(reqPath, quantity.String(), fmt.Sprintf("must be equal to %s limit", resourceName)))
} else if quantity.Cmp(limitQuantity) > 0 {
allErrs = append(allErrs, field.Invalid(reqPath, quantity.String(), fmt.Sprintf("must be less than or equal to %s limit", resourceName)))
}
} else if resourceName == core.ResourceNvidiaGPU {
allErrs = append(allErrs, field.Invalid(reqPath, quantity.String(), fmt.Sprintf("must be equal to %s request", core.ResourceNvidiaGPU)))
} else if !helper.IsOvercommitAllowed(resourceName) {
allErrs = append(allErrs, field.Required(limPath, "Limit must be set for non overcommitable resources"))
}
if helper.IsHugePageResourceName(resourceName) {
reqContainsHugePages = true
}
if supportedQoSComputeResources.Has(string(resourceName)) {
reqContainsCpuOrMemory = true
}
}
if !limContainsCpuOrMemory && !reqContainsCpuOrMemory && (reqContainsHugePages || limContainsHugePages) {
allErrs = append(allErrs, field.Forbidden(fldPath, fmt.Sprintf("HugePages require cpu or memory")))
}
return allErrs

View file

@ -469,7 +469,7 @@ func TestValidatePersistentVolumeSourceUpdate(t *testing.T) {
validPvSourceNoUpdate := validVolume.DeepCopy()
invalidPvSourceUpdateType := validVolume.DeepCopy()
invalidPvSourceUpdateType.Spec.PersistentVolumeSource = core.PersistentVolumeSource{
FlexVolume: &core.FlexVolumeSource{
FlexVolume: &core.FlexPersistentVolumeSource{
Driver: "kubernetes.io/blue",
FSType: "ext4",
},
@ -3345,6 +3345,32 @@ func TestAlphaHugePagesIsolation(t *testing.T) {
successCases := []core.Pod{
{ // Basic fields.
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"},
Spec: core.PodSpec{
Containers: []core.Container{
{
Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File",
Resources: core.ResourceRequirements{
Requests: core.ResourceList{
core.ResourceName(core.ResourceCPU): resource.MustParse("10"),
core.ResourceName(core.ResourceMemory): resource.MustParse("10G"),
core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"),
},
Limits: core.ResourceList{
core.ResourceName(core.ResourceCPU): resource.MustParse("10"),
core.ResourceName(core.ResourceMemory): resource.MustParse("10G"),
core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"),
},
},
},
},
RestartPolicy: core.RestartPolicyAlways,
DNSPolicy: core.DNSClusterFirst,
},
},
}
failureCases := []core.Pod{
{ // Basic fields.
ObjectMeta: metav1.ObjectMeta{Name: "hugepages-requireCpuOrMemory", Namespace: "ns"},
Spec: core.PodSpec{
Containers: []core.Container{
{
@ -3363,8 +3389,6 @@ func TestAlphaHugePagesIsolation(t *testing.T) {
DNSPolicy: core.DNSClusterFirst,
},
},
}
failureCases := []core.Pod{
{ // Basic fields.
ObjectMeta: metav1.ObjectMeta{Name: "hugepages-shared", Namespace: "ns"},
Spec: core.PodSpec{
@ -3373,10 +3397,14 @@ func TestAlphaHugePagesIsolation(t *testing.T) {
Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File",
Resources: core.ResourceRequirements{
Requests: core.ResourceList{
core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"),
core.ResourceName(core.ResourceCPU): resource.MustParse("10"),
core.ResourceName(core.ResourceMemory): resource.MustParse("10G"),
core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"),
},
Limits: core.ResourceList{
core.ResourceName("hugepages-2Mi"): resource.MustParse("2Gi"),
core.ResourceName(core.ResourceCPU): resource.MustParse("10"),
core.ResourceName(core.ResourceMemory): resource.MustParse("10G"),
core.ResourceName("hugepages-2Mi"): resource.MustParse("2Gi"),
},
},
},
@ -3393,12 +3421,15 @@ func TestAlphaHugePagesIsolation(t *testing.T) {
Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File",
Resources: core.ResourceRequirements{
Requests: core.ResourceList{
core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"),
core.ResourceName("hugepages-1Gi"): resource.MustParse("2Gi"),
core.ResourceName(core.ResourceCPU): resource.MustParse("10"),
core.ResourceName(core.ResourceMemory): resource.MustParse("10G"),
core.ResourceName("hugepages-1Gi"): resource.MustParse("2Gi"),
},
Limits: core.ResourceList{
core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"),
core.ResourceName("hugepages-1Gi"): resource.MustParse("2Gi"),
core.ResourceName(core.ResourceCPU): resource.MustParse("10"),
core.ResourceName(core.ResourceMemory): resource.MustParse("10G"),
core.ResourceName("hugepages-2Mi"): resource.MustParse("1Gi"),
core.ResourceName("hugepages-1Gi"): resource.MustParse("2Gi"),
},
},
},
@ -6848,6 +6879,28 @@ func TestValidatePod(t *testing.T) {
},
},
},
"invalid extended resource requirement without limit": {
expectedError: "Limit must be set",
spec: core.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"},
Spec: core.PodSpec{
Containers: []core.Container{
{
Name: "invalid",
Image: "image",
ImagePullPolicy: "IfNotPresent",
Resources: core.ResourceRequirements{
Requests: core.ResourceList{
core.ResourceName("example.com/a"): resource.MustParse("2"),
},
},
},
},
RestartPolicy: core.RestartPolicyAlways,
DNSPolicy: core.DNSClusterFirst,
},
},
},
"invalid fractional extended resource in container request": {
expectedError: "must be an integer",
spec: core.Pod{

View file

@ -1547,6 +1547,38 @@ func (in *FCVolumeSource) DeepCopy() *FCVolumeSource {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FlexPersistentVolumeSource) DeepCopyInto(out *FlexPersistentVolumeSource) {
*out = *in
if in.SecretRef != nil {
in, out := &in.SecretRef, &out.SecretRef
if *in == nil {
*out = nil
} else {
*out = new(SecretReference)
**out = **in
}
}
if in.Options != nil {
in, out := &in.Options, &out.Options
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlexPersistentVolumeSource.
func (in *FlexPersistentVolumeSource) DeepCopy() *FlexPersistentVolumeSource {
if in == nil {
return nil
}
out := new(FlexPersistentVolumeSource)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FlexVolumeSource) DeepCopyInto(out *FlexVolumeSource) {
*out = *in
@ -3152,7 +3184,7 @@ func (in *PersistentVolumeSource) DeepCopyInto(out *PersistentVolumeSource) {
if *in == nil {
*out = nil
} else {
*out = new(FlexVolumeSource)
*out = new(FlexPersistentVolumeSource)
(*in).DeepCopyInto(*out)
}
}

View file

@ -9,8 +9,8 @@ load(
go_test(
name = "go_default_test",
srcs = ["helpers_test.go"],
embed = [":go_default_library"],
importpath = "k8s.io/kubernetes/pkg/apis/extensions",
library = ":go_default_library",
)
go_library(