explicit kubelet config key in Node.Spec.ConfigSource.ConfigMap
This makes the Kubelet config key in the ConfigMap an explicit part of the API, so we can stop using magic key names. As part of this change, we are retiring ConfigMapRef for ConfigMap.
This commit is contained in:
@@ -60,7 +60,6 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
&ServiceProxyOptions{},
|
||||
&NodeList{},
|
||||
&Node{},
|
||||
&NodeConfigSource{},
|
||||
&NodeProxyOptions{},
|
||||
&Endpoints{},
|
||||
&EndpointsList{},
|
||||
|
||||
@@ -3257,12 +3257,48 @@ type NodeSpec struct {
|
||||
DoNotUse_ExternalID string
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// NodeConfigSource specifies a source of node configuration. Exactly one subfield must be non-nil.
|
||||
type NodeConfigSource struct {
|
||||
metav1.TypeMeta
|
||||
ConfigMapRef *ObjectReference
|
||||
ConfigMap *ConfigMapNodeConfigSource
|
||||
}
|
||||
|
||||
type ConfigMapNodeConfigSource struct {
|
||||
// Namespace is the metadata.namespace of the referenced ConfigMap.
|
||||
// This field is required in all cases.
|
||||
Namespace string
|
||||
|
||||
// Name is the metadata.name of the referenced ConfigMap.
|
||||
// This field is required in all cases.
|
||||
Name string
|
||||
|
||||
// UID is the metadata.UID of the referenced ConfigMap.
|
||||
// This field is currently reqired in Node.Spec.
|
||||
// TODO(#61643): This field will be forbidden in Node.Spec when #61643 is resolved.
|
||||
// #61643 changes the behavior of dynamic Kubelet config to respect
|
||||
// ConfigMap updates, and thus removes the ability to pin the Spec to a given UID.
|
||||
// TODO(#56896): This field will be required in Node.Status when #56896 is resolved.
|
||||
// #63314 (the PR that resolves #56896) adds a structured status to the Node
|
||||
// object for reporting information about the config. This status requires UID
|
||||
// and ResourceVersion, so that it represents a fully-explicit description of
|
||||
// the configuration in use, while (see previous TODO) the Spec will be
|
||||
// restricted to namespace/name in #61643.
|
||||
// +optional
|
||||
UID types.UID
|
||||
|
||||
// ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap.
|
||||
// This field is forbidden in Node.Spec.
|
||||
// TODO(#56896): This field will be required in Node.Status when #56896 is resolved.
|
||||
// #63314 (the PR that resolves #56896) adds a structured status to the Node
|
||||
// object for reporting information about the config. This status requires UID
|
||||
// and ResourceVersion, so that it represents a fully-explicit description of
|
||||
// the configuration in use, while (see previous TODO) the Spec will be
|
||||
// restricted to namespace/name in #61643.
|
||||
// +optional
|
||||
ResourceVersion string
|
||||
|
||||
// KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure
|
||||
// This field is required in all cases.
|
||||
KubeletConfigKey string
|
||||
}
|
||||
|
||||
// DaemonEndpoint contains information about a single Daemon endpoint.
|
||||
|
||||
34
pkg/apis/core/v1/zz_generated.conversion.go
generated
34
pkg/apis/core/v1/zz_generated.conversion.go
generated
@@ -82,6 +82,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
|
||||
Convert_core_ConfigMapKeySelector_To_v1_ConfigMapKeySelector,
|
||||
Convert_v1_ConfigMapList_To_core_ConfigMapList,
|
||||
Convert_core_ConfigMapList_To_v1_ConfigMapList,
|
||||
Convert_v1_ConfigMapNodeConfigSource_To_core_ConfigMapNodeConfigSource,
|
||||
Convert_core_ConfigMapNodeConfigSource_To_v1_ConfigMapNodeConfigSource,
|
||||
Convert_v1_ConfigMapProjection_To_core_ConfigMapProjection,
|
||||
Convert_core_ConfigMapProjection_To_v1_ConfigMapProjection,
|
||||
Convert_v1_ConfigMapVolumeSource_To_core_ConfigMapVolumeSource,
|
||||
@@ -941,6 +943,34 @@ func Convert_core_ConfigMapList_To_v1_ConfigMapList(in *core.ConfigMapList, out
|
||||
return autoConvert_core_ConfigMapList_To_v1_ConfigMapList(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_ConfigMapNodeConfigSource_To_core_ConfigMapNodeConfigSource(in *v1.ConfigMapNodeConfigSource, out *core.ConfigMapNodeConfigSource, s conversion.Scope) error {
|
||||
out.Namespace = in.Namespace
|
||||
out.Name = in.Name
|
||||
out.UID = types.UID(in.UID)
|
||||
out.ResourceVersion = in.ResourceVersion
|
||||
out.KubeletConfigKey = in.KubeletConfigKey
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_ConfigMapNodeConfigSource_To_core_ConfigMapNodeConfigSource is an autogenerated conversion function.
|
||||
func Convert_v1_ConfigMapNodeConfigSource_To_core_ConfigMapNodeConfigSource(in *v1.ConfigMapNodeConfigSource, out *core.ConfigMapNodeConfigSource, s conversion.Scope) error {
|
||||
return autoConvert_v1_ConfigMapNodeConfigSource_To_core_ConfigMapNodeConfigSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_core_ConfigMapNodeConfigSource_To_v1_ConfigMapNodeConfigSource(in *core.ConfigMapNodeConfigSource, out *v1.ConfigMapNodeConfigSource, s conversion.Scope) error {
|
||||
out.Namespace = in.Namespace
|
||||
out.Name = in.Name
|
||||
out.UID = types.UID(in.UID)
|
||||
out.ResourceVersion = in.ResourceVersion
|
||||
out.KubeletConfigKey = in.KubeletConfigKey
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_core_ConfigMapNodeConfigSource_To_v1_ConfigMapNodeConfigSource is an autogenerated conversion function.
|
||||
func Convert_core_ConfigMapNodeConfigSource_To_v1_ConfigMapNodeConfigSource(in *core.ConfigMapNodeConfigSource, out *v1.ConfigMapNodeConfigSource, s conversion.Scope) error {
|
||||
return autoConvert_core_ConfigMapNodeConfigSource_To_v1_ConfigMapNodeConfigSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_ConfigMapProjection_To_core_ConfigMapProjection(in *v1.ConfigMapProjection, out *core.ConfigMapProjection, s conversion.Scope) error {
|
||||
if err := Convert_v1_LocalObjectReference_To_core_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil {
|
||||
return err
|
||||
@@ -2586,7 +2616,7 @@ func Convert_core_NodeCondition_To_v1_NodeCondition(in *core.NodeCondition, out
|
||||
}
|
||||
|
||||
func autoConvert_v1_NodeConfigSource_To_core_NodeConfigSource(in *v1.NodeConfigSource, out *core.NodeConfigSource, s conversion.Scope) error {
|
||||
out.ConfigMapRef = (*core.ObjectReference)(unsafe.Pointer(in.ConfigMapRef))
|
||||
out.ConfigMap = (*core.ConfigMapNodeConfigSource)(unsafe.Pointer(in.ConfigMap))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2596,7 +2626,7 @@ func Convert_v1_NodeConfigSource_To_core_NodeConfigSource(in *v1.NodeConfigSourc
|
||||
}
|
||||
|
||||
func autoConvert_core_NodeConfigSource_To_v1_NodeConfigSource(in *core.NodeConfigSource, out *v1.NodeConfigSource, s conversion.Scope) error {
|
||||
out.ConfigMapRef = (*v1.ObjectReference)(unsafe.Pointer(in.ConfigMapRef))
|
||||
out.ConfigMap = (*v1.ConfigMapNodeConfigSource)(unsafe.Pointer(in.ConfigMap))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -4120,7 +4120,7 @@ func ValidateNodeUpdate(node, oldNode *core.Node) field.ErrorList {
|
||||
// Allow updates to Node.Spec.ConfigSource if DynamicKubeletConfig feature gate is enabled
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.DynamicKubeletConfig) {
|
||||
if node.Spec.ConfigSource != nil {
|
||||
allErrs = append(allErrs, validateNodeConfigSource(node.Spec.ConfigSource, field.NewPath("spec", "configSource"))...)
|
||||
allErrs = append(allErrs, validateNodeConfigSourceSpec(node.Spec.ConfigSource, field.NewPath("spec", "configSource"))...)
|
||||
}
|
||||
oldNode.Spec.ConfigSource = node.Spec.ConfigSource
|
||||
}
|
||||
@@ -4135,15 +4135,13 @@ func ValidateNodeUpdate(node, oldNode *core.Node) field.ErrorList {
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateNodeConfigSource(source *core.NodeConfigSource, fldPath *field.Path) field.ErrorList {
|
||||
// validation specific to Node.Spec.ConfigSource
|
||||
func validateNodeConfigSourceSpec(source *core.NodeConfigSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
count := int(0)
|
||||
if ref := source.ConfigMapRef; ref != nil {
|
||||
if source.ConfigMap != nil {
|
||||
count++
|
||||
// name, namespace, and UID must all be non-empty for ConfigMapRef
|
||||
if ref.Name == "" || ref.Namespace == "" || string(ref.UID) == "" {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("configMapRef"), ref, "name, namespace, and UID must all be non-empty"))
|
||||
}
|
||||
allErrs = append(allErrs, validateConfigMapNodeConfigSourceSpec(source.ConfigMap, fldPath.Child("configMap"))...)
|
||||
}
|
||||
// add more subfields here in the future as they are added to NodeConfigSource
|
||||
|
||||
@@ -4154,6 +4152,50 @@ func validateNodeConfigSource(source *core.NodeConfigSource, fldPath *field.Path
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validation specific to Node.Spec.ConfigSource.ConfigMap
|
||||
func validateConfigMapNodeConfigSourceSpec(source *core.ConfigMapNodeConfigSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
// TODO(#61643): Prevent ref.UID from being set here when we switch from requiring UID to respecting all ConfigMap updates
|
||||
if string(source.UID) == "" {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("uid"), "uid must be set in spec"))
|
||||
}
|
||||
// resourceVersion must not be set in spec
|
||||
if source.ResourceVersion != "" {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("resourceVersion"), "resourceVersion must not be set in spec"))
|
||||
}
|
||||
return append(allErrs, validateConfigMapNodeConfigSource(source, fldPath)...)
|
||||
}
|
||||
|
||||
// common validation
|
||||
func validateConfigMapNodeConfigSource(source *core.ConfigMapNodeConfigSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
// validate target configmap namespace
|
||||
if source.Namespace == "" {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("namespace"), "namespace must be set in spec"))
|
||||
} else {
|
||||
for _, msg := range ValidateNameFunc(ValidateNamespaceName)(source.Namespace, false) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), source.Namespace, msg))
|
||||
}
|
||||
}
|
||||
// validate target configmap name
|
||||
if source.Name == "" {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("name"), "name must be set in spec"))
|
||||
} else {
|
||||
for _, msg := range ValidateNameFunc(ValidateConfigMapName)(source.Name, false) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), source.Name, msg))
|
||||
}
|
||||
}
|
||||
// validate kubeletConfigKey against rules for configMap key names
|
||||
if source.KubeletConfigKey == "" {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("kubeletConfigKey"), "kubeletConfigKey must be set in spec"))
|
||||
} else {
|
||||
for _, msg := range validation.IsConfigMapKey(source.KubeletConfigKey) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("kubeletConfigKey"), source.KubeletConfigKey, msg))
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// Validate compute resource typename.
|
||||
// Refer to docs/design/resources.md for more details.
|
||||
func validateResourceName(value string, fldPath *field.Path) field.ErrorList {
|
||||
|
||||
31
pkg/apis/core/zz_generated.deepcopy.go
generated
31
pkg/apis/core/zz_generated.deepcopy.go
generated
@@ -631,6 +631,22 @@ func (in *ConfigMapList) DeepCopyObject() runtime.Object {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ConfigMapNodeConfigSource) DeepCopyInto(out *ConfigMapNodeConfigSource) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapNodeConfigSource.
|
||||
func (in *ConfigMapNodeConfigSource) DeepCopy() *ConfigMapNodeConfigSource {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ConfigMapNodeConfigSource)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ConfigMapProjection) DeepCopyInto(out *ConfigMapProjection) {
|
||||
*out = *in
|
||||
@@ -2364,13 +2380,12 @@ func (in *NodeCondition) DeepCopy() *NodeCondition {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NodeConfigSource) DeepCopyInto(out *NodeConfigSource) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if in.ConfigMapRef != nil {
|
||||
in, out := &in.ConfigMapRef, &out.ConfigMapRef
|
||||
if in.ConfigMap != nil {
|
||||
in, out := &in.ConfigMap, &out.ConfigMap
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(ObjectReference)
|
||||
*out = new(ConfigMapNodeConfigSource)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
@@ -2387,14 +2402,6 @@ func (in *NodeConfigSource) DeepCopy() *NodeConfigSource {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *NodeConfigSource) 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 *NodeDaemonEndpoints) DeepCopyInto(out *NodeDaemonEndpoints) {
|
||||
*out = *in
|
||||
|
||||
Reference in New Issue
Block a user