Merge pull request #4653 from thockin/secret_fixups

Secrets fixups
This commit is contained in:
Tim Hockin 2015-02-23 13:49:19 -08:00
commit eed36455a7
21 changed files with 162 additions and 160 deletions

View File

@ -273,7 +273,8 @@ type Secret struct {
ObjectMeta
// Data contains the secret data. Each key must be a 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.
Data map[string][]byte `json:"data,omitempty"`
// Used to facilitate programatic handling of secret data.
@ -283,9 +284,9 @@ type Secret struct {
type SecretType string
const (
SecretTypeOpaque SecretType = "opaque" // Opaque (arbitrary data; default)
SecretTypeKubernetesAuthToken SecretType = "kubernetes-auth" // Kubernetes auth token
SecretTypeDockerRegistryAuth SecretType = "docker-reg-auth" // Docker registry auth
SecretTypeOpaque SecretType = "Opaque" // Opaque (arbitrary data; default)
SecretTypeKubernetesAuthToken SecretType = "KubernetesAuth" // Kubernetes auth token
SecretTypeDockerRegistryAuth SecretType = "DockerRegistryAuth" // Docker registry auth
// FUTURE: other type values
)
@ -398,8 +399,9 @@ To create a pod that uses an ssh key stored as a secret, we first need to create
}
```
**Note:** The values of secret data are encoded as base64-encoded strings. Newlines are not
valid within these strings and must be omitted.
**Note:** The serialized JSON and YAML values of secret data are encoded as
base64 strings. Newlines are not valid within these strings and must be
omitted.
Now we can create a pod which references the secret with the ssh key and consumes it in a volume:

View File

@ -181,7 +181,7 @@ func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
func(vs *api.VolumeSource, c fuzz.Continue) {
// Exactly one of the fields should be set.
//FIXME: the fuzz can still end up nil. What if fuzz allowed me to say that?
fuzzOneOf(c, &vs.HostPath, &vs.EmptyDir, &vs.GCEPersistentDisk, &vs.GitRepo)
fuzzOneOf(c, &vs.HostPath, &vs.EmptyDir, &vs.GCEPersistentDisk, &vs.GitRepo, &vs.Secret)
},
func(d *api.DNSPolicy, c fuzz.Continue) {
policies := []api.DNSPolicy{api.DNSClusterFirst, api.DNSDefault}
@ -235,6 +235,7 @@ func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
c.Fuzz(&s.ObjectMeta)
s.Type = api.SecretTypeOpaque
c.Fuzz(&s.Data)
},
func(ep *api.Endpoint, c fuzz.Continue) {
// TODO: If our API used a particular type for IP fields we could just catch that here.

View File

@ -170,24 +170,24 @@ type VolumeSource struct {
// machine. Most containers will NOT need this.
// TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not
// mount host directories as read/write.
HostPath *HostPath `json:"hostPath"`
HostPath *HostPathVolumeSource `json:"hostPath"`
// EmptyDir represents a temporary directory that shares a pod's lifetime.
EmptyDir *EmptyDir `json:"emptyDir"`
EmptyDir *EmptyDirVolumeSource `json:"emptyDir"`
// GCEPersistentDisk represents a GCE Disk resource that is attached to a
// kubelet's host machine and then exposed to the pod.
GCEPersistentDisk *GCEPersistentDisk `json:"persistentDisk"`
GCEPersistentDisk *GCEPersistentDiskVolumeSource `json:"persistentDisk"`
// GitRepo represents a git repository at a particular revision.
GitRepo *GitRepo `json:"gitRepo"`
GitRepo *GitRepoVolumeSource `json:"gitRepo"`
// Secret represents a secret that should populate this volume.
Secret *SecretSource `json:"secret"`
Secret *SecretVolumeSource `json:"secret"`
}
// HostPath represents bare host directory volume.
type HostPath struct {
// HostPathVolumeSource represents bare host directory volume.
type HostPathVolumeSource struct {
Path string `json:"path"`
}
type EmptyDir struct{}
type EmptyDirVolumeSource struct{}
// Protocol defines network protocols supported for things like conatiner ports.
type Protocol string
@ -199,12 +199,12 @@ const (
ProtocolUDP Protocol = "UDP"
)
// GCEPersistentDisk represents a Persistent Disk resource in Google Compute Engine.
// GCEPersistentDiskVolumeSource represents a Persistent Disk resource in Google Compute Engine.
//
// A GCE PD must exist and be formatted before mounting to a container.
// The disk must also be in the same GCE project and zone as the kubelet.
// A GCE PD can only be mounted as read/write once.
type GCEPersistentDisk struct {
type GCEPersistentDiskVolumeSource struct {
// Unique name of the PD resource. Used to identify the disk in GCE
PDName string `json:"pdName"`
// Required: Filesystem type to mount.
@ -221,8 +221,8 @@ type GCEPersistentDisk struct {
ReadOnly bool `json:"readOnly,omitempty"`
}
// GitRepo represents a volume that is pulled from git when the pod is created.
type GitRepo struct {
// GitRepoVolumeSource represents a volume that is pulled from git when the pod is created.
type GitRepoVolumeSource struct {
// Repository URL
Repository string `json:"repository"`
// Commit hash, this is optional
@ -230,11 +230,11 @@ type GitRepo struct {
// TODO: Consider credentials here.
}
// Adapts a Secret into a VolumeSource.
// SecretVolumeSource adapts a Secret into a VolumeSource.
//
// The contents of the target Secret's Data field will be presented in a volume
// as files using the keys in the Data field as the file names.
type SecretSource struct {
type SecretVolumeSource struct {
// Reference to a Secret
Target ObjectReference `json:"target"`
}
@ -1343,7 +1343,8 @@ type Secret struct {
ObjectMeta `json:"metadata,omitempty"`
// Data contains the secret data. Each key must be a 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.
Data map[string][]byte `json:"data,omitempty"`
// Used to facilitate programatic handling of secret data.
@ -1355,7 +1356,7 @@ const MaxSecretSize = 1 * 1024 * 1024
type SecretType string
const (
SecretTypeOpaque SecretType = "opaque" // Default; arbitrary user-defined data
SecretTypeOpaque SecretType = "Opaque" // Default; arbitrary user-defined data
)
type SecretList struct {

View File

@ -28,7 +28,7 @@ func init() {
func(obj *Volume) {
if util.AllPtrFieldsNil(&obj.Source) {
obj.Source = VolumeSource{
EmptyDir: &EmptyDir{},
EmptyDir: &EmptyDirVolumeSource{},
}
}
},

View File

@ -95,24 +95,24 @@ type VolumeSource struct {
// things that are allowed to see the host machine. Most containers will NOT need this.
// TODO(jonesdl) We need to restrict who can use host directory mounts and
// who can/can not mount host directories as read/write.
HostDir *HostPath `json:"hostDir" description:"pre-existing host file or directory; generally for privileged system daemons or other agents tied to the host"`
HostDir *HostPathVolumeSource `json:"hostDir" description:"pre-existing host file or directory; generally for privileged system daemons or other agents tied to the host"`
// EmptyDir represents a temporary directory that shares a pod's lifetime.
EmptyDir *EmptyDir `json:"emptyDir" description:"temporary directory that shares a pod's lifetime"`
EmptyDir *EmptyDirVolumeSource `json:"emptyDir" description:"temporary directory that shares a pod's lifetime"`
// GCEPersistentDisk represents a GCE Disk resource that is attached to a
// kubelet's host machine and then exposed to the pod.
GCEPersistentDisk *GCEPersistentDisk `json:"persistentDisk" description:"GCE disk resource attached to the host machine on demand"`
GCEPersistentDisk *GCEPersistentDiskVolumeSource `json:"persistentDisk" description:"GCE disk resource attached to the host machine on demand"`
// GitRepo represents a git repository at a particular revision.
GitRepo *GitRepo `json:"gitRepo" description:"git repository at a particular revision"`
GitRepo *GitRepoVolumeSource `json:"gitRepo" description:"git repository at a particular revision"`
// Secret represents a secret to populate the volume with
Secret *SecretSource `json:"secret" description:"secret to populate volume with"`
Secret *SecretVolumeSource `json:"secret" description:"secret to populate volume with"`
}
// HostPath represents bare host directory volume.
type HostPath struct {
// HostPathVolumeSource represents bare host directory volume.
type HostPathVolumeSource struct {
Path string `json:"path" description:"path of the directory on the host"`
}
type EmptyDir struct{}
type EmptyDirVolumeSource struct{}
// Protocol defines network protocols supported for things like conatiner ports.
type Protocol string
@ -124,12 +124,12 @@ const (
ProtocolUDP Protocol = "UDP"
)
// GCEPersistentDisk represents a Persistent Disk resource in Google Compute Engine.
// GCEPersistentDiskVolumeSource represents a Persistent Disk resource in Google Compute Engine.
//
// A GCE PD must exist and be formatted before mounting to a container.
// The disk must also be in the same GCE project and zone as the kubelet.
// A GCE PD can only be mounted as read/write once.
type GCEPersistentDisk struct {
type GCEPersistentDiskVolumeSource struct {
// Unique name of the PD resource. Used to identify the disk in GCE
PDName string `json:"pdName" description:"unique name of the PD resource in GCE"`
// Required: Filesystem type to mount.
@ -147,16 +147,16 @@ type GCEPersistentDisk struct {
ReadOnly bool `json:"readOnly,omitempty" description:"read-only if true, read-write otherwise (false or unspecified)"`
}
// GitRepo represents a volume that is pulled from git when the pod is created.
type GitRepo struct {
// GitRepoVolumeSource represents a volume that is pulled from git when the pod is created.
type GitRepoVolumeSource struct {
// Repository URL
Repository string `json:"repository" description:"repository URL"`
// Commit hash, this is optional
Revision string `json:"revision" description:"commit hash for the specified revision"`
}
// Adapts a Secret into a VolumeSource
type SecretSource struct {
// SecretVolumeSource adapts a Secret into a VolumeSource
type SecretVolumeSource struct {
// Reference to a Secret
Target ObjectReference `json:"target" description:"target is a reference to a secret"`
}
@ -1115,7 +1115,8 @@ type Secret struct {
TypeMeta `json:",inline"`
// Data contains the secret data. Each key must be a 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.
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"`
// Used to facilitate programatic handling of secret data.
@ -1127,7 +1128,7 @@ const MaxSecretSize = 1 * 1024 * 1024
type SecretType string
const (
SecretTypeOpaque SecretType = "opaque" // Default; arbitrary user-defined data
SecretTypeOpaque SecretType = "Opaque" // Default; arbitrary user-defined data
)
type SecretList struct {

View File

@ -30,7 +30,7 @@ func init() {
if util.AllPtrFieldsNil(&obj.Source) {
glog.Errorf("Defaulting volume source for %v", obj)
obj.Source = VolumeSource{
EmptyDir: &EmptyDir{},
EmptyDir: &EmptyDirVolumeSource{},
}
}
},

View File

@ -64,27 +64,27 @@ type VolumeSource struct {
// things that are allowed to see the host machine. Most containers will NOT need this.
// TODO(jonesdl) We need to restrict who can use host directory mounts and
// who can/can not mount host directories as read/write.
HostDir *HostPath `json:"hostDir" description:"pre-existing host file or directory; generally for privileged system daemons or other agents tied to the host"`
HostDir *HostPathVolumeSource `json:"hostDir" description:"pre-existing host file or directory; generally for privileged system daemons or other agents tied to the host"`
// EmptyDir represents a temporary directory that shares a pod's lifetime.
EmptyDir *EmptyDir `json:"emptyDir" description:"temporary directory that shares a pod's lifetime"`
EmptyDir *EmptyDirVolumeSource `json:"emptyDir" description:"temporary directory that shares a pod's lifetime"`
// A persistent disk that is mounted to the
// kubelet's host machine and then exposed to the pod.
GCEPersistentDisk *GCEPersistentDisk `json:"persistentDisk" description:"GCE disk resource attached to the host machine on demand"`
GCEPersistentDisk *GCEPersistentDiskVolumeSource `json:"persistentDisk" description:"GCE disk resource attached to the host machine on demand"`
// GitRepo represents a git repository at a particular revision.
GitRepo *GitRepo `json:"gitRepo" description:"git repository at a particular revision"`
GitRepo *GitRepoVolumeSource `json:"gitRepo" description:"git repository at a particular revision"`
// Secret is a secret to populate the volume with
Secret *SecretSource `json:"secret" description:"secret to populate volume"`
Secret *SecretVolumeSource `json:"secret" description:"secret to populate volume"`
}
// HostPath represents bare host directory volume.
type HostPath struct {
// HostPathVolumeSource represents bare host directory volume.
type HostPathVolumeSource struct {
Path string `json:"path" description:"path of the directory on the host"`
}
type EmptyDir struct{}
type EmptyDirVolumeSource struct{}
// Adapts a Secret into a VolumeSource
type SecretSource struct {
// SecretVolumeSource adapts a Secret into a VolumeSource
type SecretVolumeSource struct {
// Reference to a Secret
Target ObjectReference `json:"target" description:"target is a reference to a secret"`
}
@ -114,12 +114,12 @@ type ContainerPort struct {
HostIP string `json:"hostIP,omitempty" description:"host IP to bind the port to"`
}
// GCEPersistentDisk represents a Persistent Disk resource in Google Compute Engine.
// GCEPersistentDiskVolumeSource represents a Persistent Disk resource in Google Compute Engine.
//
// A GCE PD must exist and be formatted before mounting to a container.
// The disk must also be in the same GCE project and zone as the kubelet.
// A GCE PD can only be mounted as read/write once.
type GCEPersistentDisk struct {
type GCEPersistentDiskVolumeSource struct {
// Unique name of the PD resource. Used to identify the disk in GCE
PDName string `json:"pdName" description:"unique name of the PD resource in GCE"`
// Required: Filesystem type to mount.
@ -137,8 +137,8 @@ type GCEPersistentDisk struct {
ReadOnly bool `json:"readOnly,omitempty" description:"read-only if true, read-write otherwise (false or unspecified)"`
}
// GitRepo represents a volume that is pulled from git when the pod is created.
type GitRepo struct {
// GitRepoVolumeSource represents a volume that is pulled from git when the pod is created.
type GitRepoVolumeSource struct {
// Repository URL
Repository string `json:"repository" description:"repository URL"`
// Commit hash, this is optional
@ -1118,7 +1118,8 @@ type Secret struct {
TypeMeta `json:",inline"`
// Data contains the secret data. Each key must be a 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.
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"`
// Used to facilitate programatic handling of secret data.
@ -1130,7 +1131,7 @@ const MaxSecretSize = 1 * 1024 * 1024
type SecretType string
const (
SecretTypeOpaque SecretType = "opaque" // Default; arbitrary user-defined data
SecretTypeOpaque SecretType = "Opaque" // Default; arbitrary user-defined data
)
type SecretList struct {

View File

@ -28,7 +28,7 @@ func init() {
func(obj *Volume) {
if util.AllPtrFieldsNil(&obj.Source) {
obj.Source = VolumeSource{
EmptyDir: &EmptyDir{},
EmptyDir: &EmptyDirVolumeSource{},
}
}
},

View File

@ -189,24 +189,24 @@ type VolumeSource struct {
// to see the host machine. Most containers will NOT need this.
// TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not
// mount host directories as read/write.
HostPath *HostPath `json:"hostPath"`
HostPath *HostPathVolumeSource `json:"hostPath"`
// EmptyDir represents a temporary directory that shares a pod's lifetime.
EmptyDir *EmptyDir `json:"emptyDir"`
EmptyDir *EmptyDirVolumeSource `json:"emptyDir"`
// GCEPersistentDisk represents a GCE Disk resource that is attached to a
// kubelet's host machine and then exposed to the pod.
GCEPersistentDisk *GCEPersistentDisk `json:"gcePersistentDisk"`
GCEPersistentDisk *GCEPersistentDiskVolumeSource `json:"gcePersistentDisk"`
// GitRepo represents a git repository at a particular revision.
GitRepo *GitRepo `json:"gitRepo"`
GitRepo *GitRepoVolumeSource `json:"gitRepo"`
// Secret represents a secret that should populate this volume.
Secret *SecretSource `json:"secret"`
Secret *SecretVolumeSource `json:"secret"`
}
// HostPath represents bare host directory volume.
type HostPath struct {
// HostPathVolumeSource represents bare host directory volume.
type HostPathVolumeSource struct {
Path string `json:"path"`
}
type EmptyDir struct{}
type EmptyDirVolumeSource struct{}
// Protocol defines network protocols supported for things like conatiner ports.
type Protocol string
@ -218,12 +218,12 @@ const (
ProtocolUDP Protocol = "UDP"
)
// GCEPersistentDisk represents a Persistent Disk resource in Google Compute Engine.
// GCEPersistentDiskVolumeSource represents a Persistent Disk resource in Google Compute Engine.
//
// A GCE PD must exist and be formatted before mounting to a container.
// The disk must also be in the same GCE project and zone as the kubelet.
// A GCE PD can only be mounted as read/write once.
type GCEPersistentDisk struct {
type GCEPersistentDiskVolumeSource struct {
// Unique name of the PD resource. Used to identify the disk in GCE
PDName string `json:"pdName"`
// Required: Filesystem type to mount.
@ -240,16 +240,16 @@ type GCEPersistentDisk struct {
ReadOnly bool `json:"readOnly,omitempty"`
}
// GitRepo represents a volume that is pulled from git when the pod is created.
type GitRepo struct {
// GitRepoVolumeSource represents a volume that is pulled from git when the pod is created.
type GitRepoVolumeSource struct {
// Repository URL
Repository string `json:"repository"`
// Commit hash, this is optional
Revision string `json:"revision"`
}
// Adapts a Secret into a VolumeSource
type SecretSource struct {
// SecretVolumeSource adapts a Secret into a VolumeSource
type SecretVolumeSource struct {
// Reference to a Secret
Target ObjectReference `json:"target" description:"target is a reference to a secret"`
}
@ -1279,7 +1279,8 @@ type Secret struct {
ObjectMeta `json:"metadata,omitempty"`
// Data contains the secret data. Each key must be a 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.
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"`
// Used to facilitate programatic handling of secret data.
@ -1291,7 +1292,7 @@ const MaxSecretSize = 1 * 1024 * 1024
type SecretType string
const (
SecretTypeOpaque SecretType = "opaque" // Default; arbitrary user-defined data
SecretTypeOpaque SecretType = "Opaque" // Default; arbitrary user-defined data
)
type SecretList struct {

View File

@ -116,6 +116,28 @@ func ValidateNamespaceName(name string, prefix bool) (bool, string) {
return nameIsDNSSubdomain(name, prefix)
}
// ValidateLimitRangeName can be used to check whether the given limit range name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidateLimitRangeName(name string, prefix bool) (bool, string) {
return nameIsDNSSubdomain(name, prefix)
}
// ValidateResourceQuotaName can be used to check whether the given
// resource quota name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidateResourceQuotaName(name string, prefix bool) (bool, string) {
return nameIsDNSSubdomain(name, prefix)
}
// ValidateSecretName can be used to check whether the given secret name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidateSecretName(name string, prefix bool) (bool, string) {
return nameIsDNSSubdomain(name, prefix)
}
// nameIsDNSSubdomain is a ValidateNameFunc for names that must be a DNS subdomain.
func nameIsDNSSubdomain(name string, prefix bool) (bool, string) {
if prefix {
@ -233,7 +255,7 @@ func validateSource(source *api.VolumeSource) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
if source.HostPath != nil {
numVolumes++
allErrs = append(allErrs, validateHostPath(source.HostPath).Prefix("hostPath")...)
allErrs = append(allErrs, validateHostPathVolumeSource(source.HostPath).Prefix("hostPath")...)
}
if source.EmptyDir != nil {
numVolumes++
@ -241,15 +263,15 @@ func validateSource(source *api.VolumeSource) errs.ValidationErrorList {
}
if source.GitRepo != nil {
numVolumes++
allErrs = append(allErrs, validateGitRepo(source.GitRepo).Prefix("gitRepo")...)
allErrs = append(allErrs, validateGitRepoVolumeSource(source.GitRepo).Prefix("gitRepo")...)
}
if source.GCEPersistentDisk != nil {
numVolumes++
allErrs = append(allErrs, validateGCEPersistentDisk(source.GCEPersistentDisk).Prefix("persistentDisk")...)
allErrs = append(allErrs, validateGCEPersistentDiskVolumeSource(source.GCEPersistentDisk).Prefix("persistentDisk")...)
}
if source.Secret != nil {
numVolumes++
allErrs = append(allErrs, validateSecretSource(source.Secret).Prefix("secret")...)
allErrs = append(allErrs, validateSecretVolumeSource(source.Secret).Prefix("secret")...)
}
if numVolumes != 1 {
allErrs = append(allErrs, errs.NewFieldInvalid("", source, "exactly 1 volume type is required"))
@ -257,7 +279,7 @@ func validateSource(source *api.VolumeSource) errs.ValidationErrorList {
return allErrs
}
func validateHostPath(hostDir *api.HostPath) errs.ValidationErrorList {
func validateHostPathVolumeSource(hostDir *api.HostPathVolumeSource) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
if hostDir.Path == "" {
allErrs = append(allErrs, errs.NewFieldRequired("path", hostDir.Path))
@ -265,7 +287,7 @@ func validateHostPath(hostDir *api.HostPath) errs.ValidationErrorList {
return allErrs
}
func validateGitRepo(gitRepo *api.GitRepo) errs.ValidationErrorList {
func validateGitRepoVolumeSource(gitRepo *api.GitRepoVolumeSource) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
if gitRepo.Repository == "" {
allErrs = append(allErrs, errs.NewFieldRequired("repository", gitRepo.Repository))
@ -273,7 +295,7 @@ func validateGitRepo(gitRepo *api.GitRepo) errs.ValidationErrorList {
return allErrs
}
func validateGCEPersistentDisk(PD *api.GCEPersistentDisk) errs.ValidationErrorList {
func validateGCEPersistentDiskVolumeSource(PD *api.GCEPersistentDiskVolumeSource) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
if PD.PDName == "" {
allErrs = append(allErrs, errs.NewFieldRequired("pdName", PD.PDName))
@ -287,7 +309,7 @@ func validateGCEPersistentDisk(PD *api.GCEPersistentDisk) errs.ValidationErrorLi
return allErrs
}
func validateSecretSource(secretSource *api.SecretSource) errs.ValidationErrorList {
func validateSecretVolumeSource(secretSource *api.SecretVolumeSource) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
if secretSource.Target.Name == "" {
allErrs = append(allErrs, errs.NewFieldRequired("target.name", ""))
@ -815,16 +837,8 @@ func validateResourceName(value string, field string) errs.ValidationErrorList {
// ValidateLimitRange tests if required fields in the LimitRange are set.
func ValidateLimitRange(limitRange *api.LimitRange) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
if len(limitRange.Name) == 0 {
allErrs = append(allErrs, errs.NewFieldRequired("name", limitRange.Name))
} else if !util.IsDNSSubdomain(limitRange.Name) {
allErrs = append(allErrs, errs.NewFieldInvalid("name", limitRange.Name, dnsSubdomainErrorMsg))
}
if len(limitRange.Namespace) == 0 {
allErrs = append(allErrs, errs.NewFieldRequired("namespace", limitRange.Namespace))
} else if !util.IsDNSSubdomain(limitRange.Namespace) {
allErrs = append(allErrs, errs.NewFieldInvalid("namespace", limitRange.Namespace, dnsSubdomainErrorMsg))
}
allErrs = append(allErrs, ValidateObjectMeta(&limitRange.ObjectMeta, true, ValidateLimitRangeName).Prefix("metadata")...)
// ensure resource names are properly qualified per docs/resources.md
for i := range limitRange.Spec.Limits {
limit := limitRange.Spec.Limits[i]
@ -841,21 +855,12 @@ func ValidateLimitRange(limitRange *api.LimitRange) errs.ValidationErrorList {
// ValidateSecret tests if required fields in the Secret are set.
func ValidateSecret(secret *api.Secret) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
if len(secret.Name) == 0 {
allErrs = append(allErrs, errs.NewFieldRequired("name", secret.Name))
} else if !util.IsDNSSubdomain(secret.Name) {
allErrs = append(allErrs, errs.NewFieldInvalid("name", secret.Name, ""))
}
if len(secret.Namespace) == 0 {
allErrs = append(allErrs, errs.NewFieldRequired("namespace", secret.Namespace))
} else if !util.IsDNSSubdomain(secret.Namespace) {
allErrs = append(allErrs, errs.NewFieldInvalid("namespace", secret.Namespace, ""))
}
allErrs = append(allErrs, ValidateObjectMeta(&secret.ObjectMeta, true, ValidateSecretName).Prefix("metadata")...)
totalSize := 0
for key, value := range secret.Data {
if !util.IsDNSSubdomain(key) {
allErrs = append(allErrs, errs.NewFieldInvalid(fmt.Sprintf("data[%v]", key), key, cIdentifierErrorMsg))
allErrs = append(allErrs, errs.NewFieldInvalid(fmt.Sprintf("data[%s]", key), key, cIdentifierErrorMsg))
}
totalSize += len(value)
@ -893,16 +898,8 @@ func validateResourceRequirements(container *api.Container) errs.ValidationError
// ValidateResourceQuota tests if required fields in the ResourceQuota are set.
func ValidateResourceQuota(resourceQuota *api.ResourceQuota) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
if len(resourceQuota.Name) == 0 {
allErrs = append(allErrs, errs.NewFieldRequired("name", resourceQuota.Name))
} else if !util.IsDNSSubdomain(resourceQuota.Name) {
allErrs = append(allErrs, errs.NewFieldInvalid("name", resourceQuota.Name, dnsSubdomainErrorMsg))
}
if len(resourceQuota.Namespace) == 0 {
allErrs = append(allErrs, errs.NewFieldRequired("namespace", resourceQuota.Namespace))
} else if !util.IsDNSSubdomain(resourceQuota.Namespace) {
allErrs = append(allErrs, errs.NewFieldInvalid("namespace", resourceQuota.Namespace, dnsSubdomainErrorMsg))
}
allErrs = append(allErrs, ValidateObjectMeta(&resourceQuota.ObjectMeta, true, ValidateResourceQuotaName).Prefix("metadata")...)
for k := range resourceQuota.Spec.Hard {
allErrs = append(allErrs, validateResourceName(string(k), string(resourceQuota.TypeMeta.Kind))...)
}

View File

@ -147,13 +147,13 @@ func TestValidateAnnotations(t *testing.T) {
func TestValidateVolumes(t *testing.T) {
successCase := []api.Volume{
{Name: "abc", Source: api.VolumeSource{HostPath: &api.HostPath{"/mnt/path1"}}},
{Name: "123", Source: api.VolumeSource{HostPath: &api.HostPath{"/mnt/path2"}}},
{Name: "abc-123", Source: api.VolumeSource{HostPath: &api.HostPath{"/mnt/path3"}}},
{Name: "empty", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}},
{Name: "gcepd", Source: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDisk{"my-PD", "ext4", 1, false}}},
{Name: "gitrepo", Source: api.VolumeSource{GitRepo: &api.GitRepo{"my-repo", "hashstring"}}},
{Name: "secret", Source: api.VolumeSource{Secret: &api.SecretSource{api.ObjectReference{Namespace: api.NamespaceDefault, Name: "my-secret", Kind: "Secret"}}}},
{Name: "abc", Source: api.VolumeSource{HostPath: &api.HostPathVolumeSource{"/mnt/path1"}}},
{Name: "123", Source: api.VolumeSource{HostPath: &api.HostPathVolumeSource{"/mnt/path2"}}},
{Name: "abc-123", Source: api.VolumeSource{HostPath: &api.HostPathVolumeSource{"/mnt/path3"}}},
{Name: "empty", Source: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}},
{Name: "gcepd", Source: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{"my-PD", "ext4", 1, false}}},
{Name: "gitrepo", Source: api.VolumeSource{GitRepo: &api.GitRepoVolumeSource{"my-repo", "hashstring"}}},
{Name: "secret", Source: api.VolumeSource{Secret: &api.SecretVolumeSource{api.ObjectReference{Namespace: api.NamespaceDefault, Name: "my-secret", Kind: "Secret"}}}},
}
names, errs := validateVolumes(successCase)
if len(errs) != 0 {
@ -162,7 +162,7 @@ func TestValidateVolumes(t *testing.T) {
if len(names) != len(successCase) || !names.HasAll("abc", "123", "abc-123", "empty", "gcepd", "gitrepo", "secret") {
t.Errorf("wrong names result: %v", names)
}
emptyVS := api.VolumeSource{EmptyDir: &api.EmptyDir{}}
emptyVS := api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}
errorCases := map[string]struct {
V []api.Volume
T errors.ValidationErrorType
@ -573,8 +573,8 @@ func TestValidateManifest(t *testing.T) {
{
Version: "v1beta1",
ID: "abc",
Volumes: []api.Volume{{Name: "vol1", Source: api.VolumeSource{HostPath: &api.HostPath{"/mnt/vol1"}}},
{Name: "vol2", Source: api.VolumeSource{HostPath: &api.HostPath{"/mnt/vol2"}}}},
Volumes: []api.Volume{{Name: "vol1", Source: api.VolumeSource{HostPath: &api.HostPathVolumeSource{"/mnt/vol1"}}},
{Name: "vol2", Source: api.VolumeSource{HostPath: &api.HostPathVolumeSource{"/mnt/vol2"}}}},
Containers: []api.Container{
{
Name: "abc",
@ -624,7 +624,7 @@ func TestValidateManifest(t *testing.T) {
"invalid volume name": {
Version: "v1beta1",
ID: "abc",
Volumes: []api.Volume{{Name: "vol.1", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}}},
Volumes: []api.Volume{{Name: "vol.1", Source: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
DNSPolicy: api.DNSClusterFirst,
},
@ -647,14 +647,14 @@ func TestValidateManifest(t *testing.T) {
func TestValidatePodSpec(t *testing.T) {
successCases := []api.PodSpec{
{ // Populate basic fields, leave defaults for most.
Volumes: []api.Volume{{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}}},
Volumes: []api.Volume{{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
DNSPolicy: api.DNSClusterFirst,
},
{ // Populate all fields.
Volumes: []api.Volume{
{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}},
{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}},
},
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
@ -703,7 +703,7 @@ func TestValidatePod(t *testing.T) {
{ // Basic fields.
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: "ns"},
Spec: api.PodSpec{
Volumes: []api.Volume{{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}}},
Volumes: []api.Volume{{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
DNSPolicy: api.DNSClusterFirst,
@ -713,7 +713,7 @@ func TestValidatePod(t *testing.T) {
ObjectMeta: api.ObjectMeta{Name: "abc.123.do-re-mi", Namespace: "ns"},
Spec: api.PodSpec{
Volumes: []api.Volume{
{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}},
{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}},
},
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
@ -1005,7 +1005,7 @@ func TestValidateBoundPods(t *testing.T) {
{ // Basic fields.
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: "ns"},
Spec: api.PodSpec{
Volumes: []api.Volume{{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}}},
Volumes: []api.Volume{{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
DNSPolicy: api.DNSClusterFirst,
@ -1015,7 +1015,7 @@ func TestValidateBoundPods(t *testing.T) {
ObjectMeta: api.ObjectMeta{Name: "abc.123.do-re-mi", Namespace: "ns"},
Spec: api.PodSpec{
Volumes: []api.Volume{
{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}},
{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}},
},
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
@ -1477,7 +1477,7 @@ func TestValidateReplicationControllerUpdate(t *testing.T) {
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
DNSPolicy: api.DNSClusterFirst,
Volumes: []api.Volume{{Name: "gcepd", Source: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDisk{"my-PD", "ext4", 1, false}}}},
Volumes: []api.Volume{{Name: "gcepd", Source: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{"my-PD", "ext4", 1, false}}}},
},
},
}
@ -1635,7 +1635,7 @@ func TestValidateReplicationController(t *testing.T) {
Labels: validSelector,
},
Spec: api.PodSpec{
Volumes: []api.Volume{{Name: "gcepd", Source: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDisk{"my-PD", "ext4", 1, false}}}},
Volumes: []api.Volume{{Name: "gcepd", Source: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{"my-PD", "ext4", 1, false}}}},
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
DNSPolicy: api.DNSClusterFirst,
},
@ -2302,8 +2302,7 @@ func TestValidateLimitRange(t *testing.T) {
for i := range errs {
field := errs[i].(*errors.ValidationError).Field
detail := errs[i].(*errors.ValidationError).Detail
if field != "name" &&
field != "namespace" {
if field != "metadata.name" && field != "metadata.namespace" {
t.Errorf("%s: missing prefix for: %v", k, errs[i])
}
if detail != v.D {
@ -2370,8 +2369,7 @@ func TestValidateResourceQuota(t *testing.T) {
for i := range errs {
field := errs[i].(*errors.ValidationError).Field
detail := errs[i].(*errors.ValidationError).Detail
if field != "name" &&
field != "namespace" {
if field != "metadata.name" && field != "metadata.namespace" {
t.Errorf("%s: missing prefix for: %v", k, errs[i])
}
if detail != v.D {

View File

@ -89,11 +89,11 @@ func TestMerge(t *testing.T) {
Volumes: []api.Volume{
{
Name: "v1",
Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}},
Source: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}},
},
{
Name: "v2",
Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}},
Source: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}},
},
},
RestartPolicy: api.RestartPolicy{

View File

@ -47,7 +47,7 @@ func ExampleManifestAndPod(id string) (v1beta1.ContainerManifest, api.BoundPod)
{
Name: "host-dir",
Source: v1beta1.VolumeSource{
HostDir: &v1beta1.HostPath{"/dir/path"},
HostDir: &v1beta1.HostPathVolumeSource{"/dir/path"},
},
},
},
@ -68,7 +68,7 @@ func ExampleManifestAndPod(id string) (v1beta1.ContainerManifest, api.BoundPod)
{
Name: "host-dir",
Source: api.VolumeSource{
HostPath: &api.HostPath{"/dir/path"},
HostPath: &api.HostPathVolumeSource{"/dir/path"},
},
},
},

View File

@ -36,7 +36,7 @@ func TestCanSupport(t *testing.T) {
if plug.Name() != "kubernetes.io/empty-dir" {
t.Errorf("Wrong name: %s", plug.Name())
}
if !plug.CanSupport(&api.Volume{Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}}) {
if !plug.CanSupport(&api.Volume{Source: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}) {
t.Errorf("Expected true")
}
if !plug.CanSupport(&api.Volume{Source: api.VolumeSource{}}) {
@ -54,7 +54,7 @@ func TestPlugin(t *testing.T) {
}
spec := &api.Volume{
Name: "vol1",
Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}},
Source: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}},
}
builder, err := plug.NewBuilder(spec, types.UID("poduid"))
if err != nil {
@ -134,11 +134,11 @@ func TestPluginLegacy(t *testing.T) {
if plug.Name() != "empty" {
t.Errorf("Wrong name: %s", plug.Name())
}
if plug.CanSupport(&api.Volume{Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}}) {
if plug.CanSupport(&api.Volume{Source: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}) {
t.Errorf("Expected false")
}
if _, err := plug.NewBuilder(&api.Volume{Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}}, types.UID("poduid")); err == nil {
if _, err := plug.NewBuilder(&api.Volume{Source: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}, types.UID("poduid")); err == nil {
t.Errorf("Expected failiure")
}

View File

@ -37,7 +37,7 @@ func TestCanSupport(t *testing.T) {
if plug.Name() != "kubernetes.io/gce-pd" {
t.Errorf("Wrong name: %s", plug.Name())
}
if !plug.CanSupport(&api.Volume{Source: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDisk{}}}) {
if !plug.CanSupport(&api.Volume{Source: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{}}}) {
t.Errorf("Expected true")
}
}
@ -89,7 +89,7 @@ func TestPlugin(t *testing.T) {
spec := &api.Volume{
Name: "vol1",
Source: api.VolumeSource{
GCEPersistentDisk: &api.GCEPersistentDisk{
GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{
PDName: "pd",
FSType: "ext4",
},
@ -155,11 +155,11 @@ func TestPluginLegacy(t *testing.T) {
if plug.Name() != "gce-pd" {
t.Errorf("Wrong name: %s", plug.Name())
}
if plug.CanSupport(&api.Volume{Source: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDisk{}}}) {
if plug.CanSupport(&api.Volume{Source: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{}}}) {
t.Errorf("Expected false")
}
if _, err := plug.NewBuilder(&api.Volume{Source: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDisk{}}}, types.UID("poduid")); err == nil {
if _, err := plug.NewBuilder(&api.Volume{Source: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{}}}, types.UID("poduid")); err == nil {
t.Errorf("Expected failiure")
}

View File

@ -49,7 +49,7 @@ func TestCanSupport(t *testing.T) {
if plug.Name() != "kubernetes.io/git-repo" {
t.Errorf("Wrong name: %s", plug.Name())
}
if !plug.CanSupport(&api.Volume{Source: api.VolumeSource{GitRepo: &api.GitRepo{}}}) {
if !plug.CanSupport(&api.Volume{Source: api.VolumeSource{GitRepo: &api.GitRepoVolumeSource{}}}) {
t.Errorf("Expected true")
}
}
@ -111,7 +111,7 @@ func TestPlugin(t *testing.T) {
spec := &api.Volume{
Name: "vol1",
Source: api.VolumeSource{
GitRepo: &api.GitRepo{
GitRepo: &api.GitRepoVolumeSource{
Repository: "https://github.com/GoogleCloudPlatform/kubernetes.git",
Revision: "2a30ce65c5ab586b98916d83385c5983edd353a1",
},
@ -168,11 +168,11 @@ func TestPluginLegacy(t *testing.T) {
if plug.Name() != "git" {
t.Errorf("Wrong name: %s", plug.Name())
}
if plug.CanSupport(&api.Volume{Source: api.VolumeSource{GitRepo: &api.GitRepo{}}}) {
if plug.CanSupport(&api.Volume{Source: api.VolumeSource{GitRepo: &api.GitRepoVolumeSource{}}}) {
t.Errorf("Expected false")
}
if _, err := plug.NewBuilder(&api.Volume{Source: api.VolumeSource{GitRepo: &api.GitRepo{}}}, types.UID("poduid")); err == nil {
if _, err := plug.NewBuilder(&api.Volume{Source: api.VolumeSource{GitRepo: &api.GitRepoVolumeSource{}}}, types.UID("poduid")); err == nil {
t.Errorf("Expected failiure")
}

View File

@ -35,7 +35,7 @@ func TestCanSupport(t *testing.T) {
if plug.Name() != "kubernetes.io/host-path" {
t.Errorf("Wrong name: %s", plug.Name())
}
if !plug.CanSupport(&api.Volume{Source: api.VolumeSource{HostPath: &api.HostPath{}}}) {
if !plug.CanSupport(&api.Volume{Source: api.VolumeSource{HostPath: &api.HostPathVolumeSource{}}}) {
t.Errorf("Expected true")
}
if plug.CanSupport(&api.Volume{Source: api.VolumeSource{}}) {
@ -53,7 +53,7 @@ func TestPlugin(t *testing.T) {
}
spec := &api.Volume{
Name: "vol1",
Source: api.VolumeSource{HostPath: &api.HostPath{"/vol1"}},
Source: api.VolumeSource{HostPath: &api.HostPathVolumeSource{"/vol1"}},
}
builder, err := plug.NewBuilder(spec, types.UID("poduid"))
if err != nil {

View File

@ -50,7 +50,7 @@ func TestCanSupport(t *testing.T) {
if plugin.Name() != secretPluginName {
t.Errorf("Wrong name: %s", plugin.Name())
}
if !plugin.CanSupport(&api.Volume{Source: api.VolumeSource{Secret: &api.SecretSource{Target: api.ObjectReference{}}}}) {
if !plugin.CanSupport(&api.Volume{Source: api.VolumeSource{Secret: &api.SecretVolumeSource{Target: api.ObjectReference{}}}}) {
t.Errorf("Expected true")
}
}
@ -66,7 +66,7 @@ func TestPlugin(t *testing.T) {
volumeSpec := &api.Volume{
Name: testVolumeName,
Source: api.VolumeSource{
Secret: &api.SecretSource{
Secret: &api.SecretVolumeSource{
Target: api.ObjectReference{
Namespace: testNamespace,
Name: testName,

View File

@ -277,7 +277,7 @@ func TestDiskConflicts(t *testing.T) {
Volumes: []api.Volume{
{
Source: api.VolumeSource{
GCEPersistentDisk: &api.GCEPersistentDisk{
GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{
PDName: "foo",
},
},
@ -288,7 +288,7 @@ func TestDiskConflicts(t *testing.T) {
Volumes: []api.Volume{
{
Source: api.VolumeSource{
GCEPersistentDisk: &api.GCEPersistentDisk{
GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{
PDName: "bar",
},
},

View File

@ -82,7 +82,7 @@ var _ = Describe("Secrets", func() {
{
Name: volumeName,
Source: api.VolumeSource{
Secret: &api.SecretSource{
Secret: &api.SecretVolumeSource{
Target: api.ObjectReference{
Kind: "Secret",
Namespace: ns,

View File

@ -76,7 +76,7 @@ var _ = Describe("Services", func() {
{
Name: "results",
Source: api.VolumeSource{
EmptyDir: &api.EmptyDir{},
EmptyDir: &api.EmptyDirVolumeSource{},
},
},
},