mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-28 21:13:35 +00:00
Promote Immutable Secrets/ConfigMaps feature to GA
This commit is contained in:
parent
80be1d6c72
commit
0f88bbe9b1
@ -4945,7 +4945,6 @@ type Secret struct {
|
|||||||
|
|
||||||
// Immutable field, if set, ensures that data stored in the Secret cannot
|
// Immutable field, if set, ensures that data stored in the Secret cannot
|
||||||
// be updated (only object metadata can be modified).
|
// be updated (only object metadata can be modified).
|
||||||
// This is a beta field enabled by ImmutableEphemeralVolumes feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
Immutable *bool
|
Immutable *bool
|
||||||
|
|
||||||
@ -5073,7 +5072,6 @@ type ConfigMap struct {
|
|||||||
|
|
||||||
// Immutable field, if set, ensures that data stored in the ConfigMap cannot
|
// Immutable field, if set, ensures that data stored in the ConfigMap cannot
|
||||||
// be updated (only object metadata can be modified).
|
// be updated (only object metadata can be modified).
|
||||||
// This is a beta field enabled by ImmutableEphemeralVolumes feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
Immutable *bool
|
Immutable *bool
|
||||||
|
|
||||||
|
@ -595,7 +595,8 @@ const (
|
|||||||
|
|
||||||
// owner: @wojtek-t
|
// owner: @wojtek-t
|
||||||
// alpha: v1.18
|
// alpha: v1.18
|
||||||
// beta: v1.19
|
// beta: v1.19
|
||||||
|
// ga: v1.21
|
||||||
//
|
//
|
||||||
// Enables a feature to make secrets and configmaps data immutable.
|
// Enables a feature to make secrets and configmaps data immutable.
|
||||||
ImmutableEphemeralVolumes featuregate.Feature = "ImmutableEphemeralVolumes"
|
ImmutableEphemeralVolumes featuregate.Feature = "ImmutableEphemeralVolumes"
|
||||||
@ -817,7 +818,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
|||||||
DaemonSetUpdateSurge: {Default: false, PreRelease: featuregate.Alpha},
|
DaemonSetUpdateSurge: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
ServiceTopology: {Default: false, PreRelease: featuregate.Alpha},
|
ServiceTopology: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
ServiceAppProtocol: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
|
ServiceAppProtocol: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
|
||||||
ImmutableEphemeralVolumes: {Default: true, PreRelease: featuregate.Beta},
|
ImmutableEphemeralVolumes: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.24
|
||||||
HugePageStorageMediumSize: {Default: true, PreRelease: featuregate.Beta},
|
HugePageStorageMediumSize: {Default: true, PreRelease: featuregate.Beta},
|
||||||
DownwardAPIHugePages: {Default: false, PreRelease: featuregate.Alpha},
|
DownwardAPIHugePages: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
ExternalPolicyForExternalIP: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.22
|
ExternalPolicyForExternalIP: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.22
|
||||||
|
@ -34,8 +34,6 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type listObjectFunc func(string, metav1.ListOptions) (runtime.Object, error)
|
type listObjectFunc func(string, metav1.ListOptions) (runtime.Object, error)
|
||||||
@ -208,7 +206,7 @@ func (c *objectCache) Get(namespace, name string) (runtime.Object, error) {
|
|||||||
// already have it from here
|
// already have it from here
|
||||||
// - doing that would require significant refactoring to reflector
|
// - doing that would require significant refactoring to reflector
|
||||||
// we limit ourselves to just quickly stop the reflector here.
|
// we limit ourselves to just quickly stop the reflector here.
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.ImmutableEphemeralVolumes) && c.isImmutable(object) {
|
if c.isImmutable(object) {
|
||||||
if item.stop() {
|
if item.stop() {
|
||||||
klog.V(4).Infof("Stopped watching for changes of %q/%q - object is immutable", namespace, name)
|
klog.V(4).Infof("Stopped watching for changes of %q/%q - object is immutable", namespace, name)
|
||||||
}
|
}
|
||||||
|
@ -31,14 +31,11 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
|
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
core "k8s.io/client-go/testing"
|
core "k8s.io/client-go/testing"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
|
||||||
|
|
||||||
corev1 "k8s.io/kubernetes/pkg/apis/core/v1"
|
corev1 "k8s.io/kubernetes/pkg/apis/core/v1"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
@ -197,8 +194,6 @@ func TestSecretCacheMultipleRegistrations(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestImmutableSecretStopsTheReflector(t *testing.T) {
|
func TestImmutableSecretStopsTheReflector(t *testing.T) {
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ImmutableEphemeralVolumes, true)()
|
|
||||||
|
|
||||||
secret := func(rv string, immutable bool) *v1.Secret {
|
secret := func(rv string, immutable bool) *v1.Secret {
|
||||||
result := &v1.Secret{
|
result := &v1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
@ -28,11 +28,9 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
pkgstorage "k8s.io/apiserver/pkg/storage"
|
pkgstorage "k8s.io/apiserver/pkg/storage"
|
||||||
"k8s.io/apiserver/pkg/storage/names"
|
"k8s.io/apiserver/pkg/storage/names"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// strategy implements behavior for ConfigMap objects
|
// strategy implements behavior for ConfigMap objects
|
||||||
@ -86,14 +84,7 @@ func (strategy) ValidateUpdate(ctx context.Context, newObj, oldObj runtime.Objec
|
|||||||
return validation.ValidateConfigMapUpdate(newCfg, oldCfg)
|
return validation.ValidateConfigMapUpdate(newCfg, oldCfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isImmutableInUse(configMap *api.ConfigMap) bool {
|
|
||||||
return configMap != nil && configMap.Immutable != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func dropDisabledFields(configMap *api.ConfigMap, oldConfigMap *api.ConfigMap) {
|
func dropDisabledFields(configMap *api.ConfigMap, oldConfigMap *api.ConfigMap) {
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.ImmutableEphemeralVolumes) && !isImmutableInUse(oldConfigMap) {
|
|
||||||
configMap.Immutable = nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (strategy) AllowUnconditionalUpdate() bool {
|
func (strategy) AllowUnconditionalUpdate() bool {
|
||||||
|
@ -29,11 +29,9 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
pkgstorage "k8s.io/apiserver/pkg/storage"
|
pkgstorage "k8s.io/apiserver/pkg/storage"
|
||||||
"k8s.io/apiserver/pkg/storage/names"
|
"k8s.io/apiserver/pkg/storage/names"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// strategy implements behavior for Secret objects
|
// strategy implements behavior for Secret objects
|
||||||
@ -80,14 +78,7 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie
|
|||||||
return validation.ValidateSecretUpdate(obj.(*api.Secret), old.(*api.Secret))
|
return validation.ValidateSecretUpdate(obj.(*api.Secret), old.(*api.Secret))
|
||||||
}
|
}
|
||||||
|
|
||||||
func isImmutableInUse(secret *api.Secret) bool {
|
|
||||||
return secret != nil && secret.Immutable != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func dropDisabledFields(secret *api.Secret, oldSecret *api.Secret) {
|
func dropDisabledFields(secret *api.Secret, oldSecret *api.Secret) {
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.ImmutableEphemeralVolumes) && !isImmutableInUse(oldSecret) {
|
|
||||||
secret.Immutable = nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (strategy) AllowUnconditionalUpdate() bool {
|
func (strategy) AllowUnconditionalUpdate() bool {
|
||||||
|
@ -5742,7 +5742,6 @@ type Secret struct {
|
|||||||
// be updated (only object metadata can be modified).
|
// be updated (only object metadata can be modified).
|
||||||
// If not set to true, the field can be modified at any time.
|
// If not set to true, the field can be modified at any time.
|
||||||
// Defaulted to nil.
|
// Defaulted to nil.
|
||||||
// This is a beta field enabled by ImmutableEphemeralVolumes feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
Immutable *bool `json:"immutable,omitempty" protobuf:"varint,5,opt,name=immutable"`
|
Immutable *bool `json:"immutable,omitempty" protobuf:"varint,5,opt,name=immutable"`
|
||||||
|
|
||||||
@ -5883,7 +5882,6 @@ type ConfigMap struct {
|
|||||||
// be updated (only object metadata can be modified).
|
// be updated (only object metadata can be modified).
|
||||||
// If not set to true, the field can be modified at any time.
|
// If not set to true, the field can be modified at any time.
|
||||||
// Defaulted to nil.
|
// Defaulted to nil.
|
||||||
// This is a beta field enabled by ImmutableEphemeralVolumes feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
Immutable *bool `json:"immutable,omitempty" protobuf:"varint,4,opt,name=immutable"`
|
Immutable *bool `json:"immutable,omitempty" protobuf:"varint,4,opt,name=immutable"`
|
||||||
|
|
||||||
|
@ -488,9 +488,16 @@ var _ = ginkgo.Describe("[sig-storage] ConfigMap", func() {
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// It should be forbidden to change data for configmaps marked as immutable, but
|
/*
|
||||||
// allowed to modify its metadata independently of its state.
|
Release: v1.21
|
||||||
ginkgo.It("should be immutable if `immutable` field is set", func() {
|
Testname: ConfigMap Volume, immutability
|
||||||
|
Description: Create a ConfigMap. Update it's data field, the update MUST succeed.
|
||||||
|
Mark the ConfigMap as immutable, the update MUST succeed. Try to update its data, the update MUST fail.
|
||||||
|
Try to mark the ConfigMap back as not immutable, the update MUST fail.
|
||||||
|
Try to update the ConfigMap`s metadata (labels), the update must succeed.
|
||||||
|
Try to delete the ConfigMap, the deletion must succeed.
|
||||||
|
*/
|
||||||
|
framework.ConformanceIt("should be immutable if `immutable` field is set", func() {
|
||||||
name := "immutable"
|
name := "immutable"
|
||||||
configMap := newConfigMap(f, name)
|
configMap := newConfigMap(f, name)
|
||||||
|
|
||||||
|
@ -371,9 +371,16 @@ var _ = ginkgo.Describe("[sig-storage] Secrets", func() {
|
|||||||
gomega.Eventually(pollDeleteLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("Error reading file /etc/secret-volumes/delete/data-1"))
|
gomega.Eventually(pollDeleteLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("Error reading file /etc/secret-volumes/delete/data-1"))
|
||||||
})
|
})
|
||||||
|
|
||||||
// It should be forbidden to change data for secrets marked as immutable, but
|
/*
|
||||||
// allowed to modify its metadata independently of its state.
|
Release: v1.21
|
||||||
ginkgo.It("should be immutable if `immutable` field is set", func() {
|
Testname: Secrets Volume, immutability
|
||||||
|
Description: Create a secret. Update it's data field, the update MUST succeed.
|
||||||
|
Mark the secret as immutable, the update MUST succeed. Try to update its data, the update MUST fail.
|
||||||
|
Try to mark the secret back as not immutable, the update MUST fail.
|
||||||
|
Try to update the secret`s metadata (labels), the update must succeed.
|
||||||
|
Try to delete the secret, the deletion must succeed.
|
||||||
|
*/
|
||||||
|
framework.ConformanceIt("should be immutable if `immutable` field is set", func() {
|
||||||
name := "immutable"
|
name := "immutable"
|
||||||
secret := secretForTest(f.Namespace.Name, name)
|
secret := secretForTest(f.Namespace.Name, name)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user