Merge pull request #7974 from deads2k/attach-pull-secrets-to-pods

Attach pull secrets to pods
This commit is contained in:
Daniel Smith
2015-05-19 10:26:39 -07:00
19 changed files with 342 additions and 26 deletions

View File

@@ -831,6 +831,10 @@ type PodSpec struct {
// used must be specified. // used must be specified.
// Optional: Default to false. // Optional: Default to false.
HostNetwork bool `json:"hostNetwork,omitempty"` HostNetwork bool `json:"hostNetwork,omitempty"`
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
// in the case of docker, only DockerConfig type secrets are honored.
ImagePullSecrets []LocalObjectReference `json:"imagePullSecrets,omitempty" description:"list of references to secrets in the same namespace available for pulling the container images"`
} }
// PodStatus represents information about the status of a pod. Status may trail the actual // PodStatus represents information about the status of a pod. Status may trail the actual
@@ -1630,6 +1634,12 @@ type ObjectReference struct {
FieldPath string `json:"fieldPath,omitempty"` FieldPath string `json:"fieldPath,omitempty"`
} }
// LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace.
type LocalObjectReference struct {
//TODO: Add other useful fields. apiVersion, kind, uid?
Name string
}
type SerializedReference struct { type SerializedReference struct {
TypeMeta `json:",inline"` TypeMeta `json:",inline"`
Reference ObjectReference `json:"reference,omitempty" description:"the reference to an object in the system"` Reference ObjectReference `json:"reference,omitempty" description:"the reference to an object in the system"`
@@ -1704,6 +1714,10 @@ type ContainerManifest struct {
// Required: Set DNS policy. // Required: Set DNS policy.
DNSPolicy DNSPolicy `json:"dnsPolicy"` DNSPolicy DNSPolicy `json:"dnsPolicy"`
HostNetwork bool `json:"hostNetwork,omitempty"` HostNetwork bool `json:"hostNetwork,omitempty"`
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
// in the case of docker, only DockerConfig type secrets are honored.
ImagePullSecrets []LocalObjectReference `json:"imagePullSecrets,omitempty" description:"list of references to secrets in the same namespace available for pulling the container images"`
} }
// ContainerManifestList is used to communicate container manifests to kubelet. // ContainerManifestList is used to communicate container manifests to kubelet.

View File

@@ -1599,6 +1599,22 @@ func convert_api_ListOptions_To_v1_ListOptions(in *newer.ListOptions, out *ListO
return nil return nil
} }
func convert_v1_LocalObjectReference_To_api_LocalObjectReference(in *LocalObjectReference, out *newer.LocalObjectReference, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*LocalObjectReference))(in)
}
out.Name = in.Name
return nil
}
func convert_api_LocalObjectReference_To_v1_LocalObjectReference(in *newer.LocalObjectReference, out *LocalObjectReference, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*newer.LocalObjectReference))(in)
}
out.Name = in.Name
return nil
}
func convert_v1_NFSVolumeSource_To_api_NFSVolumeSource(in *NFSVolumeSource, out *newer.NFSVolumeSource, s conversion.Scope) error { func convert_v1_NFSVolumeSource_To_api_NFSVolumeSource(in *NFSVolumeSource, out *newer.NFSVolumeSource, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*NFSVolumeSource))(in) defaulting.(func(*NFSVolumeSource))(in)
@@ -2856,6 +2872,16 @@ func convert_v1_PodSpec_To_api_PodSpec(in *PodSpec, out *newer.PodSpec, s conver
out.ServiceAccount = in.ServiceAccount out.ServiceAccount = in.ServiceAccount
out.Host = in.Host out.Host = in.Host
out.HostNetwork = in.HostNetwork out.HostNetwork = in.HostNetwork
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]newer.LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {
if err := convert_v1_LocalObjectReference_To_api_LocalObjectReference(&in.ImagePullSecrets[i], &out.ImagePullSecrets[i], s); err != nil {
return err
}
}
} else {
out.ImagePullSecrets = nil
}
return nil return nil
} }
@@ -2908,6 +2934,16 @@ func convert_api_PodSpec_To_v1_PodSpec(in *newer.PodSpec, out *PodSpec, s conver
out.ServiceAccount = in.ServiceAccount out.ServiceAccount = in.ServiceAccount
out.Host = in.Host out.Host = in.Host
out.HostNetwork = in.HostNetwork out.HostNetwork = in.HostNetwork
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {
if err := convert_api_LocalObjectReference_To_v1_LocalObjectReference(&in.ImagePullSecrets[i], &out.ImagePullSecrets[i], s); err != nil {
return err
}
}
} else {
out.ImagePullSecrets = nil
}
return nil return nil
} }
@@ -4518,6 +4554,7 @@ func init() {
convert_api_ListMeta_To_v1_ListMeta, convert_api_ListMeta_To_v1_ListMeta,
convert_api_ListOptions_To_v1_ListOptions, convert_api_ListOptions_To_v1_ListOptions,
convert_api_List_To_v1_List, convert_api_List_To_v1_List,
convert_api_LocalObjectReference_To_v1_LocalObjectReference,
convert_api_NFSVolumeSource_To_v1_NFSVolumeSource, convert_api_NFSVolumeSource_To_v1_NFSVolumeSource,
convert_api_NamespaceList_To_v1_NamespaceList, convert_api_NamespaceList_To_v1_NamespaceList,
convert_api_NamespaceSpec_To_v1_NamespaceSpec, convert_api_NamespaceSpec_To_v1_NamespaceSpec,
@@ -4628,6 +4665,7 @@ func init() {
convert_v1_ListMeta_To_api_ListMeta, convert_v1_ListMeta_To_api_ListMeta,
convert_v1_ListOptions_To_api_ListOptions, convert_v1_ListOptions_To_api_ListOptions,
convert_v1_List_To_api_List, convert_v1_List_To_api_List,
convert_v1_LocalObjectReference_To_api_LocalObjectReference,
convert_v1_NFSVolumeSource_To_api_NFSVolumeSource, convert_v1_NFSVolumeSource_To_api_NFSVolumeSource,
convert_v1_NamespaceList_To_api_NamespaceList, convert_v1_NamespaceList_To_api_NamespaceList,
convert_v1_NamespaceSpec_To_api_NamespaceSpec, convert_v1_NamespaceSpec_To_api_NamespaceSpec,

View File

@@ -825,6 +825,10 @@ type PodSpec struct {
// used must be specified. // used must be specified.
// Optional: Default to false. // Optional: Default to false.
HostNetwork bool `json:"hostNetwork,omitempty" description:"host networking requested for this pod"` HostNetwork bool `json:"hostNetwork,omitempty" description:"host networking requested for this pod"`
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
// in the case of docker, only DockerConfig type secrets are honored.
ImagePullSecrets []LocalObjectReference `json:"imagePullSecrets,omitempty" description:"list of references to secrets in the same namespace available for pulling the container images" patchStrategy:"merge" patchMergeKey:"name"`
} }
// PodStatus represents information about the status of a pod. Status may trail the actual // PodStatus represents information about the status of a pod. Status may trail the actual
@@ -1555,6 +1559,12 @@ type ObjectReference struct {
FieldPath string `json:"fieldPath,omitempty" description:"if referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]"` FieldPath string `json:"fieldPath,omitempty" description:"if referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]"`
} }
// LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace.
type LocalObjectReference struct {
//TODO: Add other useful fields. apiVersion, kind, uid?
Name string `json:"name,omitempty" description:"name of the referent"`
}
type SerializedReference struct { type SerializedReference struct {
TypeMeta `json:",inline"` TypeMeta `json:",inline"`
Reference ObjectReference `json:"reference,omitempty" description:"the reference to an object in the system"` Reference ObjectReference `json:"reference,omitempty" description:"the reference to an object in the system"`

View File

@@ -706,6 +706,9 @@ func addConversionFuncs() {
if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil { if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil {
return err return err
} }
if err := s.Convert(&in.ImagePullSecrets, &out.ImagePullSecrets, 0); err != nil {
return err
}
if in.TerminationGracePeriodSeconds != nil { if in.TerminationGracePeriodSeconds != nil {
out.TerminationGracePeriodSeconds = new(int64) out.TerminationGracePeriodSeconds = new(int64)
*out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds *out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds
@@ -729,6 +732,9 @@ func addConversionFuncs() {
if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil { if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil {
return err return err
} }
if err := s.Convert(&in.ImagePullSecrets, &out.ImagePullSecrets, 0); err != nil {
return err
}
if in.TerminationGracePeriodSeconds != nil { if in.TerminationGracePeriodSeconds != nil {
out.TerminationGracePeriodSeconds = new(int64) out.TerminationGracePeriodSeconds = new(int64)
*out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds *out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds

View File

@@ -75,6 +75,10 @@ type ContainerManifest struct {
// used must be specified. // used must be specified.
// Optional: Default to false. // Optional: Default to false.
HostNetwork bool `json:"hostNetwork,omitempty" description:"host networking requested for this pod"` HostNetwork bool `json:"hostNetwork,omitempty" description:"host networking requested for this pod"`
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
// in the case of docker, only DockerConfig type secrets are honored.
ImagePullSecrets []LocalObjectReference `json:"imagePullSecrets,omitempty" description:"list of references to secrets in the same namespace available for pulling the container images"`
} }
// ContainerManifestList is used to communicate container manifests to kubelet. // ContainerManifestList is used to communicate container manifests to kubelet.
@@ -1409,6 +1413,12 @@ type ObjectReference struct {
FieldPath string `json:"fieldPath,omitempty" description:"if referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]"` FieldPath string `json:"fieldPath,omitempty" description:"if referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]"`
} }
// LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace.
type LocalObjectReference struct {
//TODO: Add other useful fields. apiVersion, kind, uid?
Name string `json:"name,omitempty" description:"name of the referent"`
}
type SerializedReference struct { type SerializedReference struct {
TypeMeta `json:",inline"` TypeMeta `json:",inline"`
Reference ObjectReference `json:"reference,omitempty" description:"the reference to an object in the system"` Reference ObjectReference `json:"reference,omitempty" description:"the reference to an object in the system"`
@@ -1505,6 +1515,10 @@ type PodSpec struct {
// used must be specified. // used must be specified.
// Optional: Default to false. // Optional: Default to false.
HostNetwork bool `json:"hostNetwork,omitempty" description:"host networking requested for this pod"` HostNetwork bool `json:"hostNetwork,omitempty" description:"host networking requested for this pod"`
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
// in the case of docker, only DockerConfig type secrets are honored.
ImagePullSecrets []LocalObjectReference `json:"imagePullSecrets,omitempty" description:"list of references to secrets in the same namespace available for pulling the container images"`
} }
// List holds a list of objects, which may not be known by the server. // List holds a list of objects, which may not be known by the server.

View File

@@ -486,6 +486,9 @@ func addConversionFuncs() {
if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil { if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil {
return err return err
} }
if err := s.Convert(&in.ImagePullSecrets, &out.ImagePullSecrets, 0); err != nil {
return err
}
if in.TerminationGracePeriodSeconds != nil { if in.TerminationGracePeriodSeconds != nil {
out.TerminationGracePeriodSeconds = new(int64) out.TerminationGracePeriodSeconds = new(int64)
*out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds *out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds
@@ -509,6 +512,9 @@ func addConversionFuncs() {
if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil { if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil {
return err return err
} }
if err := s.Convert(&in.ImagePullSecrets, &out.ImagePullSecrets, 0); err != nil {
return err
}
if in.TerminationGracePeriodSeconds != nil { if in.TerminationGracePeriodSeconds != nil {
out.TerminationGracePeriodSeconds = new(int64) out.TerminationGracePeriodSeconds = new(int64)
*out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds *out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds

View File

@@ -1443,6 +1443,12 @@ type ObjectReference struct {
FieldPath string `json:"fieldPath,omitempty" description:"if referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]"` FieldPath string `json:"fieldPath,omitempty" description:"if referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]"`
} }
// LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace.
type LocalObjectReference struct {
//TODO: Add other useful fields. apiVersion, kind, uid?
Name string `json:"name,omitempty" description:"name of the referent"`
}
type SerializedReference struct { type SerializedReference struct {
TypeMeta `json:",inline"` TypeMeta `json:",inline"`
Reference ObjectReference `json:"reference,omitempty" description:"the reference to an object in the system"` Reference ObjectReference `json:"reference,omitempty" description:"the reference to an object in the system"`
@@ -1537,6 +1543,10 @@ type ContainerManifest struct {
// used must be specified. // used must be specified.
// Optional: Default to false. // Optional: Default to false.
HostNetwork bool `json:"hostNetwork,omitempty" description:"host networking requested for this pod"` HostNetwork bool `json:"hostNetwork,omitempty" description:"host networking requested for this pod"`
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
// in the case of docker, only DockerConfig type secrets are honored.
ImagePullSecrets []LocalObjectReference `json:"imagePullSecrets,omitempty" description:"list of references to secrets in the same namespace available for pulling the container images"`
} }
// ContainerManifestList is used to communicate container manifests to kubelet. // ContainerManifestList is used to communicate container manifests to kubelet.
@@ -1581,6 +1591,10 @@ type PodSpec struct {
// used must be specified. // used must be specified.
// Optional: Default to false. // Optional: Default to false.
HostNetwork bool `json:"hostNetwork,omitempty" description:"host networking requested for this pod"` HostNetwork bool `json:"hostNetwork,omitempty" description:"host networking requested for this pod"`
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
// in the case of docker, only DockerConfig type secrets are honored.
ImagePullSecrets []LocalObjectReference `json:"imagePullSecrets,omitempty" description:"list of references to secrets in the same namespace available for pulling the container images"`
} }
// List holds a list of objects, which may not be known by the server. // List holds a list of objects, which may not be known by the server.

View File

@@ -1413,6 +1413,22 @@ func convert_api_ListOptions_To_v1beta3_ListOptions(in *newer.ListOptions, out *
return nil return nil
} }
func convert_v1beta3_LocalObjectReference_To_api_LocalObjectReference(in *LocalObjectReference, out *newer.LocalObjectReference, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*LocalObjectReference))(in)
}
out.Name = in.Name
return nil
}
func convert_api_LocalObjectReference_To_v1beta3_LocalObjectReference(in *newer.LocalObjectReference, out *LocalObjectReference, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*newer.LocalObjectReference))(in)
}
out.Name = in.Name
return nil
}
func convert_v1beta3_NFSVolumeSource_To_api_NFSVolumeSource(in *NFSVolumeSource, out *newer.NFSVolumeSource, s conversion.Scope) error { func convert_v1beta3_NFSVolumeSource_To_api_NFSVolumeSource(in *NFSVolumeSource, out *newer.NFSVolumeSource, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*NFSVolumeSource))(in) defaulting.(func(*NFSVolumeSource))(in)
@@ -2670,6 +2686,16 @@ func convert_v1beta3_PodSpec_To_api_PodSpec(in *PodSpec, out *newer.PodSpec, s c
out.ServiceAccount = in.ServiceAccount out.ServiceAccount = in.ServiceAccount
out.Host = in.Host out.Host = in.Host
out.HostNetwork = in.HostNetwork out.HostNetwork = in.HostNetwork
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]newer.LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {
if err := convert_v1beta3_LocalObjectReference_To_api_LocalObjectReference(&in.ImagePullSecrets[i], &out.ImagePullSecrets[i], s); err != nil {
return err
}
}
} else {
out.ImagePullSecrets = nil
}
return nil return nil
} }
@@ -2722,6 +2748,16 @@ func convert_api_PodSpec_To_v1beta3_PodSpec(in *newer.PodSpec, out *PodSpec, s c
out.ServiceAccount = in.ServiceAccount out.ServiceAccount = in.ServiceAccount
out.Host = in.Host out.Host = in.Host
out.HostNetwork = in.HostNetwork out.HostNetwork = in.HostNetwork
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {
if err := convert_api_LocalObjectReference_To_v1beta3_LocalObjectReference(&in.ImagePullSecrets[i], &out.ImagePullSecrets[i], s); err != nil {
return err
}
}
} else {
out.ImagePullSecrets = nil
}
return nil return nil
} }
@@ -4331,6 +4367,7 @@ func init() {
convert_api_ListMeta_To_v1beta3_ListMeta, convert_api_ListMeta_To_v1beta3_ListMeta,
convert_api_ListOptions_To_v1beta3_ListOptions, convert_api_ListOptions_To_v1beta3_ListOptions,
convert_api_List_To_v1beta3_List, convert_api_List_To_v1beta3_List,
convert_api_LocalObjectReference_To_v1beta3_LocalObjectReference,
convert_api_NFSVolumeSource_To_v1beta3_NFSVolumeSource, convert_api_NFSVolumeSource_To_v1beta3_NFSVolumeSource,
convert_api_NamespaceList_To_v1beta3_NamespaceList, convert_api_NamespaceList_To_v1beta3_NamespaceList,
convert_api_NamespaceSpec_To_v1beta3_NamespaceSpec, convert_api_NamespaceSpec_To_v1beta3_NamespaceSpec,
@@ -4440,6 +4477,7 @@ func init() {
convert_v1beta3_ListMeta_To_api_ListMeta, convert_v1beta3_ListMeta_To_api_ListMeta,
convert_v1beta3_ListOptions_To_api_ListOptions, convert_v1beta3_ListOptions_To_api_ListOptions,
convert_v1beta3_List_To_api_List, convert_v1beta3_List_To_api_List,
convert_v1beta3_LocalObjectReference_To_api_LocalObjectReference,
convert_v1beta3_NFSVolumeSource_To_api_NFSVolumeSource, convert_v1beta3_NFSVolumeSource_To_api_NFSVolumeSource,
convert_v1beta3_NamespaceList_To_api_NamespaceList, convert_v1beta3_NamespaceList_To_api_NamespaceList,
convert_v1beta3_NamespaceSpec_To_api_NamespaceSpec, convert_v1beta3_NamespaceSpec_To_api_NamespaceSpec,

View File

@@ -829,6 +829,10 @@ type PodSpec struct {
// used must be specified. // used must be specified.
// Optional: Default to false. // Optional: Default to false.
HostNetwork bool `json:"hostNetwork,omitempty" description:"host networking requested for this pod"` HostNetwork bool `json:"hostNetwork,omitempty" description:"host networking requested for this pod"`
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
// in the case of docker, only DockerConfig type secrets are honored.
ImagePullSecrets []LocalObjectReference `json:"imagePullSecrets,omitempty" description:"list of references to secrets in the same namespace available for pulling the container images" patchStrategy:"merge" patchMergeKey:"name"`
} }
// PodStatus represents information about the status of a pod. Status may trail the actual // PodStatus represents information about the status of a pod. Status may trail the actual
@@ -1559,6 +1563,12 @@ type ObjectReference struct {
FieldPath string `json:"fieldPath,omitempty" description:"if referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]"` FieldPath string `json:"fieldPath,omitempty" description:"if referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]"`
} }
// LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace.
type LocalObjectReference struct {
//TODO: Add other useful fields. apiVersion, kind, uid?
Name string `json:"name,omitempty" description:"name of the referent"`
}
type SerializedReference struct { type SerializedReference struct {
TypeMeta `json:",inline"` TypeMeta `json:",inline"`
Reference ObjectReference `json:"reference,omitempty" description:"the reference to an object in the system"` Reference ObjectReference `json:"reference,omitempty" description:"the reference to an object in the system"`

View File

@@ -21,6 +21,7 @@ import (
"fmt" "fmt"
"net" "net"
"path" "path"
"reflect"
"regexp" "regexp"
"strings" "strings"
@@ -890,6 +891,20 @@ func validateHostNetwork(hostNetwork bool, containers []api.Container) errs.Vali
return allErrors return allErrors
} }
// validateImagePullSecrets checks to make sure the pull secrets are well formed. Right now, we only expect name to be set (it's the only field). If this ever changes
// and someone decides to set those fields, we'd like to know.
func validateImagePullSecrets(imagePullSecrets []api.LocalObjectReference) errs.ValidationErrorList {
allErrors := errs.ValidationErrorList{}
for i, currPullSecret := range imagePullSecrets {
strippedRef := api.LocalObjectReference{Name: currPullSecret.Name}
if !reflect.DeepEqual(strippedRef, currPullSecret) {
allErrors = append(allErrors, errs.NewFieldInvalid(fmt.Sprintf("[%d]", i), currPullSecret, "only name may be set"))
}
}
return allErrors
}
// ValidatePod tests if required fields in the pod are set. // ValidatePod tests if required fields in the pod are set.
func ValidatePod(pod *api.Pod) errs.ValidationErrorList { func ValidatePod(pod *api.Pod) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{} allErrs := errs.ValidationErrorList{}
@@ -913,6 +928,7 @@ func ValidatePodSpec(spec *api.PodSpec) errs.ValidationErrorList {
allErrs = append(allErrs, validateDNSPolicy(&spec.DNSPolicy).Prefix("dnsPolicy")...) allErrs = append(allErrs, validateDNSPolicy(&spec.DNSPolicy).Prefix("dnsPolicy")...)
allErrs = append(allErrs, ValidateLabels(spec.NodeSelector, "nodeSelector")...) allErrs = append(allErrs, ValidateLabels(spec.NodeSelector, "nodeSelector")...)
allErrs = append(allErrs, validateHostNetwork(spec.HostNetwork, spec.Containers).Prefix("hostNetwork")...) allErrs = append(allErrs, validateHostNetwork(spec.HostNetwork, spec.Containers).Prefix("hostNetwork")...)
allErrs = append(allErrs, validateImagePullSecrets(spec.ImagePullSecrets).Prefix("imagePullSecrets")...)
if spec.ActiveDeadlineSeconds != nil { if spec.ActiveDeadlineSeconds != nil {
if *spec.ActiveDeadlineSeconds <= 0 { if *spec.ActiveDeadlineSeconds <= 0 {

View File

@@ -147,9 +147,9 @@ 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 `json:"username,omitempty"` Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`
Email string `json:"email,omitempty"` Email string `json:"email,omitempty"`
@@ -157,7 +157,7 @@ type DockerConfigEntryWithAuth struct {
} }
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
@@ -195,8 +195,8 @@ func decodeDockerConfigFieldAuth(field string) (username, password string, err e
return return
} }
func (ident DockerConfigEntry) ConvertToDockerConfigCompatible() DockerConfigEntryWithAuth { func (ident DockerConfigEntry) ConvertToDockerConfigCompatible() dockerConfigEntryWithAuth {
ret := DockerConfigEntryWithAuth{ident.Username, ident.Password, ident.Email, ""} ret := dockerConfigEntryWithAuth{ident.Username, ident.Password, ident.Email, ""}
ret.Auth = encodeDockerConfigFieldAuth(ident.Username, ident.Password) ret.Auth = encodeDockerConfigFieldAuth(ident.Username, ident.Password)
return ret return ret

View File

@@ -17,6 +17,7 @@ limitations under the License.
package credentialprovider package credentialprovider
import ( import (
"encoding/json"
"net/url" "net/url"
"sort" "sort"
"strings" "strings"
@@ -24,6 +25,7 @@ import (
docker "github.com/fsouza/go-dockerclient" docker "github.com/fsouza/go-dockerclient"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
) )
@@ -164,3 +166,50 @@ type FakeKeyring struct {
func (f *FakeKeyring) Lookup(image string) ([]docker.AuthConfiguration, bool) { func (f *FakeKeyring) Lookup(image string) ([]docker.AuthConfiguration, bool) {
return f.auth, f.ok return f.auth, f.ok
} }
// unionDockerKeyring delegates to a set of keyrings.
type unionDockerKeyring struct {
keyrings []DockerKeyring
}
func (k *unionDockerKeyring) Lookup(image string) ([]docker.AuthConfiguration, bool) {
authConfigs := []docker.AuthConfiguration{}
for _, subKeyring := range k.keyrings {
if subKeyring == nil {
continue
}
currAuthResults, _ := subKeyring.Lookup(image)
authConfigs = append(authConfigs, currAuthResults...)
}
return authConfigs, (len(authConfigs) > 0)
}
// MakeDockerKeyring inspects the passedSecrets to see if they contain any DockerConfig secrets. If they do,
// then a DockerKeyring is built based on every hit and unioned with the defaultKeyring.
// If they do not, then the default keyring is returned
func MakeDockerKeyring(passedSecrets []api.Secret, defaultKeyring DockerKeyring) (DockerKeyring, error) {
passedCredentials := []DockerConfig{}
for _, passedSecret := range passedSecrets {
if dockercfgBytes, dockercfgExists := passedSecret.Data[api.DockerConfigKey]; (passedSecret.Type == api.SecretTypeDockercfg) && dockercfgExists && (len(dockercfgBytes) > 0) {
dockercfg := DockerConfig{}
if err := json.Unmarshal(dockercfgBytes, &dockercfg); err != nil {
return nil, err
}
passedCredentials = append(passedCredentials, dockercfg)
}
}
if len(passedCredentials) > 0 {
basicKeyring := &BasicDockerKeyring{}
for _, currCredentials := range passedCredentials {
basicKeyring.Add(currCredentials)
}
return &unionDockerKeyring{[]DockerKeyring{basicKeyring, defaultKeyring}}, nil
}
return defaultKeyring, nil
}

View File

@@ -52,7 +52,7 @@ type Runtime interface {
// exited and dead containers (used for garbage collection). // exited and dead containers (used for garbage collection).
GetPods(all bool) ([]*Pod, error) GetPods(all bool) ([]*Pod, error)
// Syncs the running pod into the desired pod. // Syncs the running pod into the desired pod.
SyncPod(pod *api.Pod, runningPod Pod, podStatus api.PodStatus) error SyncPod(pod *api.Pod, runningPod Pod, podStatus api.PodStatus, pullSecrets []api.Secret) error
// KillPod kills all the containers of a pod. // KillPod kills all the containers of a pod.
KillPod(pod Pod) error KillPod(pod Pod) error
// GetPodStatus retrieves the status of the pod, including the information of // GetPodStatus retrieves the status of the pod, including the information of
@@ -60,7 +60,7 @@ type Runtime interface {
GetPodStatus(*api.Pod) (*api.PodStatus, error) GetPodStatus(*api.Pod) (*api.PodStatus, error)
// PullImage pulls an image from the network to local storage using the supplied // PullImage pulls an image from the network to local storage using the supplied
// secrets if necessary. // secrets if necessary.
PullImage(image ImageSpec, secrets []api.Secret) error PullImage(image ImageSpec, pullSecrets []api.Secret) error
// IsImagePresent checks whether the container image is already in the local storage. // IsImagePresent checks whether the container image is already in the local storage.
IsImagePresent(image ImageSpec) (bool, error) IsImagePresent(image ImageSpec) (bool, error)
// Gets all images currently on the machine. // Gets all images currently on the machine.

View File

@@ -78,7 +78,7 @@ type KubeletContainerName struct {
// DockerPuller is an abstract interface for testability. It abstracts image pull operations. // DockerPuller is an abstract interface for testability. It abstracts image pull operations.
type DockerPuller interface { type DockerPuller interface {
Pull(image string) error Pull(image string, secrets []api.Secret) error
IsImagePresent(image string) (bool, error) IsImagePresent(image string) (bool, error)
} }
@@ -113,7 +113,7 @@ func parseImageName(image string) (string, string) {
return parsers.ParseRepositoryTag(image) return parsers.ParseRepositoryTag(image)
} }
func (p dockerPuller) Pull(image string) error { func (p dockerPuller) Pull(image string, secrets []api.Secret) error {
repoToPull, tag := parseImageName(image) repoToPull, tag := parseImageName(image)
// If no tag was specified, use the default "latest". // If no tag was specified, use the default "latest".
@@ -126,7 +126,12 @@ func (p dockerPuller) Pull(image string) error {
Tag: tag, Tag: tag,
} }
creds, haveCredentials := p.keyring.Lookup(repoToPull) keyring, err := credentialprovider.MakeDockerKeyring(secrets, p.keyring)
if err != nil {
return err
}
creds, haveCredentials := keyring.Lookup(repoToPull)
if !haveCredentials { if !haveCredentials {
glog.V(1).Infof("Pulling image %s without credentials", image) glog.V(1).Infof("Pulling image %s without credentials", image)
@@ -161,9 +166,9 @@ func (p dockerPuller) Pull(image string) error {
return utilerrors.NewAggregate(pullErrs) return utilerrors.NewAggregate(pullErrs)
} }
func (p throttledDockerPuller) Pull(image string) error { func (p throttledDockerPuller) Pull(image string, secrets []api.Secret) error {
if p.limiter.CanAccept() { if p.limiter.CanAccept() {
return p.puller.Pull(image) return p.puller.Pull(image, secrets)
} }
return fmt.Errorf("pull QPS exceeded.") return fmt.Errorf("pull QPS exceeded.")
} }

View File

@@ -17,6 +17,7 @@ limitations under the License.
package dockertools package dockertools
import ( import (
"encoding/json"
"fmt" "fmt"
"hash/adler32" "hash/adler32"
"reflect" "reflect"
@@ -220,7 +221,7 @@ func TestPullWithNoSecrets(t *testing.T) {
keyring: fakeKeyring, keyring: fakeKeyring,
} }
err := dp.Pull(test.imageName) err := dp.Pull(test.imageName, []api.Secret{})
if err != nil { if err != nil {
t.Errorf("unexpected non-nil err: %s", err) t.Errorf("unexpected non-nil err: %s", err)
continue continue
@@ -237,6 +238,73 @@ func TestPullWithNoSecrets(t *testing.T) {
} }
} }
func TestPullWithSecrets(t *testing.T) {
// auth value is equivalent to: "username":"passed-user","password":"passed-password"
dockerCfg := map[string]map[string]string{"index.docker.io/v1/": {"email": "passed-email", "auth": "cGFzc2VkLXVzZXI6cGFzc2VkLXBhc3N3b3Jk"}}
dockercfgContent, err := json.Marshal(dockerCfg)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
tests := map[string]struct {
imageName string
passedSecrets []api.Secret
builtInDockerConfig credentialprovider.DockerConfig
expectedPulls []string
}{
"no matching secrets": {
"ubuntu",
[]api.Secret{},
credentialprovider.DockerConfig(map[string]credentialprovider.DockerConfigEntry{}),
[]string{"ubuntu:latest using {}"},
},
"default keyring secrets": {
"ubuntu",
[]api.Secret{},
credentialprovider.DockerConfig(map[string]credentialprovider.DockerConfigEntry{"index.docker.io/v1/": {"built-in", "password", "email"}}),
[]string{`ubuntu:latest using {"username":"built-in","password":"password","email":"email"}`},
},
"default keyring secrets unused": {
"ubuntu",
[]api.Secret{},
credentialprovider.DockerConfig(map[string]credentialprovider.DockerConfigEntry{"extraneous": {"built-in", "password", "email"}}),
[]string{`ubuntu:latest using {}`},
},
"builtin keyring secrets, but use passed": {
"ubuntu",
[]api.Secret{{Type: api.SecretTypeDockercfg, Data: map[string][]byte{api.DockerConfigKey: dockercfgContent}}},
credentialprovider.DockerConfig(map[string]credentialprovider.DockerConfigEntry{"index.docker.io/v1/": {"built-in", "password", "email"}}),
[]string{`ubuntu:latest using {"username":"passed-user","password":"passed-password","email":"passed-email"}`},
},
}
for _, test := range tests {
builtInKeyRing := &credentialprovider.BasicDockerKeyring{}
builtInKeyRing.Add(test.builtInDockerConfig)
fakeClient := &FakeDockerClient{}
dp := dockerPuller{
client: fakeClient,
keyring: builtInKeyRing,
}
err := dp.Pull(test.imageName, test.passedSecrets)
if err != nil {
t.Errorf("unexpected non-nil err: %s", err)
continue
}
if e, a := 1, len(fakeClient.pulled); e != a {
t.Errorf("%s: expected 1 pulled image, got %d: %v", test.imageName, a, fakeClient.pulled)
continue
}
if e, a := test.expectedPulls, fakeClient.pulled; !reflect.DeepEqual(e, a) {
t.Errorf("%s: expected pull of %v, but got %v", test.imageName, e, a)
}
}
}
func TestDockerKeyringLookupFails(t *testing.T) { func TestDockerKeyringLookupFails(t *testing.T) {
fakeKeyring := &credentialprovider.FakeKeyring{} fakeKeyring := &credentialprovider.FakeKeyring{}
fakeClient := &FakeDockerClient{ fakeClient := &FakeDockerClient{
@@ -248,7 +316,7 @@ func TestDockerKeyringLookupFails(t *testing.T) {
keyring: fakeKeyring, keyring: fakeKeyring,
} }
err := dp.Pull("host/repository/image:version") err := dp.Pull("host/repository/image:version", []api.Secret{})
if err == nil { if err == nil {
t.Errorf("unexpected non-error") t.Errorf("unexpected non-error")
} }

View File

@@ -26,6 +26,7 @@ import (
"github.com/fsouza/go-dockerclient" "github.com/fsouza/go-dockerclient"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
) )
@@ -327,7 +328,7 @@ type FakeDockerPuller struct {
} }
// Pull records the image pull attempt, and optionally injects an error. // Pull records the image pull attempt, and optionally injects an error.
func (f *FakeDockerPuller) Pull(image string) (err error) { func (f *FakeDockerPuller) Pull(image string, secrets []api.Secret) (err error) {
f.Lock() f.Lock()
defer f.Unlock() defer f.Unlock()
f.ImagesPulled = append(f.ImagesPulled, image) f.ImagesPulled = append(f.ImagesPulled, image)

View File

@@ -774,7 +774,7 @@ func (dm *DockerManager) ListImages() ([]kubecontainer.Image, error) {
// TODO(vmarmol): Consider unexporting. // TODO(vmarmol): Consider unexporting.
// PullImage pulls an image from network to local storage. // PullImage pulls an image from network to local storage.
func (dm *DockerManager) PullImage(image kubecontainer.ImageSpec, secrets []api.Secret) error { func (dm *DockerManager) PullImage(image kubecontainer.ImageSpec, secrets []api.Secret) error {
return dm.Puller.Pull(image.Image) return dm.Puller.Pull(image.Image, secrets)
} }
// IsImagePresent checks whether the container image is already in the local storage. // IsImagePresent checks whether the container image is already in the local storage.
@@ -1264,8 +1264,7 @@ func (dm *DockerManager) createPodInfraContainer(pod *api.Pod) (kubeletTypes.Doc
return "", err return "", err
} }
if !ok { if !ok {
// TODO get the pull secrets from the container's ImageSpec and the pod's service account if err := dm.PullImage(spec, nil /* no pod secrets for the infra container */); err != nil {
if err := dm.PullImage(spec, nil); err != nil {
if ref != nil { if ref != nil {
dm.recorder.Eventf(ref, "failed", "Failed to pull image %q: %v", container.Image, err) dm.recorder.Eventf(ref, "failed", "Failed to pull image %q: %v", container.Image, err)
} }
@@ -1438,7 +1437,7 @@ func (dm *DockerManager) clearReasonCache(pod *api.Pod, container *api.Container
} }
// Pull the image for the specified pod and container. // Pull the image for the specified pod and container.
func (dm *DockerManager) pullImage(pod *api.Pod, container *api.Container) error { func (dm *DockerManager) pullImage(pod *api.Pod, container *api.Container, pullSecrets []api.Secret) error {
spec := kubecontainer.ImageSpec{container.Image} spec := kubecontainer.ImageSpec{container.Image}
present, err := dm.IsImagePresent(spec) present, err := dm.IsImagePresent(spec)
@@ -1456,14 +1455,13 @@ func (dm *DockerManager) pullImage(pod *api.Pod, container *api.Container) error
return nil return nil
} }
// TODO get the pull secrets from the container's ImageSpec and the pod's service account err = dm.PullImage(spec, pullSecrets)
err = dm.PullImage(spec, nil)
dm.runtimeHooks.ReportImagePull(pod, container, err) dm.runtimeHooks.ReportImagePull(pod, container, err)
return err return err
} }
// Sync the running pod to match the specified desired pod. // Sync the running pod to match the specified desired pod.
func (dm *DockerManager) SyncPod(pod *api.Pod, runningPod kubecontainer.Pod, podStatus api.PodStatus) error { func (dm *DockerManager) SyncPod(pod *api.Pod, runningPod kubecontainer.Pod, podStatus api.PodStatus, pullSecrets []api.Secret) error {
podFullName := kubecontainer.GetPodFullName(pod) podFullName := kubecontainer.GetPodFullName(pod)
containerChanges, err := dm.computePodContainerChanges(pod, runningPod, podStatus) containerChanges, err := dm.computePodContainerChanges(pod, runningPod, podStatus)
glog.V(3).Infof("Got container changes for pod %q: %+v", podFullName, containerChanges) glog.V(3).Infof("Got container changes for pod %q: %+v", podFullName, containerChanges)
@@ -1517,7 +1515,7 @@ func (dm *DockerManager) SyncPod(pod *api.Pod, runningPod kubecontainer.Pod, pod
for idx := range containerChanges.ContainersToStart { for idx := range containerChanges.ContainersToStart {
container := &pod.Spec.Containers[idx] container := &pod.Spec.Containers[idx]
glog.V(4).Infof("Creating container %+v", container) glog.V(4).Infof("Creating container %+v", container)
err := dm.pullImage(pod, container) err := dm.pullImage(pod, container, pullSecrets)
dm.updateReasonCache(pod, container, err) dm.updateReasonCache(pod, container, err)
if err != nil { if err != nil {
glog.Warningf("Failed to pull image %q from pod %q and container %q: %v", container.Image, kubecontainer.GetPodFullName(pod), container.Name, err) glog.Warningf("Failed to pull image %q from pod %q and container %q: %v", container.Image, kubecontainer.GetPodFullName(pod), container.Name, err)

View File

@@ -1060,7 +1060,13 @@ func (kl *Kubelet) syncPod(pod *api.Pod, mirrorPod *api.Pod, runningPod kubecont
return err return err
} }
err = kl.containerRuntime.SyncPod(pod, runningPod, podStatus) pullSecrets, err := kl.getPullSecretsForPod(pod)
if err != nil {
glog.Errorf("Unable to get pull secrets for pod %q (uid %q): %v", podFullName, uid, err)
return err
}
err = kl.containerRuntime.SyncPod(pod, runningPod, podStatus, pullSecrets)
if err != nil { if err != nil {
return err return err
} }
@@ -1088,6 +1094,24 @@ func (kl *Kubelet) syncPod(pod *api.Pod, mirrorPod *api.Pod, runningPod kubecont
return nil return nil
} }
// getPullSecretsForPod inspects the Pod and retrieves the referenced pull secrets
// TODO transitively search through the referenced service account to find the required secrets
// TODO duplicate secrets are being retrieved multiple times and there is no cache. Creating and using a secret manager interface will make this easier to address.
func (kl *Kubelet) getPullSecretsForPod(pod *api.Pod) ([]api.Secret, error) {
pullSecrets := []api.Secret{}
for _, secretRef := range pod.Spec.ImagePullSecrets {
secret, err := kl.kubeClient.Secrets(pod.Namespace).Get(secretRef.Name)
if err != nil {
return nil, err
}
pullSecrets = append(pullSecrets, *secret)
}
return pullSecrets, nil
}
// Stores all volumes defined by the set of pods into a map. // Stores all volumes defined by the set of pods into a map.
// Keys for each entry are in the format (POD_ID)/(VOLUME_NAME) // Keys for each entry are in the format (POD_ID)/(VOLUME_NAME)
func getDesiredVolumes(pods []*api.Pod) map[string]api.Volume { func getDesiredVolumes(pods []*api.Pod) map[string]api.Volume {

View File

@@ -789,7 +789,12 @@ func (r *runtime) PullImage(image kubecontainer.ImageSpec, pullSecrets []api.Sec
tag = "latest" tag = "latest"
} }
creds, ok := r.dockerKeyring.Lookup(repoToPull) keyring, err := credentialprovider.MakeDockerKeyring(pullSecrets, r.dockerKeyring)
if err != nil {
return err
}
creds, ok := keyring.Lookup(repoToPull)
if !ok { if !ok {
glog.V(1).Infof("Pulling image %s without credentials", img) glog.V(1).Infof("Pulling image %s without credentials", img)
} }
@@ -827,7 +832,7 @@ func (r *runtime) RemoveImage(image kubecontainer.ImageSpec) error {
} }
// SyncPod syncs the running pod to match the specified desired pod. // SyncPod syncs the running pod to match the specified desired pod.
func (r *runtime) SyncPod(pod *api.Pod, runningPod kubecontainer.Pod, podStatus api.PodStatus) error { func (r *runtime) SyncPod(pod *api.Pod, runningPod kubecontainer.Pod, podStatus api.PodStatus, pullSecrets []api.Secret) error {
podFullName := kubecontainer.GetPodFullName(pod) podFullName := kubecontainer.GetPodFullName(pod)
if len(runningPod.Containers) == 0 { if len(runningPod.Containers) == 0 {
glog.V(4).Infof("Pod %q is not running, will start it", podFullName) glog.V(4).Infof("Pod %q is not running, will start it", podFullName)