Unverified Commit b2fe2a0a authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #59847 from mtaufen/dkcfg-explicit-keys

Automatic merge from submit-queue (batch tested with PRs 63624, 59847). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. 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. ```release-note You must now specify Node.Spec.ConfigSource.ConfigMap.KubeletConfigKey when using dynamic Kubelet config to tell the Kubelet which key of the ConfigMap identifies its config file. ```
parents 508510d5 c41cf55a
...@@ -75671,6 +75671,36 @@ ...@@ -75671,6 +75671,36 @@
} }
] ]
}, },
"io.k8s.api.core.v1.ConfigMapNodeConfigSource": {
"description": "ConfigMapNodeConfigSource contains the information to reference a ConfigMap as a config source for the Node.",
"required": [
"namespace",
"name",
"kubeletConfigKey"
],
"properties": {
"kubeletConfigKey": {
"description": "KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure This field is required in all cases.",
"type": "string"
},
"name": {
"description": "Name is the metadata.name of the referenced ConfigMap. This field is required in all cases.",
"type": "string"
},
"namespace": {
"description": "Namespace is the metadata.namespace of the referenced ConfigMap. This field is required in all cases.",
"type": "string"
},
"resourceVersion": {
"description": "ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. This field is forbidden in Node.Spec.",
"type": "string"
},
"uid": {
"description": "UID is the metadata.UID of the referenced ConfigMap. This field is currently reqired in Node.Spec.",
"type": "string"
}
}
},
"io.k8s.api.core.v1.ConfigMapProjection": { "io.k8s.api.core.v1.ConfigMapProjection": {
"description": "Adapts a ConfigMap into a projected volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a projected volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. Note that this is identical to a configmap volume source without the default mode.", "description": "Adapts a ConfigMap into a projected volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a projected volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. Note that this is identical to a configmap volume source without the default mode.",
"properties": { "properties": {
...@@ -77242,25 +77272,11 @@ ...@@ -77242,25 +77272,11 @@
"io.k8s.api.core.v1.NodeConfigSource": { "io.k8s.api.core.v1.NodeConfigSource": {
"description": "NodeConfigSource specifies a source of node configuration. Exactly one subfield (excluding metadata) must be non-nil.", "description": "NodeConfigSource specifies a source of node configuration. Exactly one subfield (excluding metadata) must be non-nil.",
"properties": { "properties": {
"apiVersion": { "configMap": {
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", "description": "ConfigMap is a reference to a Node's ConfigMap",
"type": "string" "$ref": "#/definitions/io.k8s.api.core.v1.ConfigMapNodeConfigSource"
},
"configMapRef": {
"$ref": "#/definitions/io.k8s.api.core.v1.ObjectReference"
},
"kind": {
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
"type": "string"
}
},
"x-kubernetes-group-version-kind": [
{
"group": "",
"kind": "NodeConfigSource",
"version": "v1"
} }
] }
}, },
"io.k8s.api.core.v1.NodeDaemonEndpoints": { "io.k8s.api.core.v1.NodeDaemonEndpoints": {
"description": "NodeDaemonEndpoints lists ports opened by daemons running on the Node.", "description": "NodeDaemonEndpoints lists ports opened by daemons running on the Node.",
...@@ -18718,16 +18718,40 @@ ...@@ -18718,16 +18718,40 @@
"id": "v1.NodeConfigSource", "id": "v1.NodeConfigSource",
"description": "NodeConfigSource specifies a source of node configuration. Exactly one subfield (excluding metadata) must be non-nil.", "description": "NodeConfigSource specifies a source of node configuration. Exactly one subfield (excluding metadata) must be non-nil.",
"properties": { "properties": {
"kind": { "configMap": {
"$ref": "v1.ConfigMapNodeConfigSource",
"description": "ConfigMap is a reference to a Node's ConfigMap"
}
}
},
"v1.ConfigMapNodeConfigSource": {
"id": "v1.ConfigMapNodeConfigSource",
"description": "ConfigMapNodeConfigSource contains the information to reference a ConfigMap as a config source for the Node.",
"required": [
"namespace",
"name",
"kubeletConfigKey"
],
"properties": {
"namespace": {
"type": "string", "type": "string",
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds" "description": "Namespace is the metadata.namespace of the referenced ConfigMap. This field is required in all cases."
}, },
"apiVersion": { "name": {
"type": "string", "type": "string",
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources" "description": "Name is the metadata.name of the referenced ConfigMap. This field is required in all cases."
}, },
"configMapRef": { "uid": {
"$ref": "v1.ObjectReference" "type": "string",
"description": "UID is the metadata.UID of the referenced ConfigMap. This field is currently reqired in Node.Spec."
},
"resourceVersion": {
"type": "string",
"description": "ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. This field is forbidden in Node.Spec."
},
"kubeletConfigKey": {
"type": "string",
"description": "KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure This field is required in all cases."
} }
} }
}, },
......
...@@ -116,10 +116,11 @@ func updateNodeWithConfigMap(client clientset.Interface, nodeName string) error ...@@ -116,10 +116,11 @@ func updateNodeWithConfigMap(client clientset.Interface, nodeName string) error
} }
node.Spec.ConfigSource = &v1.NodeConfigSource{ node.Spec.ConfigSource = &v1.NodeConfigSource{
ConfigMapRef: &v1.ObjectReference{ ConfigMap: &v1.ConfigMapNodeConfigSource{
Name: kubeadmconstants.KubeletBaseConfigurationConfigMap, Name: kubeadmconstants.KubeletBaseConfigurationConfigMap,
Namespace: metav1.NamespaceSystem, Namespace: metav1.NamespaceSystem,
UID: kubeletCfg.UID, UID: kubeletCfg.UID,
KubeletConfigKey: kubeadmconstants.KubeletBaseConfigurationConfigMapKey,
}, },
} }
......
...@@ -50,7 +50,7 @@ func TestCreateBaseKubeletConfiguration(t *testing.T) { ...@@ -50,7 +50,7 @@ func TestCreateBaseKubeletConfiguration(t *testing.T) {
}, },
Spec: v1.NodeSpec{ Spec: v1.NodeSpec{
ConfigSource: &v1.NodeConfigSource{ ConfigSource: &v1.NodeConfigSource{
ConfigMapRef: &v1.ObjectReference{ ConfigMap: &v1.ConfigMapNodeConfigSource{
UID: "", UID: "",
}, },
}, },
...@@ -94,7 +94,7 @@ func TestUpdateNodeWithConfigMap(t *testing.T) { ...@@ -94,7 +94,7 @@ func TestUpdateNodeWithConfigMap(t *testing.T) {
}, },
Spec: v1.NodeSpec{ Spec: v1.NodeSpec{
ConfigSource: &v1.NodeConfigSource{ ConfigSource: &v1.NodeConfigSource{
ConfigMapRef: &v1.ObjectReference{ ConfigMap: &v1.ConfigMapNodeConfigSource{
UID: "", UID: "",
}, },
}, },
......
...@@ -403,9 +403,6 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; } ...@@ -403,9 +403,6 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<p><a href="#_v1_node">v1.Node</a></p> <p><a href="#_v1_node">v1.Node</a></p>
</li> </li>
<li> <li>
<p><a href="#_v1_nodeconfigsource">v1.NodeConfigSource</a></p>
</li>
<li>
<p><a href="#_v1_nodelist">v1.NodeList</a></p> <p><a href="#_v1_nodelist">v1.NodeList</a></p>
</li> </li>
<li> <li>
...@@ -3663,6 +3660,68 @@ Examples:<br> ...@@ -3663,6 +3660,68 @@ Examples:<br>
</div> </div>
<div class="sect2"> <div class="sect2">
<h3 id="_v1_configmapnodeconfigsource">v1.ConfigMapNodeConfigSource</h3>
<div class="paragraph">
<p>ConfigMapNodeConfigSource contains the information to reference a ConfigMap as a config source for the Node.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">namespace</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Namespace is the metadata.namespace of the referenced ConfigMap. This field is required in all cases.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">name</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Name is the metadata.name of the referenced ConfigMap. This field is required in all cases.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">uid</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">UID is the metadata.UID of the referenced ConfigMap. This field is currently reqired in Node.Spec.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">resourceVersion</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. This field is forbidden in Node.Spec.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">kubeletConfigKey</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure This field is required in all cases.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_endpointport">v1.EndpointPort</h3> <h3 id="_v1_endpointport">v1.EndpointPort</h3>
<div class="paragraph"> <div class="paragraph">
<p>EndpointPort is a tuple that describes a single port.</p> <p>EndpointPort is a tuple that describes a single port.</p>
...@@ -5830,24 +5889,10 @@ Examples:<br> ...@@ -5830,24 +5889,10 @@ Examples:<br>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">kind</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">configMap</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: <a href="https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds">https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds</a></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">ConfigMap is a reference to a Node&#8217;s ConfigMap</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">apiVersion</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: <a href="https://git.k8s.io/community/contributors/devel/api-conventions.md#resources">https://git.k8s.io/community/contributors/devel/api-conventions.md#resources</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">configMapRef</p></td>
<td class="tableblock halign-left valign-top"></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_objectreference">v1.ObjectReference</a></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_configmapnodeconfigsource">v1.ConfigMapNodeConfigSource</a></p></td>
<td class="tableblock halign-left valign-top"></td> <td class="tableblock halign-left valign-top"></td>
</tr> </tr>
</tbody> </tbody>
......
...@@ -60,7 +60,6 @@ func addKnownTypes(scheme *runtime.Scheme) error { ...@@ -60,7 +60,6 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&ServiceProxyOptions{}, &ServiceProxyOptions{},
&NodeList{}, &NodeList{},
&Node{}, &Node{},
&NodeConfigSource{},
&NodeProxyOptions{}, &NodeProxyOptions{},
&Endpoints{}, &Endpoints{},
&EndpointsList{}, &EndpointsList{},
......
...@@ -3257,12 +3257,48 @@ type NodeSpec struct { ...@@ -3257,12 +3257,48 @@ type NodeSpec struct {
DoNotUse_ExternalID string 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. // NodeConfigSource specifies a source of node configuration. Exactly one subfield must be non-nil.
type NodeConfigSource struct { type NodeConfigSource struct {
metav1.TypeMeta ConfigMap *ConfigMapNodeConfigSource
ConfigMapRef *ObjectReference }
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. // DaemonEndpoint contains information about a single Daemon endpoint.
......
...@@ -82,6 +82,8 @@ func RegisterConversions(scheme *runtime.Scheme) error { ...@@ -82,6 +82,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
Convert_core_ConfigMapKeySelector_To_v1_ConfigMapKeySelector, Convert_core_ConfigMapKeySelector_To_v1_ConfigMapKeySelector,
Convert_v1_ConfigMapList_To_core_ConfigMapList, Convert_v1_ConfigMapList_To_core_ConfigMapList,
Convert_core_ConfigMapList_To_v1_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_v1_ConfigMapProjection_To_core_ConfigMapProjection,
Convert_core_ConfigMapProjection_To_v1_ConfigMapProjection, Convert_core_ConfigMapProjection_To_v1_ConfigMapProjection,
Convert_v1_ConfigMapVolumeSource_To_core_ConfigMapVolumeSource, Convert_v1_ConfigMapVolumeSource_To_core_ConfigMapVolumeSource,
...@@ -941,6 +943,34 @@ func Convert_core_ConfigMapList_To_v1_ConfigMapList(in *core.ConfigMapList, out ...@@ -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) 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 { 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 { if err := Convert_v1_LocalObjectReference_To_core_LocalObjectReference(&in.LocalObjectReference, &out.LocalObjectReference, s); err != nil {
return err return err
...@@ -2586,7 +2616,7 @@ func Convert_core_NodeCondition_To_v1_NodeCondition(in *core.NodeCondition, out ...@@ -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 { 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 return nil
} }
...@@ -2596,7 +2626,7 @@ func Convert_v1_NodeConfigSource_To_core_NodeConfigSource(in *v1.NodeConfigSourc ...@@ -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 { 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 return nil
} }
......
...@@ -4116,7 +4116,7 @@ func ValidateNodeUpdate(node, oldNode *core.Node) field.ErrorList { ...@@ -4116,7 +4116,7 @@ func ValidateNodeUpdate(node, oldNode *core.Node) field.ErrorList {
// Allow updates to Node.Spec.ConfigSource if DynamicKubeletConfig feature gate is enabled // Allow updates to Node.Spec.ConfigSource if DynamicKubeletConfig feature gate is enabled
if utilfeature.DefaultFeatureGate.Enabled(features.DynamicKubeletConfig) { if utilfeature.DefaultFeatureGate.Enabled(features.DynamicKubeletConfig) {
if node.Spec.ConfigSource != nil { 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 oldNode.Spec.ConfigSource = node.Spec.ConfigSource
} }
...@@ -4131,15 +4131,13 @@ func ValidateNodeUpdate(node, oldNode *core.Node) field.ErrorList { ...@@ -4131,15 +4131,13 @@ func ValidateNodeUpdate(node, oldNode *core.Node) field.ErrorList {
return allErrs 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{} allErrs := field.ErrorList{}
count := int(0) count := int(0)
if ref := source.ConfigMapRef; ref != nil { if source.ConfigMap != nil {
count++ count++
// name, namespace, and UID must all be non-empty for ConfigMapRef allErrs = append(allErrs, validateConfigMapNodeConfigSourceSpec(source.ConfigMap, fldPath.Child("configMap"))...)
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"))
}
} }
// add more subfields here in the future as they are added to NodeConfigSource // add more subfields here in the future as they are added to NodeConfigSource
...@@ -4150,6 +4148,50 @@ func validateNodeConfigSource(source *core.NodeConfigSource, fldPath *field.Path ...@@ -4150,6 +4148,50 @@ func validateNodeConfigSource(source *core.NodeConfigSource, fldPath *field.Path
return allErrs 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. // Validate compute resource typename.
// Refer to docs/design/resources.md for more details. // Refer to docs/design/resources.md for more details.
func validateResourceName(value string, fldPath *field.Path) field.ErrorList { func validateResourceName(value string, fldPath *field.Path) field.ErrorList {
......
...@@ -632,6 +632,22 @@ func (in *ConfigMapList) DeepCopyObject() runtime.Object { ...@@ -632,6 +632,22 @@ func (in *ConfigMapList) DeepCopyObject() runtime.Object {
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-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) { func (in *ConfigMapProjection) DeepCopyInto(out *ConfigMapProjection) {
*out = *in *out = *in
out.LocalObjectReference = in.LocalObjectReference out.LocalObjectReference = in.LocalObjectReference
...@@ -2364,13 +2380,12 @@ func (in *NodeCondition) DeepCopy() *NodeCondition { ...@@ -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. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeConfigSource) DeepCopyInto(out *NodeConfigSource) { func (in *NodeConfigSource) DeepCopyInto(out *NodeConfigSource) {
*out = *in *out = *in
out.TypeMeta = in.TypeMeta if in.ConfigMap != nil {
if in.ConfigMapRef != nil { in, out := &in.ConfigMap, &out.ConfigMap
in, out := &in.ConfigMapRef, &out.ConfigMapRef
if *in == nil { if *in == nil {
*out = nil *out = nil
} else { } else {
*out = new(ObjectReference) *out = new(ConfigMapNodeConfigSource)
**out = **in **out = **in
} }
} }
...@@ -2387,14 +2402,6 @@ func (in *NodeConfigSource) DeepCopy() *NodeConfigSource { ...@@ -2387,14 +2402,6 @@ func (in *NodeConfigSource) DeepCopy() *NodeConfigSource {
return out 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. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeDaemonEndpoints) DeepCopyInto(out *NodeDaemonEndpoints) { func (in *NodeDaemonEndpoints) DeepCopyInto(out *NodeDaemonEndpoints) {
*out = *in *out = *in
......
...@@ -17,6 +17,7 @@ go_library( ...@@ -17,6 +17,7 @@ go_library(
], ],
importpath = "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig", importpath = "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig",
deps = [ deps = [
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
......
...@@ -46,6 +46,7 @@ func addKnownTypes(scheme *runtime.Scheme) error { ...@@ -46,6 +46,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
// TODO this will get cleaned up with the scheme types are fixed // TODO this will get cleaned up with the scheme types are fixed
scheme.AddKnownTypes(SchemeGroupVersion, scheme.AddKnownTypes(SchemeGroupVersion,
&KubeletConfiguration{}, &KubeletConfiguration{},
&SerializedNodeConfigSource{},
) )
return nil return nil
} }
...@@ -17,6 +17,7 @@ limitations under the License. ...@@ -17,6 +17,7 @@ limitations under the License.
package kubeletconfig package kubeletconfig
import ( import (
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
...@@ -333,3 +334,15 @@ type KubeletAnonymousAuthentication struct { ...@@ -333,3 +334,15 @@ type KubeletAnonymousAuthentication struct {
// Anonymous requests have a username of system:anonymous, and a group name of system:unauthenticated. // Anonymous requests have a username of system:anonymous, and a group name of system:unauthenticated.
Enabled bool Enabled bool
} }
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// SerializedNodeConfigSource allows us to serialize NodeConfigSource
// This type is used internally by the Kubelet for tracking checkpointed dynamic configs.
// It exists in the kubeletconfig API group because it is classified as a versioned input to the Kubelet.
type SerializedNodeConfigSource struct {
metav1.TypeMeta
// Source is the source that we are serializing
// +optional
Source v1.NodeConfigSource
}
...@@ -23,6 +23,7 @@ go_library( ...@@ -23,6 +23,7 @@ go_library(
"//pkg/kubelet/types:go_default_library", "//pkg/kubelet/types:go_default_library",
"//pkg/master/ports:go_default_library", "//pkg/master/ports:go_default_library",
"//pkg/util/pointer:go_default_library", "//pkg/util/pointer:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library", "//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
......
...@@ -45,6 +45,7 @@ func init() { ...@@ -45,6 +45,7 @@ func init() {
func addKnownTypes(scheme *runtime.Scheme) error { func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion, scheme.AddKnownTypes(SchemeGroupVersion,
&KubeletConfiguration{}, &KubeletConfiguration{},
&SerializedNodeConfigSource{},
) )
return nil return nil
} }
...@@ -17,6 +17,7 @@ limitations under the License. ...@@ -17,6 +17,7 @@ limitations under the License.
package v1beta1 package v1beta1
import ( import (
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
...@@ -512,3 +513,15 @@ type KubeletAnonymousAuthentication struct { ...@@ -512,3 +513,15 @@ type KubeletAnonymousAuthentication struct {
// +optional // +optional
Enabled *bool `json:"enabled,omitempty"` Enabled *bool `json:"enabled,omitempty"`
} }
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// SerializedNodeConfigSource allows us to serialize v1.NodeConfigSource.
// This type is used internally by the Kubelet for tracking checkpointed dynamic configs.
// It exists in the kubeletconfig API group because it is classified as a versioned input to the Kubelet.
type SerializedNodeConfigSource struct {
metav1.TypeMeta `json:",inline"`
// Source is the source that we are serializing
// +optional
Source v1.NodeConfigSource `json:"source,omitempty" protobuf:"bytes,1,opt,name=source"`
}
...@@ -51,6 +51,8 @@ func RegisterConversions(scheme *runtime.Scheme) error { ...@@ -51,6 +51,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
Convert_kubeletconfig_KubeletWebhookAuthorization_To_v1beta1_KubeletWebhookAuthorization, Convert_kubeletconfig_KubeletWebhookAuthorization_To_v1beta1_KubeletWebhookAuthorization,
Convert_v1beta1_KubeletX509Authentication_To_kubeletconfig_KubeletX509Authentication, Convert_v1beta1_KubeletX509Authentication_To_kubeletconfig_KubeletX509Authentication,
Convert_kubeletconfig_KubeletX509Authentication_To_v1beta1_KubeletX509Authentication, Convert_kubeletconfig_KubeletX509Authentication_To_v1beta1_KubeletX509Authentication,
Convert_v1beta1_SerializedNodeConfigSource_To_kubeletconfig_SerializedNodeConfigSource,
Convert_kubeletconfig_SerializedNodeConfigSource_To_v1beta1_SerializedNodeConfigSource,
) )
} }
...@@ -453,3 +455,23 @@ func autoConvert_kubeletconfig_KubeletX509Authentication_To_v1beta1_KubeletX509A ...@@ -453,3 +455,23 @@ func autoConvert_kubeletconfig_KubeletX509Authentication_To_v1beta1_KubeletX509A
func Convert_kubeletconfig_KubeletX509Authentication_To_v1beta1_KubeletX509Authentication(in *kubeletconfig.KubeletX509Authentication, out *KubeletX509Authentication, s conversion.Scope) error { func Convert_kubeletconfig_KubeletX509Authentication_To_v1beta1_KubeletX509Authentication(in *kubeletconfig.KubeletX509Authentication, out *KubeletX509Authentication, s conversion.Scope) error {
return autoConvert_kubeletconfig_KubeletX509Authentication_To_v1beta1_KubeletX509Authentication(in, out, s) return autoConvert_kubeletconfig_KubeletX509Authentication_To_v1beta1_KubeletX509Authentication(in, out, s)
} }
func autoConvert_v1beta1_SerializedNodeConfigSource_To_kubeletconfig_SerializedNodeConfigSource(in *SerializedNodeConfigSource, out *kubeletconfig.SerializedNodeConfigSource, s conversion.Scope) error {
out.Source = in.Source
return nil
}
// Convert_v1beta1_SerializedNodeConfigSource_To_kubeletconfig_SerializedNodeConfigSource is an autogenerated conversion function.
func Convert_v1beta1_SerializedNodeConfigSource_To_kubeletconfig_SerializedNodeConfigSource(in *SerializedNodeConfigSource, out *kubeletconfig.SerializedNodeConfigSource, s conversion.Scope) error {
return autoConvert_v1beta1_SerializedNodeConfigSource_To_kubeletconfig_SerializedNodeConfigSource(in, out, s)
}
func autoConvert_kubeletconfig_SerializedNodeConfigSource_To_v1beta1_SerializedNodeConfigSource(in *kubeletconfig.SerializedNodeConfigSource, out *SerializedNodeConfigSource, s conversion.Scope) error {
out.Source = in.Source
return nil
}
// Convert_kubeletconfig_SerializedNodeConfigSource_To_v1beta1_SerializedNodeConfigSource is an autogenerated conversion function.
func Convert_kubeletconfig_SerializedNodeConfigSource_To_v1beta1_SerializedNodeConfigSource(in *kubeletconfig.SerializedNodeConfigSource, out *SerializedNodeConfigSource, s conversion.Scope) error {
return autoConvert_kubeletconfig_SerializedNodeConfigSource_To_v1beta1_SerializedNodeConfigSource(in, out, s)
}
...@@ -426,3 +426,29 @@ func (in *KubeletX509Authentication) DeepCopy() *KubeletX509Authentication { ...@@ -426,3 +426,29 @@ func (in *KubeletX509Authentication) DeepCopy() *KubeletX509Authentication {
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SerializedNodeConfigSource) DeepCopyInto(out *SerializedNodeConfigSource) {
*out = *in
out.TypeMeta = in.TypeMeta
in.Source.DeepCopyInto(&out.Source)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SerializedNodeConfigSource.
func (in *SerializedNodeConfigSource) DeepCopy() *SerializedNodeConfigSource {
if in == nil {
return nil
}
out := new(SerializedNodeConfigSource)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *SerializedNodeConfigSource) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
...@@ -246,3 +246,29 @@ func (in *KubeletX509Authentication) DeepCopy() *KubeletX509Authentication { ...@@ -246,3 +246,29 @@ func (in *KubeletX509Authentication) DeepCopy() *KubeletX509Authentication {
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SerializedNodeConfigSource) DeepCopyInto(out *SerializedNodeConfigSource) {
*out = *in
out.TypeMeta = in.TypeMeta
in.Source.DeepCopyInto(&out.Source)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SerializedNodeConfigSource.
func (in *SerializedNodeConfigSource) DeepCopy() *SerializedNodeConfigSource {
if in == nil {
return nil
}
out := new(SerializedNodeConfigSource)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *SerializedNodeConfigSource) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
...@@ -19,12 +19,12 @@ go_library( ...@@ -19,12 +19,12 @@ go_library(
"//pkg/kubelet/kubeletconfig/checkpoint:go_default_library", "//pkg/kubelet/kubeletconfig/checkpoint:go_default_library",
"//pkg/kubelet/kubeletconfig/checkpoint/store:go_default_library", "//pkg/kubelet/kubeletconfig/checkpoint/store:go_default_library",
"//pkg/kubelet/kubeletconfig/status:go_default_library", "//pkg/kubelet/kubeletconfig/status:go_default_library",
"//pkg/kubelet/kubeletconfig/util/equal:go_default_library",
"//pkg/kubelet/kubeletconfig/util/log:go_default_library", "//pkg/kubelet/kubeletconfig/util/log:go_default_library",
"//pkg/kubelet/kubeletconfig/util/panic:go_default_library", "//pkg/kubelet/kubeletconfig/util/panic:go_default_library",
"//pkg/util/filesystem:go_default_library", "//pkg/util/filesystem:go_default_library",
"//vendor/github.com/golang/glog:go_default_library", "//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library", "//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
......
...@@ -31,7 +31,9 @@ go_library( ...@@ -31,7 +31,9 @@ go_library(
], ],
importpath = "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint", importpath = "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/checkpoint",
deps = [ deps = [
"//pkg/api/legacyscheme:go_default_library", "//pkg/kubelet/apis/kubeletconfig:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/scheme:go_default_library",
"//pkg/kubelet/apis/kubeletconfig/v1beta1:go_default_library",
"//pkg/kubelet/kubeletconfig/status:go_default_library", "//pkg/kubelet/kubeletconfig/status:go_default_library",
"//pkg/kubelet/kubeletconfig/util/codec:go_default_library", "//pkg/kubelet/kubeletconfig/util/codec:go_default_library",
"//pkg/kubelet/kubeletconfig/util/log:go_default_library", "//pkg/kubelet/kubeletconfig/util/log:go_default_library",
......
...@@ -24,7 +24,9 @@ import ( ...@@ -24,7 +24,9 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
"k8s.io/kubernetes/pkg/api/legacyscheme" kubeletconfiginternal "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/scheme"
kubeletconfigv1beta1 "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1beta1"
"k8s.io/kubernetes/pkg/kubelet/kubeletconfig/status" "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/status"
utilcodec "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/codec" utilcodec "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/codec"
utillog "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/log" utillog "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/log"
...@@ -46,6 +48,8 @@ type Payload interface { ...@@ -46,6 +48,8 @@ type Payload interface {
type RemoteConfigSource interface { type RemoteConfigSource interface {
// UID returns a globally unique identifier of the source described by the remote config source object // UID returns a globally unique identifier of the source described by the remote config source object
UID() string UID() string
// KubeletFilename returns the name of the Kubelet config file as it should appear in the keys of Payload.Files()
KubeletFilename() string
// APIPath returns the API path to the remote resource, e.g. its SelfLink // APIPath returns the API path to the remote resource, e.g. its SelfLink
APIPath() string APIPath() string
// Download downloads the remote config source object returns a Payload backed by the object, // Download downloads the remote config source object returns a Payload backed by the object,
...@@ -60,25 +64,18 @@ type RemoteConfigSource interface { ...@@ -60,25 +64,18 @@ type RemoteConfigSource interface {
object() interface{} object() interface{}
} }
// NewRemoteConfigSource constructs a RemoteConfigSource from a v1/NodeConfigSource object, or returns // NewRemoteConfigSource constructs a RemoteConfigSource from a v1/NodeConfigSource object
// a sanitized failure reason and an error if the `source` is blatantly invalid.
// You should only call this with a non-nil config source. // You should only call this with a non-nil config source.
// Note that the API server validates Node.Spec.ConfigSource.
func NewRemoteConfigSource(source *apiv1.NodeConfigSource) (RemoteConfigSource, string, error) { func NewRemoteConfigSource(source *apiv1.NodeConfigSource) (RemoteConfigSource, string, error) {
// exactly one subfield of the config source must be non-nil, toady ConfigMapRef is the only reference // NOTE: Even though the API server validates the config, we check whether all *known* fields are
if source.ConfigMapRef == nil { // nil here, so that if a new API server allows a new config source type, old clients can send
return nil, status.FailSyncReasonAllNilSubfields, fmt.Errorf("%s, NodeConfigSource was: %#v", status.FailSyncReasonAllNilSubfields, source) // an error message rather than crashing due to a nil pointer dereference.
}
// validate the NodeConfigSource:
// at this point we know we're using the ConfigMapRef subfield
ref := source.ConfigMapRef
// name, namespace, and UID must all be non-empty for ConfigMapRef // exactly one reference subfield of the config source must be non-nil, today ConfigMap is the only reference subfield
if ref.Name == "" || ref.Namespace == "" || string(ref.UID) == "" { if source.ConfigMap == nil {
return nil, status.FailSyncReasonPartialObjectReference, fmt.Errorf("%s, ObjectReference was: %#v", status.FailSyncReasonPartialObjectReference, ref) return nil, status.FailSyncReasonAllNilSubfields, fmt.Errorf("%s, NodeConfigSource was: %#v", status.FailSyncReasonAllNilSubfields, source)
} }
return &remoteConfigMap{source}, "", nil return &remoteConfigMap{source}, "", nil
} }
...@@ -86,21 +83,25 @@ func NewRemoteConfigSource(source *apiv1.NodeConfigSource) (RemoteConfigSource, ...@@ -86,21 +83,25 @@ func NewRemoteConfigSource(source *apiv1.NodeConfigSource) (RemoteConfigSource,
// e.g. the metadata stored by checkpoint/store/fsstore.go // e.g. the metadata stored by checkpoint/store/fsstore.go
func DecodeRemoteConfigSource(data []byte) (RemoteConfigSource, error) { func DecodeRemoteConfigSource(data []byte) (RemoteConfigSource, error) {
// decode the remote config source // decode the remote config source
obj, err := runtime.Decode(legacyscheme.Codecs.UniversalDecoder(), data) _, codecs, err := scheme.NewSchemeAndCodecs()
if err != nil {
return nil, err
}
obj, err := runtime.Decode(codecs.UniversalDecoder(), data)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to decode, error: %v", err) return nil, fmt.Errorf("failed to decode, error: %v", err)
} }
// for now we assume we are trying to load an apiv1.NodeConfigSource, // for now we assume we are trying to load an kubeletconfigv1beta1.SerializedNodeConfigSource,
// this may need to be extended if e.g. a new version of the api is born // this may need to be extended if e.g. a new version of the api is born
cs, ok := obj.(*kubeletconfiginternal.SerializedNodeConfigSource)
// convert it to the external NodeConfigSource type, so we're consistently working with the external type outside of the on-disk representation if !ok {
cs := &apiv1.NodeConfigSource{} return nil, fmt.Errorf("failed to cast decoded remote config source to *k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig.SerializedNodeConfigSource")
err = legacyscheme.Scheme.Convert(obj, cs, nil)
if err != nil {
return nil, fmt.Errorf("failed to convert decoded object into a v1 NodeConfigSource, error: %v", err)
} }
source, _, err := NewRemoteConfigSource(cs)
// we use the v1.NodeConfigSource type on internal and external, so no need to convert to external here
source, _, err := NewRemoteConfigSource(&cs.Source)
return source, err return source, err
} }
...@@ -121,32 +122,36 @@ type remoteConfigMap struct { ...@@ -121,32 +122,36 @@ type remoteConfigMap struct {
var _ RemoteConfigSource = (*remoteConfigMap)(nil) var _ RemoteConfigSource = (*remoteConfigMap)(nil)
func (r *remoteConfigMap) UID() string { func (r *remoteConfigMap) UID() string {
return string(r.source.ConfigMapRef.UID) return string(r.source.ConfigMap.UID)
}
func (r *remoteConfigMap) KubeletFilename() string {
return r.source.ConfigMap.KubeletConfigKey
} }
const configMapAPIPathFmt = "/api/v1/namespaces/%s/configmaps/%s" const configMapAPIPathFmt = "/api/v1/namespaces/%s/configmaps/%s"
func (r *remoteConfigMap) APIPath() string { func (r *remoteConfigMap) APIPath() string {
ref := r.source.ConfigMapRef ref := r.source.ConfigMap
return fmt.Sprintf(configMapAPIPathFmt, ref.Namespace, ref.Name) return fmt.Sprintf(configMapAPIPathFmt, ref.Namespace, ref.Name)
} }
func (r *remoteConfigMap) Download(client clientset.Interface) (Payload, string, error) { func (r *remoteConfigMap) Download(client clientset.Interface) (Payload, string, error) {
var reason string var reason string
uid := string(r.source.ConfigMapRef.UID) uid := string(r.source.ConfigMap.UID)
utillog.Infof("attempting to download ConfigMap with UID %q", uid) utillog.Infof("attempting to download ConfigMap with UID %q", uid)
// get the ConfigMap via namespace/name, there doesn't seem to be a way to get it by UID // get the ConfigMap via namespace/name, there doesn't seem to be a way to get it by UID
cm, err := client.CoreV1().ConfigMaps(r.source.ConfigMapRef.Namespace).Get(r.source.ConfigMapRef.Name, metav1.GetOptions{}) cm, err := client.CoreV1().ConfigMaps(r.source.ConfigMap.Namespace).Get(r.source.ConfigMap.Name, metav1.GetOptions{})
if err != nil { if err != nil {
reason = fmt.Sprintf(status.FailSyncReasonDownloadFmt, r.APIPath()) reason = fmt.Sprintf(status.FailSyncReasonDownloadFmt, r.APIPath())
return nil, reason, fmt.Errorf("%s, error: %v", reason, err) return nil, reason, fmt.Errorf("%s, error: %v", reason, err)
} }
// ensure that UID matches the UID on the reference, the ObjectReference must be unambiguous // ensure that UID matches the UID on the source
if r.source.ConfigMapRef.UID != cm.UID { if r.source.ConfigMap.UID != cm.UID {
reason = fmt.Sprintf(status.FailSyncReasonUIDMismatchFmt, r.source.ConfigMapRef.UID, r.APIPath(), cm.UID) reason = fmt.Sprintf(status.FailSyncReasonUIDMismatchFmt, r.source.ConfigMap.UID, r.APIPath(), cm.UID)
return nil, reason, fmt.Errorf(reason) return nil, reason, fmt.Errorf(reason)
} }
...@@ -161,11 +166,12 @@ func (r *remoteConfigMap) Download(client clientset.Interface) (Payload, string, ...@@ -161,11 +166,12 @@ func (r *remoteConfigMap) Download(client clientset.Interface) (Payload, string,
} }
func (r *remoteConfigMap) Encode() ([]byte, error) { func (r *remoteConfigMap) Encode() ([]byte, error) {
encoder, err := utilcodec.NewYAMLEncoder(apiv1.GroupName) encoder, err := utilcodec.NewKubeletconfigYAMLEncoder(kubeletconfigv1beta1.SchemeGroupVersion)
if err != nil { if err != nil {
return nil, err return nil, err
} }
data, err := runtime.Encode(encoder, r.source)
data, err := runtime.Encode(encoder, &kubeletconfigv1beta1.SerializedNodeConfigSource{Source: *r.source})
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -36,33 +36,30 @@ func TestNewRemoteConfigSource(t *testing.T) { ...@@ -36,33 +36,30 @@ func TestNewRemoteConfigSource(t *testing.T) {
expect RemoteConfigSource expect RemoteConfigSource
err string err string
}{ }{
// all NodeConfigSource subfields nil {
{"all NodeConfigSource subfields nil", desc: "all NodeConfigSource subfields nil",
&apiv1.NodeConfigSource{}, nil, "exactly one subfield must be non-nil"}, source: &apiv1.NodeConfigSource{},
{"ConfigMapRef: empty name, namespace, and UID", expect: nil,
&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{}}, nil, "invalid ObjectReference"}, err: "exactly one subfield must be non-nil",
// ConfigMapRef: empty name and namespace },
{"ConfigMapRef: empty name and namespace", {
&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{UID: "uid"}}, nil, "invalid ObjectReference"}, desc: "ConfigMap: valid reference",
// ConfigMapRef: empty name and UID source: &apiv1.NodeConfigSource{
{"ConfigMapRef: empty name and UID", ConfigMap: &apiv1.ConfigMapNodeConfigSource{
&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Namespace: "namespace"}}, nil, "invalid ObjectReference"}, Name: "name",
// ConfigMapRef: empty namespace and UID Namespace: "namespace",
{"ConfigMapRef: empty namespace and UID", UID: "uid",
&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "name"}}, nil, "invalid ObjectReference"}, KubeletConfigKey: "kubelet",
// ConfigMapRef: empty UID }},
{"ConfigMapRef: empty namespace and UID", expect: &remoteConfigMap{&apiv1.NodeConfigSource{
&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace"}}, nil, "invalid ObjectReference"}, ConfigMap: &apiv1.ConfigMapNodeConfigSource{
// ConfigMapRef: empty namespace Name: "name",
{"ConfigMapRef: empty namespace and UID", Namespace: "namespace",
&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "name", UID: "uid"}}, nil, "invalid ObjectReference"}, UID: "uid",
// ConfigMapRef: empty name KubeletConfigKey: "kubelet",
{"ConfigMapRef: empty namespace and UID", }}},
&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Namespace: "namespace", UID: "uid"}}, nil, "invalid ObjectReference"}, err: "",
// ConfigMapRef: valid reference },
{"ConfigMapRef: valid reference",
&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: "uid"}},
&remoteConfigMap{&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: "uid"}}}, ""},
} }
for _, c := range cases { for _, c := range cases {
...@@ -82,7 +79,12 @@ func TestNewRemoteConfigSource(t *testing.T) { ...@@ -82,7 +79,12 @@ func TestNewRemoteConfigSource(t *testing.T) {
func TestRemoteConfigMapUID(t *testing.T) { func TestRemoteConfigMapUID(t *testing.T) {
const expect = "uid" const expect = "uid"
source, _, err := NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: expect}}) source, _, err := NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: "name",
Namespace: "namespace",
UID: expect,
KubeletConfigKey: "kubelet",
}})
if err != nil { if err != nil {
t.Fatalf("error constructing remote config source: %v", err) t.Fatalf("error constructing remote config source: %v", err)
} }
...@@ -93,14 +95,22 @@ func TestRemoteConfigMapUID(t *testing.T) { ...@@ -93,14 +95,22 @@ func TestRemoteConfigMapUID(t *testing.T) {
} }
func TestRemoteConfigMapAPIPath(t *testing.T) { func TestRemoteConfigMapAPIPath(t *testing.T) {
const namespace = "namespace" const (
const name = "name" name = "name"
source, _, err := NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: name, Namespace: namespace, UID: "uid"}}) namespace = "namespace"
)
source, _, err := NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: name,
Namespace: namespace,
UID: "uid",
KubeletConfigKey: "kubelet",
}})
if err != nil { if err != nil {
t.Fatalf("error constructing remote config source: %v", err) t.Fatalf("error constructing remote config source: %v", err)
} }
expect := fmt.Sprintf(configMapAPIPathFmt, namespace, name) expect := fmt.Sprintf(configMapAPIPathFmt, namespace, name)
path := source.APIPath() path := source.APIPath()
if expect != path { if expect != path {
t.Errorf("expect %q, but got %q", expect, path) t.Errorf("expect %q, but got %q", expect, path)
} }
...@@ -133,18 +143,39 @@ func TestRemoteConfigMapDownload(t *testing.T) { ...@@ -133,18 +143,39 @@ func TestRemoteConfigMapDownload(t *testing.T) {
expect Payload expect Payload
err string err string
}{ }{
// object doesn't exist {
{"object doesn't exist", desc: "object doesn't exist",
makeSource(&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "bogus", Namespace: "namespace", UID: "bogus"}}), source: makeSource(&apiv1.NodeConfigSource{ConfigMap: &apiv1.ConfigMapNodeConfigSource{
nil, "not found"}, Name: "bogus",
// UID of downloaded object doesn't match UID of referent found via namespace/name Namespace: "namespace",
{"UID is incorrect for namespace/name", UID: "bogus",
makeSource(&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: "bogus"}}), KubeletConfigKey: "kubelet",
nil, "does not match"}, }}),
// successful download expect: nil,
{"object exists and reference is correct", err: "not found",
makeSource(&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: "uid"}}), },
payload, ""}, {
desc: "UID is incorrect for namespace/name",
source: makeSource(&apiv1.NodeConfigSource{ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: "name",
Namespace: "namespace",
UID: "bogus",
KubeletConfigKey: "kubelet",
}}),
expect: nil,
err: "does not match",
},
{
desc: "object exists and reference is correct",
source: makeSource(&apiv1.NodeConfigSource{ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: "name",
Namespace: "namespace",
UID: "uid",
KubeletConfigKey: "kubelet",
}}),
expect: payload,
err: "",
},
} }
for _, c := range cases { for _, c := range cases {
...@@ -173,10 +204,12 @@ func TestEqualRemoteConfigSources(t *testing.T) { ...@@ -173,10 +204,12 @@ func TestEqualRemoteConfigSources(t *testing.T) {
{"a nil", nil, &remoteConfigMap{}, false}, {"a nil", nil, &remoteConfigMap{}, false},
{"b nil", &remoteConfigMap{}, nil, false}, {"b nil", &remoteConfigMap{}, nil, false},
{"neither nil, equal", &remoteConfigMap{}, &remoteConfigMap{}, true}, {"neither nil, equal", &remoteConfigMap{}, &remoteConfigMap{}, true},
{"neither nil, not equal", {
&remoteConfigMap{&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "a"}}}, desc: "neither nil, not equal",
&remoteConfigMap{}, a: &remoteConfigMap{&apiv1.NodeConfigSource{ConfigMap: &apiv1.ConfigMapNodeConfigSource{Name: "a"}}},
false}, b: &remoteConfigMap{&apiv1.NodeConfigSource{ConfigMap: &apiv1.ConfigMapNodeConfigSource{KubeletConfigKey: "kubelet"}}},
expect: false,
},
} }
for _, c := range cases { for _, c := range cases {
......
...@@ -35,7 +35,6 @@ const ( ...@@ -35,7 +35,6 @@ const (
lastKnownGoodFile = "last-known-good" lastKnownGoodFile = "last-known-good"
checkpointsDir = "checkpoints" checkpointsDir = "checkpoints"
kubeletKey = "kubelet" // TODO(mtaufen): eventually the API will have a way to parameterize the kubelet file name, and then we can remove this
) )
// fsStore is for tracking checkpoints in the local filesystem, implements Store // fsStore is for tracking checkpoints in the local filesystem, implements Store
...@@ -101,7 +100,7 @@ func (s *fsStore) Load(source checkpoint.RemoteConfigSource) (*kubeletconfig.Kub ...@@ -101,7 +100,7 @@ func (s *fsStore) Load(source checkpoint.RemoteConfigSource) (*kubeletconfig.Kub
} }
// load the kubelet config file // load the kubelet config file
utillog.Infof("loading kubelet configuration checkpoint for source %s", sourceFmt) utillog.Infof("loading kubelet configuration checkpoint for source %s", sourceFmt)
loader, err := configfiles.NewFsLoader(s.fs, filepath.Join(s.checkpointPath(source.UID()), kubeletKey)) loader, err := configfiles.NewFsLoader(s.fs, filepath.Join(s.checkpointPath(source.UID()), source.KubeletFilename()))
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -125,7 +125,12 @@ func TestFsStoreExists(t *testing.T) { ...@@ -125,7 +125,12 @@ func TestFsStoreExists(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.desc, func(t *testing.T) { t.Run(c.desc, func(t *testing.T) {
source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{
ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: c.uid}}) ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: "name",
Namespace: "namespace",
UID: c.uid,
KubeletConfigKey: "kubelet",
}})
if err != nil { if err != nil {
t.Fatalf("error constructing remote config source: %v", err) t.Fatalf("error constructing remote config source: %v", err)
} }
...@@ -214,7 +219,10 @@ func TestFsStoreLoad(t *testing.T) { ...@@ -214,7 +219,10 @@ func TestFsStoreLoad(t *testing.T) {
t.Fatalf("error encoding KubeletConfiguration: %v", err) t.Fatalf("error encoding KubeletConfiguration: %v", err)
} }
// construct a payload that contains the kubeletconfig // construct a payload that contains the kubeletconfig
const uid = "uid" const (
uid = "uid"
kubeletKey = "kubelet"
)
p, err := checkpoint.NewConfigMapPayload(&apiv1.ConfigMap{ p, err := checkpoint.NewConfigMapPayload(&apiv1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{UID: types.UID(uid)}, ObjectMeta: metav1.ObjectMeta{UID: types.UID(uid)},
Data: map[string]string{ Data: map[string]string{
...@@ -241,7 +249,12 @@ func TestFsStoreLoad(t *testing.T) { ...@@ -241,7 +249,12 @@ func TestFsStoreLoad(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.desc, func(t *testing.T) { t.Run(c.desc, func(t *testing.T) {
source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{
ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: c.uid}}) ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: "name",
Namespace: "namespace",
UID: c.uid,
KubeletConfigKey: kubeletKey,
}})
if err != nil { if err != nil {
t.Fatalf("error constructing remote config source: %v", err) t.Fatalf("error constructing remote config source: %v", err)
} }
...@@ -291,7 +304,12 @@ func TestFsStoreCurrent(t *testing.T) { ...@@ -291,7 +304,12 @@ func TestFsStoreCurrent(t *testing.T) {
} }
source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{
ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: "uid"}}) ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: "name",
Namespace: "namespace",
UID: "uid",
KubeletConfigKey: "kubelet",
}})
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -329,7 +347,12 @@ func TestFsStoreLastKnownGood(t *testing.T) { ...@@ -329,7 +347,12 @@ func TestFsStoreLastKnownGood(t *testing.T) {
} }
source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{
ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: "uid"}}) ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: "name",
Namespace: "namespace",
UID: "uid",
KubeletConfigKey: "kubelet",
}})
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -367,15 +390,21 @@ func TestFsStoreSetCurrent(t *testing.T) { ...@@ -367,15 +390,21 @@ func TestFsStoreSetCurrent(t *testing.T) {
} }
const uid = "uid" const uid = "uid"
expect := fmt.Sprintf(`apiVersion: v1 expect := fmt.Sprintf(`apiVersion: kubelet.config.k8s.io/v1beta1
configMapRef: kind: SerializedNodeConfigSource
name: name source:
namespace: namespace configMap:
uid: %s kubeletConfigKey: kubelet
kind: NodeConfigSource name: name
namespace: namespace
uid: %s
`, uid) `, uid)
source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{ source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: "name", Namespace: "namespace", UID: types.UID(uid)}}) Name: "name",
Namespace: "namespace",
UID: types.UID(uid),
KubeletConfigKey: "kubelet",
}})
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -399,15 +428,21 @@ func TestFsStoreSetLastKnownGood(t *testing.T) { ...@@ -399,15 +428,21 @@ func TestFsStoreSetLastKnownGood(t *testing.T) {
} }
const uid = "uid" const uid = "uid"
expect := fmt.Sprintf(`apiVersion: v1 expect := fmt.Sprintf(`apiVersion: kubelet.config.k8s.io/v1beta1
configMapRef: kind: SerializedNodeConfigSource
name: name source:
namespace: namespace configMap:
uid: %s kubeletConfigKey: kubelet
kind: NodeConfigSource name: name
namespace: namespace
uid: %s
`, uid) `, uid)
source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{ source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: "name", Namespace: "namespace", UID: types.UID(uid)}}) Name: "name",
Namespace: "namespace",
UID: types.UID(uid),
KubeletConfigKey: "kubelet",
}})
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -430,11 +465,21 @@ func TestFsStoreReset(t *testing.T) { ...@@ -430,11 +465,21 @@ func TestFsStoreReset(t *testing.T) {
t.Fatalf("error constructing store: %v", err) t.Fatalf("error constructing store: %v", err)
} }
source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: "uid"}}) source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: "name",
Namespace: "namespace",
UID: "uid",
KubeletConfigKey: "kubelet",
}})
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
otherSource, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "other-name", Namespace: "namespace", UID: "other-uid"}}) otherSource, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: "other-name",
Namespace: "namespace",
UID: "other-uid",
KubeletConfigKey: "kubelet",
}})
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -498,7 +543,12 @@ func TestFsStoreReadRemoteConfigSource(t *testing.T) { ...@@ -498,7 +543,12 @@ func TestFsStoreReadRemoteConfigSource(t *testing.T) {
} }
source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{
ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: "uid"}}) ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: "name",
Namespace: "namespace",
UID: "uid",
KubeletConfigKey: "kubelet",
}})
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -534,7 +584,12 @@ func TestFsStoreWriteRemoteConfigSource(t *testing.T) { ...@@ -534,7 +584,12 @@ func TestFsStoreWriteRemoteConfigSource(t *testing.T) {
t.Fatalf("error constructing store: %v", err) t.Fatalf("error constructing store: %v", err)
} }
source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: "uid"}}) source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: "name",
Namespace: "namespace",
UID: "uid",
KubeletConfigKey: "kubelet",
}})
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
......
...@@ -26,11 +26,21 @@ import ( ...@@ -26,11 +26,21 @@ import (
) )
func TestReset(t *testing.T) { func TestReset(t *testing.T) {
source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "name", Namespace: "namespace", UID: "uid"}}) source, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: "name",
Namespace: "namespace",
UID: "uid",
KubeletConfigKey: "kubelet",
}})
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
otherSource, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMapRef: &apiv1.ObjectReference{Name: "other-name", Namespace: "namespace", UID: "other-uid"}}) otherSource, _, err := checkpoint.NewRemoteConfigSource(&apiv1.NodeConfigSource{ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Name: "other-name",
Namespace: "namespace",
UID: "other-uid",
KubeletConfigKey: "kubelet",
}})
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
......
...@@ -65,11 +65,11 @@ const ( ...@@ -65,11 +65,11 @@ const (
FailSyncReasonFmt = "failed to sync, reason: %s" FailSyncReasonFmt = "failed to sync, reason: %s"
// FailSyncReasonAllNilSubfields is used when no subfields are set // FailSyncReasonAllNilSubfields is used when no subfields are set
FailSyncReasonAllNilSubfields = "invalid NodeConfigSource, exactly one subfield must be non-nil, but all were nil" FailSyncReasonAllNilSubfields = "invalid NodeConfigSource, exactly one subfield must be non-nil, but all were nil"
// FailSyncReasonPartialObjectReference is used when some required subfields remain unset // FailSyncReasonPartialConfigMapSource is used when some required subfields remain unset
FailSyncReasonPartialObjectReference = "invalid ObjectReference, all of UID, Name, and Namespace must be specified" FailSyncReasonPartialConfigMapSource = "invalid ConfigSource.ConfigMap, all of UID, Name, Namespace, and KubeletConfigKey must be specified"
// FailSyncReasonUIDMismatchFmt is used when there is a UID mismatch between the referenced and downloaded ConfigMaps, // FailSyncReasonUIDMismatchFmt is used when there is a UID mismatch between the referenced and downloaded ConfigMaps,
// this can happen because objects must be downloaded by namespace/name, rather than by UID // this can happen because objects must be downloaded by namespace/name, rather than by UID
FailSyncReasonUIDMismatchFmt = "invalid ConfigSource.ConfigMapRef.UID: %s does not match %s.UID: %s" FailSyncReasonUIDMismatchFmt = "invalid ConfigSource.ConfigMap.UID: %s does not match %s.UID: %s"
// FailSyncReasonDownloadFmt is used when the download fails, e.g. due to network issues // FailSyncReasonDownloadFmt is used when the download fails, e.g. due to network issues
FailSyncReasonDownloadFmt = "failed to download: %s" FailSyncReasonDownloadFmt = "failed to download: %s"
// FailSyncReasonInformer is used when the informer fails to report the Node object // FailSyncReasonInformer is used when the informer fails to report the Node object
......
...@@ -32,7 +32,7 @@ import ( ...@@ -32,7 +32,7 @@ import (
// EncodeKubeletConfig encodes an internal KubeletConfiguration to an external YAML representation // EncodeKubeletConfig encodes an internal KubeletConfiguration to an external YAML representation
func EncodeKubeletConfig(internal *kubeletconfig.KubeletConfiguration, targetVersion schema.GroupVersion) ([]byte, error) { func EncodeKubeletConfig(internal *kubeletconfig.KubeletConfiguration, targetVersion schema.GroupVersion) ([]byte, error) {
encoder, err := newKubeletConfigYAMLEncoder(targetVersion) encoder, err := NewKubeletconfigYAMLEncoder(targetVersion)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -44,8 +44,8 @@ func EncodeKubeletConfig(internal *kubeletconfig.KubeletConfiguration, targetVer ...@@ -44,8 +44,8 @@ func EncodeKubeletConfig(internal *kubeletconfig.KubeletConfiguration, targetVer
return data, nil return data, nil
} }
// newKubeletConfigYAMLEncoder returns an encoder that can write a KubeletConfig to YAML // NewKubeletconfigYAMLEncoder returns an encoder that can write objects in the kubeletconfig API group to YAML
func newKubeletConfigYAMLEncoder(targetVersion schema.GroupVersion) (runtime.Encoder, error) { func NewKubeletconfigYAMLEncoder(targetVersion schema.GroupVersion) (runtime.Encoder, error) {
_, codecs, err := scheme.NewSchemeAndCodecs() _, codecs, err := scheme.NewSchemeAndCodecs()
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -18,33 +18,6 @@ package equal ...@@ -18,33 +18,6 @@ package equal
import apiv1 "k8s.io/api/core/v1" import apiv1 "k8s.io/api/core/v1"
// ConfigSourceEq returns true if the two config sources are semantically equivalent in the context of dynamic config
func ConfigSourceEq(a, b *apiv1.NodeConfigSource) bool {
if a == b {
return true
} else if a == nil || b == nil {
// not equal, and one is nil
return false
}
// check equality of config source subifelds
if a.ConfigMapRef != b.ConfigMapRef {
return ObjectRefEq(a.ConfigMapRef, b.ConfigMapRef)
}
// all internal subfields of the config source are equal
return true
}
// ObjectRefEq returns true if the two object references are semantically equivalent in the context of dynamic config
func ObjectRefEq(a, b *apiv1.ObjectReference) bool {
if a == b {
return true
} else if a == nil || b == nil {
// not equal, and one is nil
return false
}
return a.UID == b.UID && a.Namespace == b.Namespace && a.Name == b.Name
}
// KubeletConfigOkEq returns true if the two conditions are semantically equivalent in the context of dynamic config // KubeletConfigOkEq returns true if the two conditions are semantically equivalent in the context of dynamic config
func KubeletConfigOkEq(a, b *apiv1.NodeCondition) bool { func KubeletConfigOkEq(a, b *apiv1.NodeCondition) bool {
return a.Message == b.Message && a.Reason == b.Reason && a.Status == b.Status return a.Message == b.Message && a.Reason == b.Reason && a.Status == b.Status
......
...@@ -21,13 +21,13 @@ import ( ...@@ -21,13 +21,13 @@ import (
"time" "time"
apiv1 "k8s.io/api/core/v1" apiv1 "k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/fields"
kuberuntime "k8s.io/apimachinery/pkg/runtime" kuberuntime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
utilequal "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/equal"
utillog "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/log" utillog "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/log"
) )
...@@ -94,7 +94,7 @@ func (cc *Controller) onUpdateNodeEvent(oldObj interface{}, newObj interface{}) ...@@ -94,7 +94,7 @@ func (cc *Controller) onUpdateNodeEvent(oldObj interface{}, newObj interface{})
utillog.Errorf("failed to cast old object to Node, couldn't handle event") utillog.Errorf("failed to cast old object to Node, couldn't handle event")
return return
} }
if !utilequal.ConfigSourceEq(oldNode.Spec.ConfigSource, newNode.Spec.ConfigSource) { if !apiequality.Semantic.DeepEqual(oldNode.Spec.ConfigSource, newNode.Spec.ConfigSource) {
cc.pokeConfigSourceWorker() cc.pokeConfigSourceWorker()
} }
} }
......
...@@ -91,9 +91,19 @@ func Test_nodePlugin_Admit(t *testing.T) { ...@@ -91,9 +91,19 @@ func Test_nodePlugin_Admit(t *testing.T) {
mynodeObjMeta = metav1.ObjectMeta{Name: "mynode"} mynodeObjMeta = metav1.ObjectMeta{Name: "mynode"}
mynodeObj = &api.Node{ObjectMeta: mynodeObjMeta} mynodeObj = &api.Node{ObjectMeta: mynodeObjMeta}
mynodeObjConfigA = &api.Node{ObjectMeta: mynodeObjMeta, Spec: api.NodeSpec{ConfigSource: &api.NodeConfigSource{ mynodeObjConfigA = &api.Node{ObjectMeta: mynodeObjMeta, Spec: api.NodeSpec{ConfigSource: &api.NodeConfigSource{
ConfigMapRef: &api.ObjectReference{Name: "foo", Namespace: "bar", UID: "fooUID"}}}} ConfigMap: &api.ConfigMapNodeConfigSource{
Name: "foo",
Namespace: "bar",
UID: "fooUID",
KubeletConfigKey: "kubelet",
}}}}
mynodeObjConfigB = &api.Node{ObjectMeta: mynodeObjMeta, Spec: api.NodeSpec{ConfigSource: &api.NodeConfigSource{ mynodeObjConfigB = &api.Node{ObjectMeta: mynodeObjMeta, Spec: api.NodeSpec{ConfigSource: &api.NodeConfigSource{
ConfigMapRef: &api.ObjectReference{Name: "qux", Namespace: "bar", UID: "quxUID"}}}} ConfigMap: &api.ConfigMapNodeConfigSource{
Name: "qux",
Namespace: "bar",
UID: "quxUID",
KubeletConfigKey: "kubelet",
}}}}
othernodeObj = &api.Node{ObjectMeta: metav1.ObjectMeta{Name: "othernode"}} othernodeObj = &api.Node{ObjectMeta: metav1.ObjectMeta{Name: "othernode"}}
mymirrorpod = makeTestPod("ns", "mymirrorpod", "mynode", true) mymirrorpod = makeTestPod("ns", "mymirrorpod", "mynode", true)
......
...@@ -408,7 +408,7 @@ func (g *Graph) DeleteVolumeAttachment(name string) { ...@@ -408,7 +408,7 @@ func (g *Graph) DeleteVolumeAttachment(name string) {
g.deleteVertex_locked(vaVertexType, "", name) g.deleteVertex_locked(vaVertexType, "", name)
} }
// SetNodeConfigMap sets up edges for the Node.Spec.ConfigSource.ConfigMapRef relationship: // SetNodeConfigMap sets up edges for the Node.Spec.ConfigSource.ConfigMap relationship:
// //
// configmap -> node // configmap -> node
func (g *Graph) SetNodeConfigMap(nodeName, configMapName, configMapNamespace string) { func (g *Graph) SetNodeConfigMap(nodeName, configMapName, configMapNamespace string) {
......
...@@ -84,19 +84,19 @@ func (g *graphPopulator) updateNode(oldObj, obj interface{}) { ...@@ -84,19 +84,19 @@ func (g *graphPopulator) updateNode(oldObj, obj interface{}) {
oldNode = oldObj.(*api.Node) oldNode = oldObj.(*api.Node)
} }
// we only set up rules for ConfigMapRef today, because that is the only reference type // we only set up rules for ConfigMap today, because that is the only reference type
var name, namespace string var name, namespace string
if source := node.Spec.ConfigSource; source != nil && source.ConfigMapRef != nil { if source := node.Spec.ConfigSource; source != nil && source.ConfigMap != nil {
name = source.ConfigMapRef.Name name = source.ConfigMap.Name
namespace = source.ConfigMapRef.Namespace namespace = source.ConfigMap.Namespace
} }
var oldName, oldNamespace string var oldName, oldNamespace string
if oldNode != nil { if oldNode != nil {
if oldSource := oldNode.Spec.ConfigSource; oldSource != nil && oldSource.ConfigMapRef != nil { if oldSource := oldNode.Spec.ConfigSource; oldSource != nil && oldSource.ConfigMap != nil {
oldName = oldSource.ConfigMapRef.Name oldName = oldSource.ConfigMap.Name
oldNamespace = oldSource.ConfigMapRef.Namespace oldNamespace = oldSource.ConfigMap.Namespace
} }
} }
......
...@@ -753,10 +753,11 @@ func generate(opts sampleDataOpts) ([]*api.Node, []*api.Pod, []*api.PersistentVo ...@@ -753,10 +753,11 @@ func generate(opts sampleDataOpts) ([]*api.Node, []*api.Pod, []*api.PersistentVo
ObjectMeta: metav1.ObjectMeta{Name: nodeName}, ObjectMeta: metav1.ObjectMeta{Name: nodeName},
Spec: api.NodeSpec{ Spec: api.NodeSpec{
ConfigSource: &api.NodeConfigSource{ ConfigSource: &api.NodeConfigSource{
ConfigMapRef: &api.ObjectReference{ ConfigMap: &api.ConfigMapNodeConfigSource{
Name: name, Name: name,
Namespace: "ns0", Namespace: "ns0",
UID: types.UID(fmt.Sprintf("ns0-%s", name)), UID: types.UID(fmt.Sprintf("ns0-%s", name)),
KubeletConfigKey: "kubelet",
}, },
}, },
}, },
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -439,6 +439,34 @@ message ConfigMapList { ...@@ -439,6 +439,34 @@ message ConfigMapList {
repeated ConfigMap items = 2; repeated ConfigMap items = 2;
} }
// ConfigMapNodeConfigSource contains the information to reference a ConfigMap as a config source for the Node.
message ConfigMapNodeConfigSource {
// Namespace is the metadata.namespace of the referenced ConfigMap.
// This field is required in all cases.
optional string namespace = 1;
// Name is the metadata.name of the referenced ConfigMap.
// This field is required in all cases.
optional string name = 2;
// 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.
// TODO(#56896): This field will be required in Node.Status when #56896 is resolved.
// +optional
optional string uid = 3;
// 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.
// +optional
optional string resourceVersion = 4;
// KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure
// This field is required in all cases.
optional string kubeletConfigKey = 5;
}
// Adapts a ConfigMap into a projected volume. // Adapts a ConfigMap into a projected volume.
// //
// The contents of the target ConfigMap's Data field will be presented in a // The contents of the target ConfigMap's Data field will be presented in a
...@@ -1815,7 +1843,8 @@ message NodeCondition { ...@@ -1815,7 +1843,8 @@ message NodeCondition {
// NodeConfigSource specifies a source of node configuration. Exactly one subfield (excluding metadata) must be non-nil. // NodeConfigSource specifies a source of node configuration. Exactly one subfield (excluding metadata) must be non-nil.
message NodeConfigSource { message NodeConfigSource {
optional ObjectReference configMapRef = 1; // ConfigMap is a reference to a Node's ConfigMap
optional ConfigMapNodeConfigSource configMap = 2;
} }
// NodeDaemonEndpoints lists ports opened by daemons running on the Node. // NodeDaemonEndpoints lists ports opened by daemons running on the Node.
......
...@@ -57,7 +57,6 @@ func addKnownTypes(scheme *runtime.Scheme) error { ...@@ -57,7 +57,6 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&Endpoints{}, &Endpoints{},
&EndpointsList{}, &EndpointsList{},
&Node{}, &Node{},
&NodeConfigSource{},
&NodeList{}, &NodeList{},
&NodeProxyOptions{}, &NodeProxyOptions{},
&Binding{}, &Binding{},
......
...@@ -3640,12 +3640,49 @@ type NodeSpec struct { ...@@ -3640,12 +3640,49 @@ type NodeSpec struct {
DoNotUse_ExternalID string `json:"externalID,omitempty" protobuf:"bytes,2,opt,name=externalID"` DoNotUse_ExternalID string `json:"externalID,omitempty" protobuf:"bytes,2,opt,name=externalID"`
} }
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// NodeConfigSource specifies a source of node configuration. Exactly one subfield (excluding metadata) must be non-nil. // NodeConfigSource specifies a source of node configuration. Exactly one subfield (excluding metadata) must be non-nil.
type NodeConfigSource struct { type NodeConfigSource struct {
metav1.TypeMeta `json:",inline"` // For historical context, regarding the below kind, apiVersion, and configMapRef deprecation tags:
ConfigMapRef *ObjectReference `json:"configMapRef,omitempty" protobuf:"bytes,1,opt,name=configMapRef"` // 1. kind/apiVersion were used by the kubelet to persist this struct to disk (they had no protobuf tags)
// 2. configMapRef and proto tag 1 were used by the API to refer to a configmap,
// but used a generic ObjectReference type that didn't really have the fields we needed
// All uses/persistence of the NodeConfigSource struct prior to 1.11 were gated by alpha feature flags,
// so there was no persisted data for these fields that needed to be migrated/handled.
// +k8s:deprecated=kind
// +k8s:deprecated=apiVersion
// +k8s:deprecated=configMapRef,protobuf=1
// ConfigMap is a reference to a Node's ConfigMap
ConfigMap *ConfigMapNodeConfigSource `json:"configMap,omitempty" protobuf:"bytes,2,opt,name=configMap"`
}
// ConfigMapNodeConfigSource contains the information to reference a ConfigMap as a config source for the Node.
type ConfigMapNodeConfigSource struct {
// Namespace is the metadata.namespace of the referenced ConfigMap.
// This field is required in all cases.
Namespace string `json:"namespace" protobuf:"bytes,1,opt,name=namespace"`
// Name is the metadata.name of the referenced ConfigMap.
// This field is required in all cases.
Name string `json:"name" protobuf:"bytes,2,opt,name=name"`
// 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.
// TODO(#56896): This field will be required in Node.Status when #56896 is resolved.
// +optional
UID types.UID `json:"uid,omitempty" protobuf:"bytes,3,opt,name=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.
// +optional
ResourceVersion string `json:"resourceVersion,omitempty" protobuf:"bytes,4,opt,name=resourceVersion"`
// KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure
// This field is required in all cases.
KubeletConfigKey string `json:"kubeletConfigKey" protobuf:"bytes,5,opt,name=kubeletConfigKey"`
} }
// DaemonEndpoint contains information about a single Daemon endpoint. // DaemonEndpoint contains information about a single Daemon endpoint.
......
...@@ -262,6 +262,19 @@ func (ConfigMapList) SwaggerDoc() map[string]string { ...@@ -262,6 +262,19 @@ func (ConfigMapList) SwaggerDoc() map[string]string {
return map_ConfigMapList return map_ConfigMapList
} }
var map_ConfigMapNodeConfigSource = map[string]string{
"": "ConfigMapNodeConfigSource contains the information to reference a ConfigMap as a config source for the Node.",
"namespace": "Namespace is the metadata.namespace of the referenced ConfigMap. This field is required in all cases.",
"name": "Name is the metadata.name of the referenced ConfigMap. This field is required in all cases.",
"uid": "UID is the metadata.UID of the referenced ConfigMap. This field is currently reqired in Node.Spec.",
"resourceVersion": "ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. This field is forbidden in Node.Spec.",
"kubeletConfigKey": "KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure This field is required in all cases.",
}
func (ConfigMapNodeConfigSource) SwaggerDoc() map[string]string {
return map_ConfigMapNodeConfigSource
}
var map_ConfigMapProjection = map[string]string{ var map_ConfigMapProjection = map[string]string{
"": "Adapts a ConfigMap into a projected volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a projected volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. Note that this is identical to a configmap volume source without the default mode.", "": "Adapts a ConfigMap into a projected volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a projected volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. Note that this is identical to a configmap volume source without the default mode.",
"items": "If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.", "items": "If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.",
...@@ -969,7 +982,8 @@ func (NodeCondition) SwaggerDoc() map[string]string { ...@@ -969,7 +982,8 @@ func (NodeCondition) SwaggerDoc() map[string]string {
} }
var map_NodeConfigSource = map[string]string{ var map_NodeConfigSource = map[string]string{
"": "NodeConfigSource specifies a source of node configuration. Exactly one subfield (excluding metadata) must be non-nil.", "": "NodeConfigSource specifies a source of node configuration. Exactly one subfield (excluding metadata) must be non-nil.",
"configMap": "ConfigMap is a reference to a Node's ConfigMap",
} }
func (NodeConfigSource) SwaggerDoc() map[string]string { func (NodeConfigSource) SwaggerDoc() map[string]string {
......
...@@ -632,6 +632,22 @@ func (in *ConfigMapList) DeepCopyObject() runtime.Object { ...@@ -632,6 +632,22 @@ func (in *ConfigMapList) DeepCopyObject() runtime.Object {
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-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) { func (in *ConfigMapProjection) DeepCopyInto(out *ConfigMapProjection) {
*out = *in *out = *in
out.LocalObjectReference = in.LocalObjectReference out.LocalObjectReference = in.LocalObjectReference
...@@ -2360,13 +2376,12 @@ func (in *NodeCondition) DeepCopy() *NodeCondition { ...@@ -2360,13 +2376,12 @@ func (in *NodeCondition) DeepCopy() *NodeCondition {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeConfigSource) DeepCopyInto(out *NodeConfigSource) { func (in *NodeConfigSource) DeepCopyInto(out *NodeConfigSource) {
*out = *in *out = *in
out.TypeMeta = in.TypeMeta if in.ConfigMap != nil {
if in.ConfigMapRef != nil { in, out := &in.ConfigMap, &out.ConfigMap
in, out := &in.ConfigMapRef, &out.ConfigMapRef
if *in == nil { if *in == nil {
*out = nil *out = nil
} else { } else {
*out = new(ObjectReference) *out = new(ConfigMapNodeConfigSource)
**out = **in **out = **in
} }
} }
...@@ -2383,14 +2398,6 @@ func (in *NodeConfigSource) DeepCopy() *NodeConfigSource { ...@@ -2383,14 +2398,6 @@ func (in *NodeConfigSource) DeepCopy() *NodeConfigSource {
return out 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. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeDaemonEndpoints) DeepCopyInto(out *NodeDaemonEndpoints) { func (in *NodeDaemonEndpoints) DeepCopyInto(out *NodeDaemonEndpoints) {
*out = *in *out = *in
......
...@@ -57,8 +57,10 @@ var startServices = flag.Bool("start-services", true, "If true, start local node ...@@ -57,8 +57,10 @@ var startServices = flag.Bool("start-services", true, "If true, start local node
var stopServices = flag.Bool("stop-services", true, "If true, stop local node services after running tests") var stopServices = flag.Bool("stop-services", true, "If true, stop local node services after running tests")
var busyboxImage = "busybox" var busyboxImage = "busybox"
// Kubelet internal cgroup name for node allocatable cgroup. const (
const defaultNodeAllocatableCgroup = "kubepods" // Kubelet internal cgroup name for node allocatable cgroup.
defaultNodeAllocatableCgroup = "kubepods"
)
func getNodeSummary() (*stats.Summary, error) { func getNodeSummary() (*stats.Summary, error) {
req, err := http.NewRequest("GET", *kubeletAddress+"/stats/summary", nil) req, err := http.NewRequest("GET", *kubeletAddress+"/stats/summary", nil)
...@@ -167,10 +169,11 @@ func setKubeletConfiguration(f *framework.Framework, kubeCfg *kubeletconfig.Kube ...@@ -167,10 +169,11 @@ func setKubeletConfiguration(f *framework.Framework, kubeCfg *kubeletconfig.Kube
// create the reference and set Node.Spec.ConfigSource // create the reference and set Node.Spec.ConfigSource
src := &apiv1.NodeConfigSource{ src := &apiv1.NodeConfigSource{
ConfigMapRef: &apiv1.ObjectReference{ ConfigMap: &apiv1.ConfigMapNodeConfigSource{
Namespace: "kube-system", Namespace: "kube-system",
Name: cm.Name, Name: cm.Name,
UID: cm.UID, UID: cm.UID,
KubeletConfigKey: "kubelet",
}, },
} }
......
...@@ -54,7 +54,6 @@ var kindWhiteList = sets.NewString( ...@@ -54,7 +54,6 @@ var kindWhiteList = sets.NewString(
"ExportOptions", "ExportOptions",
"GetOptions", "GetOptions",
"ListOptions", "ListOptions",
"NodeConfigSource",
"NodeProxyOptions", "NodeProxyOptions",
"PodAttachOptions", "PodAttachOptions",
"PodExecOptions", "PodExecOptions",
......
...@@ -286,12 +286,13 @@ func TestNodeAuthorizer(t *testing.T) { ...@@ -286,12 +286,13 @@ func TestNodeAuthorizer(t *testing.T) {
return err return err
} }
node2.Spec.ConfigSource = &api.NodeConfigSource{ node2.Spec.ConfigSource = &api.NodeConfigSource{
ConfigMapRef: &api.ObjectReference{ ConfigMap: &api.ConfigMapNodeConfigSource{
Namespace: "ns", Namespace: "ns",
Name: "myconfigmapconfigsource", Name: "myconfigmapconfigsource",
// validation just requires UID to be non-empty and it isn't necessary for GET, // validation just requires UID to be non-empty and it isn't necessary for GET,
// so we just use a bogus one for the test // so we just use a bogus one for the test
UID: "uid", UID: "uid",
KubeletConfigKey: "kubelet",
}, },
} }
_, err = client.Core().Nodes().Update(node2) _, err = client.Core().Nodes().Update(node2)
......
...@@ -437,7 +437,6 @@ var ephemeralWhiteList = createEphemeralWhiteList( ...@@ -437,7 +437,6 @@ var ephemeralWhiteList = createEphemeralWhiteList(
gvk("", "v1", "RangeAllocation"), // stored in various places in etcd but cannot be directly created gvk("", "v1", "RangeAllocation"), // stored in various places in etcd but cannot be directly created
gvk("", "v1", "ComponentStatus"), // status info not stored in etcd gvk("", "v1", "ComponentStatus"), // status info not stored in etcd
gvk("", "v1", "SerializedReference"), // used for serilization, not stored in etcd gvk("", "v1", "SerializedReference"), // used for serilization, not stored in etcd
gvk("", "v1", "NodeConfigSource"), // subfield of node.spec, but shouldn't be directly created
gvk("", "v1", "PodStatusResult"), // wrapper object not stored in etcd gvk("", "v1", "PodStatusResult"), // wrapper object not stored in etcd
// -- // --
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment