Merge pull request #57938 from dims/add-binary-configmap

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Add binary configmap

Reviving code from https://github.com/kubernetes/kubernetes/pull/33549 submitted by @zreigz

**What this PR does / why we need it**:
Add support for binary files in ConfigMap

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes #32432

**Special notes for your reviewer**:

**Release note**:

```release-note
ConfigMap objects now support binary data via a new `binaryData` field. When using `kubectl create configmap --from-file`, files containing non-UTF8 data will be placed in this new field in order to preserve the non-UTF8 data. Use of this feature requires 1.10+ apiserver and kubelets.
```
This commit is contained in:
Kubernetes Submit Queue
2018-01-26 04:34:33 -08:00
committed by GitHub
20 changed files with 1254 additions and 752 deletions

View File

@@ -4356,10 +4356,22 @@ func ValidateConfigMap(cfg *core.ConfigMap) field.ErrorList {
for _, msg := range validation.IsConfigMapKey(key) {
allErrs = append(allErrs, field.Invalid(field.NewPath("data").Key(key), key, msg))
}
// check if we have a duplicate key in the other bag
if _, isValue := cfg.BinaryData[key]; isValue {
msg := "duplicate of key present in binaryData"
allErrs = append(allErrs, field.Invalid(field.NewPath("data").Key(key), key, msg))
}
totalSize += len(value)
}
for key, value := range cfg.BinaryData {
for _, msg := range validation.IsConfigMapKey(key) {
allErrs = append(allErrs, field.Invalid(field.NewPath("binaryData").Key(key), key, msg))
}
totalSize += len(value)
}
if totalSize > core.MaxSecretSize {
allErrs = append(allErrs, field.TooLong(field.NewPath("data"), "", core.MaxSecretSize))
// pass back "" to indicate that the error refers to the whole object.
allErrs = append(allErrs, field.TooLong(field.NewPath(""), cfg, core.MaxSecretSize))
}
return allErrs

View File

@@ -17,6 +17,7 @@ limitations under the License.
package validation
import (
"bytes"
"fmt"
"math"
"reflect"
@@ -11800,48 +11801,65 @@ func TestValidPodLogOptions(t *testing.T) {
}
func TestValidateConfigMap(t *testing.T) {
newConfigMap := func(name, namespace string, data map[string]string) core.ConfigMap {
newConfigMap := func(name, namespace string, data map[string]string, binaryData map[string][]byte) core.ConfigMap {
return core.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Data: data,
Data: data,
BinaryData: binaryData,
}
}
var (
validConfigMap = newConfigMap("validname", "validns", map[string]string{"key": "value"})
maxKeyLength = newConfigMap("validname", "validns", map[string]string{strings.Repeat("a", 253): "value"})
validConfigMap = newConfigMap("validname", "validns", map[string]string{"key": "value"}, map[string][]byte{"bin": []byte("value")})
maxKeyLength = newConfigMap("validname", "validns", map[string]string{strings.Repeat("a", 253): "value"}, nil)
emptyName = newConfigMap("", "validns", nil)
invalidName = newConfigMap("NoUppercaseOrSpecialCharsLike=Equals", "validns", nil)
emptyNs = newConfigMap("validname", "", nil)
invalidNs = newConfigMap("validname", "NoUppercaseOrSpecialCharsLike=Equals", nil)
invalidKey = newConfigMap("validname", "validns", map[string]string{"a*b": "value"})
leadingDotKey = newConfigMap("validname", "validns", map[string]string{".ab": "value"})
dotKey = newConfigMap("validname", "validns", map[string]string{".": "value"})
doubleDotKey = newConfigMap("validname", "validns", map[string]string{"..": "value"})
overMaxKeyLength = newConfigMap("validname", "validns", map[string]string{strings.Repeat("a", 254): "value"})
overMaxSize = newConfigMap("validname", "validns", map[string]string{"key": strings.Repeat("a", core.MaxSecretSize+1)})
emptyName = newConfigMap("", "validns", nil, nil)
invalidName = newConfigMap("NoUppercaseOrSpecialCharsLike=Equals", "validns", nil, nil)
emptyNs = newConfigMap("validname", "", nil, nil)
invalidNs = newConfigMap("validname", "NoUppercaseOrSpecialCharsLike=Equals", nil, nil)
invalidKey = newConfigMap("validname", "validns", map[string]string{"a*b": "value"}, nil)
leadingDotKey = newConfigMap("validname", "validns", map[string]string{".ab": "value"}, nil)
dotKey = newConfigMap("validname", "validns", map[string]string{".": "value"}, nil)
doubleDotKey = newConfigMap("validname", "validns", map[string]string{"..": "value"}, nil)
overMaxKeyLength = newConfigMap("validname", "validns", map[string]string{strings.Repeat("a", 254): "value"}, nil)
overMaxSize = newConfigMap("validname", "validns", map[string]string{"key": strings.Repeat("a", v1.MaxSecretSize+1)}, nil)
duplicatedKey = newConfigMap("validname", "validns", map[string]string{"key": "value1"}, map[string][]byte{"key": []byte("value2")})
binDataInvalidKey = newConfigMap("validname", "validns", nil, map[string][]byte{"a*b": []byte("value")})
binDataLeadingDotKey = newConfigMap("validname", "validns", nil, map[string][]byte{".ab": []byte("value")})
binDataDotKey = newConfigMap("validname", "validns", nil, map[string][]byte{".": []byte("value")})
binDataDoubleDotKey = newConfigMap("validname", "validns", nil, map[string][]byte{"..": []byte("value")})
binDataOverMaxKeyLength = newConfigMap("validname", "validns", nil, map[string][]byte{strings.Repeat("a", 254): []byte("value")})
binDataOverMaxSize = newConfigMap("validname", "validns", nil, map[string][]byte{"bin": bytes.Repeat([]byte("a"), v1.MaxSecretSize+1)})
binNonUtf8Value = newConfigMap("validname", "validns", nil, map[string][]byte{"key": {0, 0xFE, 0, 0xFF}})
)
tests := map[string]struct {
cfg core.ConfigMap
isValid bool
}{
"valid": {validConfigMap, true},
"max key length": {maxKeyLength, true},
"leading dot key": {leadingDotKey, true},
"empty name": {emptyName, false},
"invalid name": {invalidName, false},
"invalid key": {invalidKey, false},
"empty namespace": {emptyNs, false},
"invalid namespace": {invalidNs, false},
"dot key": {dotKey, false},
"double dot key": {doubleDotKey, false},
"over max key length": {overMaxKeyLength, false},
"over max size": {overMaxSize, false},
"valid": {validConfigMap, true},
"max key length": {maxKeyLength, true},
"leading dot key": {leadingDotKey, true},
"empty name": {emptyName, false},
"invalid name": {invalidName, false},
"invalid key": {invalidKey, false},
"empty namespace": {emptyNs, false},
"invalid namespace": {invalidNs, false},
"dot key": {dotKey, false},
"double dot key": {doubleDotKey, false},
"over max key length": {overMaxKeyLength, false},
"over max size": {overMaxSize, false},
"duplicated key": {duplicatedKey, false},
"binary data invalid key": {binDataInvalidKey, false},
"binary data leading dot key": {binDataLeadingDotKey, true},
"binary data dot key": {binDataDotKey, false},
"binary data double dot key": {binDataDoubleDotKey, false},
"binary data over max key length": {binDataOverMaxKeyLength, false},
"binary data max size": {binDataOverMaxSize, false},
"binary data non utf-8 bytes": {binNonUtf8Value, true},
}
for name, tc := range tests {