rebase: update kubernetes dep to 1.24.0

As kubernetes 1.24.0 is released, updating
kubernetes dependencies to 1.24.0

updates: #3086

Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
This commit is contained in:
Madhu Rajanna
2022-05-05 08:17:06 +05:30
committed by mergify[bot]
parent fc1529f268
commit c4f79d455f
959 changed files with 80055 additions and 27456 deletions

View File

@ -1,5 +1,5 @@
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- justinsb
- freehan
- justinsb
- freehan

View File

@ -2,7 +2,7 @@
# approval on api packages bubbles to api-approvers
reviewers:
- sig-apps-api-reviewers
- sig-apps-api-approvers
- sig-apps-api-reviewers
- sig-apps-api-approvers
labels:
- sig/apps
- sig/apps

View File

@ -92,9 +92,20 @@ const (
// RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType.
type RollingUpdateStatefulSetStrategy struct {
// Partition indicates the ordinal at which the StatefulSet should be
// partitioned.
// Partition indicates the ordinal at which the StatefulSet should be partitioned
// for updates. During a rolling update, all pods from ordinal Replicas-1 to
// Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched.
// This is helpful in being able to do a canary based deployment. The default value is 0.
Partition int32
// The maximum number of pods that can be unavailable during the update.
// Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%).
// Absolute number is calculated from percentage by rounding up. This can not be 0.
// Defaults to 1. This field is alpha-level and is only honored by servers that enable the
// MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to
// Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it
// will be counted towards MaxUnavailable.
// +optional
MaxUnavailable *intstr.IntOrString
}
// PersistentVolumeClaimRetentionPolicyType is a string enumeration of the policies that will determine
@ -246,6 +257,7 @@ type StatefulSetStatus struct {
// Total number of available pods (ready for at least minReadySeconds) targeted by this statefulset.
// This is a beta field and requires enabling StatefulSetMinReadySeconds feature gate.
// +optional
AvailableReplicas int32
}

View File

@ -24,6 +24,7 @@ package apps
import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
intstr "k8s.io/apimachinery/pkg/util/intstr"
core "k8s.io/kubernetes/pkg/apis/core"
)
@ -621,6 +622,11 @@ func (in *RollingUpdateDeployment) DeepCopy() *RollingUpdateDeployment {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RollingUpdateStatefulSetStrategy) DeepCopyInto(out *RollingUpdateStatefulSetStrategy) {
*out = *in
if in.MaxUnavailable != nil {
in, out := &in.MaxUnavailable, &out.MaxUnavailable
*out = new(intstr.IntOrString)
**out = **in
}
return
}
@ -807,7 +813,7 @@ func (in *StatefulSetUpdateStrategy) DeepCopyInto(out *StatefulSetUpdateStrategy
if in.RollingUpdate != nil {
in, out := &in.RollingUpdate, &out.RollingUpdate
*out = new(RollingUpdateStatefulSetStrategy)
**out = **in
(*in).DeepCopyInto(*out)
}
return
}

View File

@ -1,14 +1,12 @@
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- thockin
- lavalamp
- smarterclayton
- wojtek-t
- deads2k
- caesarxuchao
- sttts
- ncdc
- piosz
- dims
- errordeveloper
- thockin
- lavalamp
- smarterclayton
- wojtek-t
- deads2k
- caesarxuchao
- sttts
- ncdc
- dims

View File

@ -2,7 +2,7 @@
# approval on api packages bubbles to api-approvers
reviewers:
- sig-apps-api-reviewers
- sig-apps-api-approvers
- sig-apps-api-reviewers
- sig-apps-api-approvers
labels:
- sig/apps
- sig/apps

View File

@ -194,9 +194,10 @@ type JobSpec struct {
// `$(job-name)-$(index)-$(random-string)`,
// the Pod hostname takes the form `$(job-name)-$(index)`.
//
// This field is beta-level. More completion modes can be added in the future.
// If the Job controller observes a mode that it doesn't recognize, the
// controller skips updates for the Job.
// More completion modes can be added in the future.
// If the Job controller observes a mode that it doesn't recognize, which
// is possible during upgrades due to version skew, the controller
// skips updates for the Job.
// +optional
CompletionMode *CompletionMode
@ -208,9 +209,6 @@ type JobSpec struct {
// Suspending a Job will reset the StartTime field of the Job, effectively
// resetting the ActiveDeadlineSeconds timer too. Defaults to false.
//
// This field is beta-level, gated by SuspendJob feature flag (enabled by
// default).
//
// +optional
Suspend *bool
}
@ -247,8 +245,8 @@ type JobStatus struct {
// The number of active pods which have a Ready condition.
//
// This field is alpha-level. The job controller populates the field when
// the feature gate JobReadyPods is enabled (disabled by default).
// This field is beta-level. The job controller populates the field when
// the feature gate JobReadyPods is enabled (enabled by default).
// +optional
Ready *int32
@ -378,6 +376,12 @@ type CronJobSpec struct {
// The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron.
Schedule string
// The time zone for the given schedule, see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones.
// If not specified, this will rely on the time zone of the kube-controller-manager process.
// ALPHA: This field is in alpha and must be enabled via the `CronJobTimeZone` feature gate.
// +optional
TimeZone *string
// Optional deadline in seconds for starting the job if it misses scheduled
// time for any reason. Missed jobs executions will be counted as failed ones.
// +optional

View File

@ -92,6 +92,11 @@ func (in *CronJobList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CronJobSpec) DeepCopyInto(out *CronJobSpec) {
*out = *in
if in.TimeZone != nil {
in, out := &in.TimeZone, &out.TimeZone
*out = new(string)
**out = **in
}
if in.StartingDeadlineSeconds != nil {
in, out := &in.StartingDeadlineSeconds, &out.StartingDeadlineSeconds
*out = new(int64)

View File

@ -1,4 +1,4 @@
# See the OWNERS docs at https://go.k8s.io/owners
labels:
- sig/apps
- sig/apps

View File

@ -123,9 +123,8 @@ var standardResourceQuotaScopes = sets.NewString(
)
// IsStandardResourceQuotaScope returns true if the scope is a standard value
func IsStandardResourceQuotaScope(str string, allowNamespaceAffinityScope bool) bool {
return standardResourceQuotaScopes.Has(str) ||
(allowNamespaceAffinityScope && str == string(core.ResourceQuotaScopeCrossNamespacePodAffinity))
func IsStandardResourceQuotaScope(str string) bool {
return standardResourceQuotaScopes.Has(str) || str == string(core.ResourceQuotaScopeCrossNamespacePodAffinity)
}
var podObjectCountQuotaResources = sets.NewString(

View File

@ -1,9 +1,9 @@
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- lavalamp
- smarterclayton
- deads2k
- caesarxuchao
- liggitt
- dims
- lavalamp
- smarterclayton
- deads2k
- caesarxuchao
- liggitt
- dims

View File

@ -472,7 +472,7 @@ type PersistentVolumeClaimSpec struct {
// * While DataSource ignores disallowed values (dropping them), DataSourceRef
// preserves all values, and generates an error if a disallowed value is
// specified.
// (Alpha) Using this field requires the AnyVolumeDataSource feature gate to be enabled.
// (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled.
// +optional
DataSourceRef *TypedLocalObjectReference
}
@ -2160,7 +2160,7 @@ type Container struct {
Name string
// Required.
Image string
// Optional: The docker image's entrypoint is used if this is not provided; cannot be updated.
// Optional: The container image's entrypoint is used if this is not provided; cannot be updated.
// Variable references $(VAR_NAME) are expanded using the container's environment. If a variable
// cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced
// to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
@ -2168,7 +2168,7 @@ type Container struct {
// of whether the variable exists or not.
// +optional
Command []string
// Optional: The docker image's cmd is used if this is not provided; cannot be updated.
// Optional: The container image's cmd is used if this is not provided; cannot be updated.
// Variable references $(VAR_NAME) are expanded using the container's environment. If a variable
// cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced
// to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
@ -2176,7 +2176,7 @@ type Container struct {
// of whether the variable exists or not.
// +optional
Args []string
// Optional: Defaults to Docker's default.
// Optional: Defaults to the container runtime's default working directory.
// +optional
WorkingDir string
// +optional
@ -2243,7 +2243,7 @@ type ProbeHandler struct {
TCPSocket *TCPSocketAction
// GRPC specifies an action involving a GRPC port.
// This is an alpha field and requires enabling GRPCContainerProbe feature gate.
// This is a beta field and requires enabling GRPCContainerProbe feature gate.
// +featureGate=GRPCContainerProbe
// +optional
GRPC *GRPCAction
@ -2662,7 +2662,7 @@ type PodAffinityTerm struct {
// namespaces specifies a static list of namespace names that the term applies to.
// The term is applied to the union of the namespaces listed in this field
// and the ones selected by namespaceSelector.
// null or empty namespaces list and null namespaceSelector means "this pod's namespace"
// null or empty namespaces list and null namespaceSelector 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
@ -2676,7 +2676,6 @@ type PodAffinityTerm struct {
// and the ones listed in the namespaces field.
// null selector and null or empty namespaces list means "this pod's namespace".
// An empty selector ({}) matches all namespaces.
// This field is beta-level and is only honored when PodAffinityNamespaceSelector feature is enabled.
// +optional
NamespaceSelector *metav1.LabelSelector
}
@ -2868,8 +2867,7 @@ type PodSpec struct {
// +optional
SecurityContext *PodSecurityContext
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
// in the case of docker, only DockerConfig type secrets are honored.
// If specified, these secrets will be passed to individual puller implementations for them to use.
// +optional
ImagePullSecrets []LocalObjectReference
// Specifies the hostname of the Pod.
@ -2918,7 +2916,6 @@ type PodSpec struct {
// PreemptionPolicy is the Policy for preempting pods with lower priority.
// One of Never, PreemptLowerPriority.
// Defaults to PreemptLowerPriority if unset.
// This field is beta-level, gated by the NonPreemptingPriority feature-gate.
// +optional
PreemptionPolicy *PreemptionPolicy
// Specifies the DNS parameters of a pod.
@ -2946,7 +2943,6 @@ type PodSpec struct {
// set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value
// defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero.
// More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead
// This field is beta-level as of Kubernetes v1.18, and is only honored by servers that enable the PodOverhead feature.
// +optional
Overhead ResourceList
// EnableServiceLinks indicates whether information about services should be injected into pod's
@ -2987,7 +2983,7 @@ type PodSpec struct {
// - spec.containers[*].securityContext.runAsUser
// - spec.containers[*].securityContext.runAsGroup
// +optional
// This is an alpha field and requires the IdentifyPodOS feature
// This is a beta field and requires the IdentifyPodOS feature
OS *PodOS
}
@ -3233,7 +3229,7 @@ type EphemeralContainerCommon struct {
Name string
// Required.
Image string
// Optional: The docker image's entrypoint is used if this is not provided; cannot be updated.
// Optional: The container image's entrypoint is used if this is not provided; cannot be updated.
// Variable references $(VAR_NAME) are expanded using the container's environment. If a variable
// cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced
// to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
@ -3241,7 +3237,7 @@ type EphemeralContainerCommon struct {
// of whether the variable exists or not.
// +optional
Command []string
// Optional: The docker image's cmd is used if this is not provided; cannot be updated.
// Optional: The container image's cmd is used if this is not provided; cannot be updated.
// Variable references $(VAR_NAME) are expanded using the container's environment. If a variable
// cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced
// to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
@ -3249,7 +3245,7 @@ type EphemeralContainerCommon struct {
// of whether the variable exists or not.
// +optional
Args []string
// Optional: Defaults to Docker's default.
// Optional: Defaults to the container runtime's default working directory.
// +optional
WorkingDir string
// Ports are not allowed for ephemeral containers.
@ -3380,11 +3376,7 @@ type PodStatus struct {
// startTime set.
// More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-and-container-status
InitContainerStatuses []ContainerStatus
// The list has one entry per container in the manifest. Each entry is
// currently the output of `docker inspect`. This output format is *not*
// final and should not be relied upon.
// TODO: Make real decisions about what our info should look like. Re-enable fuzz test
// when we have done this.
// The list has one entry per app container in the manifest.
// +optional
ContainerStatuses []ContainerStatus
@ -3840,6 +3832,10 @@ type ServiceSpec struct {
// This feature depends on whether the underlying cloud-provider supports specifying
// the loadBalancerIP when a load balancer is created.
// This field will be ignored if the cloud-provider does not support the feature.
// Deprecated: This field was under-specified and its meaning varies across implementations,
// and it cannot support dual-stack.
// As of Kubernetes v1.24, users are encouraged to use implementation-specific annotations when available.
// This field may be removed in a future API version.
// +optional
LoadBalancerIP string
@ -3892,7 +3888,6 @@ type ServiceSpec struct {
// value), those requests will be respected, regardless of this field.
// This field may only be set for services with type LoadBalancer and will
// be cleared if the type is changed to any other type.
// This field is beta-level and is only honored by servers that enable the ServiceLBNodePortControl feature.
// +optional
AllocateLoadBalancerNodePorts *bool
@ -3935,7 +3930,7 @@ type ServicePort struct {
// The application protocol for this port.
// This field follows standard Kubernetes label syntax.
// Un-prefixed names are reserved for IANA standard service names (as per
// RFC-6335 and http://www.iana.org/assignments/service-names).
// RFC-6335 and https://www.iana.org/assignments/service-names).
// Non-standard protocols should use prefixed names such as
// mycompany.com/my-custom-protocol.
// +optional
@ -3987,7 +3982,10 @@ type ServiceAccount struct {
// +optional
metav1.ObjectMeta
// Secrets is the list of secrets allowed to be used by pods running using this ServiceAccount
// Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use.
// Pods are only limited to this list if this service account has a "kubernetes.io/enforce-mountable-secrets" annotation set to "true".
// This field should not be used to find auto-generated service account token secrets for use outside of pods.
// Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created.
Secrets []ObjectReference
// ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images
@ -4085,7 +4083,7 @@ type EndpointPort struct {
// The application protocol for this port.
// This field follows standard Kubernetes label syntax.
// Un-prefixed names are reserved for IANA standard service names (as per
// RFC-6335 and http://www.iana.org/assignments/service-names).
// RFC-6335 and https://www.iana.org/assignments/service-names).
// Non-standard protocols should use prefixed names such as
// mycompany.com/my-custom-protocol.
// +optional
@ -4124,8 +4122,7 @@ type NodeSpec struct {
// +optional
Taints []Taint
// If specified, the source to get node configuration from
// The DynamicKubeletConfig feature gate must be enabled for the Kubelet to use this field
// Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed from Kubelets as of 1.24 and will be fully removed in 1.26.
// +optional
ConfigSource *NodeConfigSource
@ -4135,12 +4132,12 @@ type NodeSpec struct {
DoNotUseExternalID string
}
// NodeConfigSource specifies a source of node configuration. Exactly one subfield must be non-nil.
// Deprecated: NodeConfigSource specifies a source of node configuration. Exactly one subfield must be non-nil.
type NodeConfigSource struct {
ConfigMap *ConfigMapNodeConfigSource
}
// ConfigMapNodeConfigSource represents the config map of a node
// Deprecated: ConfigMapNodeConfigSource represents the config map of a node
type ConfigMapNodeConfigSource struct {
// Namespace is the metadata.namespace of the referenced ConfigMap.
// This field is required in all cases.
@ -5064,7 +5061,6 @@ const (
// Match all pod objects that have priority class mentioned
ResourceQuotaScopePriorityClass ResourceQuotaScope = "PriorityClass"
// Match all pod objects that have cross-namespace pod (anti)affinity mentioned
// This is a beta feature enabled by the PodAffinityNamespaceSelector feature flag.
ResourceQuotaScopeCrossNamespacePodAffinity ResourceQuotaScope = "CrossNamespacePodAffinity"
)
@ -5603,15 +5599,18 @@ type TopologySpreadConstraint struct {
// MaxSkew describes the degree to which pods may be unevenly distributed.
// When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference
// between the number of matching pods in the target topology and the global minimum.
// The global minimum is the minimum number of matching pods in an eligible domain
// or zero if the number of eligible domains is less than MinDomains.
// For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same
// labelSelector spread as 1/1/0:
// labelSelector spread as 2/2/1:
// In this case, the global minimum is 1.
// +-------+-------+-------+
// | zone1 | zone2 | zone3 |
// +-------+-------+-------+
// | P | P | |
// | P P | P P | P |
// +-------+-------+-------+
// - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 1/1/1;
// scheduling it onto zone1(zone2) would make the ActualSkew(2-0) on zone1(zone2)
// - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2;
// scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2)
// violate MaxSkew(1).
// - if MaxSkew is 2, incoming pod can be scheduled onto any zone.
// When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence
@ -5622,6 +5621,10 @@ type TopologySpreadConstraint struct {
// and identical values are considered to be in the same topology.
// We consider each <key, value> as a "bucket", and try to put balanced number
// of pods into each bucket.
// We define a domain as a particular instance of a topology.
// Also, we define an eligible domain as a domain whose nodes match the node selector.
// e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology.
// And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology.
// It's a required field.
TopologyKey string
// WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy
@ -5651,6 +5654,32 @@ type TopologySpreadConstraint struct {
// in their corresponding topology domain.
// +optional
LabelSelector *metav1.LabelSelector
// MinDomains indicates a minimum number of eligible domains.
// When the number of eligible domains with matching topology keys is less than minDomains,
// Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed.
// And when the number of eligible domains with matching topology keys equals or greater than minDomains,
// this value has no effect on scheduling.
// As a result, when the number of eligible domains is less than minDomains,
// scheduler won't schedule more than maxSkew Pods to those domains.
// If value is nil, the constraint behaves as if MinDomains is equal to 1.
// Valid values are integers greater than 0.
// When value is not nil, WhenUnsatisfiable must be DoNotSchedule.
//
// For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same
// labelSelector spread as 2/2/2:
// +-------+-------+-------+
// | zone1 | zone2 | zone3 |
// +-------+-------+-------+
// | P P | P P | P P |
// +-------+-------+-------+
// The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0.
// In this situation, new pod with the same labelSelector cannot be scheduled,
// because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones,
// it will violate MaxSkew.
//
// This is an alpha field and requires enabling MinDomainsInPodTopologySpread feature gate.
// +optional
MinDomains *int32
}
// These are the built-in errors for PortStatus.

View File

@ -1,32 +1,24 @@
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- thockin
- lavalamp
- smarterclayton
- wojtek-t
- deads2k
- yujuhong
- brendandburns
- derekwaynecarr
- caesarxuchao
- vishh
- mikedanese
- liggitt
- davidopp
- pmorie
- sttts
- dchen1107
- saad-ali
- luxas
- janetkuo
- justinsb
- ncdc
- tallclair
- piosz
- jsafrane
- dims
- errordeveloper
- krousey
- jayunit100
- rootfs
- thockin
- lavalamp
- smarterclayton
- wojtek-t
- deads2k
- yujuhong
- derekwaynecarr
- caesarxuchao
- mikedanese
- liggitt
- sttts
- dchen1107
- saad-ali
- luxas
- janetkuo
- justinsb
- ncdc
- tallclair
- jsafrane
- dims
- jayunit100

View File

@ -22,11 +22,10 @@ import (
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/kubernetes/pkg/util/parsers"
utilpointer "k8s.io/utils/pointer"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/util/parsers"
"k8s.io/utils/pointer"
)
func addDefaultingFuncs(scheme *runtime.Scheme) error {
@ -64,7 +63,7 @@ func SetDefaults_ReplicationController(obj *v1.ReplicationController) {
}
}
func SetDefaults_Volume(obj *v1.Volume) {
if utilpointer.AllPtrFieldsNil(&obj.VolumeSource) {
if pointer.AllPtrFieldsNil(&obj.VolumeSource) {
obj.VolumeSource = v1.VolumeSource{
EmptyDir: &v1.EmptyDirVolumeSource{},
}
@ -131,16 +130,19 @@ func SetDefaults_Service(obj *v1.Service) {
obj.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeCluster
}
if utilfeature.DefaultFeatureGate.Enabled(features.ServiceInternalTrafficPolicy) && obj.Spec.InternalTrafficPolicy == nil {
serviceInternalTrafficPolicyCluster := v1.ServiceInternalTrafficPolicyCluster
obj.Spec.InternalTrafficPolicy = &serviceInternalTrafficPolicyCluster
if utilfeature.DefaultFeatureGate.Enabled(features.ServiceInternalTrafficPolicy) {
if obj.Spec.InternalTrafficPolicy == nil {
if obj.Spec.Type == v1.ServiceTypeNodePort || obj.Spec.Type == v1.ServiceTypeLoadBalancer || obj.Spec.Type == v1.ServiceTypeClusterIP {
serviceInternalTrafficPolicyCluster := v1.ServiceInternalTrafficPolicyCluster
obj.Spec.InternalTrafficPolicy = &serviceInternalTrafficPolicyCluster
}
}
}
if utilfeature.DefaultFeatureGate.Enabled(features.ServiceLBNodePortControl) {
if obj.Spec.Type == v1.ServiceTypeLoadBalancer {
if obj.Spec.AllocateLoadBalancerNodePorts == nil {
obj.Spec.AllocateLoadBalancerNodePorts = utilpointer.BoolPtr(true)
}
if obj.Spec.Type == v1.ServiceTypeLoadBalancer {
if obj.Spec.AllocateLoadBalancerNodePorts == nil {
obj.Spec.AllocateLoadBalancerNodePorts = pointer.BoolPtr(true)
}
}
}
@ -326,20 +328,17 @@ func SetDefaults_HTTPGetAction(obj *v1.HTTPGetAction) {
// SetDefaults_Namespace adds a default label for all namespaces
func SetDefaults_Namespace(obj *v1.Namespace) {
// TODO, remove the feature gate in 1.22
// we can't SetDefaults for nameless namespaces (generateName).
// This code needs to be kept in sync with the implementation that exists
// in Namespace Canonicalize strategy (pkg/registry/core/namespace)
// note that this can result in many calls to feature enablement in some cases, but
// we assume that there's no real cost there.
if utilfeature.DefaultFeatureGate.Enabled(features.NamespaceDefaultLabelName) {
if len(obj.Name) > 0 {
if obj.Labels == nil {
obj.Labels = map[string]string{}
}
obj.Labels[v1.LabelMetadataName] = obj.Name
if len(obj.Name) > 0 {
if obj.Labels == nil {
obj.Labels = map[string]string{}
}
obj.Labels[v1.LabelMetadataName] = obj.Name
}
}

View File

@ -7994,6 +7994,7 @@ func autoConvert_v1_TopologySpreadConstraint_To_core_TopologySpreadConstraint(in
out.TopologyKey = in.TopologyKey
out.WhenUnsatisfiable = core.UnsatisfiableConstraintAction(in.WhenUnsatisfiable)
out.LabelSelector = (*metav1.LabelSelector)(unsafe.Pointer(in.LabelSelector))
out.MinDomains = (*int32)(unsafe.Pointer(in.MinDomains))
return nil
}
@ -8007,6 +8008,7 @@ func autoConvert_core_TopologySpreadConstraint_To_v1_TopologySpreadConstraint(in
out.TopologyKey = in.TopologyKey
out.WhenUnsatisfiable = v1.UnsatisfiableConstraintAction(in.WhenUnsatisfiable)
out.LabelSelector = (*metav1.LabelSelector)(unsafe.Pointer(in.LabelSelector))
out.MinDomains = (*int32)(unsafe.Pointer(in.MinDomains))
return nil
}

View File

@ -1,31 +1,23 @@
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- thockin
- lavalamp
- smarterclayton
- wojtek-t
- deads2k
- yujuhong
- brendandburns
- derekwaynecarr
- caesarxuchao
- vishh
- mikedanese
- liggitt
- davidopp
- pmorie
- sttts
- quinton-hoole
- dchen1107
- janetkuo
- justinsb
- pwittrock
- tallclair
- soltysh
- piosz
- jsafrane
- dims
- fejta
- krousey
- rootfs
- thockin
- lavalamp
- smarterclayton
- wojtek-t
- deads2k
- yujuhong
- derekwaynecarr
- caesarxuchao
- mikedanese
- liggitt
- sttts
- dchen1107
- janetkuo
- justinsb
- pwittrock
- tallclair
- soltysh
- jsafrane
- dims
- fejta

View File

@ -29,6 +29,7 @@ import (
"unicode"
"unicode/utf8"
"github.com/google/go-cmp/cmp"
v1 "k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/resource"
@ -36,7 +37,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
unversionedvalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation"
@ -53,7 +53,6 @@ import (
"k8s.io/kubernetes/pkg/cluster/ports"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/fieldpath"
"k8s.io/kubernetes/pkg/security/apparmor"
netutils "k8s.io/utils/net"
)
@ -288,9 +287,6 @@ var ValidateServiceAccountName = apimachineryvalidation.ValidateServiceAccountNa
// trailing dashes are allowed.
var ValidateEndpointsName = apimachineryvalidation.NameIsDNSSubdomain
// ValidateClusterName can be used to check whether the given cluster name is valid.
var ValidateClusterName = apimachineryvalidation.ValidateClusterName
// ValidateClassName can be used to check whether the given class name is valid.
// It is defined here to avoid import cycle between pkg/apis/storage/validation
// (where it should be) and this file.
@ -1589,12 +1585,12 @@ func validateCSIPersistentVolumeSource(csi *core.CSIPersistentVolumeSource, fldP
if csi.NodePublishSecretRef != nil {
if len(csi.NodePublishSecretRef.Name) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("nodePublishSecretRef ", "name"), ""))
allErrs = append(allErrs, field.Required(fldPath.Child("nodePublishSecretRef", "name"), ""))
} else {
allErrs = append(allErrs, ValidateDNS1123Label(csi.NodePublishSecretRef.Name, fldPath.Child("name"))...)
}
if len(csi.NodePublishSecretRef.Namespace) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("nodePublishSecretRef ", "namespace"), ""))
allErrs = append(allErrs, field.Required(fldPath.Child("nodePublishSecretRef", "namespace"), ""))
} else {
allErrs = append(allErrs, ValidateDNS1123Label(csi.NodePublishSecretRef.Namespace, fldPath.Child("namespace"))...)
}
@ -1609,7 +1605,7 @@ func validateCSIVolumeSource(csi *core.CSIVolumeSource, fldPath *field.Path) fie
if csi.NodePublishSecretRef != nil {
if len(csi.NodePublishSecretRef.Name) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("nodePublishSecretRef ", "name"), ""))
allErrs = append(allErrs, field.Required(fldPath.Child("nodePublishSecretRef", "name"), ""))
} else {
for _, msg := range ValidateSecretName(csi.NodePublishSecretRef.Name, false) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), csi.NodePublishSecretRef.Name, msg))
@ -1998,7 +1994,7 @@ func ValidatePersistentVolumeUpdate(newPv, oldPv *core.PersistentVolume, opts Pe
// PersistentVolumeSource should be immutable after creation.
if !apiequality.Semantic.DeepEqual(newPv.Spec.PersistentVolumeSource, oldPv.Spec.PersistentVolumeSource) {
pvcSourceDiff := diff.ObjectDiff(newPv.Spec.PersistentVolumeSource, oldPv.Spec.PersistentVolumeSource)
pvcSourceDiff := cmp.Diff(oldPv.Spec.PersistentVolumeSource, newPv.Spec.PersistentVolumeSource)
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "persistentvolumesource"), fmt.Sprintf("spec.persistentvolumesource is immutable after creation\n%v", pvcSourceDiff)))
}
allErrs = append(allErrs, ValidateImmutableField(newPv.Spec.VolumeMode, oldPv.Spec.VolumeMode, field.NewPath("volumeMode"))...)
@ -2023,8 +2019,6 @@ func ValidatePersistentVolumeStatusUpdate(newPv, oldPv *core.PersistentVolume) f
type PersistentVolumeClaimSpecValidationOptions struct {
// Allow spec to contain the "ReadWiteOncePod" access mode
AllowReadWriteOncePod bool
// Allow pvc expansion after PVC is created and bound to a PV
EnableExpansion bool
// Allow users to recover from previously failing expansion operation
EnableRecoverFromExpansionFailure bool
}
@ -2032,7 +2026,6 @@ type PersistentVolumeClaimSpecValidationOptions struct {
func ValidationOptionsForPersistentVolumeClaim(pvc, oldPvc *core.PersistentVolumeClaim) PersistentVolumeClaimSpecValidationOptions {
opts := PersistentVolumeClaimSpecValidationOptions{
AllowReadWriteOncePod: utilfeature.DefaultFeatureGate.Enabled(features.ReadWriteOncePod),
EnableExpansion: utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes),
EnableRecoverFromExpansionFailure: utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure),
}
if oldPvc == nil {
@ -2179,40 +2172,30 @@ func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *core.PersistentVolumeCl
allErrs = append(allErrs, ValidateImmutableAnnotation(newPvc.ObjectMeta.Annotations[v1.BetaStorageClassAnnotation], oldPvc.ObjectMeta.Annotations[v1.BetaStorageClassAnnotation], v1.BetaStorageClassAnnotation, field.NewPath("metadata"))...)
}
if opts.EnableExpansion {
// lets make sure storage values are same.
if newPvc.Status.Phase == core.ClaimBound && newPvcClone.Spec.Resources.Requests != nil {
newPvcClone.Spec.Resources.Requests["storage"] = oldPvc.Spec.Resources.Requests["storage"] // +k8s:verify-mutation:reason=clone
}
// lets make sure storage values are same.
if newPvc.Status.Phase == core.ClaimBound && newPvcClone.Spec.Resources.Requests != nil {
newPvcClone.Spec.Resources.Requests["storage"] = oldPvc.Spec.Resources.Requests["storage"] // +k8s:verify-mutation:reason=clone
}
oldSize := oldPvc.Spec.Resources.Requests["storage"]
newSize := newPvc.Spec.Resources.Requests["storage"]
statusSize := oldPvc.Status.Capacity["storage"]
oldSize := oldPvc.Spec.Resources.Requests["storage"]
newSize := newPvc.Spec.Resources.Requests["storage"]
statusSize := oldPvc.Status.Capacity["storage"]
if !apiequality.Semantic.DeepEqual(newPvcClone.Spec, oldPvcClone.Spec) {
specDiff := diff.ObjectDiff(newPvcClone.Spec, oldPvcClone.Spec)
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), fmt.Sprintf("spec is immutable after creation except resources.requests for bound claims\n%v", specDiff)))
}
if newSize.Cmp(oldSize) < 0 {
if !opts.EnableRecoverFromExpansionFailure {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "resources", "requests", "storage"), "field can not be less than previous value"))
} else {
// This validation permits reducing pvc requested size up to capacity recorded in pvc.status
// so that users can recover from volume expansion failure, but Kubernetes does not actually
// support volume shrinking
if newSize.Cmp(statusSize) <= 0 {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "resources", "requests", "storage"), "field can not be less than status.capacity"))
}
if !apiequality.Semantic.DeepEqual(newPvcClone.Spec, oldPvcClone.Spec) {
specDiff := cmp.Diff(oldPvcClone.Spec, newPvcClone.Spec)
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), fmt.Sprintf("spec is immutable after creation except resources.requests for bound claims\n%v", specDiff)))
}
if newSize.Cmp(oldSize) < 0 {
if !opts.EnableRecoverFromExpansionFailure {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "resources", "requests", "storage"), "field can not be less than previous value"))
} else {
// This validation permits reducing pvc requested size up to capacity recorded in pvc.status
// so that users can recover from volume expansion failure, but Kubernetes does not actually
// support volume shrinking
if newSize.Cmp(statusSize) <= 0 {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "resources", "requests", "storage"), "field can not be less than status.capacity"))
}
}
} 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(newPvcClone.Spec, oldPvcClone.Spec) {
specDiff := diff.ObjectDiff(newPvcClone.Spec, oldPvcClone.Spec)
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), fmt.Sprintf("field is immutable after creation\n%v", specDiff)))
}
}
allErrs = append(allErrs, ValidateImmutableField(newPvc.Spec.VolumeMode, oldPvc.Spec.VolumeMode, field.NewPath("volumeMode"))...)
@ -3236,9 +3219,7 @@ func validatePodDNSConfig(dnsConfig *core.PodDNSConfig, dnsPolicy *core.DNSPolic
}
for i, search := range dnsConfig.Searches {
// it is fine to have a trailing dot
if strings.HasSuffix(search, ".") {
search = search[0 : len(search)-1]
}
search = strings.TrimSuffix(search, ".")
allErrs = append(allErrs, ValidateDNS1123Subdomain(search, fldPath.Child("searches").Index(i))...)
}
// Validate options.
@ -4060,7 +4041,7 @@ func ValidateAppArmorPodAnnotations(annotations map[string]string, spec *core.Po
allErrs = append(allErrs, field.Invalid(fldPath.Key(k), containerName, "container not found"))
}
if err := apparmor.ValidateProfileFormat(p); err != nil {
if err := ValidateAppArmorProfileFormat(p); err != nil {
allErrs = append(allErrs, field.Invalid(fldPath.Key(k), p, err.Error()))
}
}
@ -4068,6 +4049,16 @@ func ValidateAppArmorPodAnnotations(annotations map[string]string, spec *core.Po
return allErrs
}
func ValidateAppArmorProfileFormat(profile string) error {
if profile == "" || profile == v1.AppArmorBetaProfileRuntimeDefault || profile == v1.AppArmorBetaProfileNameUnconfined {
return nil
}
if !strings.HasPrefix(profile, v1.AppArmorBetaProfileNamePrefix) {
return fmt.Errorf("invalid AppArmor profile name: %q", profile)
}
return nil
}
func podSpecHasContainer(spec *core.PodSpec, containerName string) bool {
var hasContainer bool
podshelper.VisitContainersWithPath(spec, field.NewPath("spec"), func(c *core.Container, _ *field.Path) bool {
@ -4372,7 +4363,7 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel
if !apiequality.Semantic.DeepEqual(mungedPodSpec, oldPod.Spec) {
// This diff isn't perfect, but it's a helluva lot better an "I'm not going to tell you what the difference is".
//TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff
specDiff := diff.ObjectDiff(mungedPodSpec, oldPod.Spec)
specDiff := cmp.Diff(oldPod.Spec, mungedPodSpec)
allErrs = append(allErrs, field.Forbidden(specPath, fmt.Sprintf("pod updates may not change fields other than `spec.containers[*].image`, `spec.initContainers[*].image`, `spec.activeDeadlineSeconds`, `spec.tolerations` (only additions to existing tolerations) or `spec.terminationGracePeriodSeconds` (allow it to be set to 1 if it was previously negative)\n%v", specDiff)))
}
@ -4473,7 +4464,7 @@ func ValidatePodEphemeralContainersUpdate(newPod, oldPod *core.Pod, opts PodVali
if new, ok := newContainerIndex[old.Name]; !ok {
allErrs = append(allErrs, field.Forbidden(specPath, fmt.Sprintf("existing ephemeral containers %q may not be removed\n", old.Name)))
} else if !apiequality.Semantic.DeepEqual(old, *new) {
specDiff := diff.ObjectDiff(old, *new)
specDiff := cmp.Diff(old, *new)
allErrs = append(allErrs, field.Forbidden(specPath, fmt.Sprintf("existing ephemeral containers %q may not be changed\n%v", old.Name, specDiff)))
}
}
@ -4685,10 +4676,8 @@ func ValidateService(service *core.Service) field.ErrorList {
allErrs = append(allErrs, field.Forbidden(specPath.Child("allocateLoadBalancerNodePorts"), "may only be used when `type` is 'LoadBalancer'"))
}
if utilfeature.DefaultFeatureGate.Enabled(features.ServiceLBNodePortControl) {
if service.Spec.Type == core.ServiceTypeLoadBalancer && service.Spec.AllocateLoadBalancerNodePorts == nil {
allErrs = append(allErrs, field.Required(field.NewPath("allocateLoadBalancerNodePorts"), ""))
}
if service.Spec.Type == core.ServiceTypeLoadBalancer && service.Spec.AllocateLoadBalancerNodePorts == nil {
allErrs = append(allErrs, field.Required(field.NewPath("allocateLoadBalancerNodePorts"), ""))
}
// validate LoadBalancerClass field
@ -4811,7 +4800,12 @@ func validateServiceInternalTrafficFieldsValue(service *core.Service) field.Erro
if utilfeature.DefaultFeatureGate.Enabled(features.ServiceInternalTrafficPolicy) {
if service.Spec.InternalTrafficPolicy == nil {
allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("internalTrafficPolicy"), ""))
// We do not forbid internalTrafficPolicy on other Service types because of historical reasons.
// We did not check that before it went beta and we don't want to invalidate existing stored objects.
if service.Spec.Type == core.ServiceTypeNodePort ||
service.Spec.Type == core.ServiceTypeLoadBalancer || service.Spec.Type == core.ServiceTypeClusterIP {
allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("internalTrafficPolicy"), ""))
}
}
}
@ -5564,13 +5558,13 @@ func ValidateSecret(secret *core.Secret) field.ErrorList {
// username or password might be empty, but the field must be present
if !usernameFieldExists && !passwordFieldExists {
allErrs = append(allErrs, field.Required(field.NewPath("data[%s]").Key(core.BasicAuthUsernameKey), ""))
allErrs = append(allErrs, field.Required(field.NewPath("data[%s]").Key(core.BasicAuthPasswordKey), ""))
allErrs = append(allErrs, field.Required(dataPath.Key(core.BasicAuthUsernameKey), ""))
allErrs = append(allErrs, field.Required(dataPath.Key(core.BasicAuthPasswordKey), ""))
break
}
case core.SecretTypeSSHAuth:
if len(secret.Data[core.SSHAuthPrivateKey]) == 0 {
allErrs = append(allErrs, field.Required(field.NewPath("data[%s]").Key(core.SSHAuthPrivateKey), ""))
allErrs = append(allErrs, field.Required(dataPath.Key(core.SSHAuthPrivateKey), ""))
break
}
@ -5754,7 +5748,7 @@ func validateResourceQuantityHugePageValue(name core.ResourceName, quantity reso
}
// validateResourceQuotaScopes ensures that each enumerated hard resource constraint is valid for set of scopes
func validateResourceQuotaScopes(resourceQuotaSpec *core.ResourceQuotaSpec, opts ResourceQuotaValidationOptions, fld *field.Path) field.ErrorList {
func validateResourceQuotaScopes(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if len(resourceQuotaSpec.Scopes) == 0 {
return allErrs
@ -5766,7 +5760,7 @@ func validateResourceQuotaScopes(resourceQuotaSpec *core.ResourceQuotaSpec, opts
fldPath := fld.Child("scopes")
scopeSet := sets.NewString()
for _, scope := range resourceQuotaSpec.Scopes {
if !helper.IsStandardResourceQuotaScope(string(scope), opts.AllowPodAffinityNamespaceSelector) {
if !helper.IsStandardResourceQuotaScope(string(scope)) {
allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "unsupported scope"))
}
for _, k := range hardLimits.List() {
@ -5789,7 +5783,7 @@ func validateResourceQuotaScopes(resourceQuotaSpec *core.ResourceQuotaSpec, opts
}
// validateScopedResourceSelectorRequirement tests that the match expressions has valid data
func validateScopedResourceSelectorRequirement(resourceQuotaSpec *core.ResourceQuotaSpec, opts ResourceQuotaValidationOptions, fld *field.Path) field.ErrorList {
func validateScopedResourceSelectorRequirement(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
hardLimits := sets.NewString()
for k := range resourceQuotaSpec.Hard {
@ -5798,7 +5792,7 @@ func validateScopedResourceSelectorRequirement(resourceQuotaSpec *core.ResourceQ
fldPath := fld.Child("matchExpressions")
scopeSet := sets.NewString()
for _, req := range resourceQuotaSpec.ScopeSelector.MatchExpressions {
if !helper.IsStandardResourceQuotaScope(string(req.ScopeName), opts.AllowPodAffinityNamespaceSelector) {
if !helper.IsStandardResourceQuotaScope(string(req.ScopeName)) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("scopeName"), req.ScopeName, "unsupported scope"))
}
for _, k := range hardLimits.List() {
@ -5844,26 +5838,20 @@ func validateScopedResourceSelectorRequirement(resourceQuotaSpec *core.ResourceQ
}
// validateScopeSelector tests that the specified scope selector has valid data
func validateScopeSelector(resourceQuotaSpec *core.ResourceQuotaSpec, opts ResourceQuotaValidationOptions, fld *field.Path) field.ErrorList {
func validateScopeSelector(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if resourceQuotaSpec.ScopeSelector == nil {
return allErrs
}
allErrs = append(allErrs, validateScopedResourceSelectorRequirement(resourceQuotaSpec, opts, fld.Child("scopeSelector"))...)
allErrs = append(allErrs, validateScopedResourceSelectorRequirement(resourceQuotaSpec, fld.Child("scopeSelector"))...)
return allErrs
}
// ResourceQuotaValidationOptions contains the different settings for ResourceQuota validation
type ResourceQuotaValidationOptions struct {
// Allow pod-affinity namespace selector validation.
AllowPodAffinityNamespaceSelector bool
}
// ValidateResourceQuota tests if required fields in the ResourceQuota are set.
func ValidateResourceQuota(resourceQuota *core.ResourceQuota, opts ResourceQuotaValidationOptions) field.ErrorList {
func ValidateResourceQuota(resourceQuota *core.ResourceQuota) field.ErrorList {
allErrs := ValidateObjectMeta(&resourceQuota.ObjectMeta, true, ValidateResourceQuotaName, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateResourceQuotaSpec(&resourceQuota.Spec, opts, field.NewPath("spec"))...)
allErrs = append(allErrs, ValidateResourceQuotaSpec(&resourceQuota.Spec, field.NewPath("spec"))...)
allErrs = append(allErrs, ValidateResourceQuotaStatus(&resourceQuota.Status, field.NewPath("status"))...)
return allErrs
@ -5888,7 +5876,7 @@ func ValidateResourceQuotaStatus(status *core.ResourceQuotaStatus, fld *field.Pa
return allErrs
}
func ValidateResourceQuotaSpec(resourceQuotaSpec *core.ResourceQuotaSpec, opts ResourceQuotaValidationOptions, fld *field.Path) field.ErrorList {
func ValidateResourceQuotaSpec(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
fldPath := fld.Child("hard")
@ -5898,8 +5886,8 @@ func ValidateResourceQuotaSpec(resourceQuotaSpec *core.ResourceQuotaSpec, opts R
allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
}
allErrs = append(allErrs, validateResourceQuotaScopes(resourceQuotaSpec, opts, fld)...)
allErrs = append(allErrs, validateScopeSelector(resourceQuotaSpec, opts, fld)...)
allErrs = append(allErrs, validateResourceQuotaScopes(resourceQuotaSpec, fld)...)
allErrs = append(allErrs, validateScopeSelector(resourceQuotaSpec, fld)...)
return allErrs
}
@ -5917,9 +5905,9 @@ func ValidateResourceQuantityValue(resource string, value resource.Quantity, fld
}
// ValidateResourceQuotaUpdate tests to see if the update is legal for an end user to make.
func ValidateResourceQuotaUpdate(newResourceQuota, oldResourceQuota *core.ResourceQuota, opts ResourceQuotaValidationOptions) field.ErrorList {
func ValidateResourceQuotaUpdate(newResourceQuota, oldResourceQuota *core.ResourceQuota) field.ErrorList {
allErrs := ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, &oldResourceQuota.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateResourceQuotaSpec(&newResourceQuota.Spec, opts, field.NewPath("spec"))...)
allErrs = append(allErrs, ValidateResourceQuotaSpec(&newResourceQuota.Spec, field.NewPath("spec"))...)
// ensure scopes cannot change, and that resources are still valid for scope
fldPath := field.NewPath("spec", "scopes")
@ -6377,7 +6365,7 @@ func validateWindowsHostProcessPod(podSpec *core.PodSpec, fieldPath *field.Path,
}
// At present Windows Pods which contain HostProcess containers must also set HostNetwork.
if hostNetwork != true {
if !hostNetwork {
errMsg := "hostNetwork must be true if pod contains any hostProcess containers"
allErrs = append(allErrs, field.Invalid(fieldPath.Child("hostNetwork"), hostNetwork, errMsg))
}
@ -6524,6 +6512,7 @@ func validateTopologySpreadConstraints(constraints []core.TopologySpreadConstrai
if err := ValidateSpreadConstraintNotRepeat(subFldPath.Child("{topologyKey, whenUnsatisfiable}"), constraint, constraints[i+1:]); err != nil {
allErrs = append(allErrs, err)
}
allErrs = append(allErrs, validateMinDomains(subFldPath.Child("minDomains"), constraint.MinDomains, constraint.WhenUnsatisfiable)...)
}
return allErrs
@ -6537,6 +6526,22 @@ func ValidateMaxSkew(fldPath *field.Path, maxSkew int32) *field.Error {
return nil
}
// validateMinDomains tests that the argument is a valid MinDomains.
func validateMinDomains(fldPath *field.Path, minDomains *int32, action core.UnsatisfiableConstraintAction) field.ErrorList {
if minDomains == nil {
return nil
}
var allErrs field.ErrorList
if *minDomains <= 0 {
allErrs = append(allErrs, field.Invalid(fldPath, minDomains, isNotPositiveErrorMsg))
}
// When MinDomains is non-nil, whenUnsatisfiable must be DoNotSchedule.
if action != core.DoNotSchedule {
allErrs = append(allErrs, field.Invalid(fldPath, minDomains, fmt.Sprintf("can only use minDomains if whenUnsatisfiable=%s, not %s", string(core.DoNotSchedule), string(action))))
}
return allErrs
}
// ValidateTopologyKey tests that the argument is a valid TopologyKey.
func ValidateTopologyKey(fldPath *field.Path, topologyKey string) *field.Error {
if len(topologyKey) == 0 {

View File

@ -5629,6 +5629,11 @@ func (in *TopologySpreadConstraint) DeepCopyInto(out *TopologySpreadConstraint)
*out = new(v1.LabelSelector)
(*in).DeepCopyInto(*out)
}
if in.MinDomains != nil {
in, out := &in.MinDomains, &out.MinDomains
*out = new(int32)
**out = **in
}
return
}

View File

@ -1,32 +1,23 @@
# See the OWNERS docs at https://go.k8s.io/owners
reviewers:
- thockin
- lavalamp
- smarterclayton
- wojtek-t
- deads2k
- brendandburns
- derekwaynecarr
- caesarxuchao
- mikedanese
- liggitt
- pmorie
- sttts
- saad-ali
- janetkuo
- justinsb
- ncdc
- tallclair
- mwielgus
- soltysh
- piosz
- dims
- errordeveloper
- rootfs
- resouer
- therc
- pweil-
- lukaszo
- thockin
- lavalamp
- smarterclayton
- wojtek-t
- deads2k
- derekwaynecarr
- caesarxuchao
- mikedanese
- liggitt
- sttts
- saad-ali
- janetkuo
- justinsb
- ncdc
- tallclair
- mwielgus
- soltysh
- dims
labels:
- sig/apps
- sig/apps

View File

@ -1,8 +1,8 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- sig-network-api-approvers
- sig-network-api-approvers
reviewers:
- sig-network-api-reviewers
- sig-network-api-reviewers
labels:
- sig/network
- sig/network

View File

@ -33,6 +33,11 @@ type NetworkPolicy struct {
// Specification of the desired behavior for this NetworkPolicy.
// +optional
Spec NetworkPolicySpec
// Status is the current state of the NetworkPolicy.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
// +optional
Status NetworkPolicyStatus
}
// PolicyType describes the NetworkPolicy type
@ -195,6 +200,42 @@ type NetworkPolicyPeer struct {
IPBlock *IPBlock
}
// NetworkPolicyConditionType is the type for status conditions on
// a NetworkPolicy. This type should be used with the
// NetworkPolicyStatus.Conditions field.
type NetworkPolicyConditionType string
const (
// NetworkPolicyConditionStatusAccepted represents status of a Network Policy that could be properly parsed by
// the Network Policy provider and will be implemented in the cluster
NetworkPolicyConditionStatusAccepted NetworkPolicyConditionType = "Accepted"
// NetworkPolicyConditionStatusPartialFailure represents status of a Network Policy that could be partially
// parsed by the Network Policy provider and may not be completely implemented due to a lack of a feature or some
// other condition
NetworkPolicyConditionStatusPartialFailure NetworkPolicyConditionType = "PartialFailure"
// NetworkPolicyConditionStatusFailure represents status of a Network Policy that could not be parsed by the
// Network Policy provider and will not be implemented in the cluster
NetworkPolicyConditionStatusFailure NetworkPolicyConditionType = "Failure"
)
// NetworkPolicyConditionReason defines the set of reasons that explain why a
// particular NetworkPolicy condition type has been raised.
type NetworkPolicyConditionReason string
const (
// NetworkPolicyConditionReasonFeatureNotSupported represents a reason where the Network Policy may not have been
// implemented in the cluster due to a lack of some feature not supported by the Network Policy provider
NetworkPolicyConditionReasonFeatureNotSupported NetworkPolicyConditionReason = "FeatureNotSupported"
)
// NetworkPolicyStatus describe the current state of the NetworkPolicy.
type NetworkPolicyStatus struct {
// Conditions holds an array of metav1.Condition that describe the state of the NetworkPolicy.
Conditions []metav1.Condition
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// NetworkPolicyList is a list of NetworkPolicy objects.

View File

@ -432,6 +432,7 @@ func (in *NetworkPolicy) DeepCopyInto(out *NetworkPolicy) {
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
return
}
@ -644,6 +645,29 @@ func (in *NetworkPolicySpec) DeepCopy() *NetworkPolicySpec {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetworkPolicyStatus) DeepCopyInto(out *NetworkPolicyStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]v1.Condition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkPolicyStatus.
func (in *NetworkPolicyStatus) DeepCopy() *NetworkPolicyStatus {
if in == nil {
return nil
}
out := new(NetworkPolicyStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceBackendPort) DeepCopyInto(out *ServiceBackendPort) {
*out = *in

View File

@ -2,10 +2,10 @@
# approval on api packages bubbles to api-approvers
reviewers:
- sig-apps-api-reviewers
- sig-apps-api-approvers
- sig-auth-policy-approvers
- sig-auth-policy-reviewers
- sig-apps-api-reviewers
- sig-apps-api-approvers
- sig-auth-policy-approvers
- sig-auth-policy-reviewers
labels:
- sig/auth
- sig/auth
- sig/apps

View File

@ -1,20 +0,0 @@
/*
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.
*/
// +k8s:deepcopy-gen=package
// +groupName=scheduling.k8s.io
package scheduling // import "k8s.io/kubernetes/pkg/apis/scheduling"

View File

@ -1,53 +0,0 @@
/*
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 scheduling
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name use in this package
const GroupName = "scheduling.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
// Kind takes an unqualified kind and returns a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
// SchemeBuilder points to a list of functions added to Scheme.
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
// AddToScheme applies all the stored functions to the scheme.
AddToScheme = SchemeBuilder.AddToScheme
)
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&PriorityClass{},
&PriorityClassList{},
)
return nil
}

View File

@ -1,89 +0,0 @@
/*
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 scheduling
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/apis/core"
)
const (
// DefaultPriorityWhenNoDefaultClassExists is used to set priority of pods
// that do not specify any priority class and there is no priority class
// marked as default.
DefaultPriorityWhenNoDefaultClassExists = 0
// HighestUserDefinablePriority is the highest priority for user defined priority classes. Priority values larger than 1 billion are reserved for Kubernetes system use.
HighestUserDefinablePriority = int32(1000000000)
// SystemCriticalPriority is the beginning of the range of priority values for critical system components.
SystemCriticalPriority = 2 * HighestUserDefinablePriority
// SystemPriorityClassPrefix is the prefix reserved for system priority class names. Other priority
// classes are not allowed to start with this prefix.
// NOTE: In order to avoid conflict of names with user-defined priority classes, all the names must
// start with SystemPriorityClassPrefix.
SystemPriorityClassPrefix = "system-"
// SystemClusterCritical is the system priority class name that represents cluster-critical.
SystemClusterCritical = SystemPriorityClassPrefix + "cluster-critical"
// SystemNodeCritical is the system priority class name that represents node-critical.
SystemNodeCritical = SystemPriorityClassPrefix + "node-critical"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// PriorityClass defines the mapping from a priority class name to the priority
// integer value. The value can be any valid integer.
type PriorityClass struct {
metav1.TypeMeta
// Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata.
// +optional
metav1.ObjectMeta
// The value of this priority class. This is the actual priority that pods
// receive when they have the name of this class in their pod spec.
Value int32
// globalDefault specifies whether this PriorityClass should be considered as
// the default priority for pods that do not have any priority class.
// Only one PriorityClass can be marked as `globalDefault`. However, if more than
// one PriorityClasses exists with their `globalDefault` field set to true,
// the smallest value of such global default PriorityClasses will be used as the default priority.
// +optional
GlobalDefault bool
// Description is an arbitrary string that usually provides guidelines on
// when this priority class should be used.
// +optional
Description string
// PreemptionPolicy it the Policy for preempting pods with lower priority.
// This field is beta-level.
// +optional
PreemptionPolicy *core.PreemptionPolicy
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// PriorityClassList is a collection of priority classes.
type PriorityClassList struct {
metav1.TypeMeta
// Standard list metadata.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
// +optional
metav1.ListMeta
// Items is the list of PriorityClasses.
Items []PriorityClass
}

View File

@ -1,91 +0,0 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright 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.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package scheduling
import (
runtime "k8s.io/apimachinery/pkg/runtime"
core "k8s.io/kubernetes/pkg/apis/core"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PriorityClass) DeepCopyInto(out *PriorityClass) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
if in.PreemptionPolicy != nil {
in, out := &in.PreemptionPolicy, &out.PreemptionPolicy
*out = new(core.PreemptionPolicy)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PriorityClass.
func (in *PriorityClass) DeepCopy() *PriorityClass {
if in == nil {
return nil
}
out := new(PriorityClass)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *PriorityClass) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PriorityClassList) DeepCopyInto(out *PriorityClassList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]PriorityClass, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PriorityClassList.
func (in *PriorityClassList) DeepCopy() *PriorityClassList {
if in == nil {
return nil
}
out := new(PriorityClassList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *PriorityClassList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}

View File

@ -1,16 +1,17 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- deads2k
- derekwaynecarr
- mikedanese
- janetkuo
- cheftako
- sig-apps-approvers
- deads2k
- derekwaynecarr
- mikedanese
- janetkuo
- cheftako
- andrewsykim
- sig-apps-approvers
reviewers:
- andrewsykim
- deads2k
- cheftako
- sig-apps-reviewers
- andrewsykim
- deads2k
- cheftako
- sig-apps-reviewers
labels:
- sig/apps
- sig/apps

View File

@ -504,10 +504,10 @@ func validateControllerRef(controllerRef *metav1.OwnerReference) error {
if len(controllerRef.Kind) == 0 {
return fmt.Errorf("controllerRef has empty Kind")
}
if controllerRef.Controller == nil || *controllerRef.Controller != true {
if controllerRef.Controller == nil || !*controllerRef.Controller {
return fmt.Errorf("controllerRef.Controller is not set to true")
}
if controllerRef.BlockOwnerDeletion == nil || *controllerRef.BlockOwnerDeletion != true {
if controllerRef.BlockOwnerDeletion == nil || !*controllerRef.BlockOwnerDeletion {
return fmt.Errorf("controllerRef.BlockOwnerDeletion is not set")
}
return nil

View File

@ -900,7 +900,8 @@ func GetDeploymentsForReplicaSet(deploymentLister appslisters.DeploymentLister,
for _, d := range dList {
selector, err := metav1.LabelSelectorAsSelector(d.Spec.Selector)
if err != nil {
return nil, fmt.Errorf("invalid label selector: %v", err)
// This object has an invalid selector, it does not match the replicaset
continue
}
// If a deployment with a nil or empty selector creeps in, it should match nothing, not everything.
if selector.Empty() || !selector.Matches(labels.Set(rs.Labels)) {

View File

@ -1,4 +1,4 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- feature-approvers
- feature-approvers

View File

@ -78,17 +78,20 @@ const (
// owner: @gnufied
// beta: v1.11
// GA: 1.24
// Ability to Expand persistent volumes
ExpandPersistentVolumes featuregate.Feature = "ExpandPersistentVolumes"
// owner: @mlmhl
// owner: @mlmhl @gnufied
// beta: v1.15
// GA: 1.24
// Ability to expand persistent volumes' file system without unmounting volumes.
ExpandInUsePersistentVolumes featuregate.Feature = "ExpandInUsePersistentVolumes"
// owner: @gnufied
// alpha: v1.14
// beta: v1.16
// GA: 1.24
// Ability to expand CSI volumes
ExpandCSIVolumes featuregate.Feature = "ExpandCSIVolumes"
@ -157,12 +160,15 @@ const (
// owner: @pohly
// alpha: v1.19
// beta: v1.21
// GA: v1.24
//
// Enables tracking of available storage capacity that CSI drivers provide.
CSIStorageCapacity featuregate.Feature = "CSIStorageCapacity"
// owner: @alculquicondor
// alpha: v1.19
// beta: v1.20
// GA: v1.24
//
// Enables the use of PodTopologySpread scheduling plugin to do default
// spreading and disables legacy SelectorSpread plugin.
@ -179,6 +185,7 @@ const (
// owner: @chendave
// alpha: v1.21
// beta: v1.22
// GA: v1.24
//
// PreferNominatedNode tells scheduler whether the nominated node will be checked first before looping
// all the rest of nodes in the cluster.
@ -187,14 +194,6 @@ const (
// and hence is the best candidate instead.
PreferNominatedNode featuregate.Feature = "PreferNominatedNode"
// owner: @tallclair
// alpha: v1.12
// beta: v1.14
// GA: v1.20
//
// Enables RuntimeClass, for selecting between multiple runtimes to run a pod.
RuntimeClass featuregate.Feature = "RuntimeClass"
// owner: @rikatz
// kep: http://kep.k8s.io/2079
// alpha: v1.21
@ -219,6 +218,7 @@ const (
// owner: @alculquicondor
// alpha: v1.21
// beta: v1.22
// stable: v1.24
//
// Allows Job controller to manage Pod completions per completion index.
IndexedJob featuregate.Feature = "IndexedJob"
@ -235,6 +235,7 @@ const (
// owner: @alculquicondor
// alpha: v1.23
// beta: v1.24
//
// Track the number of pods with Ready condition in the Job status.
JobReadyPods featuregate.Feature = "JobReadyPods"
@ -282,6 +283,7 @@ const (
// owner: @andyzhangx
// alpha: v1.15
// beta: v1.19
// GA: v1.24
//
// Enables the Azure Disk in-tree driver to Azure Disk Driver migration feature.
CSIMigrationAzureDisk featuregate.Feature = "CSIMigrationAzureDisk"
@ -306,7 +308,7 @@ const (
InTreePluginAzureFileUnregister featuregate.Feature = "InTreePluginAzureFileUnregister"
// owner: @divyenpatel
// beta: v1.19 (requires: vSphere vCenter/ESXi Version: 7.0u1, HW Version: VM version 15)
// beta: v1.19 (requires: vSphere vCenter/ESXi Version: 7.0u2, HW Version: VM version 15)
//
// Enables the vSphere in-tree driver to vSphere CSI Driver migration feature.
CSIMigrationvSphere featuregate.Feature = "CSIMigrationvSphere"
@ -346,7 +348,7 @@ const (
// alpha: v1.23
//
// Enables the RBD in-tree driver to RBD CSI Driver migration feature.
CSIMigrationRBD featuregate.Feature = "csiMigrationRBD"
CSIMigrationRBD featuregate.Feature = "CSIMigrationRBD"
// owner: @humblec
// alpha: v1.23
@ -388,6 +390,7 @@ const (
// owner: @denkensk
// alpha: v1.15
// beta: v1.19
// ga: v1.24
//
// Enables NonPreempting option for priorityClass and pod.
NonPreemptingPriority featuregate.Feature = "NonPreemptingPriority"
@ -395,6 +398,7 @@ const (
// owner: @egernst
// alpha: v1.16
// beta: v1.18
// ga: v1.24
//
// Enables PodOverhead, for accounting pod overheads which are specific to a given RuntimeClass
PodOverhead featuregate.Feature = "PodOverhead"
@ -403,6 +407,7 @@ const (
// kep: http://kep.k8s.io/563
// alpha: v1.15
// beta: v1.21
// ga: v1.23
//
// Enables ipv6 dual stack
IPv6DualStack featuregate.Feature = "IPv6DualStack"
@ -447,24 +452,6 @@ const (
// DaemonSets allow workloads to maintain availability during update per node
DaemonSetUpdateSurge featuregate.Feature = "DaemonSetUpdateSurge"
// owner: @wojtek-t
// alpha: v1.18
// beta: v1.19
// ga: v1.21
//
// Enables a feature to make secrets and configmaps data immutable.
ImmutableEphemeralVolumes featuregate.Feature = "ImmutableEphemeralVolumes"
// owner: @bart0sh
// alpha: v1.18
// beta: v1.19
// GA: 1.22
//
// Enables usage of HugePages-<size> in a volume medium,
// e.g. emptyDir:
// medium: HugePages-1Gi
HugePageStorageMediumSize featuregate.Feature = "HugePageStorageMediumSize"
// owner: @derekwaynecarr
// alpha: v1.20
// beta: v1.21 (off by default until 1.22)
@ -474,20 +461,11 @@ const (
// owner: @bswartz
// alpha: v1.18
// beta: v1.24
//
// Enables usage of any object for volume data source in PVCs
AnyVolumeDataSource featuregate.Feature = "AnyVolumeDataSource"
// owner: @javidiaz
// kep: http://kep.k8s.io/1797
// alpha: v1.19
// beta: v1.20
// GA: v1.22
//
// Allow setting the Fully Qualified Domain Name (FQDN) in the hostname of a Pod. If a Pod does not
// have FQDN, this feature has no effect.
SetHostnameAsFQDN featuregate.Feature = "SetHostnameAsFQDN"
// owner: @ksubrmnn
// alpha: v1.14
// beta: v1.20
@ -552,8 +530,9 @@ const (
// Lock to default and remove after v1.22 based on user feedback that should be reflected in KEP #1972 update
ExecProbeTimeout featuregate.Feature = "ExecProbeTimeout"
// owner: @andrewsykim
// owner: @andrewsykim @adisky
// alpha: v1.20
// beta: v1.24
//
// Enable kubelet exec plugins for image pull credentials.
KubeletCredentialProviders featuregate.Feature = "KubeletCredentialProviders"
@ -587,7 +566,7 @@ const (
// owner: @wzshiming
// alpha: v1.23
//
// beta: v1.24
// Make the kubelet use shutdown configuration based on pod priority values for graceful shutdown.
GracefulNodeShutdownBasedOnPodPriority featuregate.Feature = "GracefulNodeShutdownBasedOnPodPriority"
@ -595,13 +574,15 @@ const (
// kep: http://kep.k8s.io/1864
// alpha: v1.20
// beta: v1.22
// ga: v1.24
//
// Allows control if NodePorts shall be created for services with "type: LoadBalancer" by defining the spec.AllocateLoadBalancerNodePorts field (bool)
ServiceLBNodePortControl featuregate.Feature = "ServiceLBNodePortControl"
// owner: @janosi
// owner: @janosi @bridgetkromhout
// kep: http://kep.k8s.io/1435
// alpha: v1.20
// beta: v1.24
//
// Enables the usage of different protocols in the same Service with type=LoadBalancer
MixedProtocolLBService featuregate.Feature = "MixedProtocolLBService"
@ -646,6 +627,7 @@ const (
// owner: @ahg-g
// alpha: v1.21
// beta: v1.22
// GA: v1.24
//
// Allow specifying NamespaceSelector in PodAffinityTerm.
PodAffinityNamespaceSelector featuregate.Feature = "PodAffinityNamespaceSelector"
@ -654,6 +636,7 @@ const (
// kep: http://kep.k8s.io/1959
// alpha: v1.21
// beta: v1.22
// GA: v1.24
//
// Enable support multiple Service "type: LoadBalancer" implementations in a cluster by specifying LoadBalancerClass
ServiceLoadBalancerClass featuregate.Feature = "ServiceLoadBalancerClass"
@ -685,6 +668,7 @@ const (
// owner: @adtac
// alpha: v1.21
// beta: v1.22
// GA: v1.24
//
// Allows jobs to be created in the suspended state.
SuspendJob featuregate.Feature = "SuspendJob"
@ -695,14 +679,6 @@ const (
// Enable POD resources API to return allocatable resources
KubeletPodResourcesGetAllocatable featuregate.Feature = "KubeletPodResourcesGetAllocatable"
// owner: @jayunit100 @abhiraut @rikatz
// kep: http://kep.k8s.io/2161
// beta: v1.21
// ga: v1.22
//
// Labels all namespaces with a default label "kubernetes.io/metadata.name: <namespaceName>"
NamespaceDefaultLabelName featuregate.Feature = "NamespaceDefaultLabelName"
// owner: @fengzixu
// alpha: v1.21
//
@ -725,7 +701,7 @@ const (
// owner: @ravig
// alpha: v1.23
//
// beta: v1.24
// IdentifyPodOS allows user to specify OS on which they'd like the Pod run. The user should still set the nodeSelector
// with appropriate `kubernetes.io/os` label for scheduler to identify appropriate node for the pod to run.
IdentifyPodOS featuregate.Feature = "IdentifyPodOS"
@ -758,6 +734,7 @@ const (
// owner: @enj
// beta: v1.22
// ga: v1.24
//
// Allows clients to request a duration for certificates issued via the Kubernetes CSR API.
CSRDuration featuregate.Feature = "CSRDuration"
@ -787,6 +764,7 @@ const (
// owner: @jiahuif
// alpha: v1.21
// beta: v1.22
// GA: v1.24
//
// Enables Leader Migration for kube-controller-manager and cloud-controller-manager
ControllerManagerLeaderMigration featuregate.Feature = "ControllerManagerLeaderMigration"
@ -849,12 +827,61 @@ const (
// Allow users to recover from volume expansion failure
RecoverVolumeExpansionFailure featuregate.Feature = "RecoverVolumeExpansionFailure"
// owner: @yuzhiquan, @bowei, @PxyUp
// owner: @yuzhiquan, @bowei, @PxyUp, @SergeyKanzhelev
// kep: http://kep.k8s.io/2727
// alpha: v1.23
// beta: v1.24
//
// Enables GRPC probe method for {Liveness,Readiness,Startup}Probe.
GRPCContainerProbe featuregate.Feature = "GRPCContainerProbe"
// owner: @zshihang
// kep: http://kep.k8s.io/2800
// beta: v1.24
//
// Stop auto-generation of secret-based service account tokens.
LegacyServiceAccountTokenNoAutoGeneration featuregate.Feature = "LegacyServiceAccountTokenNoAutoGeneration"
// owner: @sanposhiho
// kep: http://kep.k8s.io/3022
// alpha: v1.24
//
// Enable MinDomains in Pod Topology Spread.
MinDomainsInPodTopologySpread featuregate.Feature = "MinDomainsInPodTopologySpread"
// owner: @aojea
// kep: http://kep.k8s.io/3070
// alpha: v1.24
//
// Subdivide the ClusterIP range for dynamic and static IP allocation.
ServiceIPStaticSubrange featuregate.Feature = "ServiceIPStaticSubrange"
// owner: @xing-yang @sonasingh46
// kep: http://kep.k8s.io/2268
// alpha: v1.24
//
// Allow pods to failover to a different node in case of non graceful node shutdown
NodeOutOfServiceVolumeDetach featuregate.Feature = "NodeOutOfServiceVolumeDetach"
// owner: @krmayankk
// alpha: v1.24
//
// Enables maxUnavailable for StatefulSet
MaxUnavailableStatefulSet featuregate.Feature = "MaxUnavailableStatefulSet"
// owner: @rikatz
// kep: http://kep.k8s.io/2943
// alpha: v1.24
//
// Enables NetworkPolicy status subresource
NetworkPolicyStatus featuregate.Feature = "NetworkPolicyStatus"
// owner: @deejross
// kep: http://kep.k8s.io/3140
// alpha: v1.24
//
// Enables support for time zones in CronJobs.
CronJobTimeZone featuregate.Feature = "CronJobTimeZone"
)
func init() {
@ -866,16 +893,16 @@ func init() {
// available throughout Kubernetes binaries.
var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
AppArmor: {Default: true, PreRelease: featuregate.Beta},
DynamicKubeletConfig: {Default: false, PreRelease: featuregate.Deprecated}, // feature gate is deprecated in 1.22, remove no early than 1.23
DynamicKubeletConfig: {Default: false, PreRelease: featuregate.Deprecated}, // feature gate is deprecated in 1.22, kubelet logic is removed in 1.24, api server logic can be removed in 1.26
ExperimentalHostUserNamespaceDefaultingGate: {Default: false, PreRelease: featuregate.Beta},
DevicePlugins: {Default: true, PreRelease: featuregate.Beta},
RotateKubeletServerCertificate: {Default: true, PreRelease: featuregate.Beta},
LocalStorageCapacityIsolation: {Default: true, PreRelease: featuregate.Beta},
EphemeralContainers: {Default: true, PreRelease: featuregate.Beta},
QOSReserved: {Default: false, PreRelease: featuregate.Alpha},
ExpandPersistentVolumes: {Default: true, PreRelease: featuregate.Beta},
ExpandInUsePersistentVolumes: {Default: true, PreRelease: featuregate.Beta},
ExpandCSIVolumes: {Default: true, PreRelease: featuregate.Beta},
ExpandPersistentVolumes: {Default: true, PreRelease: featuregate.GA}, // remove in 1.25
ExpandInUsePersistentVolumes: {Default: true, PreRelease: featuregate.GA}, // remove in 1.25
ExpandCSIVolumes: {Default: true, PreRelease: featuregate.GA}, // remove in 1.25
CPUManager: {Default: true, PreRelease: featuregate.Beta},
MemoryManager: {Default: true, PreRelease: featuregate.Beta},
CPUCFSQuotaPeriod: {Default: false, PreRelease: featuregate.Alpha},
@ -886,13 +913,13 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
InTreePluginGCEUnregister: {Default: false, PreRelease: featuregate.Alpha},
CSIMigrationAWS: {Default: true, PreRelease: featuregate.Beta},
InTreePluginAWSUnregister: {Default: false, PreRelease: featuregate.Alpha},
CSIMigrationAzureDisk: {Default: true, PreRelease: featuregate.Beta}, // On by default in 1.23 (requires Azure Disk CSI driver)
CSIMigrationAzureDisk: {Default: true, PreRelease: featuregate.GA}, // On by default in 1.23 (requires Azure Disk CSI driver)
InTreePluginAzureDiskUnregister: {Default: false, PreRelease: featuregate.Alpha},
CSIMigrationAzureFile: {Default: false, PreRelease: featuregate.Beta}, // Off by default (requires Azure File CSI driver)
CSIMigrationAzureFile: {Default: true, PreRelease: featuregate.Beta}, // On by default in 1.24 (requires Azure File CSI driver)
InTreePluginAzureFileUnregister: {Default: false, PreRelease: featuregate.Alpha},
CSIMigrationvSphere: {Default: false, PreRelease: featuregate.Beta}, // Off by default (requires vSphere CSI driver)
InTreePluginvSphereUnregister: {Default: false, PreRelease: featuregate.Alpha},
CSIMigrationOpenStack: {Default: true, PreRelease: featuregate.Beta},
CSIMigrationOpenStack: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26
InTreePluginOpenStackUnregister: {Default: false, PreRelease: featuregate.Alpha},
CSIMigrationRBD: {Default: false, PreRelease: featuregate.Alpha}, // Off by default (requires RBD CSI driver)
InTreePluginRBDUnregister: {Default: false, PreRelease: featuregate.Alpha},
@ -900,22 +927,21 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
CSIMigrationPortworx: {Default: false, PreRelease: featuregate.Alpha}, // Off by default (requires Portworx CSI driver)
InTreePluginPortworxUnregister: {Default: false, PreRelease: featuregate.Alpha},
CSIInlineVolume: {Default: true, PreRelease: featuregate.Beta},
CSIStorageCapacity: {Default: true, PreRelease: featuregate.Beta},
CSIStorageCapacity: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26
CSIServiceAccountToken: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.23
GenericEphemeralVolume: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.25
CSIVolumeFSGroupPolicy: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.25
VolumeSubpath: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.25
RuntimeClass: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.23
NetworkPolicyEndPort: {Default: true, PreRelease: featuregate.Beta},
ProcMountType: {Default: false, PreRelease: featuregate.Alpha},
TTLAfterFinished: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.25
IndexedJob: {Default: true, PreRelease: featuregate.Beta},
JobTrackingWithFinalizers: {Default: true, PreRelease: featuregate.Beta},
JobReadyPods: {Default: false, PreRelease: featuregate.Alpha},
IndexedJob: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26
JobTrackingWithFinalizers: {Default: false, PreRelease: featuregate.Beta}, // Disabled due to #109485
JobReadyPods: {Default: true, PreRelease: featuregate.Beta},
KubeletPodResources: {Default: true, PreRelease: featuregate.Beta},
LocalStorageCapacityIsolationFSQuotaMonitoring: {Default: false, PreRelease: featuregate.Alpha},
NonPreemptingPriority: {Default: true, PreRelease: featuregate.Beta},
PodOverhead: {Default: true, PreRelease: featuregate.Beta},
NonPreemptingPriority: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.25
PodOverhead: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26
IPv6DualStack: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.25
EndpointSlice: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.25
EndpointSliceProxying: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.25
@ -925,38 +951,34 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
WindowsEndpointSliceProxying: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.25
PodDisruptionBudget: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.25
DaemonSetUpdateSurge: {Default: true, PreRelease: featuregate.Beta}, // on by default in 1.22
ImmutableEphemeralVolumes: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.24
HugePageStorageMediumSize: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.24
DownwardAPIHugePages: {Default: true, PreRelease: featuregate.Beta}, // on by default in 1.22
AnyVolumeDataSource: {Default: false, PreRelease: featuregate.Alpha},
DefaultPodTopologySpread: {Default: true, PreRelease: featuregate.Beta},
SetHostnameAsFQDN: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.24
AnyVolumeDataSource: {Default: true, PreRelease: featuregate.Beta}, // on by default in 1.24
DefaultPodTopologySpread: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26
WinOverlay: {Default: true, PreRelease: featuregate.Beta},
WinDSR: {Default: false, PreRelease: featuregate.Alpha},
DisableAcceleratorUsageMetrics: {Default: true, PreRelease: featuregate.Beta},
HPAContainerMetrics: {Default: false, PreRelease: featuregate.Alpha},
SizeMemoryBackedVolumes: {Default: true, PreRelease: featuregate.Beta},
ExecProbeTimeout: {Default: true, PreRelease: featuregate.GA}, // lock to default and remove after v1.22 based on KEP #1972 update
KubeletCredentialProviders: {Default: false, PreRelease: featuregate.Alpha},
KubeletCredentialProviders: {Default: true, PreRelease: featuregate.Beta},
GracefulNodeShutdown: {Default: true, PreRelease: featuregate.Beta},
GracefulNodeShutdownBasedOnPodPriority: {Default: false, PreRelease: featuregate.Alpha},
ServiceLBNodePortControl: {Default: true, PreRelease: featuregate.Beta},
MixedProtocolLBService: {Default: false, PreRelease: featuregate.Alpha},
GracefulNodeShutdownBasedOnPodPriority: {Default: true, PreRelease: featuregate.Beta},
ServiceLBNodePortControl: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26
MixedProtocolLBService: {Default: true, PreRelease: featuregate.Beta},
VolumeCapacityPriority: {Default: false, PreRelease: featuregate.Alpha},
PreferNominatedNode: {Default: true, PreRelease: featuregate.Beta},
ProbeTerminationGracePeriod: {Default: false, PreRelease: featuregate.Beta}, // Default to false in beta 1.22, set to true in 1.24
PreferNominatedNode: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.25
ProbeTerminationGracePeriod: {Default: false, PreRelease: featuregate.Beta}, // Default to false in beta 1.22, set to true in 1.24
NodeSwap: {Default: false, PreRelease: featuregate.Alpha},
PodDeletionCost: {Default: true, PreRelease: featuregate.Beta},
StatefulSetAutoDeletePVC: {Default: false, PreRelease: featuregate.Alpha},
TopologyAwareHints: {Default: false, PreRelease: featuregate.Beta},
PodAffinityNamespaceSelector: {Default: true, PreRelease: featuregate.Beta},
ServiceLoadBalancerClass: {Default: true, PreRelease: featuregate.Beta},
IngressClassNamespacedParams: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.24
TopologyAwareHints: {Default: true, PreRelease: featuregate.Beta},
PodAffinityNamespaceSelector: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26
ServiceLoadBalancerClass: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26
IngressClassNamespacedParams: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.25
ServiceInternalTrafficPolicy: {Default: true, PreRelease: featuregate.Beta},
LogarithmicScaleDown: {Default: true, PreRelease: featuregate.Beta},
SuspendJob: {Default: true, PreRelease: featuregate.Beta},
SuspendJob: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26
KubeletPodResourcesGetAllocatable: {Default: true, PreRelease: featuregate.Beta},
NamespaceDefaultLabelName: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.24
CSIVolumeHealth: {Default: false, PreRelease: featuregate.Alpha},
WindowsHostProcessContainers: {Default: true, PreRelease: featuregate.Beta},
DisableCloudProviders: {Default: false, PreRelease: featuregate.Alpha},
@ -966,35 +988,39 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
SeccompDefault: {Default: false, PreRelease: featuregate.Alpha},
PodSecurity: {Default: true, PreRelease: featuregate.Beta},
ReadWriteOncePod: {Default: false, PreRelease: featuregate.Alpha},
CSRDuration: {Default: true, PreRelease: featuregate.Beta},
CSRDuration: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26
DelegateFSGroupToCSIDriver: {Default: true, PreRelease: featuregate.Beta},
KubeletInUserNamespace: {Default: false, PreRelease: featuregate.Alpha},
MemoryQoS: {Default: false, PreRelease: featuregate.Alpha},
CPUManagerPolicyOptions: {Default: true, PreRelease: featuregate.Beta},
ControllerManagerLeaderMigration: {Default: true, PreRelease: featuregate.Beta},
ControllerManagerLeaderMigration: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26
CPUManagerPolicyAlphaOptions: {Default: false, PreRelease: featuregate.Alpha},
CPUManagerPolicyBetaOptions: {Default: true, PreRelease: featuregate.Beta},
JobMutableNodeSchedulingDirectives: {Default: true, PreRelease: featuregate.Beta},
IdentifyPodOS: {Default: false, PreRelease: featuregate.Alpha},
IdentifyPodOS: {Default: true, PreRelease: featuregate.Beta},
PodAndContainerStatsFromCRI: {Default: false, PreRelease: featuregate.Alpha},
HonorPVReclaimPolicy: {Default: false, PreRelease: featuregate.Alpha},
RecoverVolumeExpansionFailure: {Default: false, PreRelease: featuregate.Alpha},
GRPCContainerProbe: {Default: false, PreRelease: featuregate.Alpha},
GRPCContainerProbe: {Default: true, PreRelease: featuregate.Beta},
LegacyServiceAccountTokenNoAutoGeneration: {Default: true, PreRelease: featuregate.Beta},
MinDomainsInPodTopologySpread: {Default: false, PreRelease: featuregate.Alpha},
ServiceIPStaticSubrange: {Default: false, PreRelease: featuregate.Alpha},
NodeOutOfServiceVolumeDetach: {Default: false, PreRelease: featuregate.Alpha},
MaxUnavailableStatefulSet: {Default: false, PreRelease: featuregate.Alpha},
NetworkPolicyStatus: {Default: false, PreRelease: featuregate.Alpha},
CronJobTimeZone: {Default: false, PreRelease: featuregate.Alpha},
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
// unintentionally on either side:
genericfeatures.StreamingProxyRedirects: {Default: false, PreRelease: featuregate.Deprecated}, // remove in 1.24
genericfeatures.ValidateProxyRedirects: {Default: true, PreRelease: featuregate.Deprecated},
genericfeatures.AdvancedAuditing: {Default: true, PreRelease: featuregate.GA},
genericfeatures.APIResponseCompression: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.APIListChunking: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.DryRun: {Default: true, PreRelease: featuregate.GA},
genericfeatures.ServerSideApply: {Default: true, PreRelease: featuregate.GA},
genericfeatures.APIPriorityAndFairness: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.WarningHeaders: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.24
genericfeatures.OpenAPIEnums: {Default: false, PreRelease: featuregate.Alpha},
genericfeatures.OpenAPIEnums: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.CustomResourceValidationExpressions: {Default: false, PreRelease: featuregate.Alpha},
genericfeatures.OpenAPIV3: {Default: false, PreRelease: featuregate.Alpha},
genericfeatures.OpenAPIV3: {Default: true, PreRelease: featuregate.Beta},
genericfeatures.ServerSideFieldValidation: {Default: false, PreRelease: featuregate.Alpha},
// features that enable backwards compatibility but are scheduled to be removed
// ...

View File

@ -4,6 +4,6 @@
options:
no_parent_owners: true
approvers:
- api-approvers
- api-approvers
reviewers:
- sig-node-api-reviewers
- sig-node-api-reviewers

View File

@ -98,7 +98,7 @@ type KubeletConfiguration struct {
// staticPodURL is the URL for accessing static pods to run
StaticPodURL string
// staticPodURLHeader is a map of slices with HTTP headers to use when accessing the podURL
StaticPodURLHeader map[string][]string
StaticPodURLHeader map[string][]string `datapolicy:"token"`
// address is the IP address for the Kubelet to serve on (set to 0.0.0.0
// for all interfaces)
Address string
@ -340,9 +340,10 @@ type KubeletConfiguration struct {
ContainerLogMaxFiles int32
// ConfigMapAndSecretChangeDetectionStrategy is a mode in which config map and secret managers are running.
ConfigMapAndSecretChangeDetectionStrategy ResourceChangeDetectionStrategy
// A comma separated allowlist of unsafe sysctls or sysctl patterns (ending in *).
// Unsafe sysctl groups are kernel.shm*, kernel.msg*, kernel.sem, fs.mqueue.*, and net.*.
// These sysctls are namespaced but not allowed by default. For example: "kernel.msg*,net.ipv4.route.min_pmtu"
// A comma separated allowlist of unsafe sysctls or sysctl patterns (ending in `*`).
// Unsafe sysctl groups are `kernel.shm*`, `kernel.msg*`, `kernel.sem`, `fs.mqueue.*`, and `net.*`.
// These sysctls are namespaced but not allowed by default.
// For example: "`kernel.msg*,net.ipv4.route.min_pmtu`"
// +optional
AllowedUnsafeSysctls []string
// kernelMemcgNotification if enabled, the kubelet will integrate with the kernel memcg
@ -554,9 +555,9 @@ type CredentialProvider struct {
//
// Each entry in matchImages is a pattern which can optionally contain a port and a path.
// Globs can be used in the domain, but not in the port or the path. Globs are supported
// as subdomains like '*.k8s.io' or 'k8s.*.io', and top-level-domains such as 'k8s.*'.
// Matching partial subdomains like 'app*.k8s.io' is also supported. Each glob can only match
// a single subdomain segment, so *.io does not match *.k8s.io.
// as subdomains like `*.k8s.io` or `k8s.*.io`, and top-level-domains such as `k8s.*`.
// Matching partial subdomains like `app*.k8s.io` is also supported. Each glob can only match
// a single subdomain segment, so `*.io` does not match *.k8s.io.
//
// A match exists between an image and a matchImage when all of the below are true:
// - Both contain the same number of domain parts and each part matches.
@ -564,11 +565,11 @@ type CredentialProvider struct {
// - If the imageMatch contains a port, then the port must match in the image as well.
//
// Example values of matchImages:
// - 123456789.dkr.ecr.us-east-1.amazonaws.com
// - *.azurecr.io
// - gcr.io
// - *.*.registry.io
// - registry.io:8080/path
// - `123456789.dkr.ecr.us-east-1.amazonaws.com`
// - `*.azurecr.io`
// - `gcr.io`
// - `*.*.registry.io`
// - `registry.io:8080/path`
MatchImages []string
// defaultCacheDuration is the default duration the plugin will cache credentials in-memory
@ -578,6 +579,7 @@ type CredentialProvider struct {
// Required input version of the exec CredentialProviderRequest. The returned CredentialProviderResponse
// MUST use the same encoding version as the input. Current supported values are:
// - credentialprovider.kubelet.k8s.io/v1alpha1
// - credentialprovider.kubelet.k8s.io/v1beta1
APIVersion string
// Arguments to pass to the command when executing it.

View File

@ -0,0 +1,101 @@
/*
Copyright 2019 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 metrics
import (
"sync"
"time"
"k8s.io/component-base/metrics"
"k8s.io/component-base/metrics/legacyregistry"
)
const (
kubeletSubsystem = "kubelet"
)
var (
// HTTPRequests tracks the number of the http requests received since the server started.
HTTPRequests = metrics.NewCounterVec(
&metrics.CounterOpts{
Subsystem: kubeletSubsystem,
Name: "http_requests_total",
Help: "Number of the http requests received since the server started",
StabilityLevel: metrics.ALPHA,
},
// server_type aims to differentiate the readonly server and the readwrite server.
// long_running marks whether the request is long-running or not.
// Currently, long-running requests include exec/attach/portforward/debug.
[]string{"method", "path", "server_type", "long_running"},
)
// HTTPRequestsDuration tracks the duration in seconds to serve http requests.
HTTPRequestsDuration = metrics.NewHistogramVec(
&metrics.HistogramOpts{
Subsystem: kubeletSubsystem,
Name: "http_requests_duration_seconds",
Help: "Duration in seconds to serve http requests",
// Use DefBuckets for now, will customize the buckets if necessary.
Buckets: metrics.DefBuckets,
StabilityLevel: metrics.ALPHA,
},
[]string{"method", "path", "server_type", "long_running"},
)
// HTTPInflightRequests tracks the number of the inflight http requests.
HTTPInflightRequests = metrics.NewGaugeVec(
&metrics.GaugeOpts{
Subsystem: kubeletSubsystem,
Name: "http_inflight_requests",
Help: "Number of the inflight http requests",
StabilityLevel: metrics.ALPHA,
},
[]string{"method", "path", "server_type", "long_running"},
)
// VolumeStatCalDuration tracks the duration in seconds to calculate volume stats.
// this metric is mainly for comparison between fsquota monitoring and `du` for disk usage.
VolumeStatCalDuration = metrics.NewHistogramVec(
&metrics.HistogramOpts{
Subsystem: kubeletSubsystem,
Name: "volume_metric_collection_duration_seconds",
Help: "Duration in seconds to calculate volume stats",
Buckets: metrics.DefBuckets,
StabilityLevel: metrics.ALPHA,
},
[]string{"metric_source"},
)
)
var registerMetrics sync.Once
// Register all metrics.
func Register() {
registerMetrics.Do(func() {
legacyregistry.MustRegister(HTTPRequests)
legacyregistry.MustRegister(HTTPRequestsDuration)
legacyregistry.MustRegister(HTTPInflightRequests)
legacyregistry.MustRegister(VolumeStatCalDuration)
})
}
// SinceInSeconds gets the time since the specified start in seconds.
func SinceInSeconds(start time.Time) float64 {
return time.Since(start).Seconds()
}
// CollectVolumeStatCalDuration collects the duration in seconds to calculate volume stats.
func CollectVolumeStatCalDuration(metricSource string, start time.Time) {
VolumeStatCalDuration.WithLabelValues(metricSource).Observe(SinceInSeconds(start))
}

View File

@ -1,46 +0,0 @@
/*
Copyright 2015 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 types
const (
// ResolvConfDefault is the system default DNS resolver configuration.
ResolvConfDefault = "/etc/resolv.conf"
// RFC3339NanoFixed is the fixed width version of time.RFC3339Nano.
RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
// RFC3339NanoLenient is the variable width RFC3339 time format for lenient parsing of strings into timestamps.
RFC3339NanoLenient = "2006-01-02T15:04:05.999999999Z07:00"
)
// Different container runtimes.
const (
DockerContainerRuntime = "docker"
RemoteContainerRuntime = "remote"
)
// User visible keys for managing node allocatable enforcement on the node.
const (
NodeAllocatableEnforcementKey = "pods"
SystemReservedEnforcementKey = "system-reserved"
KubeReservedEnforcementKey = "kube-reserved"
NodeAllocatableNoneKey = "none"
)
// SwapBehavior types
const (
LimitedSwap = "LimitedSwap"
UnlimitedSwap = "UnlimitedSwap"
)

View File

@ -1,18 +0,0 @@
/*
Copyright 2015 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 types contains common types in the Kubelet.
package types // import "k8s.io/kubernetes/pkg/kubelet/types"

View File

@ -1,45 +0,0 @@
/*
Copyright 2016 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 types
// Label keys for labels used in this package.
const (
KubernetesPodNameLabel = "io.kubernetes.pod.name"
KubernetesPodNamespaceLabel = "io.kubernetes.pod.namespace"
KubernetesPodUIDLabel = "io.kubernetes.pod.uid"
KubernetesContainerNameLabel = "io.kubernetes.container.name"
)
// GetContainerName returns the value of the KubernetesContainerNameLabel.
func GetContainerName(labels map[string]string) string {
return labels[KubernetesContainerNameLabel]
}
// GetPodName returns the value of the KubernetesPodNameLabel.
func GetPodName(labels map[string]string) string {
return labels[KubernetesPodNameLabel]
}
// GetPodUID returns the value of the KubernetesPodUIDLabel.
func GetPodUID(labels map[string]string) string {
return labels[KubernetesPodUIDLabel]
}
// GetPodNamespace returns the value of the KubernetesPodNamespaceLabel.
func GetPodNamespace(labels map[string]string) string {
return labels[KubernetesPodNamespaceLabel]
}

View File

@ -1,194 +0,0 @@
/*
Copyright 2014 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 types
import (
"fmt"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/apis/scheduling"
)
// Annotation keys for annotations used in this package.
const (
ConfigSourceAnnotationKey = "kubernetes.io/config.source"
ConfigMirrorAnnotationKey = v1.MirrorPodAnnotationKey
ConfigFirstSeenAnnotationKey = "kubernetes.io/config.seen"
ConfigHashAnnotationKey = "kubernetes.io/config.hash"
)
// PodOperation defines what changes will be made on a pod configuration.
type PodOperation int
// These constants identify the PodOperations that can be made on a pod configuration.
const (
// SET is the current pod configuration.
SET PodOperation = iota
// ADD signifies pods that are new to this source.
ADD
// DELETE signifies pods that are gracefully deleted from this source.
DELETE
// REMOVE signifies pods that have been removed from this source.
REMOVE
// UPDATE signifies pods have been updated in this source.
UPDATE
// RECONCILE signifies pods that have unexpected status in this source,
// kubelet should reconcile status with this source.
RECONCILE
)
// These constants identify the sources of pods.
const (
// Filesource idenitified updates from a file.
FileSource = "file"
// HTTPSource identifies updates from querying a web page.
HTTPSource = "http"
// ApiserverSource identifies updates from Kubernetes API Server.
ApiserverSource = "api"
// AllSource identifies updates from all sources.
AllSource = "*"
)
// NamespaceDefault is a string representing the default namespace.
const NamespaceDefault = metav1.NamespaceDefault
// PodUpdate defines an operation sent on the channel. You can add or remove single services by
// sending an array of size one and Op == ADD|REMOVE (with REMOVE, only the ID is required).
// For setting the state of the system to a given state for this source configuration, set
// Pods as desired and Op to SET, which will reset the system state to that specified in this
// operation for this source channel. To remove all pods, set Pods to empty object and Op to SET.
//
// Additionally, Pods should never be nil - it should always point to an empty slice. While
// functionally similar, this helps our unit tests properly check that the correct PodUpdates
// are generated.
type PodUpdate struct {
Pods []*v1.Pod
Op PodOperation
Source string
}
// GetValidatedSources gets all validated sources from the specified sources.
func GetValidatedSources(sources []string) ([]string, error) {
validated := make([]string, 0, len(sources))
for _, source := range sources {
switch source {
case AllSource:
return []string{FileSource, HTTPSource, ApiserverSource}, nil
case FileSource, HTTPSource, ApiserverSource:
validated = append(validated, source)
case "":
// Skip
default:
return []string{}, fmt.Errorf("unknown pod source %q", source)
}
}
return validated, nil
}
// GetPodSource returns the source of the pod based on the annotation.
func GetPodSource(pod *v1.Pod) (string, error) {
if pod.Annotations != nil {
if source, ok := pod.Annotations[ConfigSourceAnnotationKey]; ok {
return source, nil
}
}
return "", fmt.Errorf("cannot get source of pod %q", pod.UID)
}
// SyncPodType classifies pod updates, eg: create, update.
type SyncPodType int
const (
// SyncPodSync is when the pod is synced to ensure desired state
SyncPodSync SyncPodType = iota
// SyncPodUpdate is when the pod is updated from source
SyncPodUpdate
// SyncPodCreate is when the pod is created from source
SyncPodCreate
// SyncPodKill is when the pod should have no running containers. A pod stopped in this way could be
// restarted in the future due config changes.
SyncPodKill
)
func (sp SyncPodType) String() string {
switch sp {
case SyncPodCreate:
return "create"
case SyncPodUpdate:
return "update"
case SyncPodSync:
return "sync"
case SyncPodKill:
return "kill"
default:
return "unknown"
}
}
// IsMirrorPod returns true if the passed Pod is a Mirror Pod.
func IsMirrorPod(pod *v1.Pod) bool {
if pod.Annotations == nil {
return false
}
_, ok := pod.Annotations[ConfigMirrorAnnotationKey]
return ok
}
// IsStaticPod returns true if the pod is a static pod.
func IsStaticPod(pod *v1.Pod) bool {
source, err := GetPodSource(pod)
return err == nil && source != ApiserverSource
}
// IsCriticalPod returns true if pod's priority is greater than or equal to SystemCriticalPriority.
func IsCriticalPod(pod *v1.Pod) bool {
if IsStaticPod(pod) {
return true
}
if IsMirrorPod(pod) {
return true
}
if pod.Spec.Priority != nil && IsCriticalPodBasedOnPriority(*pod.Spec.Priority) {
return true
}
return false
}
// Preemptable returns true if preemptor pod can preempt preemptee pod
// if preemptee is not critical or if preemptor's priority is greater than preemptee's priority
func Preemptable(preemptor, preemptee *v1.Pod) bool {
if IsCriticalPod(preemptor) && !IsCriticalPod(preemptee) {
return true
}
if (preemptor != nil && preemptor.Spec.Priority != nil) &&
(preemptee != nil && preemptee.Spec.Priority != nil) {
return *(preemptor.Spec.Priority) > *(preemptee.Spec.Priority)
}
return false
}
// IsCriticalPodBasedOnPriority checks if the given pod is a critical pod based on priority resolved from pod Spec.
func IsCriticalPodBasedOnPriority(priority int32) bool {
return priority >= scheduling.SystemCriticalPriority
}
// IsNodeCriticalPod checks if the given pod is a system-node-critical
func IsNodeCriticalPod(pod *v1.Pod) bool {
return IsCriticalPod(pod) && (pod.Spec.PriorityClassName == scheduling.SystemNodeCritical)
}

View File

@ -1,115 +0,0 @@
/*
Copyright 2015 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 types
import (
"net/http"
"time"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
)
// TODO: Reconcile custom types in kubelet/types and this subpackage
// HTTPGetter is an interface representing the ability to perform HTTP GET requests.
type HTTPGetter interface {
// Get issues a GET to the specified URL.
Get(url string) (*http.Response, error)
}
// Timestamp wraps around time.Time and offers utilities to format and parse
// the time using RFC3339Nano
type Timestamp struct {
time time.Time
}
// NewTimestamp returns a Timestamp object using the current time.
func NewTimestamp() *Timestamp {
return &Timestamp{time.Now()}
}
// ConvertToTimestamp takes a string, parses it using the RFC3339NanoLenient layout,
// and converts it to a Timestamp object.
func ConvertToTimestamp(timeString string) *Timestamp {
parsed, _ := time.Parse(RFC3339NanoLenient, timeString)
return &Timestamp{parsed}
}
// Get returns the time as time.Time.
func (t *Timestamp) Get() time.Time {
return t.time
}
// GetString returns the time in the string format using the RFC3339NanoFixed
// layout.
func (t *Timestamp) GetString() string {
return t.time.Format(RFC3339NanoFixed)
}
// SortedContainerStatuses is a type to help sort container statuses based on container names.
type SortedContainerStatuses []v1.ContainerStatus
func (s SortedContainerStatuses) Len() int { return len(s) }
func (s SortedContainerStatuses) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s SortedContainerStatuses) Less(i, j int) bool {
return s[i].Name < s[j].Name
}
// SortInitContainerStatuses ensures that statuses are in the order that their
// init container appears in the pod spec
func SortInitContainerStatuses(p *v1.Pod, statuses []v1.ContainerStatus) {
containers := p.Spec.InitContainers
current := 0
for _, container := range containers {
for j := current; j < len(statuses); j++ {
if container.Name == statuses[j].Name {
statuses[current], statuses[j] = statuses[j], statuses[current]
current++
break
}
}
}
}
// SortStatusesOfInitContainers returns the statuses of InitContainers of pod p,
// in the order that they appear in its spec.
func SortStatusesOfInitContainers(p *v1.Pod, statusMap map[string]*v1.ContainerStatus) []v1.ContainerStatus {
containers := p.Spec.InitContainers
statuses := []v1.ContainerStatus{}
for _, container := range containers {
if status, found := statusMap[container.Name]; found {
statuses = append(statuses, *status)
}
}
return statuses
}
// Reservation represents reserved resources for non-pod components.
type Reservation struct {
// System represents resources reserved for non-kubernetes components.
System v1.ResourceList
// Kubernetes represents resources reserved for kubernetes system components.
Kubernetes v1.ResourceList
}
// ResolvedPodUID is a pod UID which has been translated/resolved to the representation known to kubelets.
type ResolvedPodUID types.UID
// MirrorPodUID is a pod UID for a mirror pod.
type MirrorPodUID types.UID

View File

@ -78,6 +78,37 @@ func BuildPortsToEndpointsMap(endpoints *v1.Endpoints) map[string][]string {
return portsToEndpoints
}
// ContainsIPv4Loopback returns true if the input is empty or one of the CIDR contains an IPv4 loopback address.
func ContainsIPv4Loopback(cidrStrings []string) bool {
if len(cidrStrings) == 0 {
return true
}
// RFC 5735 127.0.0.0/8 - This block is assigned for use as the Internet host loopback address
ipv4LoopbackStart := netutils.ParseIPSloppy("127.0.0.0")
for _, cidr := range cidrStrings {
if IsZeroCIDR(cidr) {
return true
}
ip, ipnet, err := netutils.ParseCIDRSloppy(cidr)
if err != nil {
continue
}
if netutils.IsIPv6CIDR(ipnet) {
continue
}
if ip.IsLoopback() {
return true
}
if ipnet.Contains(ipv4LoopbackStart) {
return true
}
}
return false
}
// IsZeroCIDR checks whether the input CIDR string is either
// the IPv4 or IPv6 zero CIDR
func IsZeroCIDR(cidr string) bool {
@ -97,7 +128,7 @@ func IsProxyableIP(ip string) error {
}
func isProxyableIP(ip net.IP) error {
if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsInterfaceLocalMulticast() {
if !ip.IsGlobalUnicast() {
return ErrAddressNotAllowed
}
return nil
@ -490,7 +521,8 @@ func GetClusterIPByFamily(ipFamily v1.IPFamily, service *v1.Service) string {
}
type LineBuffer struct {
b bytes.Buffer
b bytes.Buffer
lines int
}
// Write takes a list of arguments, each a string or []string, joins all the
@ -516,22 +548,34 @@ func (buf *LineBuffer) Write(args ...interface{}) {
}
}
buf.b.WriteByte('\n')
buf.lines++
}
// WriteBytes writes bytes to buffer, and terminates with newline.
func (buf *LineBuffer) WriteBytes(bytes []byte) {
buf.b.Write(bytes)
buf.b.WriteByte('\n')
buf.lines++
}
// Reset clears buf
func (buf *LineBuffer) Reset() {
buf.b.Reset()
buf.lines = 0
}
// Bytes returns the contents of buf as a []byte
func (buf *LineBuffer) Bytes() []byte {
return buf.b.Bytes()
}
// Lines returns the number of lines in buf. Note that more precisely, this returns the
// number of times Write() or WriteBytes() was called; it assumes that you never wrote
// any newlines to the buffer yourself.
func (buf *LineBuffer) Lines() int {
return buf.lines
}
// RevertPorts is closing ports in replacementPortsMap but not in originalPortsMap. In other words, it only
// closes the ports opened in this sync.
func RevertPorts(replacementPortsMap, originalPortsMap map[netutils.LocalPort]netutils.Closeable) {
@ -543,8 +587,3 @@ func RevertPorts(replacementPortsMap, originalPortsMap map[netutils.LocalPort]ne
}
}
}
// CountBytesLines counts the number of lines in a bytes slice
func CountBytesLines(b []byte) int {
return bytes.Count(b, []byte{'\n'})
}

View File

@ -1,62 +0,0 @@
/*
Copyright 2016 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 apparmor
import (
"strings"
"k8s.io/api/core/v1"
)
// Checks whether app armor is required for pod to be run.
func isRequired(pod *v1.Pod) bool {
for key, value := range pod.Annotations {
if strings.HasPrefix(key, v1.AppArmorBetaContainerAnnotationKeyPrefix) {
return value != v1.AppArmorBetaProfileNameUnconfined
}
}
return false
}
// GetProfileName returns the name of the profile to use with the container.
func GetProfileName(pod *v1.Pod, containerName string) string {
return GetProfileNameFromPodAnnotations(pod.Annotations, containerName)
}
// GetProfileNameFromPodAnnotations gets the name of the profile to use with container from
// pod annotations
func GetProfileNameFromPodAnnotations(annotations map[string]string, containerName string) string {
return annotations[v1.AppArmorBetaContainerAnnotationKeyPrefix+containerName]
}
// SetProfileName sets the name of the profile to use with the container.
func SetProfileName(pod *v1.Pod, containerName, profileName string) error {
if pod.Annotations == nil {
pod.Annotations = map[string]string{}
}
pod.Annotations[v1.AppArmorBetaContainerAnnotationKeyPrefix+containerName] = profileName
return nil
}
// SetProfileNameFromPodAnnotations sets the name of the profile to use with the container.
func SetProfileNameFromPodAnnotations(annotations map[string]string, containerName, profileName string) error {
if annotations == nil {
return nil
}
annotations[v1.AppArmorBetaContainerAnnotationKeyPrefix+containerName] = profileName
return nil
}

View File

@ -1,214 +0,0 @@
/*
Copyright 2016 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 apparmor
import (
"bufio"
"errors"
"fmt"
"os"
"path"
"strings"
"github.com/opencontainers/runc/libcontainer/apparmor"
v1 "k8s.io/api/core/v1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
"k8s.io/kubernetes/pkg/features"
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
utilpath "k8s.io/utils/path"
)
// Whether AppArmor should be disabled by default.
// Set to true if the wrong build tags are set (see validate_disabled.go).
var isDisabledBuild bool
// Validator is a interface for validating that a pod with an AppArmor profile can be run by a Node.
type Validator interface {
Validate(pod *v1.Pod) error
ValidateHost() error
}
// NewValidator is in order to find AppArmor FS
func NewValidator(runtime string) Validator {
if err := validateHost(runtime); err != nil {
return &validator{validateHostErr: err}
}
appArmorFS, err := getAppArmorFS()
if err != nil {
return &validator{
validateHostErr: fmt.Errorf("error finding AppArmor FS: %v", err),
}
}
return &validator{
appArmorFS: appArmorFS,
}
}
type validator struct {
validateHostErr error
appArmorFS string
}
func (v *validator) Validate(pod *v1.Pod) error {
if !isRequired(pod) {
return nil
}
if v.ValidateHost() != nil {
return v.validateHostErr
}
loadedProfiles, err := v.getLoadedProfiles()
if err != nil {
return fmt.Errorf("could not read loaded profiles: %v", err)
}
var retErr error
podutil.VisitContainers(&pod.Spec, podutil.AllContainers, func(container *v1.Container, containerType podutil.ContainerType) bool {
retErr = validateProfile(GetProfileName(pod, container.Name), loadedProfiles)
if retErr != nil {
return false
}
return true
})
return retErr
}
func (v *validator) ValidateHost() error {
return v.validateHostErr
}
// Verify that the host and runtime is capable of enforcing AppArmor profiles.
func validateHost(runtime string) error {
// Check feature-gates
if !utilfeature.DefaultFeatureGate.Enabled(features.AppArmor) {
return errors.New("AppArmor disabled by feature-gate")
}
// Check build support.
if isDisabledBuild {
return errors.New("binary not compiled for linux")
}
// Check kernel support.
if !apparmor.IsEnabled() {
return errors.New("AppArmor is not enabled on the host")
}
// Check runtime support. Currently only Docker is supported.
if runtime != kubetypes.DockerContainerRuntime && runtime != kubetypes.RemoteContainerRuntime {
return fmt.Errorf("AppArmor is only enabled for 'docker' and 'remote' runtimes. Found: %q", runtime)
}
return nil
}
// Verify that the profile is valid and loaded.
func validateProfile(profile string, loadedProfiles map[string]bool) error {
if err := ValidateProfileFormat(profile); err != nil {
return err
}
if strings.HasPrefix(profile, v1.AppArmorBetaProfileNamePrefix) {
profileName := strings.TrimPrefix(profile, v1.AppArmorBetaProfileNamePrefix)
if !loadedProfiles[profileName] {
return fmt.Errorf("profile %q is not loaded", profileName)
}
}
return nil
}
// ValidateProfileFormat checks the format of the profile.
func ValidateProfileFormat(profile string) error {
if profile == "" || profile == v1.AppArmorBetaProfileRuntimeDefault || profile == v1.AppArmorBetaProfileNameUnconfined {
return nil
}
if !strings.HasPrefix(profile, v1.AppArmorBetaProfileNamePrefix) {
return fmt.Errorf("invalid AppArmor profile name: %q", profile)
}
return nil
}
func (v *validator) getLoadedProfiles() (map[string]bool, error) {
profilesPath := path.Join(v.appArmorFS, "profiles")
profilesFile, err := os.Open(profilesPath)
if err != nil {
return nil, fmt.Errorf("failed to open %s: %v", profilesPath, err)
}
defer profilesFile.Close()
profiles := map[string]bool{}
scanner := bufio.NewScanner(profilesFile)
for scanner.Scan() {
profileName := parseProfileName(scanner.Text())
if profileName == "" {
// Unknown line format; skip it.
continue
}
profiles[profileName] = true
}
return profiles, nil
}
// The profiles file is formatted with one profile per line, matching a form:
// namespace://profile-name (mode)
// profile-name (mode)
// Where mode is {enforce, complain, kill}. The "namespace://" is only included for namespaced
// profiles. For the purposes of Kubernetes, we consider the namespace part of the profile name.
func parseProfileName(profileLine string) string {
modeIndex := strings.IndexRune(profileLine, '(')
if modeIndex < 0 {
return ""
}
return strings.TrimSpace(profileLine[:modeIndex])
}
func getAppArmorFS() (string, error) {
mountsFile, err := os.Open("/proc/mounts")
if err != nil {
return "", fmt.Errorf("could not open /proc/mounts: %v", err)
}
defer mountsFile.Close()
scanner := bufio.NewScanner(mountsFile)
for scanner.Scan() {
fields := strings.Fields(scanner.Text())
if len(fields) < 3 {
// Unknown line format; skip it.
continue
}
if fields[2] == "securityfs" {
appArmorFS := path.Join(fields[1], "apparmor")
if ok, err := utilpath.Exists(utilpath.CheckFollowSymlink, appArmorFS); !ok {
msg := fmt.Sprintf("path %s does not exist", appArmorFS)
if err != nil {
return "", fmt.Errorf("%s: %v", msg, err)
}
return "", errors.New(msg)
}
return appArmorFS, nil
}
}
if err := scanner.Err(); err != nil {
return "", fmt.Errorf("error scanning mounts: %v", err)
}
return "", errors.New("securityfs not found")
}

View File

@ -1,25 +0,0 @@
//go:build !linux
// +build !linux
/*
Copyright 2016 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 apparmor
func init() {
// If Kubernetes was not built for linux, apparmor is always disabled.
isDisabledBuild = true
}

View File

@ -1,19 +0,0 @@
/*
Copyright 2015 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 selinux contains wrapper functions for the libcontainer SELinux
// package. A NOP implementation is provided for non-linux platforms.
package selinux // import "k8s.io/kubernetes/pkg/util/selinux"

View File

@ -1,39 +0,0 @@
/*
Copyright 2014 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 selinux
// Note: the libcontainer SELinux package is only built for Linux, so it is
// necessary to have a NOP wrapper which is built for non-Linux platforms to
// allow code that links to this package not to differentiate its own methods
// for Linux and non-Linux platforms.
//
// SELinuxRunner wraps certain libcontainer SELinux calls. For more
// information, see:
//
// https://github.com/opencontainers/runc/blob/master/libcontainer/selinux/selinux.go
type SELinuxRunner interface {
// Getfilecon returns the SELinux context for the given path or returns an
// error.
Getfilecon(path string) (string, error)
}
// NewSELinuxRunner returns a new SELinuxRunner appropriate for the platform.
// On Linux, all methods short-circuit and return NOP values if SELinux is
// disabled. On non-Linux platforms, a NOP implementation is returned.
func NewSELinuxRunner() SELinuxRunner {
return &realSELinuxRunner{}
}

View File

@ -1,58 +0,0 @@
//go:build linux
// +build linux
/*
Copyright 2014 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 selinux
import (
selinux "github.com/opencontainers/selinux/go-selinux"
)
// SELinuxEnabled returns whether SELinux is enabled on the system. SELinux
// has a tri-state:
//
// 1. disabled: SELinux Kernel modules not loaded, SELinux policy is not
// checked during Kernel MAC checks
// 2. enforcing: Enabled; SELinux policy violations are denied and logged
// in the audit log
// 3. permissive: Enabled, but SELinux policy violations are permitted and
// logged in the audit log
//
// SELinuxEnabled returns true if SELinux is enforcing or permissive, and
// false if it is disabled.
func SELinuxEnabled() bool {
return selinux.GetEnabled()
}
// realSELinuxRunner is the real implementation of SELinuxRunner interface for
// Linux.
type realSELinuxRunner struct{}
var _ SELinuxRunner = &realSELinuxRunner{}
func (_ *realSELinuxRunner) Getfilecon(path string) (string, error) {
if !SELinuxEnabled() {
return "", nil
}
return selinux.FileLabel(path)
}
// SetFileLabel applies the SELinux label on the path or returns an error.
func SetFileLabel(path string, label string) error {
return selinux.SetFileLabel(path, label)
}

View File

@ -1,39 +0,0 @@
//go:build !linux
// +build !linux
/*
Copyright 2014 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 selinux
// SELinuxEnabled always returns false on non-linux platforms.
func SELinuxEnabled() bool {
return false
}
// realSELinuxRunner is the NOP implementation of the SELinuxRunner interface.
type realSELinuxRunner struct{}
var _ SELinuxRunner = &realSELinuxRunner{}
func (_ *realSELinuxRunner) Getfilecon(path string) (string, error) {
return "", nil
}
// FileLabel returns the SELinux label for this path or returns an error.
func SetFileLabel(path string, label string) error {
return nil
}

View File

@ -275,6 +275,16 @@ func TaintExists(taints []v1.Taint, taintToFind *v1.Taint) bool {
return false
}
// TaintKeyExists checks if the given taint key exists in list of taints. Returns true if exists false otherwise.
func TaintKeyExists(taints []v1.Taint, taintKeyToMatch string) bool {
for _, taint := range taints {
if taint.Key == taintKeyToMatch {
return true
}
}
return false
}
func TaintSetDiff(t1, t2 []v1.Taint) (taintsToAdd []*v1.Taint, taintsToRemove []*v1.Taint) {
for _, taint := range t1 {
if !TaintExists(t2, &taint) {

View File

@ -1,8 +1,8 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- sig-storage-approvers
- sig-storage-approvers
reviewers:
- sig-storage-reviewers
- sig-storage-reviewers
labels:
- sig/storage
- sig/storage

View File

@ -21,9 +21,11 @@ import (
"io"
"os"
"runtime"
"time"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
servermetrics "k8s.io/kubernetes/pkg/kubelet/server/metrics"
)
var _ MetricsProvider = &metricsBlock{}
@ -49,6 +51,9 @@ func NewMetricsBlock(device string) MetricsProvider {
// tools. Storage systems may have more information that they can provide by
// going through specialized APIs.
func (mb *metricsBlock) GetMetrics() (*Metrics, error) {
startTime := time.Now()
defer servermetrics.CollectVolumeStatCalDuration("block", startTime)
// TODO: Windows does not yet support VolumeMode=Block
if runtime.GOOS == "windows" {
return nil, NewNotImplementedError("Windows does not support Block volumes")

View File

@ -17,8 +17,11 @@ limitations under the License.
package volume
import (
"time"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
servermetrics "k8s.io/kubernetes/pkg/kubelet/server/metrics"
"k8s.io/kubernetes/pkg/volume/util/fs"
)
@ -40,6 +43,9 @@ func NewMetricsStatFS(path string) MetricsProvider {
// GetMetrics calculates the volume usage and device free space by executing "du"
// and gathering filesystem info for the Volume path.
func (md *metricsStatFS) GetMetrics() (*Metrics, error) {
startTime := time.Now()
defer servermetrics.CollectVolumeStatCalDuration("statfs", startTime)
metrics := &Metrics{Time: metav1.Now()}
if md.path == "" {
return metrics, NewNoPathDefinedError()

View File

@ -53,9 +53,6 @@ type ProbeEvent struct {
Op ProbeOperation // The operation to the plugin
}
// CSIVolumePhaseType stores information about CSI volume path.
type CSIVolumePhaseType string
const (
// Common parameter which can be specified in StorageClass to specify the desired FSType
// Provisioners SHOULD implement support for this if they are block device based
@ -65,8 +62,6 @@ const (
ProbeAddOrUpdate ProbeOperation = 1 << iota
ProbeRemove
CSIVolumeStaged CSIVolumePhaseType = "staged"
CSIVolumePublished CSIVolumePhaseType = "published"
)
var (
@ -124,15 +119,12 @@ type NodeResizeOptions struct {
NewSize resource.Quantity
OldSize resource.Quantity
// CSIVolumePhase contains volume phase on the node
CSIVolumePhase CSIVolumePhaseType
}
type DynamicPluginProber interface {
Init() error
// If an error occurs, events are undefined.
// aggregates events for successful drivers and errors for failed drivers
Probe() (events []ProbeEvent, err error)
}
@ -503,7 +495,6 @@ func (spec *Spec) IsKubeletExpandable() bool {
return spec.PersistentVolume.Spec.FlexVolume != nil
default:
return false
}
}
@ -708,30 +699,26 @@ func (pm *VolumePluginMgr) FindPluginByName(name string) (VolumePlugin, error) {
defer pm.mutex.RUnlock()
// Once we can get rid of legacy names we can reduce this to a map lookup.
matches := []VolumePlugin{}
var match VolumePlugin
if v, found := pm.plugins[name]; found {
matches = append(matches, v)
match = v
}
pm.refreshProbedPlugins()
if plugin, found := pm.probedPlugins[name]; found {
matches = append(matches, plugin)
if match != nil {
return nil, fmt.Errorf("multiple volume plugins matched: %s and %s", match.GetPluginName(), plugin.GetPluginName())
}
match = plugin
}
if len(matches) == 0 {
if match == nil {
return nil, fmt.Errorf("no volume plugin matched name: %s", name)
}
if len(matches) > 1 {
matchedPluginNames := []string{}
for _, plugin := range matches {
matchedPluginNames = append(matchedPluginNames, plugin.GetPluginName())
}
return nil, fmt.Errorf("multiple volume plugins matched: %s", strings.Join(matchedPluginNames, ","))
}
// Issue warning if the matched provider is deprecated
pm.logDeprecation(matches[0].GetPluginName())
return matches[0], nil
pm.logDeprecation(match.GetPluginName())
return match, nil
}
// logDeprecation logs warning when a deprecated plugin is used.
@ -748,11 +735,14 @@ func (pm *VolumePluginMgr) logDeprecation(plugin string) {
// If it is, initialize all probed plugins and replace the cache with them.
func (pm *VolumePluginMgr) refreshProbedPlugins() {
events, err := pm.prober.Probe()
if err != nil {
klog.ErrorS(err, "Error dynamically probing plugins")
return // Use cached plugins upon failure.
}
// because the probe function can return a list of valid plugins
// even when an error is present we still must add the plugins
// or they will be skipped because each event only fires once
for _, event := range events {
if event.Op == ProbeAddOrUpdate {
if err := pm.initProbedPlugin(event.Plugin); err != nil {
@ -1084,7 +1074,7 @@ func NewPersistentVolumeRecyclerPodTemplate() *v1.Pod {
Containers: []v1.Container{
{
Name: "pv-recycler",
Image: "busybox:1.27",
Image: "k8s.gcr.io/debian-base:v2.0.0",
Command: []string{"/bin/sh"},
Args: []string{"-c", "test -e /scrub && rm -rf /scrub/..?* /scrub/.[!.]* /scrub/* && test -z \"$(ls -A /scrub)\" || exit 1"},
VolumeMounts: []v1.VolumeMount{

View File

@ -24,9 +24,11 @@ import (
"os"
"path/filepath"
"syscall"
"time"
"golang.org/x/sys/unix"
servermetrics "k8s.io/kubernetes/pkg/kubelet/server/metrics"
"k8s.io/kubernetes/pkg/volume/util/fsquota"
)
@ -71,9 +73,13 @@ func DiskUsage(path string) (UsageInfo, error) {
// First check whether the quota system knows about this directory
// A nil quantity or error means that the path does not support quotas
// or xfs_quota tool is missing and we should use other mechanisms.
startTime := time.Now()
consumption, _ := fsquota.GetConsumption(path)
if consumption != nil {
usage.Bytes = consumption.Value()
defer servermetrics.CollectVolumeStatCalDuration("fsquota", startTime)
} else {
defer servermetrics.CollectVolumeStatCalDuration("du", startTime)
}
inodes, _ := fsquota.GetInodes(path)

View File

@ -27,9 +27,9 @@ import (
"strings"
"syscall"
"github.com/opencontainers/selinux/go-selinux"
"golang.org/x/sys/unix"
"k8s.io/klog/v2"
"k8s.io/kubernetes/pkg/util/selinux"
"k8s.io/mount-utils"
utilpath "k8s.io/utils/path"
)
@ -263,7 +263,7 @@ func GetSELinux(path string, mountInfoFilename string, selinuxEnabled seLinuxEna
// GetSELinuxSupport returns true if given path is on a mount that supports
// SELinux.
func (hu *HostUtil) GetSELinuxSupport(pathname string) (bool, error) {
return GetSELinux(pathname, procMountInfoPath, selinux.SELinuxEnabled)
return GetSELinux(pathname, procMountInfoPath, selinux.GetEnabled)
}
// GetOwner returns the integer ID for the user and group of the given path

View File

@ -10,4 +10,3 @@ approvers:
- jingxu97
- saad-ali
- jsafrane

View File

@ -260,7 +260,12 @@ func doCleanSubPaths(mounter mount.Interface, podDir string, volumeName string)
// scan /var/lib/kubelet/pods/<uid>/volume-subpaths/<volume>/<container name>/*
fullContainerDirPath := filepath.Join(subPathDir, containerDir.Name())
err = filepath.Walk(fullContainerDirPath, func(path string, info os.FileInfo, _ error) error {
// The original traversal method here was ReadDir, which was not so robust to handle some error such as "stale NFS file handle",
// so it was replaced with filepath.Walk in a later patch, which can pass through error and handled by the callback WalkFunc.
// After go 1.16, WalkDir was introduced, it's more effective than Walk because the callback WalkDirFunc is called before
// reading a directory, making it save some time when a container's subPath contains lots of dirs.
// See https://github.com/kubernetes/kubernetes/pull/71804 and https://github.com/kubernetes/kubernetes/issues/107667 for more details.
err = filepath.WalkDir(fullContainerDirPath, func(path string, info os.DirEntry, _ error) error {
if path == fullContainerDirPath {
// Skip top level directory
return nil

View File

@ -115,9 +115,9 @@ type Metrics struct {
// Attributes represents the attributes of this mounter.
type Attributes struct {
ReadOnly bool
Managed bool
SupportsSELinux bool
ReadOnly bool
Managed bool
SELinuxRelabel bool
}
// MounterArgs provides more easily extensible arguments to Mounter
@ -136,17 +136,6 @@ type Mounter interface {
// Uses Interface to provide the path for Docker binds.
Volume
// CanMount is called immediately prior to Setup to check if
// the required components (binaries, etc.) are available on
// the underlying node to complete the subsequent SetUp (mount)
// operation. If CanMount returns error, the mount operation is
// aborted and an event is generated indicating that the node
// does not have the required binaries to complete the mount.
// If CanMount succeeds, the mount operation continues
// normally. The CanMount check can be enabled or disabled
// using the experimental-check-mount-binaries binary flag
CanMount() error
// SetUp prepares and mounts/unpacks the volume to a
// self-determined directory path. The mount point and its
// content should be owned by `fsUser` or 'fsGroup' so that it can be

View File

@ -98,7 +98,7 @@ func changeFilePermission(filename string, fsGroup *int64, readonly bool, info o
err = os.Chmod(filename, info.Mode()|mask)
if err != nil {
klog.ErrorS(err, "Chown failed", "path", filename)
klog.ErrorS(err, "chmod failed", "path", filename)
}
return nil

View File

@ -86,16 +86,6 @@ rules:
- k8s.io/kubernetes/pkg/kubelet/config
- k8s.io/kubernetes/pkg/kubelet/configmap
- k8s.io/kubernetes/pkg/kubelet/container
- k8s.io/kubernetes/pkg/kubelet/dockershim
- k8s.io/kubernetes/pkg/kubelet/dockershim/cm
- k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker
- k8s.io/kubernetes/pkg/kubelet/dockershim/metrics
- k8s.io/kubernetes/pkg/kubelet/dockershim/network
- k8s.io/kubernetes/pkg/kubelet/dockershim/network/cni
- k8s.io/kubernetes/pkg/kubelet/dockershim/network/hostport
- k8s.io/kubernetes/pkg/kubelet/dockershim/network/kubenet
- k8s.io/kubernetes/pkg/kubelet/dockershim/network/metrics
- k8s.io/kubernetes/pkg/kubelet/dockershim/remote
- k8s.io/kubernetes/pkg/kubelet/envvars
- k8s.io/kubernetes/pkg/kubelet/eviction
- k8s.io/kubernetes/pkg/kubelet/eviction/api
@ -197,6 +187,9 @@ rules:
- k8s.io/kubernetes/pkg/scheduler/nodeinfo
- k8s.io/kubernetes/pkg/scheduler/util
- k8s.io/kubernetes/pkg/scheduler/volumebinder
- k8s.io/kubernetes/pkg/scheduler
- k8s.io/kubernetes/pkg/scheduler/profile
- k8s.io/kubernetes/pkg/scheduler/testing
- k8s.io/kubernetes/pkg/security/apparmor
- k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp
- k8s.io/kubernetes/pkg/security/podsecuritypolicy/sysctl
@ -249,6 +242,7 @@ rules:
- k8s.io/kubernetes/pkg/scheduler/internal/cache
- selectorRegexp: k8s[.]io/kubernetes/test/
allowedPrefixes:
- k8s.io/kubernetes/test/e2e/common
- k8s.io/kubernetes/test/e2e/framework
- k8s.io/kubernetes/test/e2e/framework/auth
- k8s.io/kubernetes/test/e2e/framework/ginkgowrapper

View File

@ -1,23 +1,22 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- sig-testing-approvers
- timothysc
- andrewsykim
- fabriziopandini
- pohly
- oomichi
- neolit123
- SataQiu
- sig-testing-approvers
- andrewsykim
- fabriziopandini
- pohly
- oomichi
- neolit123
- SataQiu
reviewers:
- sig-testing-reviewers
- timothysc
- andrewsykim
- fabriziopandini
- pohly
- oomichi
- neolit123
- SataQiu
- alejandrox1
- sig-testing-reviewers
- andrewsykim
- fabriziopandini
- pohly
- oomichi
- neolit123
- SataQiu
labels:
- area/e2e-test-framework
- area/e2e-test-framework
emeritus_approvers:
- timothysc

View File

@ -23,7 +23,7 @@ import (
"net/url"
"strings"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/scheme"
restclient "k8s.io/client-go/rest"
@ -75,7 +75,7 @@ func (f *Framework) ExecWithOptions(options ExecOptions) (string, string, error)
}, scheme.ParameterCodec)
var stdout, stderr bytes.Buffer
Logf("ExecWithOptions: execute(POST %s %s)", req.URL())
Logf("ExecWithOptions: execute(POST %s)", req.URL())
err = execute("POST", req.URL(), config, options.Stdin, &stdout, &stderr, tty)
if options.PreserveWhitespace {
return stdout.String(), stderr.String(), err

View File

@ -24,8 +24,8 @@ package framework
import (
"context"
"fmt"
"io/ioutil"
"math/rand"
"os"
"path"
"strings"
"sync"
@ -47,6 +47,7 @@ import (
"k8s.io/client-go/rest"
"k8s.io/client-go/restmapper"
scaleclient "k8s.io/client-go/scale"
admissionapi "k8s.io/pod-security-admission/api"
"github.com/onsi/ginkgo"
"github.com/onsi/gomega"
@ -78,11 +79,12 @@ type Framework struct {
ScalesGetter scaleclient.ScalesGetter
SkipNamespaceCreation bool // Whether to skip creating a namespace
Namespace *v1.Namespace // Every test has at least one namespace unless creation is skipped
namespacesToDelete []*v1.Namespace // Some tests have more than one.
NamespaceDeletionTimeout time.Duration
SkipPrivilegedPSPBinding bool // Whether to skip creating a binding to the privileged PSP in the test namespace
SkipNamespaceCreation bool // Whether to skip creating a namespace
Namespace *v1.Namespace // Every test has at least one namespace unless creation is skipped
namespacesToDelete []*v1.Namespace // Some tests have more than one.
NamespaceDeletionTimeout time.Duration
SkipPrivilegedPSPBinding bool // Whether to skip creating a binding to the privileged PSP in the test namespace
NamespacePodSecurityEnforceLevel admissionapi.Level // The pod security enforcement level for namespaces to be applied.
gatherer *ContainerResourceGatherer
// Constraints that passed to a check which is executed after data is gathered to
@ -328,7 +330,7 @@ func printSummaries(summaries []TestDataSummary, testBaseName string) {
} else {
// TODO: learn to extract test name and append it to the kind instead of timestamp.
filePath := path.Join(TestContext.ReportDir, summaries[i].SummaryKind()+"_"+testBaseName+"_"+now.Format(time.RFC3339)+".txt")
if err := ioutil.WriteFile(filePath, []byte(summaries[i].PrintHumanReadable()), 0644); err != nil {
if err := os.WriteFile(filePath, []byte(summaries[i].PrintHumanReadable()), 0644); err != nil {
Logf("Failed to write file %v with test performance data: %v", filePath, err)
}
}
@ -345,7 +347,7 @@ func printSummaries(summaries []TestDataSummary, testBaseName string) {
// TODO: learn to extract test name and append it to the kind instead of timestamp.
filePath := path.Join(TestContext.ReportDir, summaries[i].SummaryKind()+"_"+testBaseName+"_"+now.Format(time.RFC3339)+".json")
Logf("Writing to %s", filePath)
if err := ioutil.WriteFile(filePath, []byte(summaries[i].PrintJSON()), 0644); err != nil {
if err := os.WriteFile(filePath, []byte(summaries[i].PrintJSON()), 0644); err != nil {
Logf("Failed to write file %v with test performance data: %v", filePath, err)
}
}
@ -521,6 +523,23 @@ func (f *Framework) CreateNamespace(baseName string, labels map[string]string) (
if createTestingNS == nil {
createTestingNS = CreateTestingNS
}
if labels == nil {
labels = make(map[string]string)
} else {
labelsCopy := make(map[string]string)
for k, v := range labels {
labelsCopy[k] = v
}
labels = labelsCopy
}
enforceLevel := admissionapi.LevelRestricted
if f.NamespacePodSecurityEnforceLevel != "" {
enforceLevel = f.NamespacePodSecurityEnforceLevel
}
labels[admissionapi.EnforceLevelLabel] = string(enforceLevel)
ns, err := createTestingNS(baseName, f.ClientSet, labels)
// check ns instead of err to see if it's nil as we may
// fail to create serviceAccount in it.

View File

@ -142,10 +142,6 @@ func (tk *TestKubeconfig) WriteFileViaContainer(podName, containerName string, p
}
}
command := fmt.Sprintf("echo '%s' > '%s'; sync", contents, path)
// TODO(mauriciopoppe): remove this statement once we add `sync` to the test image, ref #101172
if e2epod.NodeOSDistroIs("windows") {
command = fmt.Sprintf("echo '%s' > '%s';", contents, path)
}
stdout, stderr, err := tk.kubectlExecWithRetry(tk.Namespace, podName, containerName, "--", "/bin/sh", "-c", command)
if err != nil {
e2elog.Logf("error running kubectl exec to write file: %v\nstdout=%v\nstderr=%v)", err, string(stdout), string(stderr))

View File

@ -19,7 +19,7 @@ package metrics
import (
"context"
"fmt"
"io/ioutil"
"io"
"net/http"
"sort"
"strconv"
@ -73,7 +73,7 @@ func GrabKubeletMetricsWithoutProxy(nodeName, path string) (KubeletMetrics, erro
return KubeletMetrics{}, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return KubeletMetrics{}, err
}

View File

@ -25,16 +25,11 @@ import (
utilpointer "k8s.io/utils/pointer"
)
// PreconfiguredRuntimeClassHandler returns configured runtime handler.
func PreconfiguredRuntimeClassHandler(handler string) string {
if handler == "docker" {
return handler
}
// test-handler is the name of the runtime handler that is expected to be
// preconfigured in the test environment.
return "test-handler"
}
const (
// PreconfiguredRuntimeClassHandler is the name of the runtime handler
// that is expected to be preconfigured in the test environment.
PreconfiguredRuntimeClassHandler = "test-handler"
)
// NewRuntimeClassPod returns a test pod with the given runtimeClassName
func NewRuntimeClassPod(runtimeClassName string) *v1.Pod {

View File

@ -34,7 +34,7 @@ import (
e2essh "k8s.io/kubernetes/test/e2e/framework/ssh"
)
const etcdImage = "3.5.1-0"
const etcdImage = "3.5.3-0"
// EtcdUpgrade upgrades etcd on GCE.
func EtcdUpgrade(targetStorage, targetVersion string) error {

View File

@ -20,7 +20,7 @@ import (
"context"
"errors"
"fmt"
"io/ioutil"
"io"
"net"
"net/http"
"regexp"
@ -116,7 +116,7 @@ func (d *Dialer) DialContainerPort(ctx context.Context, addr Addr) (conn net.Con
}
errorStream.Close()
go func() {
message, err := ioutil.ReadAll(errorStream)
message, err := io.ReadAll(errorStream)
switch {
case err != nil:
klog.ErrorS(err, "error reading from error stream")

View File

@ -576,6 +576,28 @@ func CreateExecPodOrFail(client clientset.Interface, ns, generateName string, tw
return execPod
}
// WithWindowsHostProcess sets the Pod's Windows HostProcess option to true. When this option is set,
// HostNetwork can be enabled.
// Containers running as HostProcess will require certain usernames to be set, otherwise the Pod will
// not start: NT AUTHORITY\SYSTEM, NT AUTHORITY\Local service, NT AUTHORITY\NetworkService.
// If the given username is empty, NT AUTHORITY\SYSTEM will be used instead.
// See: https://kubernetes.io/docs/tasks/configure-pod-container/create-hostprocess-pod/
func WithWindowsHostProcess(pod *v1.Pod, username string) {
if pod.Spec.SecurityContext == nil {
pod.Spec.SecurityContext = &v1.PodSecurityContext{}
}
if pod.Spec.SecurityContext.WindowsOptions == nil {
pod.Spec.SecurityContext.WindowsOptions = &v1.WindowsSecurityContextOptions{}
}
trueVar := true
if username == "" {
username = "NT AUTHORITY\\SYSTEM"
}
pod.Spec.SecurityContext.WindowsOptions.HostProcess = &trueVar
pod.Spec.SecurityContext.WindowsOptions.RunAsUserName = &username
}
// CheckPodsRunningReady returns whether all pods whose names are listed in
// podNames in namespace ns are running and ready, using c and waiting at most
// timeout.

View File

@ -21,6 +21,7 @@ import (
v1 "k8s.io/api/core/v1"
imageutils "k8s.io/kubernetes/test/utils/image"
"k8s.io/utils/pointer"
)
// NodeOSDistroIs returns true if the distro is the same as `--node-os-distro`
@ -113,3 +114,19 @@ func GetLinuxLabel() *v1.SELinuxOptions {
return &v1.SELinuxOptions{
Level: "s0:c0,c1"}
}
// GetRestrictedPodSecurityContext returns a minimal restricted pod security context.
func GetRestrictedPodSecurityContext() *v1.PodSecurityContext {
return &v1.PodSecurityContext{
RunAsNonRoot: pointer.BoolPtr(true),
SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeRuntimeDefault},
}
}
// GetRestrictedContainerSecurityContext returns a minimal restricted container security context.
func GetRestrictedContainerSecurityContext() *v1.SecurityContext {
return &v1.SecurityContext{
AllowPrivilegeEscalation: pointer.BoolPtr(false),
Capabilities: &v1.Capabilities{Drop: []v1.Capability{"ALL"}},
}
}

View File

@ -561,7 +561,7 @@ func WaitForPodFailedReason(c clientset.Interface, pod *v1.Pod, reason string, t
return false, nil
})
if waitErr != nil {
return fmt.Errorf("error waiting for pod SysctlForbidden status: %v", waitErr)
return fmt.Errorf("error waiting for pod failure status: %v", waitErr)
}
return nil
}

View File

@ -21,7 +21,7 @@ import (
"os"
"sync"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
clientset "k8s.io/client-go/kubernetes"
)
@ -97,6 +97,9 @@ type ProviderInterface interface {
CreatePD(zone string) (string, error)
DeletePD(pdName string) error
CreateShare() (string, string, string, error)
DeleteShare(accountName, shareName string) error
CreatePVSource(zone, diskName string) (*v1.PersistentVolumeSource, error)
DeletePVSource(pvSource *v1.PersistentVolumeSource) error
@ -137,6 +140,14 @@ func (n NullProvider) DeleteNode(node *v1.Node) error {
return fmt.Errorf("provider does not support DeleteNode")
}
func (n NullProvider) CreateShare() (string, string, string, error) {
return "", "", "", fmt.Errorf("provider does not support volume creation")
}
func (n NullProvider) DeleteShare(accountName, shareName string) error {
return fmt.Errorf("provider does not support volume deletion")
}
// CreatePD is a base implementation which creates PD.
func (n NullProvider) CreatePD(zone string) (string, error) {
return "", fmt.Errorf("provider does not support volume creation")

View File

@ -664,15 +664,23 @@ func createPDWithRetry(zone string) (string, error) {
for start := time.Now(); time.Since(start) < pdRetryTimeout; time.Sleep(pdRetryPollTime) {
newDiskName, err = createPD(zone)
if err != nil {
framework.Logf("Couldn't create a new PD, sleeping 5 seconds: %v", err)
framework.Logf("Couldn't create a new PD in zone %q, sleeping 5 seconds: %v", zone, err)
continue
}
framework.Logf("Successfully created a new PD: %q.", newDiskName)
framework.Logf("Successfully created a new PD in zone %q: %q.", zone, newDiskName)
return newDiskName, nil
}
return "", err
}
func CreateShare() (string, string, string, error) {
return framework.TestContext.CloudConfig.Provider.CreateShare()
}
func DeleteShare(accountName, shareName string) error {
return framework.TestContext.CloudConfig.Provider.DeleteShare(accountName, shareName)
}
// CreatePDWithRetry creates PD with retry.
func CreatePDWithRetry() (string, error) {
return createPDWithRetry("")

View File

@ -272,16 +272,6 @@ func SkipIfAppArmorNotSupported() {
SkipUnlessNodeOSDistroIs(AppArmorDistros...)
}
// RunIfContainerRuntimeIs runs if the container runtime is included in the runtimes.
func RunIfContainerRuntimeIs(runtimes ...string) {
for _, containerRuntime := range runtimes {
if containerRuntime == framework.TestContext.ContainerRuntime {
return
}
}
skipInternalf(1, "Skipped because container runtime %q is not in %s", framework.TestContext.ContainerRuntime, runtimes)
}
// RunIfSystemSpecNameIs runs if the system spec name is included in the names.
func RunIfSystemSpecNameIs(names ...string) {
for _, name := range names {
@ -313,3 +303,10 @@ func SkipUnlessComponentRunsAsPodsAndClientCanDeleteThem(componentName string, c
skipInternalf(1, "Skipped because client failed to delete component:%s pod, err:%v", componentName, err)
}
}
// SkipIfIPv6 skips if the cluster IP family is IPv6 and the provider is included in the unsupportedProviders.
func SkipIfIPv6(unsupportedProviders ...string) {
if framework.TestContext.ClusterIsIPv6() && framework.ProviderIs(unsupportedProviders...) {
skipInternalf(1, "Not supported for IPv6 clusters and providers %v (found %s)", unsupportedProviders, framework.TestContext.Provider)
}
}

View File

@ -20,7 +20,6 @@ import (
"bytes"
"context"
"fmt"
"io/ioutil"
"net"
"os"
"path/filepath"
@ -102,7 +101,7 @@ func GetSigner(provider string) (ssh.Signer, error) {
}
func makePrivateKeySignerFromFile(key string) (ssh.Signer, error) {
buffer, err := ioutil.ReadFile(key)
buffer, err := os.ReadFile(key)
if err != nil {
return nil, fmt.Errorf("error reading SSH key %s: '%v'", key, err)
}
@ -245,7 +244,7 @@ func runSSHCommand(cmd, user, host string, signer ssh.Signer) (string, string, i
err = wait.Poll(5*time.Second, 20*time.Second, func() (bool, error) {
fmt.Printf("error dialing %s@%s: '%v', retrying\n", user, host, err)
if client, err = ssh.Dial("tcp", host, config); err != nil {
return false, err
return false, nil // retrying, error will be logged above
}
return true, nil
})

View File

@ -22,7 +22,6 @@ import (
"errors"
"flag"
"fmt"
"io/ioutil"
"math"
"os"
"sort"
@ -78,13 +77,12 @@ type TestContextType struct {
KubeConfig string
KubeContext string
KubeAPIContentType string
KubeVolumeDir string
KubeletRootDir string
CertDir string
Host string
BearerToken string `datapolicy:"token"`
// TODO: Deprecating this over time... instead just use gobindata_util.go , see #23987.
RepoRoot string
DockershimCheckpointDir string
RepoRoot string
// ListImages will list off all images that are used then quit
ListImages bool
@ -109,7 +107,6 @@ type TestContextType struct {
EtcdUpgradeStorage string
EtcdUpgradeVersion string
GCEUpgradeScript string
ContainerRuntime string
ContainerRuntimeEndpoint string
ContainerRuntimeProcessName string
ContainerRuntimePidFile string
@ -308,15 +305,17 @@ func RegisterCommonFlags(flags *flag.FlagSet) {
flags.StringVar(&TestContext.ReportPrefix, "report-prefix", "", "Optional prefix for JUnit XML reports. Default is empty, which doesn't prepend anything to the default name.")
flags.StringVar(&TestContext.ReportDir, "report-dir", "", "Path to the directory where the JUnit XML reports should be saved. Default is empty, which doesn't generate these reports.")
flags.Var(cliflag.NewMapStringBool(&TestContext.FeatureGates), "feature-gates", "A set of key=value pairs that describe feature gates for alpha/experimental features.")
flags.StringVar(&TestContext.ContainerRuntime, "container-runtime", "docker", "The container runtime of cluster VM instances (docker/remote).")
flags.StringVar(&TestContext.ContainerRuntimeEndpoint, "container-runtime-endpoint", "unix:///var/run/dockershim.sock", "The container runtime endpoint of cluster VM instances.")
flags.StringVar(&TestContext.ContainerRuntimeEndpoint, "container-runtime-endpoint", "unix:///var/run/containerd/containerd.sock", "The container runtime endpoint of cluster VM instances.")
flags.StringVar(&TestContext.ContainerRuntimeProcessName, "container-runtime-process-name", "dockerd", "The name of the container runtime process.")
flags.StringVar(&TestContext.ContainerRuntimePidFile, "container-runtime-pid-file", "/var/run/docker.pid", "The pid file of the container runtime.")
flags.StringVar(&TestContext.SystemdServices, "systemd-services", "docker", "The comma separated list of systemd services the framework will dump logs for.")
flags.BoolVar(&TestContext.DumpSystemdJournal, "dump-systemd-journal", false, "Whether to dump the full systemd journal.")
flags.StringVar(&TestContext.ImageServiceEndpoint, "image-service-endpoint", "", "The image service endpoint of cluster VM instances.")
flags.StringVar(&TestContext.DockershimCheckpointDir, "dockershim-checkpoint-dir", "/var/lib/dockershim/sandbox", "The directory for dockershim to store sandbox checkpoints.")
// Expect the test suite to work with both the new and legacy non-blocking control plane taints by default
// TODO: remove the node-role.kubernetes.io/master taint in 1.25 or later.
// The change will likely require an action for some users that do not
// use k8s originated tools like kubeadm or kOps for creating clusters
// and taint their control plane nodes with "master", expecting the test
// suite to work with this legacy non-blocking taint.
flags.StringVar(&TestContext.NonblockingTaints, "non-blocking-taints", `node-role.kubernetes.io/control-plane,node-role.kubernetes.io/master`, "Nodes with taints in this comma-delimited list will not block the test framework from starting tests. The default taint 'node-role.kubernetes.io/master' is DEPRECATED and will be removed from the list in a future release.")
flags.BoolVar(&TestContext.ListImages, "list-images", false, "If true, will show list of images used for runnning tests.")
@ -338,7 +337,8 @@ func RegisterClusterFlags(flags *flag.FlagSet) {
flags.StringVar(&TestContext.KubeContext, clientcmd.FlagContext, "", "kubeconfig context to use/override. If unset, will use value from 'current-context'")
flags.StringVar(&TestContext.KubeAPIContentType, "kube-api-content-type", "application/vnd.kubernetes.protobuf", "ContentType used to communicate with apiserver")
flags.StringVar(&TestContext.KubeVolumeDir, "volume-dir", "/var/lib/kubelet", "Path to the directory containing the kubelet volumes.")
flags.StringVar(&TestContext.KubeletRootDir, "kubelet-root-dir", "/var/lib/kubelet", "The data directory of kubelet. Some tests (for example, CSI storage tests) deploy DaemonSets which need to know this value and cannot query it. Such tests only work in clusters where the data directory is the same on all nodes.")
flags.StringVar(&TestContext.KubeletRootDir, "volume-dir", "/var/lib/kubelet", "An alias for --kubelet-root-dir, kept for backwards compatibility.")
flags.StringVar(&TestContext.CertDir, "cert-dir", "", "Path to the directory containing the certs. Default is empty, which doesn't use certs.")
flags.StringVar(&TestContext.RepoRoot, "repo-root", "../../", "Root directory of kubernetes repository, for finding test files.")
// NOTE: Node E2E tests have this flag defined as well, but true by default.
@ -450,7 +450,7 @@ func AfterReadingAllFlags(t *TestContextType) {
if len(t.Host) == 0 && len(t.KubeConfig) == 0 {
// Check if we can use the in-cluster config
if clusterConfig, err := restclient.InClusterConfig(); err == nil {
if tempFile, err := ioutil.TempFile(os.TempDir(), "kubeconfig-"); err == nil {
if tempFile, err := os.CreateTemp(os.TempDir(), "kubeconfig-"); err == nil {
kubeConfig := createKubeConfig(clusterConfig)
clientcmd.WriteToFile(*kubeConfig, tempFile.Name())
t.KubeConfig = tempFile.Name()

View File

@ -29,7 +29,6 @@ import (
"errors"
"fmt"
"io/fs"
"io/ioutil"
"os"
"path"
"path/filepath"
@ -82,12 +81,12 @@ func Read(filePath string) ([]byte, error) {
}
// Here we try to generate an error that points test authors
// or users in the right direction for resolving the problem.
error := fmt.Sprintf("Test file %q was not found.\n", filePath)
err := fmt.Sprintf("Test file %q was not found.\n", filePath)
for _, filesource := range filesources {
error += filesource.DescribeFiles()
error += "\n"
err += filesource.DescribeFiles()
err += "\n"
}
return nil, errors.New(error)
return nil, errors.New(err)
}
// Exists checks whether a file could be read. Unexpected errors
@ -122,7 +121,7 @@ func (r RootFileSource) ReadTestFile(filePath string) ([]byte, error) {
} else {
fullPath = filepath.Join(r.Root, filePath)
}
data, err := ioutil.ReadFile(fullPath)
data, err := os.ReadFile(fullPath)
if os.IsNotExist(err) {
// Not an error (yet), some other provider may have the file.
return nil, nil

View File

@ -26,6 +26,7 @@ const (
podDeleteTimeout = 5 * time.Minute
claimProvisionTimeout = 5 * time.Minute
claimProvisionShortTimeout = 1 * time.Minute
dataSourceProvisionTimeout = 5 * time.Minute
claimBoundTimeout = 3 * time.Minute
pvReclaimTimeout = 3 * time.Minute
pvBoundTimeout = 3 * time.Minute
@ -56,6 +57,9 @@ type TimeoutContext struct {
// ClaimProvision is how long claims have to become dynamically provisioned.
ClaimProvision time.Duration
// DataSourceProvision is how long claims have to become dynamically provisioned from source claim.
DataSourceProvision time.Duration
// ClaimProvisionShort is the same as `ClaimProvision`, but shorter.
ClaimProvisionShort time.Duration
@ -96,6 +100,7 @@ func NewTimeoutContextWithDefaults() *TimeoutContext {
PodDelete: podDeleteTimeout,
ClaimProvision: claimProvisionTimeout,
ClaimProvisionShort: claimProvisionShortTimeout,
DataSourceProvision: dataSourceProvisionTimeout,
ClaimBound: claimBoundTimeout,
PVReclaim: pvReclaimTimeout,
PVBound: pvBoundTimeout,

View File

@ -1,11 +1,9 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- sig-storage-approvers
- rootfs
- jingxu97
- sig-storage-approvers
- jingxu97
reviewers:
- sig-storage-reviewers
- jeffvance
- copejon
- davidz627
- sig-storage-reviewers
emeritus_approvers:
- rootfs

View File

@ -41,6 +41,7 @@ package volume
import (
"context"
"crypto/sha256"
"fmt"
"path/filepath"
"strconv"
@ -51,6 +52,7 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/wait"
clientset "k8s.io/client-go/kubernetes"
clientexec "k8s.io/client-go/util/exec"
"k8s.io/kubernetes/test/e2e/framework"
@ -235,6 +237,73 @@ func CreateStorageServer(cs clientset.Interface, config TestConfig) (pod *v1.Pod
return pod, ip
}
// GetVolumeAttachmentName returns the hash value of the provisioner, the config ClientNodeSelection name,
// and the VolumeAttachment name of the PV that is bound to the PVC with the passed in claimName and claimNamespace.
func GetVolumeAttachmentName(cs clientset.Interface, config TestConfig, provisioner string, claimName string, claimNamespace string) string {
var nodeName string
// For provisioning tests, ClientNodeSelection is not set so we do not know the NodeName of the VolumeAttachment of the PV that is
// bound to the PVC with the passed in claimName and claimNamespace. We need this NodeName because it is used to generate the
// attachmentName that is returned, and used to look up a certain VolumeAttachment in WaitForVolumeAttachmentTerminated.
// To get the nodeName of the VolumeAttachment, we get all the VolumeAttachments, look for the VolumeAttachment with a
// PersistentVolumeName equal to the PV that is bound to the passed in PVC, and then we get the NodeName from that VolumeAttachment.
if config.ClientNodeSelection.Name == "" {
claim, _ := cs.CoreV1().PersistentVolumeClaims(claimNamespace).Get(context.TODO(), claimName, metav1.GetOptions{})
pvName := claim.Spec.VolumeName
volumeAttachments, _ := cs.StorageV1().VolumeAttachments().List(context.TODO(), metav1.ListOptions{})
for _, volumeAttachment := range volumeAttachments.Items {
if *volumeAttachment.Spec.Source.PersistentVolumeName == pvName {
nodeName = volumeAttachment.Spec.NodeName
break
}
}
} else {
nodeName = config.ClientNodeSelection.Name
}
handle := getVolumeHandle(cs, claimName, claimNamespace)
attachmentHash := sha256.Sum256([]byte(fmt.Sprintf("%s%s%s", handle, provisioner, nodeName)))
return fmt.Sprintf("csi-%x", attachmentHash)
}
// getVolumeHandle returns the VolumeHandle of the PV that is bound to the PVC with the passed in claimName and claimNamespace.
func getVolumeHandle(cs clientset.Interface, claimName string, claimNamespace string) string {
// re-get the claim to the latest state with bound volume
claim, err := cs.CoreV1().PersistentVolumeClaims(claimNamespace).Get(context.TODO(), claimName, metav1.GetOptions{})
if err != nil {
framework.ExpectNoError(err, "Cannot get PVC")
return ""
}
pvName := claim.Spec.VolumeName
pv, err := cs.CoreV1().PersistentVolumes().Get(context.TODO(), pvName, metav1.GetOptions{})
if err != nil {
framework.ExpectNoError(err, "Cannot get PV")
return ""
}
if pv.Spec.CSI == nil {
gomega.Expect(pv.Spec.CSI).NotTo(gomega.BeNil())
return ""
}
return pv.Spec.CSI.VolumeHandle
}
// WaitForVolumeAttachmentTerminated waits for the VolumeAttachment with the passed in attachmentName to be terminated.
func WaitForVolumeAttachmentTerminated(attachmentName string, cs clientset.Interface, timeout time.Duration) error {
waitErr := wait.PollImmediate(10*time.Second, timeout, func() (bool, error) {
_, err := cs.StorageV1().VolumeAttachments().Get(context.TODO(), attachmentName, metav1.GetOptions{})
if err != nil {
// if the volumeattachment object is not found, it means it has been terminated.
if apierrors.IsNotFound(err) {
return true, nil
}
return false, err
}
return false, nil
})
if waitErr != nil {
return fmt.Errorf("error waiting volume attachment %v to terminate: %v", attachmentName, waitErr)
}
return nil
}
// startVolumeServer starts a container specified by config.serverImage and exports all
// config.serverPorts from it. The returned pod should be used to get the server
// IP address and create appropriate VolumeSource.

View File

@ -27,8 +27,10 @@ import (
v1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
storagev1 "k8s.io/api/storage/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes/scheme"
@ -269,17 +271,19 @@ func describeItem(item interface{}) string {
var errorItemNotSupported = errors.New("not supported")
var factories = map[What]ItemFactory{
{"ClusterRole"}: &clusterRoleFactory{},
{"ClusterRoleBinding"}: &clusterRoleBindingFactory{},
{"CSIDriver"}: &csiDriverFactory{},
{"DaemonSet"}: &daemonSetFactory{},
{"Role"}: &roleFactory{},
{"RoleBinding"}: &roleBindingFactory{},
{"Secret"}: &secretFactory{},
{"Service"}: &serviceFactory{},
{"ServiceAccount"}: &serviceAccountFactory{},
{"StatefulSet"}: &statefulSetFactory{},
{"StorageClass"}: &storageClassFactory{},
{"ClusterRole"}: &clusterRoleFactory{},
{"ClusterRoleBinding"}: &clusterRoleBindingFactory{},
{"CSIDriver"}: &csiDriverFactory{},
{"DaemonSet"}: &daemonSetFactory{},
{"Role"}: &roleFactory{},
{"RoleBinding"}: &roleBindingFactory{},
{"Secret"}: &secretFactory{},
{"Service"}: &serviceFactory{},
{"ServiceAccount"}: &serviceAccountFactory{},
{"StatefulSet"}: &statefulSetFactory{},
{"Deployment"}: &deploymentFactory{},
{"StorageClass"}: &storageClassFactory{},
{"CustomResourceDefinition"}: &customResourceDefinitionFactory{},
}
// PatchName makes the name of some item unique by appending the
@ -362,6 +366,14 @@ func patchItemRecursively(f *framework.Framework, driverNamespace *v1.Namespace,
if err := patchContainerImages(item.Spec.Template.Spec.InitContainers); err != nil {
return err
}
case *appsv1.Deployment:
PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace)
if err := patchContainerImages(item.Spec.Template.Spec.Containers); err != nil {
return err
}
if err := patchContainerImages(item.Spec.Template.Spec.InitContainers); err != nil {
return err
}
case *appsv1.DaemonSet:
PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace)
if err := patchContainerImages(item.Spec.Template.Spec.Containers); err != nil {
@ -370,6 +382,8 @@ func patchItemRecursively(f *framework.Framework, driverNamespace *v1.Namespace,
if err := patchContainerImages(item.Spec.Template.Spec.InitContainers); err != nil {
return err
}
case *apiextensionsv1.CustomResourceDefinition:
// Do nothing. Patching name to all CRDs won't always be the expected behavior.
default:
return fmt.Errorf("missing support for patching item of type %T", item)
}
@ -528,6 +542,27 @@ func (*statefulSetFactory) Create(f *framework.Framework, ns *v1.Namespace, i in
}, nil
}
type deploymentFactory struct{}
func (f *deploymentFactory) New() runtime.Object {
return &appsv1.Deployment{}
}
func (*deploymentFactory) Create(f *framework.Framework, ns *v1.Namespace, i interface{}) (func() error, error) {
item, ok := i.(*appsv1.Deployment)
if !ok {
return nil, errorItemNotSupported
}
client := f.ClientSet.AppsV1().Deployments(ns.Name)
if _, err := client.Create(context.TODO(), item, metav1.CreateOptions{}); err != nil {
return nil, fmt.Errorf("create Deployment: %w", err)
}
return func() error {
return client.Delete(context.TODO(), item.GetName(), metav1.DeleteOptions{})
}, nil
}
type daemonSetFactory struct{}
func (f *daemonSetFactory) New() runtime.Object {
@ -612,6 +647,35 @@ func (*secretFactory) Create(f *framework.Framework, ns *v1.Namespace, i interfa
}, nil
}
type customResourceDefinitionFactory struct{}
func (f *customResourceDefinitionFactory) New() runtime.Object {
return &apiextensionsv1.CustomResourceDefinition{}
}
func (*customResourceDefinitionFactory) Create(f *framework.Framework, ns *v1.Namespace, i interface{}) (func() error, error) {
var err error
unstructCRD := &unstructured.Unstructured{}
gvr := schema.GroupVersionResource{Group: "apiextensions.k8s.io", Version: "v1", Resource: "customresourcedefinitions"}
item, ok := i.(*apiextensionsv1.CustomResourceDefinition)
if !ok {
return nil, errorItemNotSupported
}
unstructCRD.Object, err = runtime.DefaultUnstructuredConverter.ToUnstructured(i)
if err != nil {
return nil, err
}
if _, err = f.DynamicClient.Resource(gvr).Create(context.TODO(), unstructCRD, metav1.CreateOptions{}); err != nil {
return nil, fmt.Errorf("create CustomResourceDefinition: %w", err)
}
return func() error {
return f.DynamicClient.Resource(gvr).Delete(context.TODO(), item.GetName(), metav1.DeleteOptions{})
}, nil
}
// PrettyPrint returns a human-readable representation of an item.
func PrettyPrint(item interface{}) string {
data, err := json.MarshalIndent(item, "", " ")

View File

@ -24,6 +24,7 @@ import (
v1 "k8s.io/api/core/v1"
storagev1 "k8s.io/api/storage/v1"
"k8s.io/kubernetes/test/e2e/framework"
e2eframework "k8s.io/kubernetes/test/e2e/framework"
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
)
@ -52,6 +53,10 @@ func PatchCSIDeployment(f *framework.Framework, o PatchCSIOptions, object interf
rename := o.OldDriverName != "" && o.NewDriverName != "" &&
o.OldDriverName != o.NewDriverName
substKubeletRootDir := func(s string) string {
return strings.ReplaceAll(s, "/var/lib/kubelet/", e2eframework.TestContext.KubeletRootDir+"/")
}
patchVolumes := func(volumes []v1.Volume) {
if !rename {
return
@ -65,6 +70,8 @@ func PatchCSIDeployment(f *framework.Framework, o PatchCSIOptions, object interf
if file == o.OldDriverName {
*p = path.Join(dir, o.NewDriverName)
}
// Inject non-standard kubelet path.
*p = substKubeletRootDir(*p)
}
}
}
@ -79,6 +86,15 @@ func PatchCSIDeployment(f *framework.Framework, o PatchCSIOptions, object interf
container.Args[e] = strings.Replace(container.Args[e], "/"+o.OldDriverName+"/", "/"+o.NewDriverName+"/", 1)
}
}
// Modify --kubelet-registration-path.
for e := range container.Args {
container.Args[e] = substKubeletRootDir(container.Args[e])
}
for e := range container.VolumeMounts {
container.VolumeMounts[e].MountPath = substKubeletRootDir(container.VolumeMounts[e].MountPath)
}
// Overwrite driver name resp. provider name
// by appending a parameter with the right
// value.

View File

@ -0,0 +1,22 @@
# test/e2e/testing-manifests
## Embedded Test Data
In case one needs to use any test fixture inside your tests and those are defined inside this directory, they need to be added to the `//go:embed` directive in `embed.go`.
For example, if one wants to include this Readme as a test fixture (potential bad idea in reality!),
```
// embed.go
...
//go:embed some other files README.md
...
```
This fixture can be accessed in the e2e tests using `test/e2e/framework/testfiles.Read` like
`testfiles.Read("test/e2e/testing-manifests/README.md)`.
This is needed since [migrating to //go:embed from go-bindata][1].
[1]: https://github.com/kubernetes/kubernetes/pull/99829

View File

@ -0,0 +1,21 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: dns-backend
labels:
name: dns-backend
spec:
replicas: 1
selector:
name: dns-backend
template:
metadata:
labels:
name: dns-backend
spec:
containers:
- name: dns-backend
image: k8s.gcr.io/example-dns-backend:v1
ports:
- name: backend-port
containerPort: 8000

View File

@ -0,0 +1,9 @@
kind: Service
apiVersion: v1
metadata:
name: dns-backend
spec:
ports:
- port: 8000
selector:
name: dns-backend

View File

@ -0,0 +1,16 @@
apiVersion: v1
kind: Pod
metadata:
name: dns-frontend
labels:
name: dns-frontend
spec:
containers:
- name: dns-frontend
image: k8s.gcr.io/example-dns-frontend:v1
command:
- python
- client.py
- http://dns-backend.development.svc.cluster.local:8000
imagePullPolicy: Always
restartPolicy: Never

View File

@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2021 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.
@ -14,26 +14,20 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package types
package testing_manifests
import (
v1 "k8s.io/api/core/v1"
"embed"
e2etestfiles "k8s.io/kubernetes/test/e2e/framework/testfiles"
)
// PodConditionsByKubelet is the list of pod conditions owned by kubelet
var PodConditionsByKubelet = []v1.PodConditionType{
v1.PodScheduled,
v1.PodReady,
v1.PodInitialized,
v1.ContainersReady,
}
//go:embed cluster-dns flexvolume guestbook kubectl sample-device-plugin.yaml scheduling/nvidia-driver-installer.yaml statefulset storage-csi
var e2eTestingManifestsFS embed.FS
// PodConditionByKubelet returns if the pod condition type is owned by kubelet
func PodConditionByKubelet(conditionType v1.PodConditionType) bool {
for _, c := range PodConditionsByKubelet {
if c == conditionType {
return true
}
func GetE2ETestingManifestsFS() e2etestfiles.EmbeddedFileSource {
return e2etestfiles.EmbeddedFileSource{
EmbeddedFS: e2eTestingManifestsFS,
Root: "test/e2e/testing-manifests",
}
return false
}

View File

@ -0,0 +1,145 @@
#!/bin/sh
# 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.
# This driver is especially designed to test a long mounting scenario
# which can cause a volume to be detached while mount is in progress.
FLEX_DUMMY_LOG=${FLEX_DUMMY_LOG:-"/tmp/flex-dummy.log"}
VALID_MNTDEVICE=foo
# attach always returns one valid mount device so a different device
# showing up in a subsequent driver call implies a bug
validateMountDeviceOrDie() {
MNTDEVICE=$1
CALL=$2
if [ "$MNTDEVICE" != "$VALID_MNTDEVICE" ]; then
log "{\"status\":\"Failure\",\"message\":\"call "${CALL}" expected device "${VALID_MNTDEVICE}", got device "${MNTDEVICE}"\"}"
exit 0
fi
}
log() {
printf "$*" >&1
}
debug() {
echo "$(date) $*" >> "${FLEX_DUMMY_LOG}"
}
attach() {
debug "attach $@"
log "{\"status\":\"Success\",\"device\":\""${VALID_MNTDEVICE}"\"}"
exit 0
}
detach() {
debug "detach $@"
# TODO issue 44737 detach is passed PV name, not mount device
log "{\"status\":\"Success\"}"
exit 0
}
waitforattach() {
debug "waitforattach $@"
MNTDEVICE=$1
validateMountDeviceOrDie "$MNTDEVICE" "waitforattach"
log "{\"status\":\"Success\",\"device\":\""${MNTDEVICE}"\"}"
exit 0
}
isattached() {
debug "isattached $@"
log "{\"status\":\"Success\",\"attached\":true}"
exit 0
}
domountdevice() {
debug "domountdevice $@"
MNTDEVICE=$2
validateMountDeviceOrDie "$MNTDEVICE" "domountdevice"
MNTPATH=$1
mkdir -p ${MNTPATH} >/dev/null 2>&1
mount -t tmpfs none ${MNTPATH} >/dev/null 2>&1
sleep 120
echo "Hello from flexvolume!" >> "${MNTPATH}/index.html"
log "{\"status\":\"Success\"}"
exit 0
}
unmountdevice() {
debug "unmountdevice $@"
MNTPATH=$1
rm "${MNTPATH}/index.html" >/dev/null 2>&1
umount ${MNTPATH} >/dev/null 2>&1
log "{\"status\":\"Success\"}"
exit 0
}
expandvolume() {
debug "expandvolume $@"
log "{\"status\":\"Success\"}"
exit 0
}
expandfs() {
debug "expandfs $@"
log "{\"status\":\"Success\"}"
exit 0
}
op=$1
if [ "$op" = "init" ]; then
debug "init $@"
log "{\"status\":\"Success\",\"capabilities\":{\"attach\":true, \"requiresFSResize\":true}}"
exit 0
fi
shift
case "$op" in
attach)
attach $*
;;
detach)
detach $*
;;
waitforattach)
waitforattach $*
;;
isattached)
isattached $*
;;
mountdevice)
domountdevice $*
;;
unmountdevice)
unmountdevice $*
;;
expandvolume)
expandvolume $*
;;
expandfs)
expandfs $*
;;
*)
log "{\"status\":\"Not supported\"}"
exit 0
esac
exit 1

View File

@ -0,0 +1,70 @@
#!/bin/sh
# 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.
# This driver implements a tmpfs with a pre-populated file index.html.
FLEX_DUMMY_LOG=${FLEX_DUMMY_LOG:-"/tmp/flex-dummy.log"}
log() {
printf "$*" >&1
}
debug() {
echo "$(date) $*" >> "${FLEX_DUMMY_LOG}"
}
domount() {
debug "domount $@"
MNTPATH=$1
mkdir -p ${MNTPATH} >/dev/null 2>&1
mount -t tmpfs none ${MNTPATH} >/dev/null 2>&1
echo "Hello from flexvolume!" >> "${MNTPATH}/index.html"
log "{\"status\":\"Success\"}"
exit 0
}
unmount() {
debug "unmount $@"
MNTPATH=$1
rm ${MNTPATH}/index.html >/dev/null 2>&1
umount ${MNTPATH} >/dev/null 2>&1
log "{\"status\":\"Success\"}"
exit 0
}
op=$1
if [ "$op" = "init" ]; then
debug "init $@"
log "{\"status\":\"Success\",\"capabilities\":{\"attach\":false}}"
exit 0
fi
shift
case "$op" in
mount)
domount $*
;;
unmount)
unmount $*
;;
*)
log "{\"status\":\"Not supported\"}"
exit 0
esac
exit 1

View File

@ -0,0 +1,143 @@
#!/bin/sh
# 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.
# This driver implements a tmpfs with a pre-populated file index.html.
# Attach is required, but it is a no-op that always returns success.
FLEX_DUMMY_LOG=${FLEX_DUMMY_LOG:-"/tmp/flex-dummy.log"}
VALID_MNTDEVICE=foo
# attach always returns one valid mount device so a different device
# showing up in a subsequent driver call implies a bug
validateMountDeviceOrDie() {
MNTDEVICE=$1
CALL=$2
if [ "$MNTDEVICE" != "$VALID_MNTDEVICE" ]; then
log "{\"status\":\"Failure\",\"message\":\"call "${CALL}" expected device "${VALID_MNTDEVICE}", got device "${MNTDEVICE}"\"}"
exit 0
fi
}
log() {
printf "$*" >&1
}
debug() {
echo "$(date) $*" >> "${FLEX_DUMMY_LOG}"
}
attach() {
debug "attach $@"
log "{\"status\":\"Success\",\"device\":\""${VALID_MNTDEVICE}"\"}"
exit 0
}
detach() {
debug "detach $@"
# TODO issue 44737 detach is passed PV name, not mount device
log "{\"status\":\"Success\"}"
exit 0
}
waitforattach() {
debug "waitforattach $@"
MNTDEVICE=$1
validateMountDeviceOrDie "$MNTDEVICE" "waitforattach"
log "{\"status\":\"Success\",\"device\":\""${MNTDEVICE}"\"}"
exit 0
}
isattached() {
debug "isattached $@"
log "{\"status\":\"Success\",\"attached\":true}"
exit 0
}
domountdevice() {
debug "domountdevice $@"
MNTDEVICE=$2
validateMountDeviceOrDie "$MNTDEVICE" "domountdevice"
MNTPATH=$1
mkdir -p ${MNTPATH} >/dev/null 2>&1
mount -t tmpfs none ${MNTPATH} >/dev/null 2>&1
echo "Hello from flexvolume!" >> "${MNTPATH}/index.html"
log "{\"status\":\"Success\"}"
exit 0
}
unmountdevice() {
debug "unmountdevice $@"
MNTPATH=$1
rm "${MNTPATH}/index.html" >/dev/null 2>&1
umount ${MNTPATH} >/dev/null 2>&1
log "{\"status\":\"Success\"}"
exit 0
}
expandvolume() {
debug "expandvolume $@"
log "{\"status\":\"Success\"}"
exit 0
}
expandfs() {
debug "expandfs $@"
log "{\"status\":\"Success\"}"
exit 0
}
op=$1
if [ "$op" = "init" ]; then
debug "init $@"
log "{\"status\":\"Success\",\"capabilities\":{\"attach\":true, \"requiresFSResize\":true}}"
exit 0
fi
shift
case "$op" in
attach)
attach $*
;;
detach)
detach $*
;;
waitforattach)
waitforattach $*
;;
isattached)
isattached $*
;;
mountdevice)
domountdevice $*
;;
unmountdevice)
unmountdevice $*
;;
expandvolume)
expandvolume $*
;;
expandfs)
expandfs $*
;;
*)
log "{\"status\":\"Not supported\"}"
exit 0
esac
exit 1

View File

@ -0,0 +1,28 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: agnhost-primary
spec:
replicas: 1
selector:
matchLabels:
app: agnhost
role: primary
tier: backend
template:
metadata:
labels:
app: agnhost
role: primary
tier: backend
spec:
containers:
- name: primary
image: {{.AgnhostImage}}
args: [ "guestbook", "--http-port", "6379" ]
resources:
requests:
cpu: 100m
memory: 100Mi
ports:
- containerPort: 6379

View File

@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: agnhost-primary
labels:
app: agnhost
role: primary
tier: backend
spec:
ports:
- port: 6379
targetPort: 6379
selector:
app: agnhost
role: primary
tier: backend

View File

@ -0,0 +1,28 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: agnhost-replica
spec:
replicas: 2
selector:
matchLabels:
app: agnhost
role: replica
tier: backend
template:
metadata:
labels:
app: agnhost
role: replica
tier: backend
spec:
containers:
- name: replica
image: {{.AgnhostImage}}
args: [ "guestbook", "--replicaof", "agnhost-primary", "--http-port", "6379" ]
resources:
requests:
cpu: 100m
memory: 100Mi
ports:
- containerPort: 6379

View File

@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: agnhost-replica
labels:
app: agnhost
role: replica
tier: backend
spec:
ports:
- port: 6379
selector:
app: agnhost
role: replica
tier: backend

View File

@ -0,0 +1,26 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 3
selector:
matchLabels:
app: guestbook
tier: frontend
template:
metadata:
labels:
app: guestbook
tier: frontend
spec:
containers:
- name: guestbook-frontend
image: {{.AgnhostImage}}
args: [ "guestbook", "--backend-port", "6379" ]
resources:
requests:
cpu: 100m
memory: 100Mi
ports:
- containerPort: 80

View File

@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
# if your cluster supports it, uncomment the following to automatically create
# an external load-balanced IP for the frontend service.
# type: LoadBalancer
ports:
- port: 80
selector:
app: guestbook
tier: frontend

View File

@ -0,0 +1,29 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: frontend
spec:
replicas: 3
template:
metadata:
labels:
app: guestbook
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google_samples/gb-frontend:v4
resources:
requests:
cpu: 100m
memory: 100Mi
env:
- name: GET_HOSTS_FROM
value: dns
# If your cluster config does not include a dns service, then to
# instead access environment variables to find service host
# info, comment out the 'value: dns' line above, and uncomment the
# line below:
# value: env
ports:
- containerPort: 80

View File

@ -0,0 +1,26 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-master
labels:
app: redis
role: master
tier: backend
spec:
replicas: 1
template:
metadata:
labels:
app: redis
role: master
tier: backend
spec:
containers:
- name: master
image: docker.io/library/redis:5.0.5-alpine
resources:
requests:
cpu: 100m
memory: 100Mi
ports:
- containerPort: 6379

View File

@ -0,0 +1,37 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-slave
labels:
app: redis
role: slave
tier: backend
spec:
replicas: 2
template:
metadata:
labels:
app: redis
role: slave
tier: backend
spec:
containers:
- name: slave
image: docker.io/library/redis:5.0.5-alpine
# We are only implementing the dns option of:
# https://github.com/kubernetes/examples/blob/97c7ed0eb6555a4b667d2877f965d392e00abc45/guestbook/redis-slave/run.sh
command: [ "redis-server", "--slaveof", "redis-master", "6379" ]
resources:
requests:
cpu: 100m
memory: 100Mi
env:
- name: GET_HOSTS_FROM
value: dns
# If your cluster config does not include a dns service, then to
# instead access an environment variable to find the master
# service's host, comment out the 'value: dns' line above, and
# uncomment the line below:
# value: env
ports:
- containerPort: 6379

View File

@ -0,0 +1,27 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-master
spec:
replicas: 1
selector:
matchLabels:
app: redis
role: master
tier: backend
template:
metadata:
labels:
app: redis
role: master
tier: backend
spec:
containers:
- name: master
image: {{.RedisImage}}
resources:
requests:
cpu: 100m
memory: 100Mi
ports:
- containerPort: 6379

Some files were not shown because too many files have changed in this diff Show More