Merge pull request #112643 from SergeyKanzhelev/removeDynamicKubeletConfig

remove DynamicKubeletConfig feature gate from the code
This commit is contained in:
Kubernetes Prow Robot 2022-10-12 01:33:00 -07:00 committed by GitHub
commit 525280d285
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 59 additions and 363 deletions

View File

@ -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",

View File

@ -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",

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"),
},
},

View File

@ -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

View File

@ -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()

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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"},
})
}

View File

@ -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

View File

@ -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;

View File

@ -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"`

View File

@ -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",
}

View File

@ -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))