mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-01 07:47:56 +00:00
Merge pull request #86377 from wojtek-t/immutable_secrets_api
API for immutable Secrets and ConfigMaps
This commit is contained in:
commit
37d9c22abe
8
api/openapi-spec/swagger.json
generated
8
api/openapi-spec/swagger.json
generated
@ -5354,6 +5354,10 @@
|
|||||||
"description": "Data contains the configuration data. Each key must consist of alphanumeric characters, '-', '_' or '.'. Values with non-UTF-8 byte sequences must use the BinaryData field. The keys stored in Data must not overlap with the keys in the BinaryData field, this is enforced during validation process.",
|
"description": "Data contains the configuration data. Each key must consist of alphanumeric characters, '-', '_' or '.'. Values with non-UTF-8 byte sequences must use the BinaryData field. The keys stored in Data must not overlap with the keys in the BinaryData field, this is enforced during validation process.",
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"immutable": {
|
||||||
|
"description": "Immutable, if set to true, ensures that data stored in the ConfigMap cannot be updated (only object metadata can be modified). If not set to true, the field can be modified at any time. Defaulted to nil. This is an alpha field enabled by ImmutableEphemeralVolumes feature gate.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"kind": {
|
"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/sig-architecture/api-conventions.md#types-kinds",
|
"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/sig-architecture/api-conventions.md#types-kinds",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -9455,6 +9459,10 @@
|
|||||||
"description": "Data contains the secret data. Each key must consist of alphanumeric characters, '-', '_' or '.'. The serialized form of the secret data is a base64 encoded string, representing the arbitrary (possibly non-string) data value here. Described in https://tools.ietf.org/html/rfc4648#section-4",
|
"description": "Data contains the secret data. Each key must consist of alphanumeric characters, '-', '_' or '.'. The serialized form of the secret data is a base64 encoded string, representing the arbitrary (possibly non-string) data value here. Described in https://tools.ietf.org/html/rfc4648#section-4",
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"immutable": {
|
||||||
|
"description": "Immutable, if set to true, ensures that data stored in the Secret cannot be updated (only object metadata can be modified). If not set to true, the field can be modified at any time. Defaulted to nil. This is an alpha field enabled by ImmutableEphemeralVolumes feature gate.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"kind": {
|
"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/sig-architecture/api-conventions.md#types-kinds",
|
"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/sig-architecture/api-conventions.md#types-kinds",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -4735,6 +4735,12 @@ type Secret struct {
|
|||||||
// +optional
|
// +optional
|
||||||
metav1.ObjectMeta
|
metav1.ObjectMeta
|
||||||
|
|
||||||
|
// Immutable field, if set, ensures that data stored in the Secret cannot
|
||||||
|
// be updated (only object metadata can be modified).
|
||||||
|
// This is an alpha field enabled by ImmutableEphemeralVolumes feature gate.
|
||||||
|
// +optional
|
||||||
|
Immutable *bool
|
||||||
|
|
||||||
// Data contains the secret data. Each key must consist of alphanumeric
|
// Data contains the secret data. Each key must consist of alphanumeric
|
||||||
// characters, '-', '_' or '.'. The serialized form of the secret data is a
|
// characters, '-', '_' or '.'. The serialized form of the secret data is a
|
||||||
// base64 encoded string, representing the arbitrary (possibly non-string)
|
// base64 encoded string, representing the arbitrary (possibly non-string)
|
||||||
@ -4857,6 +4863,12 @@ type ConfigMap struct {
|
|||||||
// +optional
|
// +optional
|
||||||
metav1.ObjectMeta
|
metav1.ObjectMeta
|
||||||
|
|
||||||
|
// Immutable field, if set, ensures that data stored in the ConfigMap cannot
|
||||||
|
// be updated (only object metadata can be modified).
|
||||||
|
// This is an alpha field enabled by ImmutableEphemeralVolumes feature gate.
|
||||||
|
// +optional
|
||||||
|
Immutable *bool
|
||||||
|
|
||||||
// Data contains the configuration data.
|
// Data contains the configuration data.
|
||||||
// Each key must consist of alphanumeric characters, '-', '_' or '.'.
|
// Each key must consist of alphanumeric characters, '-', '_' or '.'.
|
||||||
// Values with non-UTF-8 byte sequences must use the BinaryData field.
|
// Values with non-UTF-8 byte sequences must use the BinaryData field.
|
||||||
|
4
pkg/apis/core/v1/zz_generated.conversion.go
generated
4
pkg/apis/core/v1/zz_generated.conversion.go
generated
@ -2642,6 +2642,7 @@ func Convert_core_ComponentStatusList_To_v1_ComponentStatusList(in *core.Compone
|
|||||||
|
|
||||||
func autoConvert_v1_ConfigMap_To_core_ConfigMap(in *v1.ConfigMap, out *core.ConfigMap, s conversion.Scope) error {
|
func autoConvert_v1_ConfigMap_To_core_ConfigMap(in *v1.ConfigMap, out *core.ConfigMap, s conversion.Scope) error {
|
||||||
out.ObjectMeta = in.ObjectMeta
|
out.ObjectMeta = in.ObjectMeta
|
||||||
|
out.Immutable = (*bool)(unsafe.Pointer(in.Immutable))
|
||||||
out.Data = *(*map[string]string)(unsafe.Pointer(&in.Data))
|
out.Data = *(*map[string]string)(unsafe.Pointer(&in.Data))
|
||||||
out.BinaryData = *(*map[string][]byte)(unsafe.Pointer(&in.BinaryData))
|
out.BinaryData = *(*map[string][]byte)(unsafe.Pointer(&in.BinaryData))
|
||||||
return nil
|
return nil
|
||||||
@ -2654,6 +2655,7 @@ func Convert_v1_ConfigMap_To_core_ConfigMap(in *v1.ConfigMap, out *core.ConfigMa
|
|||||||
|
|
||||||
func autoConvert_core_ConfigMap_To_v1_ConfigMap(in *core.ConfigMap, out *v1.ConfigMap, s conversion.Scope) error {
|
func autoConvert_core_ConfigMap_To_v1_ConfigMap(in *core.ConfigMap, out *v1.ConfigMap, s conversion.Scope) error {
|
||||||
out.ObjectMeta = in.ObjectMeta
|
out.ObjectMeta = in.ObjectMeta
|
||||||
|
out.Immutable = (*bool)(unsafe.Pointer(in.Immutable))
|
||||||
out.Data = *(*map[string]string)(unsafe.Pointer(&in.Data))
|
out.Data = *(*map[string]string)(unsafe.Pointer(&in.Data))
|
||||||
out.BinaryData = *(*map[string][]byte)(unsafe.Pointer(&in.BinaryData))
|
out.BinaryData = *(*map[string][]byte)(unsafe.Pointer(&in.BinaryData))
|
||||||
return nil
|
return nil
|
||||||
@ -7006,6 +7008,7 @@ func Convert_core_ScopedResourceSelectorRequirement_To_v1_ScopedResourceSelector
|
|||||||
|
|
||||||
func autoConvert_v1_Secret_To_core_Secret(in *v1.Secret, out *core.Secret, s conversion.Scope) error {
|
func autoConvert_v1_Secret_To_core_Secret(in *v1.Secret, out *core.Secret, s conversion.Scope) error {
|
||||||
out.ObjectMeta = in.ObjectMeta
|
out.ObjectMeta = in.ObjectMeta
|
||||||
|
out.Immutable = (*bool)(unsafe.Pointer(in.Immutable))
|
||||||
out.Data = *(*map[string][]byte)(unsafe.Pointer(&in.Data))
|
out.Data = *(*map[string][]byte)(unsafe.Pointer(&in.Data))
|
||||||
// INFO: in.StringData opted out of conversion generation
|
// INFO: in.StringData opted out of conversion generation
|
||||||
out.Type = core.SecretType(in.Type)
|
out.Type = core.SecretType(in.Type)
|
||||||
@ -7014,6 +7017,7 @@ func autoConvert_v1_Secret_To_core_Secret(in *v1.Secret, out *core.Secret, s con
|
|||||||
|
|
||||||
func autoConvert_core_Secret_To_v1_Secret(in *core.Secret, out *v1.Secret, s conversion.Scope) error {
|
func autoConvert_core_Secret_To_v1_Secret(in *core.Secret, out *v1.Secret, s conversion.Scope) error {
|
||||||
out.ObjectMeta = in.ObjectMeta
|
out.ObjectMeta = in.ObjectMeta
|
||||||
|
out.Immutable = (*bool)(unsafe.Pointer(in.Immutable))
|
||||||
out.Data = *(*map[string][]byte)(unsafe.Pointer(&in.Data))
|
out.Data = *(*map[string][]byte)(unsafe.Pointer(&in.Data))
|
||||||
out.Type = v1.SecretType(in.Type)
|
out.Type = v1.SecretType(in.Type)
|
||||||
return nil
|
return nil
|
||||||
|
@ -5005,6 +5005,16 @@ func ValidateSecretUpdate(newSecret, oldSecret *core.Secret) field.ErrorList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
allErrs = append(allErrs, ValidateImmutableField(newSecret.Type, oldSecret.Type, field.NewPath("type"))...)
|
allErrs = append(allErrs, ValidateImmutableField(newSecret.Type, oldSecret.Type, field.NewPath("type"))...)
|
||||||
|
if oldSecret.Immutable != nil && *oldSecret.Immutable {
|
||||||
|
if !reflect.DeepEqual(newSecret.Immutable, oldSecret.Immutable) {
|
||||||
|
allErrs = append(allErrs, field.Forbidden(field.NewPath("immutable"), "field is immutable when `immutable` is set"))
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(newSecret.Data, oldSecret.Data) {
|
||||||
|
allErrs = append(allErrs, field.Forbidden(field.NewPath("data"), "field is immutable when `immutable` is set"))
|
||||||
|
}
|
||||||
|
// We don't validate StringData, as it was already converted back to Data
|
||||||
|
// before validation is happening.
|
||||||
|
}
|
||||||
|
|
||||||
allErrs = append(allErrs, ValidateSecret(newSecret)...)
|
allErrs = append(allErrs, ValidateSecret(newSecret)...)
|
||||||
return allErrs
|
return allErrs
|
||||||
@ -5051,8 +5061,20 @@ func ValidateConfigMap(cfg *core.ConfigMap) field.ErrorList {
|
|||||||
func ValidateConfigMapUpdate(newCfg, oldCfg *core.ConfigMap) field.ErrorList {
|
func ValidateConfigMapUpdate(newCfg, oldCfg *core.ConfigMap) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
allErrs = append(allErrs, ValidateObjectMetaUpdate(&newCfg.ObjectMeta, &oldCfg.ObjectMeta, field.NewPath("metadata"))...)
|
allErrs = append(allErrs, ValidateObjectMetaUpdate(&newCfg.ObjectMeta, &oldCfg.ObjectMeta, field.NewPath("metadata"))...)
|
||||||
allErrs = append(allErrs, ValidateConfigMap(newCfg)...)
|
|
||||||
|
|
||||||
|
if oldCfg.Immutable != nil && *oldCfg.Immutable {
|
||||||
|
if !reflect.DeepEqual(newCfg.Immutable, oldCfg.Immutable) {
|
||||||
|
allErrs = append(allErrs, field.Forbidden(field.NewPath("immutable"), "field is immutable when `immutable` is set"))
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(newCfg.Data, oldCfg.Data) {
|
||||||
|
allErrs = append(allErrs, field.Forbidden(field.NewPath("data"), "field is immutable when `immutable` is set"))
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(newCfg.BinaryData, oldCfg.BinaryData) {
|
||||||
|
allErrs = append(allErrs, field.Forbidden(field.NewPath("binaryData"), "field is immutable when `immutable` is set"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allErrs = append(allErrs, ValidateConfigMap(newCfg)...)
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13117,6 +13117,104 @@ func TestValidateSecret(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateSecretUpdate(t *testing.T) {
|
||||||
|
validSecret := func() core.Secret {
|
||||||
|
return core.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Namespace: "bar",
|
||||||
|
ResourceVersion: "20",
|
||||||
|
},
|
||||||
|
Data: map[string][]byte{
|
||||||
|
"data-1": []byte("bar"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
falseVal := false
|
||||||
|
trueVal := true
|
||||||
|
|
||||||
|
secret := validSecret()
|
||||||
|
immutableSecret := validSecret()
|
||||||
|
immutableSecret.Immutable = &trueVal
|
||||||
|
mutableSecret := validSecret()
|
||||||
|
mutableSecret.Immutable = &falseVal
|
||||||
|
|
||||||
|
secretWithData := validSecret()
|
||||||
|
secretWithData.Data["data-2"] = []byte("baz")
|
||||||
|
immutableSecretWithData := validSecret()
|
||||||
|
immutableSecretWithData.Immutable = &trueVal
|
||||||
|
immutableSecretWithData.Data["data-2"] = []byte("baz")
|
||||||
|
|
||||||
|
secretWithChangedData := validSecret()
|
||||||
|
secretWithChangedData.Data["data-1"] = []byte("foo")
|
||||||
|
immutableSecretWithChangedData := validSecret()
|
||||||
|
immutableSecretWithChangedData.Immutable = &trueVal
|
||||||
|
immutableSecretWithChangedData.Data["data-1"] = []byte("foo")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
oldSecret core.Secret
|
||||||
|
newSecret core.Secret
|
||||||
|
valid bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "mark secret immutable",
|
||||||
|
oldSecret: secret,
|
||||||
|
newSecret: immutableSecret,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "revert immutable secret",
|
||||||
|
oldSecret: immutableSecret,
|
||||||
|
newSecret: secret,
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "makr immutable secret mutable",
|
||||||
|
oldSecret: immutableSecret,
|
||||||
|
newSecret: mutableSecret,
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "add data in secret",
|
||||||
|
oldSecret: secret,
|
||||||
|
newSecret: secretWithData,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "add data in immutable secret",
|
||||||
|
oldSecret: immutableSecret,
|
||||||
|
newSecret: immutableSecretWithData,
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "change data in secret",
|
||||||
|
oldSecret: secret,
|
||||||
|
newSecret: secretWithChangedData,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "change data in immutable secret",
|
||||||
|
oldSecret: immutableSecret,
|
||||||
|
newSecret: immutableSecretWithChangedData,
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
errs := ValidateSecretUpdate(&tc.newSecret, &tc.oldSecret)
|
||||||
|
if tc.valid && len(errs) > 0 {
|
||||||
|
t.Errorf("Unexpected error: %v", errs)
|
||||||
|
}
|
||||||
|
if !tc.valid && len(errs) == 0 {
|
||||||
|
t.Errorf("Unexpected lack of error")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestValidateDockerConfigSecret(t *testing.T) {
|
func TestValidateDockerConfigSecret(t *testing.T) {
|
||||||
validDockerSecret := func() core.Secret {
|
validDockerSecret := func() core.Secret {
|
||||||
return core.Secret{
|
return core.Secret{
|
||||||
@ -13731,40 +13829,105 @@ func TestValidateConfigMapUpdate(t *testing.T) {
|
|||||||
Data: data,
|
Data: data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
validConfigMap := func() core.ConfigMap {
|
||||||
|
return newConfigMap("1", "validname", "validdns", map[string]string{"key": "value"})
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
falseVal := false
|
||||||
validConfigMap = newConfigMap("1", "validname", "validns", map[string]string{"key": "value"})
|
trueVal := true
|
||||||
noVersion = newConfigMap("", "validname", "validns", map[string]string{"key": "value"})
|
|
||||||
)
|
configMap := validConfigMap()
|
||||||
|
immutableConfigMap := validConfigMap()
|
||||||
|
immutableConfigMap.Immutable = &trueVal
|
||||||
|
mutableConfigMap := validConfigMap()
|
||||||
|
mutableConfigMap.Immutable = &falseVal
|
||||||
|
|
||||||
|
configMapWithData := validConfigMap()
|
||||||
|
configMapWithData.Data["key-2"] = "value-2"
|
||||||
|
immutableConfigMapWithData := validConfigMap()
|
||||||
|
immutableConfigMapWithData.Immutable = &trueVal
|
||||||
|
immutableConfigMapWithData.Data["key-2"] = "value-2"
|
||||||
|
|
||||||
|
configMapWithChangedData := validConfigMap()
|
||||||
|
configMapWithChangedData.Data["key"] = "foo"
|
||||||
|
immutableConfigMapWithChangedData := validConfigMap()
|
||||||
|
immutableConfigMapWithChangedData.Immutable = &trueVal
|
||||||
|
immutableConfigMapWithChangedData.Data["key"] = "foo"
|
||||||
|
|
||||||
|
noVersion := newConfigMap("", "validname", "validns", map[string]string{"key": "value"})
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
name string
|
name string
|
||||||
newCfg core.ConfigMap
|
newCfg core.ConfigMap
|
||||||
oldCfg core.ConfigMap
|
oldCfg core.ConfigMap
|
||||||
isValid bool
|
valid bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "valid",
|
name: "valid",
|
||||||
newCfg: validConfigMap,
|
newCfg: configMap,
|
||||||
oldCfg: validConfigMap,
|
oldCfg: configMap,
|
||||||
isValid: true,
|
valid: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid",
|
name: "invalid",
|
||||||
newCfg: noVersion,
|
newCfg: noVersion,
|
||||||
oldCfg: validConfigMap,
|
oldCfg: configMap,
|
||||||
isValid: false,
|
valid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mark configmap immutable",
|
||||||
|
oldCfg: configMap,
|
||||||
|
newCfg: immutableConfigMap,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "revert immutable configmap",
|
||||||
|
oldCfg: immutableConfigMap,
|
||||||
|
newCfg: configMap,
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mark immutable configmap mutable",
|
||||||
|
oldCfg: immutableConfigMap,
|
||||||
|
newCfg: mutableConfigMap,
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "add data in configmap",
|
||||||
|
oldCfg: configMap,
|
||||||
|
newCfg: configMapWithData,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "add data in immutable configmap",
|
||||||
|
oldCfg: immutableConfigMap,
|
||||||
|
newCfg: immutableConfigMapWithData,
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "change data in configmap",
|
||||||
|
oldCfg: configMap,
|
||||||
|
newCfg: configMapWithChangedData,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "change data in immutable configmap",
|
||||||
|
oldCfg: immutableConfigMap,
|
||||||
|
newCfg: immutableConfigMapWithChangedData,
|
||||||
|
valid: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
errs := ValidateConfigMapUpdate(&tc.newCfg, &tc.oldCfg)
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
if tc.isValid && len(errs) > 0 {
|
errs := ValidateConfigMapUpdate(&tc.newCfg, &tc.oldCfg)
|
||||||
t.Errorf("%v: unexpected error: %v", tc.name, errs)
|
if tc.valid && len(errs) > 0 {
|
||||||
}
|
t.Errorf("Unexpected error: %v", errs)
|
||||||
if !tc.isValid && len(errs) == 0 {
|
}
|
||||||
t.Errorf("%v: unexpected non-error", tc.name)
|
if !tc.valid && len(errs) == 0 {
|
||||||
}
|
t.Errorf("Unexpected lack of error")
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
pkg/apis/core/zz_generated.deepcopy.go
generated
10
pkg/apis/core/zz_generated.deepcopy.go
generated
@ -519,6 +519,11 @@ func (in *ConfigMap) DeepCopyInto(out *ConfigMap) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
if in.Immutable != nil {
|
||||||
|
in, out := &in.Immutable, &out.Immutable
|
||||||
|
*out = new(bool)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
if in.Data != nil {
|
if in.Data != nil {
|
||||||
in, out := &in.Data, &out.Data
|
in, out := &in.Data, &out.Data
|
||||||
*out = make(map[string]string, len(*in))
|
*out = make(map[string]string, len(*in))
|
||||||
@ -4660,6 +4665,11 @@ func (in *Secret) DeepCopyInto(out *Secret) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
if in.Immutable != nil {
|
||||||
|
in, out := &in.Immutable, &out.Immutable
|
||||||
|
*out = new(bool)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
if in.Data != nil {
|
if in.Data != nil {
|
||||||
in, out := &in.Data, &out.Data
|
in, out := &in.Data, &out.Data
|
||||||
*out = make(map[string][]byte, len(*in))
|
*out = make(map[string][]byte, len(*in))
|
||||||
|
@ -524,6 +524,12 @@ const (
|
|||||||
//
|
//
|
||||||
// Enables topology aware service routing
|
// Enables topology aware service routing
|
||||||
ServiceTopology featuregate.Feature = "ServiceTopology"
|
ServiceTopology featuregate.Feature = "ServiceTopology"
|
||||||
|
|
||||||
|
// owner: @wojtek-t
|
||||||
|
// alpha: v1.18
|
||||||
|
//
|
||||||
|
// Enables a feature to make secrets and configmaps data immutable.
|
||||||
|
ImmutableEphemeralVolumes featuregate.Feature = "ImmutableEphemeralVolumes"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -607,6 +613,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
|||||||
AllowInsecureBackendProxy: {Default: true, PreRelease: featuregate.Beta},
|
AllowInsecureBackendProxy: {Default: true, PreRelease: featuregate.Beta},
|
||||||
PodDisruptionBudget: {Default: true, PreRelease: featuregate.Beta},
|
PodDisruptionBudget: {Default: true, PreRelease: featuregate.Beta},
|
||||||
ServiceTopology: {Default: false, PreRelease: featuregate.Alpha},
|
ServiceTopology: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
|
ImmutableEphemeralVolumes: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
|
|
||||||
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
|
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
|
||||||
// unintentionally on either side:
|
// unintentionally on either side:
|
||||||
|
@ -17,6 +17,7 @@ go_library(
|
|||||||
"//pkg/api/legacyscheme:go_default_library",
|
"//pkg/api/legacyscheme:go_default_library",
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/apis/core/validation:go_default_library",
|
"//pkg/apis/core/validation:go_default_library",
|
||||||
|
"//pkg/features:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
@ -25,6 +26,7 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,9 +28,11 @@ 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
|
||||||
@ -54,7 +56,8 @@ func (strategy) NamespaceScoped() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
_ = obj.(*api.ConfigMap)
|
configMap := obj.(*api.ConfigMap)
|
||||||
|
dropDisabledFields(configMap, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
||||||
@ -72,12 +75,9 @@ func (strategy) AllowCreateOnUpdate() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (strategy) PrepareForUpdate(ctx context.Context, newObj, oldObj runtime.Object) {
|
func (strategy) PrepareForUpdate(ctx context.Context, newObj, oldObj runtime.Object) {
|
||||||
_ = oldObj.(*api.ConfigMap)
|
oldConfigMap := oldObj.(*api.ConfigMap)
|
||||||
_ = newObj.(*api.ConfigMap)
|
newConfigMap := newObj.(*api.ConfigMap)
|
||||||
}
|
dropDisabledFields(newConfigMap, oldConfigMap)
|
||||||
|
|
||||||
func (strategy) AllowUnconditionalUpdate() bool {
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (strategy) ValidateUpdate(ctx context.Context, newObj, oldObj runtime.Object) field.ErrorList {
|
func (strategy) ValidateUpdate(ctx context.Context, newObj, oldObj runtime.Object) field.ErrorList {
|
||||||
@ -86,6 +86,20 @@ 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) {
|
||||||
|
if !utilfeature.DefaultFeatureGate.Enabled(features.ImmutableEphemeralVolumes) && !isImmutableInUse(oldConfigMap) {
|
||||||
|
configMap.Immutable = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (strategy) AllowUnconditionalUpdate() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// GetAttrs returns labels and fields of a given object for filtering purposes.
|
// GetAttrs returns labels and fields of a given object for filtering purposes.
|
||||||
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
|
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
|
||||||
configMap, ok := obj.(*api.ConfigMap)
|
configMap, ok := obj.(*api.ConfigMap)
|
||||||
|
@ -17,6 +17,7 @@ go_library(
|
|||||||
"//pkg/api/legacyscheme:go_default_library",
|
"//pkg/api/legacyscheme:go_default_library",
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/apis/core/validation:go_default_library",
|
"//pkg/apis/core/validation:go_default_library",
|
||||||
|
"//pkg/features:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||||
@ -26,6 +27,7 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -29,9 +29,11 @@ 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
|
||||||
@ -53,6 +55,8 @@ func (strategy) NamespaceScoped() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
|
secret := obj.(*api.Secret)
|
||||||
|
dropDisabledFields(secret, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
||||||
@ -67,12 +71,25 @@ func (strategy) AllowCreateOnUpdate() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (strategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
func (strategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||||
|
newSecret := obj.(*api.Secret)
|
||||||
|
oldSecret := old.(*api.Secret)
|
||||||
|
dropDisabledFields(newSecret, oldSecret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||||
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) {
|
||||||
|
if !utilfeature.DefaultFeatureGate.Enabled(features.ImmutableEphemeralVolumes) && !isImmutableInUse(oldSecret) {
|
||||||
|
secret.Immutable = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (strategy) AllowUnconditionalUpdate() bool {
|
func (strategy) AllowUnconditionalUpdate() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
1778
staging/src/k8s.io/api/core/v1/generated.pb.go
generated
1778
staging/src/k8s.io/api/core/v1/generated.pb.go
generated
File diff suppressed because it is too large
Load Diff
@ -455,6 +455,14 @@ message ConfigMap {
|
|||||||
// +optional
|
// +optional
|
||||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
||||||
|
|
||||||
|
// Immutable, if set to true, ensures that data stored in the ConfigMap cannot
|
||||||
|
// be updated (only object metadata can be modified).
|
||||||
|
// If not set to true, the field can be modified at any time.
|
||||||
|
// Defaulted to nil.
|
||||||
|
// This is an alpha field enabled by ImmutableEphemeralVolumes feature gate.
|
||||||
|
// +optional
|
||||||
|
optional bool immutable = 4;
|
||||||
|
|
||||||
// Data contains the configuration data.
|
// Data contains the configuration data.
|
||||||
// Each key must consist of alphanumeric characters, '-', '_' or '.'.
|
// Each key must consist of alphanumeric characters, '-', '_' or '.'.
|
||||||
// Values with non-UTF-8 byte sequences must use the BinaryData field.
|
// Values with non-UTF-8 byte sequences must use the BinaryData field.
|
||||||
@ -4256,6 +4264,14 @@ message Secret {
|
|||||||
// +optional
|
// +optional
|
||||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
||||||
|
|
||||||
|
// Immutable, if set to true, ensures that data stored in the Secret cannot
|
||||||
|
// be updated (only object metadata can be modified).
|
||||||
|
// If not set to true, the field can be modified at any time.
|
||||||
|
// Defaulted to nil.
|
||||||
|
// This is an alpha field enabled by ImmutableEphemeralVolumes feature gate.
|
||||||
|
// +optional
|
||||||
|
optional bool immutable = 5;
|
||||||
|
|
||||||
// Data contains the secret data. Each key must consist of alphanumeric
|
// Data contains the secret data. Each key must consist of alphanumeric
|
||||||
// characters, '-', '_' or '.'. The serialized form of the secret data is a
|
// characters, '-', '_' or '.'. The serialized form of the secret data is a
|
||||||
// base64 encoded string, representing the arbitrary (possibly non-string)
|
// base64 encoded string, representing the arbitrary (possibly non-string)
|
||||||
|
@ -5424,6 +5424,14 @@ type Secret struct {
|
|||||||
// +optional
|
// +optional
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||||
|
|
||||||
|
// Immutable, if set to true, ensures that data stored in the Secret cannot
|
||||||
|
// be updated (only object metadata can be modified).
|
||||||
|
// If not set to true, the field can be modified at any time.
|
||||||
|
// Defaulted to nil.
|
||||||
|
// This is an alpha field enabled by ImmutableEphemeralVolumes feature gate.
|
||||||
|
// +optional
|
||||||
|
Immutable *bool `json:"immutable,omitempty" protobuf:"varint,5,opt,name=immutable"`
|
||||||
|
|
||||||
// Data contains the secret data. Each key must consist of alphanumeric
|
// Data contains the secret data. Each key must consist of alphanumeric
|
||||||
// characters, '-', '_' or '.'. The serialized form of the secret data is a
|
// characters, '-', '_' or '.'. The serialized form of the secret data is a
|
||||||
// base64 encoded string, representing the arbitrary (possibly non-string)
|
// base64 encoded string, representing the arbitrary (possibly non-string)
|
||||||
@ -5557,6 +5565,14 @@ type ConfigMap struct {
|
|||||||
// +optional
|
// +optional
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||||
|
|
||||||
|
// Immutable, if set to true, ensures that data stored in the ConfigMap cannot
|
||||||
|
// be updated (only object metadata can be modified).
|
||||||
|
// If not set to true, the field can be modified at any time.
|
||||||
|
// Defaulted to nil.
|
||||||
|
// This is an alpha field enabled by ImmutableEphemeralVolumes feature gate.
|
||||||
|
// +optional
|
||||||
|
Immutable *bool `json:"immutable,omitempty" protobuf:"varint,4,opt,name=immutable"`
|
||||||
|
|
||||||
// Data contains the configuration data.
|
// Data contains the configuration data.
|
||||||
// Each key must consist of alphanumeric characters, '-', '_' or '.'.
|
// Each key must consist of alphanumeric characters, '-', '_' or '.'.
|
||||||
// Values with non-UTF-8 byte sequences must use the BinaryData field.
|
// Values with non-UTF-8 byte sequences must use the BinaryData field.
|
||||||
|
@ -252,6 +252,7 @@ func (ComponentStatusList) SwaggerDoc() map[string]string {
|
|||||||
var map_ConfigMap = map[string]string{
|
var map_ConfigMap = map[string]string{
|
||||||
"": "ConfigMap holds configuration data for pods to consume.",
|
"": "ConfigMap holds configuration data for pods to consume.",
|
||||||
"metadata": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata",
|
"metadata": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata",
|
||||||
|
"immutable": "Immutable, if set to true, ensures that data stored in the ConfigMap cannot be updated (only object metadata can be modified). If not set to true, the field can be modified at any time. Defaulted to nil. This is an alpha field enabled by ImmutableEphemeralVolumes feature gate.",
|
||||||
"data": "Data contains the configuration data. Each key must consist of alphanumeric characters, '-', '_' or '.'. Values with non-UTF-8 byte sequences must use the BinaryData field. The keys stored in Data must not overlap with the keys in the BinaryData field, this is enforced during validation process.",
|
"data": "Data contains the configuration data. Each key must consist of alphanumeric characters, '-', '_' or '.'. Values with non-UTF-8 byte sequences must use the BinaryData field. The keys stored in Data must not overlap with the keys in the BinaryData field, this is enforced during validation process.",
|
||||||
"binaryData": "BinaryData contains the binary data. Each key must consist of alphanumeric characters, '-', '_' or '.'. BinaryData can contain byte sequences that are not in the UTF-8 range. The keys stored in BinaryData must not overlap with the ones in the Data field, this is enforced during validation process. Using this field will require 1.10+ apiserver and kubelet.",
|
"binaryData": "BinaryData contains the binary data. Each key must consist of alphanumeric characters, '-', '_' or '.'. BinaryData can contain byte sequences that are not in the UTF-8 range. The keys stored in BinaryData must not overlap with the ones in the Data field, this is enforced during validation process. Using this field will require 1.10+ apiserver and kubelet.",
|
||||||
}
|
}
|
||||||
@ -2015,6 +2016,7 @@ func (ScopedResourceSelectorRequirement) SwaggerDoc() map[string]string {
|
|||||||
var map_Secret = map[string]string{
|
var map_Secret = map[string]string{
|
||||||
"": "Secret holds secret data of a certain type. The total bytes of the values in the Data field must be less than MaxSecretSize bytes.",
|
"": "Secret holds secret data of a certain type. The total bytes of the values in the Data field must be less than MaxSecretSize bytes.",
|
||||||
"metadata": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata",
|
"metadata": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata",
|
||||||
|
"immutable": "Immutable, if set to true, ensures that data stored in the Secret cannot be updated (only object metadata can be modified). If not set to true, the field can be modified at any time. Defaulted to nil. This is an alpha field enabled by ImmutableEphemeralVolumes feature gate.",
|
||||||
"data": "Data contains the secret data. Each key must consist of alphanumeric characters, '-', '_' or '.'. The serialized form of the secret data is a base64 encoded string, representing the arbitrary (possibly non-string) data value here. Described in https://tools.ietf.org/html/rfc4648#section-4",
|
"data": "Data contains the secret data. Each key must consist of alphanumeric characters, '-', '_' or '.'. The serialized form of the secret data is a base64 encoded string, representing the arbitrary (possibly non-string) data value here. Described in https://tools.ietf.org/html/rfc4648#section-4",
|
||||||
"stringData": "stringData allows specifying non-binary secret data in string form. It is provided as a write-only convenience method. All keys and values are merged into the data field on write, overwriting any existing values. It is never output when reading from the API.",
|
"stringData": "stringData allows specifying non-binary secret data in string form. It is provided as a write-only convenience method. All keys and values are merged into the data field on write, overwriting any existing values. It is never output when reading from the API.",
|
||||||
"type": "Used to facilitate programmatic handling of secret data.",
|
"type": "Used to facilitate programmatic handling of secret data.",
|
||||||
|
@ -519,6 +519,11 @@ func (in *ConfigMap) DeepCopyInto(out *ConfigMap) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
if in.Immutable != nil {
|
||||||
|
in, out := &in.Immutable, &out.Immutable
|
||||||
|
*out = new(bool)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
if in.Data != nil {
|
if in.Data != nil {
|
||||||
in, out := &in.Data, &out.Data
|
in, out := &in.Data, &out.Data
|
||||||
*out = make(map[string]string, len(*in))
|
*out = make(map[string]string, len(*in))
|
||||||
@ -4663,6 +4668,11 @@ func (in *Secret) DeepCopyInto(out *Secret) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
if in.Immutable != nil {
|
||||||
|
in, out := &in.Immutable, &out.Immutable
|
||||||
|
*out = new(bool)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
if in.Data != nil {
|
if in.Data != nil {
|
||||||
in, out := &in.Data, &out.Data
|
in, out := &in.Data, &out.Data
|
||||||
*out = make(map[string][]byte, len(*in))
|
*out = make(map[string][]byte, len(*in))
|
||||||
|
@ -40,10 +40,11 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"immutable": false,
|
||||||
"data": {
|
"data": {
|
||||||
"19": "20"
|
"19": "20"
|
||||||
},
|
},
|
||||||
"binaryData": {
|
"binaryData": {
|
||||||
"21": "Dg=="
|
"21": "Hg=="
|
||||||
}
|
}
|
||||||
}
|
}
|
Binary file not shown.
@ -1,8 +1,9 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
binaryData:
|
binaryData:
|
||||||
"21": Dg==
|
"21": Hg==
|
||||||
data:
|
data:
|
||||||
"19": "20"
|
"19": "20"
|
||||||
|
immutable: false
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
|
@ -40,11 +40,12 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"immutable": false,
|
||||||
"data": {
|
"data": {
|
||||||
"19": "Hg=="
|
"19": "xw=="
|
||||||
},
|
},
|
||||||
"stringData": {
|
"stringData": {
|
||||||
"20": "21"
|
"20": "21"
|
||||||
},
|
},
|
||||||
"type": "r鯹)晿\u003co,c鮽ort昍řČ扷5ƗǸ"
|
"type": "鯹)晿\u003c"
|
||||||
}
|
}
|
Binary file not shown.
@ -1,6 +1,7 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
data:
|
data:
|
||||||
"19": Hg==
|
"19": xw==
|
||||||
|
immutable: false
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
@ -33,4 +34,4 @@ metadata:
|
|||||||
uid: "7"
|
uid: "7"
|
||||||
stringData:
|
stringData:
|
||||||
"20": "21"
|
"20": "21"
|
||||||
type: r鯹)晿<o,c鮽ort昍řČ扷5ƗǸ
|
type: 鯹)晿<
|
||||||
|
@ -90,7 +90,14 @@ func SecretHash(sec *v1.Secret) (string, error) {
|
|||||||
// Data, Kind, and Name are taken into account.
|
// Data, Kind, and Name are taken into account.
|
||||||
func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
|
func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
|
||||||
// json.Marshal sorts the keys in a stable order in the encoding
|
// json.Marshal sorts the keys in a stable order in the encoding
|
||||||
m := map[string]interface{}{"kind": "ConfigMap", "name": cm.Name, "data": cm.Data}
|
m := map[string]interface{}{
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"name": cm.Name,
|
||||||
|
"data": cm.Data,
|
||||||
|
}
|
||||||
|
if cm.Immutable != nil {
|
||||||
|
m["immutable"] = *cm.Immutable
|
||||||
|
}
|
||||||
if len(cm.BinaryData) > 0 {
|
if len(cm.BinaryData) > 0 {
|
||||||
m["binaryData"] = cm.BinaryData
|
m["binaryData"] = cm.BinaryData
|
||||||
}
|
}
|
||||||
@ -105,7 +112,16 @@ func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
|
|||||||
// Data, Kind, Name, and Type are taken into account.
|
// Data, Kind, Name, and Type are taken into account.
|
||||||
func encodeSecret(sec *v1.Secret) (string, error) {
|
func encodeSecret(sec *v1.Secret) (string, error) {
|
||||||
// json.Marshal sorts the keys in a stable order in the encoding
|
// json.Marshal sorts the keys in a stable order in the encoding
|
||||||
data, err := json.Marshal(map[string]interface{}{"kind": "Secret", "type": sec.Type, "name": sec.Name, "data": sec.Data})
|
m := map[string]interface{}{
|
||||||
|
"kind": "Secret",
|
||||||
|
"type": sec.Type,
|
||||||
|
"name": sec.Name,
|
||||||
|
"data": sec.Data,
|
||||||
|
}
|
||||||
|
if sec.Immutable != nil {
|
||||||
|
m["immutable"] = *sec.Immutable
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -178,8 +178,8 @@ not their metadata (e.g. the Data of a ConfigMap, but nothing in ObjectMeta).
|
|||||||
obj interface{}
|
obj interface{}
|
||||||
expect int
|
expect int
|
||||||
}{
|
}{
|
||||||
{"ConfigMap", v1.ConfigMap{}, 4},
|
{"ConfigMap", v1.ConfigMap{}, 5},
|
||||||
{"Secret", v1.Secret{}, 5},
|
{"Secret", v1.Secret{}, 6},
|
||||||
}
|
}
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
val := reflect.ValueOf(c.obj)
|
val := reflect.ValueOf(c.obj)
|
||||||
|
@ -56,7 +56,14 @@ func SecretHash(sec *v1.Secret) (string, error) {
|
|||||||
// Data, Kind, and Name are taken into account.
|
// Data, Kind, and Name are taken into account.
|
||||||
func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
|
func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
|
||||||
// json.Marshal sorts the keys in a stable order in the encoding
|
// json.Marshal sorts the keys in a stable order in the encoding
|
||||||
m := map[string]interface{}{"kind": "ConfigMap", "name": cm.Name, "data": cm.Data}
|
m := map[string]interface{}{
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"name": cm.Name,
|
||||||
|
"data": cm.Data,
|
||||||
|
}
|
||||||
|
if cm.Immutable != nil {
|
||||||
|
m["immutable"] = *cm.Immutable
|
||||||
|
}
|
||||||
if len(cm.BinaryData) > 0 {
|
if len(cm.BinaryData) > 0 {
|
||||||
m["binaryData"] = cm.BinaryData
|
m["binaryData"] = cm.BinaryData
|
||||||
}
|
}
|
||||||
@ -70,8 +77,17 @@ func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
|
|||||||
// encodeSecret encodes a Secret.
|
// encodeSecret encodes a Secret.
|
||||||
// Data, Kind, Name, and Type are taken into account.
|
// Data, Kind, Name, and Type are taken into account.
|
||||||
func encodeSecret(sec *v1.Secret) (string, error) {
|
func encodeSecret(sec *v1.Secret) (string, error) {
|
||||||
|
m := map[string]interface{}{
|
||||||
|
"kind": "Secret",
|
||||||
|
"type": sec.Type,
|
||||||
|
"name": sec.Name,
|
||||||
|
"data": sec.Data,
|
||||||
|
}
|
||||||
|
if sec.Immutable != nil {
|
||||||
|
m["immutable"] = *sec.Immutable
|
||||||
|
}
|
||||||
// json.Marshal sorts the keys in a stable order in the encoding
|
// json.Marshal sorts the keys in a stable order in the encoding
|
||||||
data, err := json.Marshal(map[string]interface{}{"kind": "Secret", "type": sec.Type, "name": sec.Name, "data": sec.Data})
|
data, err := json.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -164,8 +164,8 @@ not their metadata (e.g. the Data of a ConfigMap, but nothing in ObjectMeta).
|
|||||||
obj interface{}
|
obj interface{}
|
||||||
expect int
|
expect int
|
||||||
}{
|
}{
|
||||||
{"ConfigMap", v1.ConfigMap{}, 4},
|
{"ConfigMap", v1.ConfigMap{}, 5},
|
||||||
{"Secret", v1.Secret{}, 5},
|
{"Secret", v1.Secret{}, 6},
|
||||||
}
|
}
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
val := reflect.ValueOf(c.obj)
|
val := reflect.ValueOf(c.obj)
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/onsi/ginkgo"
|
"github.com/onsi/ginkgo"
|
||||||
"github.com/onsi/gomega"
|
"github.com/onsi/gomega"
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/uuid"
|
"k8s.io/apimachinery/pkg/util/uuid"
|
||||||
"k8s.io/kubernetes/test/e2e/framework"
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
@ -549,9 +550,55 @@ var _ = ginkgo.Describe("[sig-storage] ConfigMap", func() {
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
//The pod is in pending during volume creation until the configMap objects are available
|
// It should be forbidden to change data for configmaps marked as immutable, but
|
||||||
//or until mount the configMap volume times out. There is no configMap object defined for the pod, so it should return timout exception unless it is marked optional.
|
// allowed to modify its metadata independently of its state.
|
||||||
//Slow (~5 mins)
|
ginkgo.It("should be immutable if `immutable` field is set [Feature:ImmutableEphemeralVolume]", func() {
|
||||||
|
name := "immutable"
|
||||||
|
configMap := newConfigMap(f, name)
|
||||||
|
|
||||||
|
currentConfigMap, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(configMap)
|
||||||
|
framework.ExpectNoError(err, "Failed to create config map %q in namespace %q", configMap.Name, configMap.Namespace)
|
||||||
|
|
||||||
|
currentConfigMap.Data["data-4"] = "value-4"
|
||||||
|
currentConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(currentConfigMap)
|
||||||
|
framework.ExpectNoError(err, "Failed to update config map %q in namespace %q", configMap.Name, configMap.Namespace)
|
||||||
|
|
||||||
|
// Mark config map as immutable.
|
||||||
|
trueVal := true
|
||||||
|
currentConfigMap.Immutable = &trueVal
|
||||||
|
currentConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(currentConfigMap)
|
||||||
|
framework.ExpectNoError(err, "Failed to mark config map %q in namespace %q as immutable", configMap.Name, configMap.Namespace)
|
||||||
|
|
||||||
|
// Ensure data can't be changed now.
|
||||||
|
currentConfigMap.Data["data-5"] = "value-5"
|
||||||
|
_, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(currentConfigMap)
|
||||||
|
framework.ExpectEqual(apierrors.IsInvalid(err), true)
|
||||||
|
|
||||||
|
// Ensure config map can't be switched from immutable to mutable.
|
||||||
|
currentConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Get(name, metav1.GetOptions{})
|
||||||
|
framework.ExpectNoError(err, "Failed to get config map %q in namespace %q", configMap.Name, configMap.Namespace)
|
||||||
|
framework.ExpectEqual(*currentConfigMap.Immutable, true)
|
||||||
|
|
||||||
|
falseVal := false
|
||||||
|
currentConfigMap.Immutable = &falseVal
|
||||||
|
_, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(currentConfigMap)
|
||||||
|
framework.ExpectEqual(apierrors.IsInvalid(err), true)
|
||||||
|
|
||||||
|
// Ensure that metadata can be changed.
|
||||||
|
currentConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Get(name, metav1.GetOptions{})
|
||||||
|
framework.ExpectNoError(err, "Failed to get config map %q in namespace %q", configMap.Name, configMap.Namespace)
|
||||||
|
currentConfigMap.Labels = map[string]string{"label1": "value1"}
|
||||||
|
_, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(currentConfigMap)
|
||||||
|
framework.ExpectNoError(err, "Failed to update config map %q in namespace %q", configMap.Name, configMap.Namespace)
|
||||||
|
|
||||||
|
// Ensure that immutable config map can be deleted.
|
||||||
|
err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Delete(name, &metav1.DeleteOptions{})
|
||||||
|
framework.ExpectNoError(err, "Failed to delete config map %q in namespace %q", configMap.Name, configMap.Namespace)
|
||||||
|
})
|
||||||
|
|
||||||
|
// The pod is in pending during volume creation until the configMap objects are available
|
||||||
|
// or until mount the configMap volume times out. There is no configMap object defined for the pod, so it should return timout exception unless it is marked optional.
|
||||||
|
// Slow (~5 mins)
|
||||||
ginkgo.It("Should fail non-optional pod creation due to configMap object does not exist [Slow]", func() {
|
ginkgo.It("Should fail non-optional pod creation due to configMap object does not exist [Slow]", func() {
|
||||||
volumeMountPath := "/etc/configmap-volumes"
|
volumeMountPath := "/etc/configmap-volumes"
|
||||||
podName := "pod-configmaps-" + string(uuid.NewUUID())
|
podName := "pod-configmaps-" + string(uuid.NewUUID())
|
||||||
@ -559,9 +606,9 @@ var _ = ginkgo.Describe("[sig-storage] ConfigMap", func() {
|
|||||||
framework.ExpectError(err, "created pod %q with non-optional configMap in namespace %q", podName, f.Namespace.Name)
|
framework.ExpectError(err, "created pod %q with non-optional configMap in namespace %q", podName, f.Namespace.Name)
|
||||||
})
|
})
|
||||||
|
|
||||||
//ConfigMap object defined for the pod, If a key is specified which is not present in the ConfigMap,
|
// ConfigMap object defined for the pod, If a key is specified which is not present in the ConfigMap,
|
||||||
// the volume setup will error unless it is marked optional, during the pod creation.
|
// the volume setup will error unless it is marked optional, during the pod creation.
|
||||||
//Slow (~5 mins)
|
// Slow (~5 mins)
|
||||||
ginkgo.It("Should fail non-optional pod creation due to the key in the configMap object does not exist [Slow]", func() {
|
ginkgo.It("Should fail non-optional pod creation due to the key in the configMap object does not exist [Slow]", func() {
|
||||||
volumeMountPath := "/etc/configmap-volumes"
|
volumeMountPath := "/etc/configmap-volumes"
|
||||||
podName := "pod-configmaps-" + string(uuid.NewUUID())
|
podName := "pod-configmaps-" + string(uuid.NewUUID())
|
||||||
@ -754,7 +801,7 @@ func createNonOptionalConfigMapPod(f *framework.Framework, volumeMountPath, podN
|
|||||||
createContainerName := "createcm-volume-test"
|
createContainerName := "createcm-volume-test"
|
||||||
createVolumeName := "createcm-volume"
|
createVolumeName := "createcm-volume"
|
||||||
|
|
||||||
//creating a pod without configMap object created, by mentioning the configMap volume source's local reference name
|
// creating a pod without configMap object created, by mentioning the configMap volume source's local reference name
|
||||||
pod := &v1.Pod{
|
pod := &v1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
@ -810,7 +857,7 @@ func createNonOptionalConfigMapPodWithConfig(f *framework.Framework, volumeMount
|
|||||||
if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(configMap); err != nil {
|
if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(configMap); err != nil {
|
||||||
framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
|
framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
|
||||||
}
|
}
|
||||||
//creating a pod with configMap object, but with different key which is not present in configMap object.
|
// creating a pod with configMap object, but with different key which is not present in configMap object.
|
||||||
pod := &v1.Pod{
|
pod := &v1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/uuid"
|
"k8s.io/apimachinery/pkg/util/uuid"
|
||||||
"k8s.io/kubernetes/test/e2e/framework"
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
@ -368,9 +369,55 @@ 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"))
|
||||||
})
|
})
|
||||||
|
|
||||||
//The secret is in pending during volume creation until the secret objects are available
|
// It should be forbidden to change data for secrets marked as immutable, but
|
||||||
//or until mount the secret volume times out. There is no secret object defined for the pod, so it should return timout exception unless it is marked optional.
|
// allowed to modify its metadata independently of its state.
|
||||||
//Slow (~5 mins)
|
ginkgo.It("should be immutable if `immutable` field is set [Feature:ImmutableEphemeralVolume]", func() {
|
||||||
|
name := "immutable"
|
||||||
|
secret := secretForTest(f.Namespace.Name, name)
|
||||||
|
|
||||||
|
currentSecret, err := f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Create(secret)
|
||||||
|
framework.ExpectNoError(err, "Failed to create secret %q in namespace %q", secret.Name, secret.Namespace)
|
||||||
|
|
||||||
|
currentSecret.Data["data-4"] = []byte("value-4\n")
|
||||||
|
currentSecret, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Update(currentSecret)
|
||||||
|
framework.ExpectNoError(err, "Failed to update secret %q in namespace %q", secret.Name, secret.Namespace)
|
||||||
|
|
||||||
|
// Mark secret as immutable.
|
||||||
|
trueVal := true
|
||||||
|
currentSecret.Immutable = &trueVal
|
||||||
|
currentSecret, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Update(currentSecret)
|
||||||
|
framework.ExpectNoError(err, "Failed to mark secret %q in namespace %q as immutable", secret.Name, secret.Namespace)
|
||||||
|
|
||||||
|
// Ensure data can't be changed now.
|
||||||
|
currentSecret.Data["data-5"] = []byte("value-5\n")
|
||||||
|
_, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Update(currentSecret)
|
||||||
|
framework.ExpectEqual(apierrors.IsInvalid(err), true)
|
||||||
|
|
||||||
|
// Ensure secret can't be switched from immutable to mutable.
|
||||||
|
currentSecret, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Get(name, metav1.GetOptions{})
|
||||||
|
framework.ExpectNoError(err, "Failed to get secret %q in namespace %q", secret.Name, secret.Namespace)
|
||||||
|
framework.ExpectEqual(*currentSecret.Immutable, true)
|
||||||
|
|
||||||
|
falseVal := false
|
||||||
|
currentSecret.Immutable = &falseVal
|
||||||
|
_, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Update(currentSecret)
|
||||||
|
framework.ExpectEqual(apierrors.IsInvalid(err), true)
|
||||||
|
|
||||||
|
// Ensure that metadata can be changed.
|
||||||
|
currentSecret, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Get(name, metav1.GetOptions{})
|
||||||
|
framework.ExpectNoError(err, "Failed to get secret %q in namespace %q", secret.Name, secret.Namespace)
|
||||||
|
currentSecret.Labels = map[string]string{"label1": "value1"}
|
||||||
|
_, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Update(currentSecret)
|
||||||
|
framework.ExpectNoError(err, "Failed to update secret %q in namespace %q", secret.Name, secret.Namespace)
|
||||||
|
|
||||||
|
// Ensure that immutable secret can be deleted.
|
||||||
|
err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(name, &metav1.DeleteOptions{})
|
||||||
|
framework.ExpectNoError(err, "Failed to delete secret %q in namespace %q", secret.Name, secret.Namespace)
|
||||||
|
})
|
||||||
|
|
||||||
|
// The secret is in pending during volume creation until the secret objects are available
|
||||||
|
// or until mount the secret volume times out. There is no secret object defined for the pod, so it should return timout exception unless it is marked optional.
|
||||||
|
// Slow (~5 mins)
|
||||||
ginkgo.It("Should fail non-optional pod creation due to secret object does not exist [Slow]", func() {
|
ginkgo.It("Should fail non-optional pod creation due to secret object does not exist [Slow]", func() {
|
||||||
volumeMountPath := "/etc/secret-volumes"
|
volumeMountPath := "/etc/secret-volumes"
|
||||||
podName := "pod-secrets-" + string(uuid.NewUUID())
|
podName := "pod-secrets-" + string(uuid.NewUUID())
|
||||||
@ -378,9 +425,9 @@ var _ = ginkgo.Describe("[sig-storage] Secrets", func() {
|
|||||||
framework.ExpectError(err, "created pod %q with non-optional secret in namespace %q", podName, f.Namespace.Name)
|
framework.ExpectError(err, "created pod %q with non-optional secret in namespace %q", podName, f.Namespace.Name)
|
||||||
})
|
})
|
||||||
|
|
||||||
//Secret object defined for the pod, If a key is specified which is not present in the secret,
|
// Secret object defined for the pod, If a key is specified which is not present in the secret,
|
||||||
// the volume setup will error unless it is marked optional, during the pod creation.
|
// the volume setup will error unless it is marked optional, during the pod creation.
|
||||||
//Slow (~5 mins)
|
// Slow (~5 mins)
|
||||||
ginkgo.It("Should fail non-optional pod creation due to the key in the secret object does not exist [Slow]", func() {
|
ginkgo.It("Should fail non-optional pod creation due to the key in the secret object does not exist [Slow]", func() {
|
||||||
volumeMountPath := "/etc/secret-volumes"
|
volumeMountPath := "/etc/secret-volumes"
|
||||||
podName := "pod-secrets-" + string(uuid.NewUUID())
|
podName := "pod-secrets-" + string(uuid.NewUUID())
|
||||||
@ -548,7 +595,7 @@ func createNonOptionalSecretPod(f *framework.Framework, volumeMountPath, podName
|
|||||||
createContainerName := "creates-volume-test"
|
createContainerName := "creates-volume-test"
|
||||||
createVolumeName := "creates-volume"
|
createVolumeName := "creates-volume"
|
||||||
|
|
||||||
//creating a pod without secret object created, by mentioning the secret volume source reference name
|
// creating a pod without secret object created, by mentioning the secret volume source reference name
|
||||||
pod := &v1.Pod{
|
pod := &v1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
@ -603,7 +650,7 @@ func createNonOptionalSecretPodWithSecret(f *framework.Framework, volumeMountPat
|
|||||||
if secret, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Create(secret); err != nil {
|
if secret, err = f.ClientSet.CoreV1().Secrets(f.Namespace.Name).Create(secret); err != nil {
|
||||||
framework.Failf("unable to create test secret %s: %v", secret.Name, err)
|
framework.Failf("unable to create test secret %s: %v", secret.Name, err)
|
||||||
}
|
}
|
||||||
//creating a pod with secret object, with the key which is not present in secret object.
|
// creating a pod with secret object, with the key which is not present in secret object.
|
||||||
pod := &v1.Pod{
|
pod := &v1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
|
Loading…
Reference in New Issue
Block a user