mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-04 09:49:50 +00:00
Merge pull request #7966 from deads2k/add-dockercfg-secrets
add dockercfg secret types
This commit is contained in:
commit
c27999da07
@ -1827,7 +1827,8 @@ type Secret struct {
|
|||||||
TypeMeta `json:",inline"`
|
TypeMeta `json:",inline"`
|
||||||
ObjectMeta `json:"metadata,omitempty"`
|
ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
// Data contains the secret data. Each key must be a valid DNS_SUBDOMAIN.
|
// Data contains the secret data. Each key must be a valid DNS_SUBDOMAIN
|
||||||
|
// or leading dot followed by valid DNS_SUBDOMAIN.
|
||||||
// The serialized form of the secret data is a base64 encoded string,
|
// The serialized form of the secret data is a base64 encoded string,
|
||||||
// representing the arbitrary (possibly non-string) data value here.
|
// representing the arbitrary (possibly non-string) data value here.
|
||||||
Data map[string][]byte `json:"data,omitempty"`
|
Data map[string][]byte `json:"data,omitempty"`
|
||||||
@ -1860,6 +1861,15 @@ const (
|
|||||||
ServiceAccountTokenKey = "token"
|
ServiceAccountTokenKey = "token"
|
||||||
// ServiceAccountKubeconfigKey is the key of the optional kubeconfig data for SecretTypeServiceAccountToken secrets
|
// ServiceAccountKubeconfigKey is the key of the optional kubeconfig data for SecretTypeServiceAccountToken secrets
|
||||||
ServiceAccountKubeconfigKey = "kubernetes.kubeconfig"
|
ServiceAccountKubeconfigKey = "kubernetes.kubeconfig"
|
||||||
|
|
||||||
|
// SecretTypeDockercfg contains a dockercfg file that follows the same format rules as ~/.dockercfg
|
||||||
|
//
|
||||||
|
// Required fields:
|
||||||
|
// - Secret.Data[".dockercfg"] - a serialized ~/.dockercfg file
|
||||||
|
SecretTypeDockercfg SecretType = "kubernetes.io/dockercfg"
|
||||||
|
|
||||||
|
// DockerConfigKey is the key of the required data for SecretTypeDockercfg secrets
|
||||||
|
DockerConfigKey = ".dockercfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SecretList struct {
|
type SecretList struct {
|
||||||
|
@ -1721,10 +1721,11 @@ type Secret struct {
|
|||||||
TypeMeta `json:",inline"`
|
TypeMeta `json:",inline"`
|
||||||
ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"`
|
ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"`
|
||||||
|
|
||||||
// Data contains the secret data. Each key must be a valid DNS_SUBDOMAIN.
|
// Data contains the secret data. Each key must be a valid DNS_SUBDOMAIN
|
||||||
|
// or leading dot followed by valid DNS_SUBDOMAIN.
|
||||||
// The serialized form of the secret data is a base64 encoded string,
|
// The serialized form of the secret data is a base64 encoded string,
|
||||||
// representing the arbitrary (possibly non-string) data value here.
|
// representing the arbitrary (possibly non-string) data value here.
|
||||||
Data map[string][]byte `json:"data,omitempty" description:"data contains the secret data. Each key must be a valid DNS_SUBDOMAIN. Each value must be a base64 encoded string"`
|
Data map[string][]byte `json:"data,omitempty" description:"data contains the secret data. Each key must be a valid DNS_SUBDOMAIN or leading dot followed by valid DNS_SUBDOMAIN. Each value must be a base64 encoded string as described in https://tools.ietf.org/html/rfc4648#section-4"`
|
||||||
|
|
||||||
// Used to facilitate programmatic handling of secret data.
|
// Used to facilitate programmatic handling of secret data.
|
||||||
Type SecretType `json:"type,omitempty" description:"type facilitates programmatic handling of secret data"`
|
Type SecretType `json:"type,omitempty" description:"type facilitates programmatic handling of secret data"`
|
||||||
@ -1752,6 +1753,17 @@ const (
|
|||||||
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
|
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
|
||||||
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
|
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
|
||||||
ServiceAccountTokenKey = "token"
|
ServiceAccountTokenKey = "token"
|
||||||
|
// ServiceAccountKubeconfigKey is the key of the optional kubeconfig data for SecretTypeServiceAccountToken secrets
|
||||||
|
ServiceAccountKubeconfigKey = "kubernetes.kubeconfig"
|
||||||
|
|
||||||
|
// SecretTypeDockercfg contains a dockercfg file that follows the same format rules as ~/.dockercfg
|
||||||
|
//
|
||||||
|
// Required fields:
|
||||||
|
// - Secret.Data[".dockercfg"] - a serialized ~/.dockercfg file
|
||||||
|
SecretTypeDockercfg SecretType = "kubernetes.io/dockercfg"
|
||||||
|
|
||||||
|
// DockerConfigKey is the key of the required data for SecretTypeDockercfg secrets
|
||||||
|
DockerConfigKey = ".dockercfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SecretList struct {
|
type SecretList struct {
|
||||||
|
@ -1625,10 +1625,11 @@ type NFSVolumeSource struct {
|
|||||||
type Secret struct {
|
type Secret struct {
|
||||||
TypeMeta `json:",inline"`
|
TypeMeta `json:",inline"`
|
||||||
|
|
||||||
// Data contains the secret data. Each key must be a valid DNS_SUBDOMAIN.
|
// Data contains the secret data. Each key must be a valid DNS_SUBDOMAIN
|
||||||
|
// or leading dot followed by valid DNS_SUBDOMAIN.
|
||||||
// The serialized form of the secret data is a base64 encoded string,
|
// The serialized form of the secret data is a base64 encoded string,
|
||||||
// representing the arbitrary (possibly non-string) data value here.
|
// representing the arbitrary (possibly non-string) data value here.
|
||||||
Data map[string][]byte `json:"data,omitempty" description:"data contains the secret data. Each key must be a valid DNS_SUBDOMAIN. Each value must be a base64 encoded string"`
|
Data map[string][]byte `json:"data,omitempty" description:"data contains the secret data. Each key must be a valid DNS_SUBDOMAIN or leading dot followed by valid DNS_SUBDOMAIN. Each value must be a base64 encoded string as described in https://tools.ietf.org/html/rfc4648#section-4"`
|
||||||
|
|
||||||
// Used to facilitate programmatic handling of secret data.
|
// Used to facilitate programmatic handling of secret data.
|
||||||
Type SecretType `json:"type,omitempty" description:"type facilitates programmatic handling of secret data"`
|
Type SecretType `json:"type,omitempty" description:"type facilitates programmatic handling of secret data"`
|
||||||
@ -1656,6 +1657,17 @@ const (
|
|||||||
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
|
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
|
||||||
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
|
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
|
||||||
ServiceAccountTokenKey = "token"
|
ServiceAccountTokenKey = "token"
|
||||||
|
// ServiceAccountKubeconfigKey is the key of the optional kubeconfig data for SecretTypeServiceAccountToken secrets
|
||||||
|
ServiceAccountKubeconfigKey = "kubernetes.kubeconfig"
|
||||||
|
|
||||||
|
// SecretTypeDockercfg contains a dockercfg file that follows the same format rules as ~/.dockercfg
|
||||||
|
//
|
||||||
|
// Required fields:
|
||||||
|
// - Secret.Data[".dockercfg"] - a serialized ~/.dockercfg file
|
||||||
|
SecretTypeDockercfg SecretType = "kubernetes.io/dockercfg"
|
||||||
|
|
||||||
|
// DockerConfigKey is the key of the required data for SecretTypeDockercfg secrets
|
||||||
|
DockerConfigKey = ".dockercfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SecretList struct {
|
type SecretList struct {
|
||||||
|
@ -1702,10 +1702,11 @@ type NFSVolumeSource struct {
|
|||||||
type Secret struct {
|
type Secret struct {
|
||||||
TypeMeta `json:",inline"`
|
TypeMeta `json:",inline"`
|
||||||
|
|
||||||
// Data contains the secret data. Each key must be a valid DNS_SUBDOMAIN.
|
// Data contains the secret data. Each key must be a valid DNS_SUBDOMAIN
|
||||||
|
// or leading dot followed by valid DNS_SUBDOMAIN.
|
||||||
// The serialized form of the secret data is a base64 encoded string,
|
// The serialized form of the secret data is a base64 encoded string,
|
||||||
// representing the arbitrary (possibly non-string) data value here.
|
// representing the arbitrary (possibly non-string) data value here.
|
||||||
Data map[string][]byte `json:"data,omitempty" description:"data contains the secret data. Each key must be a valid DNS_SUBDOMAIN. Each value must be a base64 encoded string"`
|
Data map[string][]byte `json:"data,omitempty" description:"data contains the secret data. Each key must be a valid DNS_SUBDOMAIN or leading dot followed by valid DNS_SUBDOMAIN. Each value must be a base64 encoded string as described in https://tools.ietf.org/html/rfc4648#section-4"`
|
||||||
|
|
||||||
// Used to facilitate programmatic handling of secret data.
|
// Used to facilitate programmatic handling of secret data.
|
||||||
Type SecretType `json:"type,omitempty" description:"type facilitates programmatic handling of secret data"`
|
Type SecretType `json:"type,omitempty" description:"type facilitates programmatic handling of secret data"`
|
||||||
@ -1733,6 +1734,17 @@ const (
|
|||||||
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
|
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
|
||||||
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
|
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
|
||||||
ServiceAccountTokenKey = "token"
|
ServiceAccountTokenKey = "token"
|
||||||
|
// ServiceAccountKubeconfigKey is the key of the optional kubeconfig data for SecretTypeServiceAccountToken secrets
|
||||||
|
ServiceAccountKubeconfigKey = "kubernetes.kubeconfig"
|
||||||
|
|
||||||
|
// SecretTypeDockercfg contains a dockercfg file that follows the same format rules as ~/.dockercfg
|
||||||
|
//
|
||||||
|
// Required fields:
|
||||||
|
// - Secret.Data[".dockercfg"] - a serialized ~/.dockercfg file
|
||||||
|
SecretTypeDockercfg SecretType = "kubernetes.io/dockercfg"
|
||||||
|
|
||||||
|
// DockerConfigKey is the key of the required data for SecretTypeDockercfg secrets
|
||||||
|
DockerConfigKey = ".dockercfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SecretList struct {
|
type SecretList struct {
|
||||||
|
@ -1721,10 +1721,11 @@ type Secret struct {
|
|||||||
TypeMeta `json:",inline"`
|
TypeMeta `json:",inline"`
|
||||||
ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"`
|
ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"`
|
||||||
|
|
||||||
// Data contains the secret data. Each key must be a valid DNS_SUBDOMAIN.
|
// Data contains the secret data. Each key must be a valid DNS_SUBDOMAIN
|
||||||
|
// or leading dot followed by valid DNS_SUBDOMAIN.
|
||||||
// The serialized form of the secret data is a base64 encoded string,
|
// The serialized form of the secret data is a base64 encoded string,
|
||||||
// representing the arbitrary (possibly non-string) data value here.
|
// representing the arbitrary (possibly non-string) data value here.
|
||||||
Data map[string][]byte `json:"data,omitempty" description:"data contains the secret data. Each key must be a valid DNS_SUBDOMAIN. Each value must be a base64 encoded string"`
|
Data map[string][]byte `json:"data,omitempty" description:"data contains the secret data. Each key must be a valid DNS_SUBDOMAIN or leading dot followed by valid DNS_SUBDOMAIN. Each value must be a base64 encoded string as described in https://tools.ietf.org/html/rfc4648#section-4"`
|
||||||
|
|
||||||
// Used to facilitate programmatic handling of secret data.
|
// Used to facilitate programmatic handling of secret data.
|
||||||
Type SecretType `json:"type,omitempty" description:"type facilitates programmatic handling of secret data"`
|
Type SecretType `json:"type,omitempty" description:"type facilitates programmatic handling of secret data"`
|
||||||
@ -1752,6 +1753,17 @@ const (
|
|||||||
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
|
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
|
||||||
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
|
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
|
||||||
ServiceAccountTokenKey = "token"
|
ServiceAccountTokenKey = "token"
|
||||||
|
// ServiceAccountKubeconfigKey is the key of the optional kubeconfig data for SecretTypeServiceAccountToken secrets
|
||||||
|
ServiceAccountKubeconfigKey = "kubernetes.kubeconfig"
|
||||||
|
|
||||||
|
// SecretTypeDockercfg contains a dockercfg file that follows the same format rules as ~/.dockercfg
|
||||||
|
//
|
||||||
|
// Required fields:
|
||||||
|
// - Secret.Data[".dockercfg"] - a serialized ~/.dockercfg file
|
||||||
|
SecretTypeDockercfg SecretType = "kubernetes.io/dockercfg"
|
||||||
|
|
||||||
|
// DockerConfigKey is the key of the required data for SecretTypeDockercfg secrets
|
||||||
|
DockerConfigKey = ".dockercfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SecretList struct {
|
type SecretList struct {
|
||||||
|
@ -17,9 +17,11 @@ limitations under the License.
|
|||||||
package validation
|
package validation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"path"
|
"path"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
@ -1257,6 +1259,16 @@ func ValidateServiceAccountUpdate(oldServiceAccount, newServiceAccount *api.Serv
|
|||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SecretKeyFmt string = "\\.?" + util.DNS1123LabelFmt + "(\\." + util.DNS1123LabelFmt + ")*"
|
||||||
|
|
||||||
|
var secretKeyRegexp = regexp.MustCompile("^" + SecretKeyFmt + "$")
|
||||||
|
|
||||||
|
// IsSecretKey tests for a string that conforms to the definition of a
|
||||||
|
// subdomain in DNS (RFC 1123), except that a leading dot is allowed
|
||||||
|
func IsSecretKey(value string) bool {
|
||||||
|
return len(value) <= util.DNS1123SubdomainMaxLength && secretKeyRegexp.MatchString(value)
|
||||||
|
}
|
||||||
|
|
||||||
// ValidateSecret tests if required fields in the Secret are set.
|
// ValidateSecret tests if required fields in the Secret are set.
|
||||||
func ValidateSecret(secret *api.Secret) errs.ValidationErrorList {
|
func ValidateSecret(secret *api.Secret) errs.ValidationErrorList {
|
||||||
allErrs := errs.ValidationErrorList{}
|
allErrs := errs.ValidationErrorList{}
|
||||||
@ -1264,8 +1276,8 @@ func ValidateSecret(secret *api.Secret) errs.ValidationErrorList {
|
|||||||
|
|
||||||
totalSize := 0
|
totalSize := 0
|
||||||
for key, value := range secret.Data {
|
for key, value := range secret.Data {
|
||||||
if !util.IsDNS1123Subdomain(key) {
|
if !IsSecretKey(key) {
|
||||||
allErrs = append(allErrs, errs.NewFieldInvalid(fmt.Sprintf("data[%s]", key), key, dnsSubdomainErrorMsg))
|
allErrs = append(allErrs, errs.NewFieldInvalid(fmt.Sprintf("data[%s]", key), key, fmt.Sprintf("must have at most %d characters and match regex %s", util.DNS1123SubdomainMaxLength, SecretKeyFmt)))
|
||||||
}
|
}
|
||||||
|
|
||||||
totalSize += len(value)
|
totalSize += len(value)
|
||||||
@ -1284,6 +1296,18 @@ func ValidateSecret(secret *api.Secret) errs.ValidationErrorList {
|
|||||||
}
|
}
|
||||||
case api.SecretTypeOpaque, "":
|
case api.SecretTypeOpaque, "":
|
||||||
// no-op
|
// no-op
|
||||||
|
case api.SecretTypeDockercfg:
|
||||||
|
dockercfgBytes, exists := secret.Data[api.DockerConfigKey]
|
||||||
|
if !exists {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldRequired(fmt.Sprintf("data[%s]", api.DockerConfigKey)))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure that the content is well-formed json.
|
||||||
|
if err := json.Unmarshal(dockercfgBytes, &map[string]interface{}{}); err != nil {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid(fmt.Sprintf("data[%s]", api.DockerConfigKey), "<secret contents redacted>", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
@ -2869,12 +2869,15 @@ func TestValidateSecret(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
emptyName = validSecret()
|
emptyName = validSecret()
|
||||||
invalidName = validSecret()
|
invalidName = validSecret()
|
||||||
emptyNs = validSecret()
|
emptyNs = validSecret()
|
||||||
invalidNs = validSecret()
|
invalidNs = validSecret()
|
||||||
overMaxSize = validSecret()
|
overMaxSize = validSecret()
|
||||||
invalidKey = validSecret()
|
invalidKey = validSecret()
|
||||||
|
leadingDotKey = validSecret()
|
||||||
|
dotKey = validSecret()
|
||||||
|
doubleDotKey = validSecret()
|
||||||
)
|
)
|
||||||
|
|
||||||
emptyName.Name = ""
|
emptyName.Name = ""
|
||||||
@ -2885,6 +2888,9 @@ func TestValidateSecret(t *testing.T) {
|
|||||||
"over": make([]byte, api.MaxSecretSize+1),
|
"over": make([]byte, api.MaxSecretSize+1),
|
||||||
}
|
}
|
||||||
invalidKey.Data["a..b"] = []byte("whoops")
|
invalidKey.Data["a..b"] = []byte("whoops")
|
||||||
|
leadingDotKey.Data[".key"] = []byte("bar")
|
||||||
|
dotKey.Data["."] = []byte("bar")
|
||||||
|
doubleDotKey.Data[".."] = []byte("bar")
|
||||||
|
|
||||||
// kubernetes.io/service-account-token secret validation
|
// kubernetes.io/service-account-token secret validation
|
||||||
validServiceAccountTokenSecret := func() api.Secret {
|
validServiceAccountTokenSecret := func() api.Secret {
|
||||||
@ -2916,18 +2922,62 @@ func TestValidateSecret(t *testing.T) {
|
|||||||
secret api.Secret
|
secret api.Secret
|
||||||
valid bool
|
valid bool
|
||||||
}{
|
}{
|
||||||
"valid": {validSecret(), true},
|
"valid": {validSecret(), true},
|
||||||
"empty name": {emptyName, false},
|
"empty name": {emptyName, false},
|
||||||
"invalid name": {invalidName, false},
|
"invalid name": {invalidName, false},
|
||||||
"empty namespace": {emptyNs, false},
|
"empty namespace": {emptyNs, false},
|
||||||
"invalid namespace": {invalidNs, false},
|
"invalid namespace": {invalidNs, false},
|
||||||
"over max size": {overMaxSize, false},
|
"over max size": {overMaxSize, false},
|
||||||
"invalid key": {invalidKey, false},
|
"invalid key": {invalidKey, false},
|
||||||
|
|
||||||
"valid service-account-token secret": {validServiceAccountTokenSecret(), true},
|
"valid service-account-token secret": {validServiceAccountTokenSecret(), true},
|
||||||
"empty service-account-token annotation": {emptyTokenAnnotation, false},
|
"empty service-account-token annotation": {emptyTokenAnnotation, false},
|
||||||
"missing service-account-token annotation": {missingTokenAnnotation, false},
|
"missing service-account-token annotation": {missingTokenAnnotation, false},
|
||||||
"missing service-account-token annotations": {missingTokenAnnotations, false},
|
"missing service-account-token annotations": {missingTokenAnnotations, false},
|
||||||
|
"leading dot key": {leadingDotKey, true},
|
||||||
|
"dot key": {dotKey, false},
|
||||||
|
"double dot key": {doubleDotKey, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range tests {
|
||||||
|
errs := ValidateSecret(&tc.secret)
|
||||||
|
if tc.valid && len(errs) > 0 {
|
||||||
|
t.Errorf("%v: Unexpected error: %v", name, errs)
|
||||||
|
}
|
||||||
|
if !tc.valid && len(errs) == 0 {
|
||||||
|
t.Errorf("%v: Unexpected non-error", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateDockerConfigSecret(t *testing.T) {
|
||||||
|
validDockerSecret := func() api.Secret {
|
||||||
|
return api.Secret{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
|
||||||
|
Type: api.SecretTypeDockercfg,
|
||||||
|
Data: map[string][]byte{
|
||||||
|
api.DockerConfigKey: []byte(`{"https://index.docker.io/v1/": {"auth": "Y2x1ZWRyb29sZXIwMDAxOnBhc3N3b3Jk","email": "fake@example.com"}}`),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
missingDockerConfigKey = validDockerSecret()
|
||||||
|
emptyDockerConfigKey = validDockerSecret()
|
||||||
|
invalidDockerConfigKey = validDockerSecret()
|
||||||
|
)
|
||||||
|
|
||||||
|
delete(missingDockerConfigKey.Data, api.DockerConfigKey)
|
||||||
|
emptyDockerConfigKey.Data[api.DockerConfigKey] = []byte("")
|
||||||
|
invalidDockerConfigKey.Data[api.DockerConfigKey] = []byte("bad")
|
||||||
|
|
||||||
|
tests := map[string]struct {
|
||||||
|
secret api.Secret
|
||||||
|
valid bool
|
||||||
|
}{
|
||||||
|
"valid": {validDockerSecret(), true},
|
||||||
|
"missing dockercfg": {missingDockerConfigKey, false},
|
||||||
|
"empty dockercfg": {emptyDockerConfigKey, false},
|
||||||
|
"invalid dockercfg": {invalidDockerConfigKey, false},
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, tc := range tests {
|
for name, tc := range tests {
|
||||||
|
@ -147,17 +147,17 @@ func readDockerConfigFileFromBytes(contents []byte) (cfg DockerConfig, err error
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// dockerConfigEntryWithAuth is used solely for deserializing the Auth field
|
// DockerConfigEntryWithAuth is used solely for deserializing the Auth field
|
||||||
// into a dockerConfigEntry during JSON deserialization.
|
// into a dockerConfigEntry during JSON deserialization.
|
||||||
type dockerConfigEntryWithAuth struct {
|
type DockerConfigEntryWithAuth struct {
|
||||||
Username string
|
Username string `json:"username,omitempty"`
|
||||||
Password string
|
Password string `json:"password,omitempty"`
|
||||||
Email string
|
Email string `json:"email,omitempty"`
|
||||||
Auth string
|
Auth string `json:"auth,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ident *DockerConfigEntry) UnmarshalJSON(data []byte) error {
|
func (ident *DockerConfigEntry) UnmarshalJSON(data []byte) error {
|
||||||
var tmp dockerConfigEntryWithAuth
|
var tmp DockerConfigEntryWithAuth
|
||||||
err := json.Unmarshal(data, &tmp)
|
err := json.Unmarshal(data, &tmp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -194,3 +194,16 @@ func decodeDockerConfigFieldAuth(field string) (username, password string, err e
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ident DockerConfigEntry) ConvertToDockerConfigCompatible() DockerConfigEntryWithAuth {
|
||||||
|
ret := DockerConfigEntryWithAuth{ident.Username, ident.Password, ident.Email, ""}
|
||||||
|
ret.Auth = encodeDockerConfigFieldAuth(ident.Username, ident.Password)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeDockerConfigFieldAuth(username, password string) string {
|
||||||
|
fieldValue := username + ":" + password
|
||||||
|
|
||||||
|
return base64.StdEncoding.EncodeToString([]byte(fieldValue))
|
||||||
|
}
|
||||||
|
@ -166,3 +166,33 @@ func TestDecodeDockerConfigFieldAuth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDockerConfigEntryJSONCompatibleEncode(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
input DockerConfigEntry
|
||||||
|
expect []byte
|
||||||
|
}{
|
||||||
|
// simple case, just decode the fields
|
||||||
|
{
|
||||||
|
expect: []byte(`{"username":"foo","password":"bar","email":"foo@example.com","auth":"Zm9vOmJhcg=="}`),
|
||||||
|
input: DockerConfigEntry{
|
||||||
|
Username: "foo",
|
||||||
|
Password: "bar",
|
||||||
|
Email: "foo@example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
toEncode := tt.input.ConvertToDockerConfigCompatible()
|
||||||
|
|
||||||
|
actual, err := json.Marshal(toEncode)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("case %d: unexpected error: %v", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(tt.expect) != string(actual) {
|
||||||
|
t.Errorf("case %d: expected %v, got %v", i, string(tt.expect), string(actual))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -63,7 +63,7 @@ func TestCreate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
&api.Secret{
|
&api.Secret{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "name"},
|
ObjectMeta: api.ObjectMeta{Name: "name"},
|
||||||
Data: map[string][]byte{".dotfile": []byte("")},
|
Data: map[string][]byte{"~.dotfile": []byte("")},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user