mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-19 09:52:49 +00:00
Merge pull request #112643 from SergeyKanzhelev/removeDynamicKubeletConfig
remove DynamicKubeletConfig feature gate from the code
This commit is contained in:
commit
525280d285
2
api/openapi-spec/swagger.json
generated
2
api/openapi-spec/swagger.json
generated
@ -6322,7 +6322,7 @@
|
||||
"properties": {
|
||||
"configSource": {
|
||||
"$ref": "#/definitions/io.k8s.api.core.v1.NodeConfigSource",
|
||||
"description": "Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed from Kubelets as of 1.24 and will be fully removed in 1.26."
|
||||
"description": "Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed."
|
||||
},
|
||||
"externalID": {
|
||||
"description": "Deprecated. Not all kubelets will set this field. Remove field after 1.13. see: https://issues.k8s.io/61966",
|
||||
|
@ -3594,7 +3594,7 @@
|
||||
"$ref": "#/components/schemas/io.k8s.api.core.v1.NodeConfigSource"
|
||||
}
|
||||
],
|
||||
"description": "Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed from Kubelets as of 1.24 and will be fully removed in 1.26."
|
||||
"description": "Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed."
|
||||
},
|
||||
"externalID": {
|
||||
"description": "Deprecated. Not all kubelets will set this field. Remove field after 1.13. see: https://issues.k8s.io/61966",
|
||||
|
@ -235,13 +235,6 @@ HTTP server: The kubelet can also listen for HTTP and respond to a simple API
|
||||
klog.InfoS("unsupported configuration:KubeletCgroups is not within KubeReservedCgroup")
|
||||
}
|
||||
|
||||
// The features.DynamicKubeletConfig is locked to false,
|
||||
// feature gate is not locked using the LockedToDefault flag
|
||||
// to make sure node authorizer can keep working with the older nodes
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.DynamicKubeletConfig) {
|
||||
return fmt.Errorf("cannot set feature gate %v to %v, feature is locked to %v", features.DynamicKubeletConfig, true, false)
|
||||
}
|
||||
|
||||
// construct a KubeletServer from kubeletFlags and kubeletConfig
|
||||
kubeletServer := &options.KubeletServer{
|
||||
KubeletFlags: *kubeletFlags,
|
||||
|
@ -4160,7 +4160,7 @@ type NodeSpec struct {
|
||||
// +optional
|
||||
Taints []Taint
|
||||
|
||||
// Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed from Kubelets as of 1.24 and will be fully removed in 1.26.
|
||||
// Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed.
|
||||
// +optional
|
||||
ConfigSource *NodeConfigSource
|
||||
|
||||
|
@ -5259,6 +5259,8 @@ func ValidateNodeUpdate(node, oldNode *core.Node) field.ErrorList {
|
||||
}
|
||||
|
||||
// validation specific to Node.Spec.ConfigSource
|
||||
// The field ConfigSource is deprecated and will not be used. The validation is kept in place
|
||||
// for the backward compatibility
|
||||
func validateNodeConfigSourceSpec(source *core.NodeConfigSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
count := int(0)
|
||||
@ -5276,6 +5278,8 @@ func validateNodeConfigSourceSpec(source *core.NodeConfigSource, fldPath *field.
|
||||
}
|
||||
|
||||
// validation specific to Node.Spec.ConfigSource.ConfigMap
|
||||
// The field ConfigSource is deprecated and will not be used. The validation is kept in place
|
||||
// for the backward compatibility
|
||||
func validateConfigMapNodeConfigSourceSpec(source *core.ConfigMapNodeConfigSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
// uid and resourceVersion must not be set in spec
|
||||
|
@ -256,12 +256,6 @@ const (
|
||||
// Enables usage of hugepages-<size> in downward API.
|
||||
DownwardAPIHugePages featuregate.Feature = "DownwardAPIHugePages"
|
||||
|
||||
// owner: @mtaufen
|
||||
// alpha: v1.4
|
||||
// beta: v1.11
|
||||
// deprecated: 1.22
|
||||
DynamicKubeletConfig featuregate.Feature = "DynamicKubeletConfig"
|
||||
|
||||
// owner: @andrewsykim
|
||||
// kep: https://kep.k8s.io/1672
|
||||
// alpha: v1.20
|
||||
@ -863,8 +857,6 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
||||
|
||||
DownwardAPIHugePages: {Default: true, PreRelease: featuregate.Beta}, // on by default in 1.22
|
||||
|
||||
DynamicKubeletConfig: {Default: false, PreRelease: featuregate.Deprecated}, // feature gate is deprecated in 1.22, kubelet logic is removed in 1.24, api server logic can be removed in 1.26
|
||||
|
||||
EndpointSliceTerminatingCondition: {Default: true, PreRelease: featuregate.Beta},
|
||||
|
||||
EphemeralContainers: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.27
|
||||
|
2
pkg/generated/openapi/zz_generated.openapi.go
generated
2
pkg/generated/openapi/zz_generated.openapi.go
generated
@ -19913,7 +19913,7 @@ func schema_k8sio_api_core_v1_NodeSpec(ref common.ReferenceCallback) common.Open
|
||||
},
|
||||
"configSource": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed from Kubelets as of 1.24 and will be fully removed in 1.26.",
|
||||
Description: "Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed.",
|
||||
Ref: ref("k8s.io/api/core/v1.NodeConfigSource"),
|
||||
},
|
||||
},
|
||||
|
@ -34,11 +34,9 @@ import (
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
pkgstorage "k8s.io/apiserver/pkg/storage"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/kubelet/client"
|
||||
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
@ -94,13 +92,13 @@ func (nodeStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Objec
|
||||
func dropDisabledFields(node *api.Node, oldNode *api.Node) {
|
||||
// Nodes allow *all* fields, including status, to be set on create.
|
||||
// for create
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.DynamicKubeletConfig) && oldNode == nil {
|
||||
if oldNode == nil {
|
||||
node.Spec.ConfigSource = nil
|
||||
node.Status.Config = nil
|
||||
}
|
||||
|
||||
// for update
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.DynamicKubeletConfig) && !nodeConfigSourceInUse(oldNode) && oldNode != nil {
|
||||
if !nodeConfigSourceInUse(oldNode) && oldNode != nil {
|
||||
node.Spec.ConfigSource = nil
|
||||
}
|
||||
|
||||
@ -170,7 +168,7 @@ func (nodeStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime
|
||||
oldNode := old.(*api.Node)
|
||||
newNode.Spec = oldNode.Spec
|
||||
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.DynamicKubeletConfig) && !nodeStatusConfigInUse(oldNode) {
|
||||
if !nodeStatusConfigInUse(oldNode) {
|
||||
newNode.Status.Config = nil
|
||||
}
|
||||
}
|
||||
@ -274,7 +272,7 @@ func dynamicKubeletConfigIsDeprecatedWarning(obj runtime.Object) []string {
|
||||
if newNode.Spec.ConfigSource != nil {
|
||||
var warnings []string
|
||||
// KEP https://github.com/kubernetes/enhancements/issues/281
|
||||
warnings = append(warnings, "spec.configSource: deprecated in v1.22, support removal is planned in v1.23")
|
||||
warnings = append(warnings, "spec.configSource: the feature is removed")
|
||||
return warnings
|
||||
}
|
||||
return nil
|
||||
|
@ -27,11 +27,8 @@ import (
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
|
||||
// ensure types are installed
|
||||
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
||||
@ -88,11 +85,10 @@ func makeNode(podCIDRs []string, addSpecDynamicConfig bool, addStatusDynamicConf
|
||||
|
||||
func TestDropFields(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
node *api.Node
|
||||
oldNode *api.Node
|
||||
compareNode *api.Node
|
||||
enableNodeDynamicConfig bool
|
||||
name string
|
||||
node *api.Node
|
||||
oldNode *api.Node
|
||||
compareNode *api.Node
|
||||
}{
|
||||
{
|
||||
name: "nil pod cidrs",
|
||||
@ -127,60 +123,45 @@ func TestDropFields(t *testing.T) {
|
||||
compareNode: makeNode([]string{"2000::/10", "10.0.0.0/8"}, false, false),
|
||||
},
|
||||
{
|
||||
name: "new with no Spec.ConfigSource and no Status.Config , enableNodeDynamicConfig disabled",
|
||||
enableNodeDynamicConfig: false,
|
||||
node: makeNode(nil, false, false),
|
||||
oldNode: nil,
|
||||
compareNode: makeNode(nil, false, false),
|
||||
name: "new with no Spec.ConfigSource and no Status.Config",
|
||||
node: makeNode(nil, false, false),
|
||||
oldNode: nil,
|
||||
compareNode: makeNode(nil, false, false),
|
||||
},
|
||||
{
|
||||
name: "new with Spec.ConfigSource and no Status.Config, enableNodeDynamicConfig disabled",
|
||||
enableNodeDynamicConfig: false,
|
||||
node: makeNode(nil, true, false),
|
||||
oldNode: nil,
|
||||
compareNode: makeNode(nil, false, false),
|
||||
name: "new with Spec.ConfigSource and no Status.Config",
|
||||
node: makeNode(nil, true, false),
|
||||
oldNode: nil,
|
||||
compareNode: makeNode(nil, false, false),
|
||||
},
|
||||
{
|
||||
name: "new with Spec.ConfigSource and Status.Config, enableNodeDynamicConfig disabled",
|
||||
enableNodeDynamicConfig: false,
|
||||
node: makeNode(nil, true, true),
|
||||
oldNode: nil,
|
||||
compareNode: makeNode(nil, false, false),
|
||||
name: "new with Spec.ConfigSource and Status.Config",
|
||||
node: makeNode(nil, true, true),
|
||||
oldNode: nil,
|
||||
compareNode: makeNode(nil, false, false),
|
||||
},
|
||||
{
|
||||
name: "update with Spec.ConfigSource and Status.Config (old has none), enableNodeDynamicConfig disabled",
|
||||
enableNodeDynamicConfig: false,
|
||||
node: makeNode(nil, true, true),
|
||||
oldNode: makeNode(nil, false, false),
|
||||
compareNode: makeNode(nil, false, true),
|
||||
name: "update with Spec.ConfigSource and Status.Config (old has none)",
|
||||
node: makeNode(nil, true, true),
|
||||
oldNode: makeNode(nil, false, false),
|
||||
compareNode: makeNode(nil, false, true),
|
||||
},
|
||||
{
|
||||
name: "update with Spec.ConfigSource and Status.Config (old has them), enableNodeDynamicConfig disabled",
|
||||
enableNodeDynamicConfig: false,
|
||||
node: makeNode(nil, true, true),
|
||||
oldNode: makeNode(nil, true, true),
|
||||
compareNode: makeNode(nil, true, true),
|
||||
name: "update with Spec.ConfigSource and Status.Config (old has them)",
|
||||
node: makeNode(nil, true, true),
|
||||
oldNode: makeNode(nil, true, true),
|
||||
compareNode: makeNode(nil, true, true),
|
||||
},
|
||||
{
|
||||
name: "update with Spec.ConfigSource and Status.Config (old has Status.Config), enableNodeDynamicConfig disabled",
|
||||
enableNodeDynamicConfig: false,
|
||||
node: makeNode(nil, true, true),
|
||||
oldNode: makeNode(nil, false, true),
|
||||
compareNode: makeNode(nil, false, true),
|
||||
},
|
||||
{
|
||||
name: "new with Spec.ConfigSource and Status.Config, enableNodeDynamicConfig enabled",
|
||||
enableNodeDynamicConfig: true,
|
||||
node: makeNode(nil, true, true),
|
||||
oldNode: nil,
|
||||
compareNode: makeNode(nil, true, true),
|
||||
name: "update with Spec.ConfigSource and Status.Config (old has Status.Config)",
|
||||
node: makeNode(nil, true, true),
|
||||
oldNode: makeNode(nil, false, true),
|
||||
compareNode: makeNode(nil, false, true),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
func() {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.DynamicKubeletConfig, tc.enableNodeDynamicConfig)()
|
||||
|
||||
dropDisabledFields(tc.node, tc.oldNode)
|
||||
|
||||
old := tc.oldNode.DeepCopy()
|
||||
|
@ -476,31 +476,3 @@ func (g *Graph) DeleteVolumeAttachment(name string) {
|
||||
defer g.lock.Unlock()
|
||||
g.deleteVertex_locked(vaVertexType, "", name)
|
||||
}
|
||||
|
||||
// SetNodeConfigMap sets up edges for the Node.Spec.ConfigSource.ConfigMap relationship:
|
||||
//
|
||||
// configmap -> node
|
||||
func (g *Graph) SetNodeConfigMap(nodeName, configMapName, configMapNamespace string) {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
graphActionsDuration.WithLabelValues("SetNodeConfigMap").Observe(time.Since(start).Seconds())
|
||||
}()
|
||||
g.lock.Lock()
|
||||
defer g.lock.Unlock()
|
||||
|
||||
// TODO(mtaufen): ensure len(nodeName) > 0 in all cases (would sure be nice to have a dependently-typed language here...)
|
||||
|
||||
// clear edges configmaps -> node where the destination is the current node *only*
|
||||
// at present, a node can only have one *direct* configmap reference at a time
|
||||
g.deleteEdges_locked(configMapVertexType, nodeVertexType, "", nodeName)
|
||||
|
||||
// establish new edges if we have a real ConfigMap to reference
|
||||
if len(configMapName) > 0 && len(configMapNamespace) > 0 {
|
||||
configmapVertex := g.getOrCreateVertex_locked(configMapVertexType, configMapNamespace, configMapName)
|
||||
nodeVertex := g.getOrCreateVertex_locked(nodeVertexType, "", nodeName)
|
||||
e := newDestinationEdge(configmapVertex, nodeVertex, nodeVertex)
|
||||
g.graph.SetEdge(e)
|
||||
g.addEdgeToDestinationIndex_locked(e)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||
package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
@ -25,11 +24,9 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
storagev1 "k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
corev1informers "k8s.io/client-go/informers/core/v1"
|
||||
storageinformers "k8s.io/client-go/informers/storage/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
type graphPopulator struct {
|
||||
@ -49,15 +46,6 @@ func AddGraphEventHandlers(
|
||||
|
||||
var hasSynced []cache.InformerSynced
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.DynamicKubeletConfig) {
|
||||
nodes.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: g.addNode,
|
||||
UpdateFunc: g.updateNode,
|
||||
DeleteFunc: g.deleteNode,
|
||||
})
|
||||
hasSynced = append(hasSynced, nodes.Informer().HasSynced)
|
||||
}
|
||||
|
||||
pods.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: g.addPod,
|
||||
UpdateFunc: g.updatePod,
|
||||
@ -82,62 +70,6 @@ func AddGraphEventHandlers(
|
||||
go cache.WaitForNamedCacheSync("node_authorizer", wait.NeverStop, hasSynced...)
|
||||
}
|
||||
|
||||
func (g *graphPopulator) addNode(obj interface{}) {
|
||||
g.updateNode(nil, obj)
|
||||
}
|
||||
|
||||
func (g *graphPopulator) updateNode(oldObj, obj interface{}) {
|
||||
node := obj.(*corev1.Node)
|
||||
var oldNode *corev1.Node
|
||||
if oldObj != nil {
|
||||
oldNode = oldObj.(*corev1.Node)
|
||||
}
|
||||
|
||||
// we only set up rules for ConfigMap today, because that is the only reference type
|
||||
|
||||
var name, namespace string
|
||||
if source := node.Spec.ConfigSource; source != nil && source.ConfigMap != nil {
|
||||
name = source.ConfigMap.Name
|
||||
namespace = source.ConfigMap.Namespace
|
||||
}
|
||||
|
||||
var oldName, oldNamespace string
|
||||
if oldNode != nil {
|
||||
if oldSource := oldNode.Spec.ConfigSource; oldSource != nil && oldSource.ConfigMap != nil {
|
||||
oldName = oldSource.ConfigMap.Name
|
||||
oldNamespace = oldSource.ConfigMap.Namespace
|
||||
}
|
||||
}
|
||||
|
||||
// if Node.Spec.ConfigSource wasn't updated, nothing for us to do
|
||||
if name == oldName && namespace == oldNamespace {
|
||||
return
|
||||
}
|
||||
|
||||
path := "nil"
|
||||
if node.Spec.ConfigSource != nil {
|
||||
path = fmt.Sprintf("%s/%s", namespace, name)
|
||||
}
|
||||
klog.V(4).Infof("updateNode configSource reference to %s for node %s", path, node.Name)
|
||||
g.graph.SetNodeConfigMap(node.Name, name, namespace)
|
||||
}
|
||||
|
||||
func (g *graphPopulator) deleteNode(obj interface{}) {
|
||||
if tombstone, ok := obj.(cache.DeletedFinalStateUnknown); ok {
|
||||
obj = tombstone.Obj
|
||||
}
|
||||
node, ok := obj.(*corev1.Node)
|
||||
if !ok {
|
||||
klog.Infof("unexpected type %T", obj)
|
||||
return
|
||||
}
|
||||
|
||||
// NOTE: We don't remove the node, because if the node is re-created not all pod -> node
|
||||
// links are re-established (we don't get relevant events because the no mutations need
|
||||
// to happen in the API; the state is already there).
|
||||
g.graph.SetNodeConfigMap(node.Name, "", "")
|
||||
}
|
||||
|
||||
func (g *graphPopulator) addPod(obj interface{}) {
|
||||
g.updatePod(nil, obj)
|
||||
}
|
||||
|
@ -343,74 +343,4 @@ func TestIndex(t *testing.T) {
|
||||
"configmap:ns/cm3": {"node:node1=1", "node:node2=1", "node:node3=1"},
|
||||
"serviceAccount:ns/sa1": {"node:node1=1", "node:node2=1", "node:node3=1"},
|
||||
})
|
||||
|
||||
// Set node->configmap references
|
||||
g.SetNodeConfigMap("node1", "cm1", "ns")
|
||||
g.SetNodeConfigMap("node2", "cm1", "ns")
|
||||
g.SetNodeConfigMap("node3", "cm1", "ns")
|
||||
g.SetNodeConfigMap("node4", "cm1", "ns")
|
||||
expectGraph(map[string][]string{
|
||||
"node:node1": {},
|
||||
"node:node2": {},
|
||||
"node:node3": {},
|
||||
"node:node4": {},
|
||||
"pod:ns/pod2": {"node:node2"},
|
||||
"pod:ns/pod3": {"node:node3"},
|
||||
"pod:ns/pod4": {"node:node1"},
|
||||
"configmap:ns/cm1": {"node:node1", "node:node2", "node:node3", "node:node4", "pod:ns/pod2", "pod:ns/pod3", "pod:ns/pod4"},
|
||||
"configmap:ns/cm2": {"pod:ns/pod2", "pod:ns/pod3", "pod:ns/pod4"},
|
||||
"configmap:ns/cm3": {"pod:ns/pod2", "pod:ns/pod3", "pod:ns/pod4"},
|
||||
"serviceAccount:ns/sa1": {"pod:ns/pod2", "pod:ns/pod3", "pod:ns/pod4"},
|
||||
})
|
||||
expectIndex(map[string][]string{
|
||||
"configmap:ns/cm1": {"node:node1=2", "node:node2=2", "node:node3=2", "node:node4=1"},
|
||||
"configmap:ns/cm2": {"node:node1=1", "node:node2=1", "node:node3=1"},
|
||||
"configmap:ns/cm3": {"node:node1=1", "node:node2=1", "node:node3=1"},
|
||||
"serviceAccount:ns/sa1": {"node:node1=1", "node:node2=1", "node:node3=1"},
|
||||
})
|
||||
|
||||
// Update node->configmap reference
|
||||
g.SetNodeConfigMap("node1", "cm2", "ns")
|
||||
expectGraph(map[string][]string{
|
||||
"node:node1": {},
|
||||
"node:node2": {},
|
||||
"node:node3": {},
|
||||
"node:node4": {},
|
||||
"pod:ns/pod2": {"node:node2"},
|
||||
"pod:ns/pod3": {"node:node3"},
|
||||
"pod:ns/pod4": {"node:node1"},
|
||||
"configmap:ns/cm1": {"node:node2", "node:node3", "node:node4", "pod:ns/pod2", "pod:ns/pod3", "pod:ns/pod4"},
|
||||
"configmap:ns/cm2": {"node:node1", "pod:ns/pod2", "pod:ns/pod3", "pod:ns/pod4"},
|
||||
"configmap:ns/cm3": {"pod:ns/pod2", "pod:ns/pod3", "pod:ns/pod4"},
|
||||
"serviceAccount:ns/sa1": {"pod:ns/pod2", "pod:ns/pod3", "pod:ns/pod4"},
|
||||
})
|
||||
expectIndex(map[string][]string{
|
||||
"configmap:ns/cm1": {"node:node1=1", "node:node2=2", "node:node3=2", "node:node4=1"},
|
||||
"configmap:ns/cm2": {"node:node1=2", "node:node2=1", "node:node3=1"},
|
||||
"configmap:ns/cm3": {"node:node1=1", "node:node2=1", "node:node3=1"},
|
||||
"serviceAccount:ns/sa1": {"node:node1=1", "node:node2=1", "node:node3=1"},
|
||||
})
|
||||
|
||||
// Remove node->configmap reference
|
||||
g.SetNodeConfigMap("node1", "", "")
|
||||
g.SetNodeConfigMap("node4", "", "")
|
||||
expectGraph(map[string][]string{
|
||||
"node:node1": {},
|
||||
"node:node2": {},
|
||||
"node:node3": {},
|
||||
"node:node4": {},
|
||||
"pod:ns/pod2": {"node:node2"},
|
||||
"pod:ns/pod3": {"node:node3"},
|
||||
"pod:ns/pod4": {"node:node1"},
|
||||
"configmap:ns/cm1": {"node:node2", "node:node3", "pod:ns/pod2", "pod:ns/pod3", "pod:ns/pod4"},
|
||||
"configmap:ns/cm2": {"pod:ns/pod2", "pod:ns/pod3", "pod:ns/pod4"},
|
||||
"configmap:ns/cm3": {"pod:ns/pod2", "pod:ns/pod3", "pod:ns/pod4"},
|
||||
"serviceAccount:ns/sa1": {"pod:ns/pod2", "pod:ns/pod3", "pod:ns/pod4"},
|
||||
})
|
||||
expectIndex(map[string][]string{
|
||||
"configmap:ns/cm1": {"node:node1=1", "node:node2=2", "node:node3=2"},
|
||||
"configmap:ns/cm2": {"node:node1=1", "node:node2=1", "node:node3=1"},
|
||||
"configmap:ns/cm3": {"node:node1=1", "node:node2=1", "node:node3=1"},
|
||||
"serviceAccount:ns/sa1": {"node:node1=1", "node:node2=1", "node:node3=1"},
|
||||
})
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
storagev1 "k8s.io/api/storage/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
@ -68,11 +67,6 @@ func TestAuthorizer(t *testing.T) {
|
||||
expect authorizer.Decision
|
||||
features featuregate.FeatureGate
|
||||
}{
|
||||
{
|
||||
name: "allowed node configmap",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "node0-configmap", Namespace: "ns0"},
|
||||
expect: authorizer.DecisionAllow,
|
||||
},
|
||||
{
|
||||
name: "allowed configmap",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "configmap0-pod0-node0", Namespace: "ns0"},
|
||||
@ -128,12 +122,6 @@ func TestAuthorizer(t *testing.T) {
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "persistentvolumes", Name: "pv0-pod0-node0-ns0", Namespace: ""},
|
||||
expect: authorizer.DecisionAllow,
|
||||
},
|
||||
|
||||
{
|
||||
name: "disallowed node configmap",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "node1-configmap", Namespace: "ns0"},
|
||||
expect: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
{
|
||||
name: "disallowed configmap",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "configmap0-pod0-node1", Namespace: "ns0"},
|
||||
@ -385,36 +373,23 @@ func TestAuthorizerSharedResources(t *testing.T) {
|
||||
}
|
||||
g.AddPod(pod3)
|
||||
|
||||
g.SetNodeConfigMap("node1", "shared-configmap", "ns1")
|
||||
g.SetNodeConfigMap("node2", "shared-configmap", "ns1")
|
||||
g.SetNodeConfigMap("node3", "configmap", "ns1")
|
||||
|
||||
testcases := []struct {
|
||||
User user.Info
|
||||
Secret string
|
||||
ConfigMap string
|
||||
ExpectAllowed bool
|
||||
User user.Info
|
||||
Secret string
|
||||
ConfigMap string
|
||||
Decision authorizer.Decision
|
||||
}{
|
||||
{User: node1, ExpectAllowed: true, Secret: "node1-only"},
|
||||
{User: node1, ExpectAllowed: true, Secret: "node1-node2-only"},
|
||||
{User: node1, ExpectAllowed: true, Secret: "shared-all"},
|
||||
{User: node1, Decision: authorizer.DecisionAllow, Secret: "node1-only"},
|
||||
{User: node1, Decision: authorizer.DecisionAllow, Secret: "node1-node2-only"},
|
||||
{User: node1, Decision: authorizer.DecisionAllow, Secret: "shared-all"},
|
||||
|
||||
{User: node2, ExpectAllowed: false, Secret: "node1-only"},
|
||||
{User: node2, ExpectAllowed: true, Secret: "node1-node2-only"},
|
||||
{User: node2, ExpectAllowed: true, Secret: "shared-all"},
|
||||
{User: node2, Decision: authorizer.DecisionNoOpinion, Secret: "node1-only"},
|
||||
{User: node2, Decision: authorizer.DecisionAllow, Secret: "node1-node2-only"},
|
||||
{User: node2, Decision: authorizer.DecisionAllow, Secret: "shared-all"},
|
||||
|
||||
{User: node3, ExpectAllowed: false, Secret: "node1-only"},
|
||||
{User: node3, ExpectAllowed: false, Secret: "node1-node2-only"},
|
||||
{User: node3, ExpectAllowed: true, Secret: "shared-all"},
|
||||
|
||||
{User: node1, ExpectAllowed: true, ConfigMap: "shared-configmap"},
|
||||
{User: node1, ExpectAllowed: false, ConfigMap: "configmap"},
|
||||
|
||||
{User: node2, ExpectAllowed: true, ConfigMap: "shared-configmap"},
|
||||
{User: node2, ExpectAllowed: false, ConfigMap: "configmap"},
|
||||
|
||||
{User: node3, ExpectAllowed: false, ConfigMap: "shared-configmap"},
|
||||
{User: node3, ExpectAllowed: true, ConfigMap: "configmap"},
|
||||
{User: node3, Decision: authorizer.DecisionNoOpinion, Secret: "node1-only"},
|
||||
{User: node3, Decision: authorizer.DecisionNoOpinion, Secret: "node1-node2-only"},
|
||||
{User: node3, Decision: authorizer.DecisionAllow, Secret: "shared-all"},
|
||||
}
|
||||
|
||||
for i, tc := range testcases {
|
||||
@ -439,8 +414,8 @@ func TestAuthorizerSharedResources(t *testing.T) {
|
||||
t.Fatalf("test case must include a request for a Secret or ConfigMap")
|
||||
}
|
||||
|
||||
if (decision == authorizer.DecisionAllow) != tc.ExpectAllowed {
|
||||
t.Errorf("%d: expected %v, got %v", i, tc.ExpectAllowed, decision)
|
||||
if decision != tc.Decision {
|
||||
t.Errorf("%d: expected %v, got %v", i, tc.Decision, decision)
|
||||
}
|
||||
}
|
||||
|
||||
@ -629,11 +604,6 @@ func BenchmarkAuthorization(b *testing.B) {
|
||||
expect authorizer.Decision
|
||||
features featuregate.FeatureGate
|
||||
}{
|
||||
{
|
||||
name: "allowed node configmap",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "node0-configmap", Namespace: "ns0"},
|
||||
expect: authorizer.DecisionAllow,
|
||||
},
|
||||
{
|
||||
name: "allowed configmap",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "configmap0-pod0-node0", Namespace: "ns0"},
|
||||
@ -649,12 +619,6 @@ func BenchmarkAuthorization(b *testing.B) {
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret0-shared", Namespace: "ns0"},
|
||||
expect: authorizer.DecisionAllow,
|
||||
},
|
||||
|
||||
{
|
||||
name: "disallowed node configmap",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "node1-configmap", Namespace: "ns0"},
|
||||
expect: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
{
|
||||
name: "disallowed configmap",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "configmap0-pod0-node1", Namespace: "ns0"},
|
||||
@ -779,9 +743,6 @@ func BenchmarkAuthorization(b *testing.B) {
|
||||
func populate(graph *Graph, nodes []*corev1.Node, pods []*corev1.Pod, pvs []*corev1.PersistentVolume, attachments []*storagev1.VolumeAttachment) {
|
||||
p := &graphPopulator{}
|
||||
p.graph = graph
|
||||
for _, node := range nodes {
|
||||
p.addNode(node)
|
||||
}
|
||||
for _, pod := range pods {
|
||||
p.addPod(pod)
|
||||
}
|
||||
@ -830,19 +791,9 @@ func generate(opts *sampleDataOpts) ([]*corev1.Node, []*corev1.Pod, []*corev1.Pe
|
||||
attachments = append(attachments, attachment)
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("%s-configmap", nodeName)
|
||||
nodes = append(nodes, &corev1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: nodeName},
|
||||
Spec: corev1.NodeSpec{
|
||||
ConfigSource: &corev1.NodeConfigSource{
|
||||
ConfigMap: &corev1.ConfigMapNodeConfigSource{
|
||||
Name: name,
|
||||
Namespace: "ns0",
|
||||
UID: types.UID(fmt.Sprintf("ns0-%s", name)),
|
||||
KubeletConfigKey: "kubelet",
|
||||
},
|
||||
},
|
||||
},
|
||||
Spec: corev1.NodeSpec{},
|
||||
})
|
||||
}
|
||||
return nodes, pods, pvs, attachments
|
||||
|
@ -2413,7 +2413,7 @@ message NodeSpec {
|
||||
// +optional
|
||||
repeated Taint taints = 5;
|
||||
|
||||
// Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed from Kubelets as of 1.24 and will be fully removed in 1.26.
|
||||
// Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed.
|
||||
// +optional
|
||||
optional NodeConfigSource configSource = 6;
|
||||
|
||||
|
@ -4898,7 +4898,7 @@ type NodeSpec struct {
|
||||
// +optional
|
||||
Taints []Taint `json:"taints,omitempty" protobuf:"bytes,5,opt,name=taints"`
|
||||
|
||||
// Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed from Kubelets as of 1.24 and will be fully removed in 1.26.
|
||||
// Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed.
|
||||
// +optional
|
||||
ConfigSource *NodeConfigSource `json:"configSource,omitempty" protobuf:"bytes,6,opt,name=configSource"`
|
||||
|
||||
|
@ -1189,7 +1189,7 @@ var map_NodeSpec = map[string]string{
|
||||
"providerID": "ID of the node assigned by the cloud provider in the format: <ProviderName>://<ProviderSpecificNodeID>",
|
||||
"unschedulable": "Unschedulable controls node schedulability of new pods. By default, node is schedulable. More info: https://kubernetes.io/docs/concepts/nodes/node/#manual-node-administration",
|
||||
"taints": "If specified, the node's taints.",
|
||||
"configSource": "Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed from Kubelets as of 1.24 and will be fully removed in 1.26.",
|
||||
"configSource": "Deprecated: Previously used to specify the source of the node's configuration for the DynamicKubeletConfig feature. This feature is removed.",
|
||||
"externalID": "Deprecated. Not all kubelets will set this field. Remove field after 1.13. see: https://issues.k8s.io/61966",
|
||||
}
|
||||
|
||||
|
@ -33,11 +33,8 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/test/integration/framework"
|
||||
"k8s.io/utils/pointer"
|
||||
)
|
||||
@ -52,9 +49,6 @@ func TestNodeAuthorizer(t *testing.T) {
|
||||
tokenNode2 = "node2-token"
|
||||
)
|
||||
|
||||
// Enable DynamicKubeletConfig feature so that Node.Spec.ConfigSource can be set
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.DynamicKubeletConfig, true)()
|
||||
|
||||
tokenFile, err := os.CreateTemp("", "kubeconfig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -106,9 +100,6 @@ func TestNodeAuthorizer(t *testing.T) {
|
||||
if _, err := superuserClient.CoreV1().ConfigMaps("ns").Create(context.TODO(), &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "myconfigmap"}}, metav1.CreateOptions{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := superuserClient.CoreV1().ConfigMaps("ns").Create(context.TODO(), &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "myconfigmapconfigsource"}}, metav1.CreateOptions{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pvName := "mypv"
|
||||
if _, err := superuserClientExternal.StorageV1().VolumeAttachments().Create(context.TODO(), &storagev1.VolumeAttachment{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "myattachment"},
|
||||
@ -160,12 +151,6 @@ func TestNodeAuthorizer(t *testing.T) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
getConfigMapConfigSource := func(client clientset.Interface) func() error {
|
||||
return func() error {
|
||||
_, err := client.CoreV1().ConfigMaps("ns").Get(context.TODO(), "myconfigmapconfigsource", metav1.GetOptions{})
|
||||
return err
|
||||
}
|
||||
}
|
||||
getPVC := func(client clientset.Interface) func() error {
|
||||
return func() error {
|
||||
_, err := client.CoreV1().PersistentVolumeClaims("ns").Get(context.TODO(), "mypvc", metav1.GetOptions{})
|
||||
@ -260,34 +245,6 @@ func TestNodeAuthorizer(t *testing.T) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
setNode2ConfigSource := func(client clientset.Interface) func() error {
|
||||
return func() error {
|
||||
node2, err := client.CoreV1().Nodes().Get(context.TODO(), "node2", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
node2.Spec.ConfigSource = &corev1.NodeConfigSource{
|
||||
ConfigMap: &corev1.ConfigMapNodeConfigSource{
|
||||
Namespace: "ns",
|
||||
Name: "myconfigmapconfigsource",
|
||||
KubeletConfigKey: "kubelet",
|
||||
},
|
||||
}
|
||||
_, err = client.CoreV1().Nodes().Update(context.TODO(), node2, metav1.UpdateOptions{})
|
||||
return err
|
||||
}
|
||||
}
|
||||
unsetNode2ConfigSource := func(client clientset.Interface) func() error {
|
||||
return func() error {
|
||||
node2, err := client.CoreV1().Nodes().Get(context.TODO(), "node2", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
node2.Spec.ConfigSource = nil
|
||||
_, err = client.CoreV1().Nodes().Update(context.TODO(), node2, metav1.UpdateOptions{})
|
||||
return err
|
||||
}
|
||||
}
|
||||
updateNode2Status := func(client clientset.Interface) func() error {
|
||||
return func() error {
|
||||
_, err := client.CoreV1().Nodes().UpdateStatus(context.TODO(), &corev1.Node{
|
||||
@ -578,20 +535,6 @@ func TestNodeAuthorizer(t *testing.T) {
|
||||
|
||||
// create node2 again
|
||||
expectAllowed(t, createNode2(node2Client))
|
||||
// node2 can not set its own config source
|
||||
expectForbidden(t, setNode2ConfigSource(node2Client))
|
||||
// node2 can not access the configmap config source yet
|
||||
expectForbidden(t, getConfigMapConfigSource(node2Client))
|
||||
// superuser can access the configmap config source
|
||||
expectAllowed(t, getConfigMapConfigSource(superuserClient))
|
||||
// superuser can set node2's config source
|
||||
expectAllowed(t, setNode2ConfigSource(superuserClient))
|
||||
// node2 can now get the configmap assigned as its config source
|
||||
expectAllowed(t, getConfigMapConfigSource(node2Client))
|
||||
// superuser can unset node2's config source
|
||||
expectAllowed(t, unsetNode2ConfigSource(superuserClient))
|
||||
// node2 can no longer get the configmap after it is unassigned as its config source
|
||||
expectForbidden(t, getConfigMapConfigSource(node2Client))
|
||||
// clean up node2
|
||||
expectAllowed(t, deleteNode2(superuserClient))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user