mirror of https://github.com/k3s-io/k3s
Add ServiceAccount API type, client
parent
6e1e7dbb24
commit
53d55f4192
|
@ -259,6 +259,7 @@ _kubectl_get()
|
|||
must_have_one_noun+=("resourcequota")
|
||||
must_have_one_noun+=("secret")
|
||||
must_have_one_noun+=("service")
|
||||
must_have_one_noun+=("serviceaccount")
|
||||
}
|
||||
|
||||
_kubectl_describe()
|
||||
|
@ -286,6 +287,7 @@ _kubectl_describe()
|
|||
must_have_one_noun+=("resourcequota")
|
||||
must_have_one_noun+=("secret")
|
||||
must_have_one_noun+=("service")
|
||||
must_have_one_noun+=("serviceaccount")
|
||||
}
|
||||
|
||||
_kubectl_create()
|
||||
|
|
|
@ -51,6 +51,8 @@ func init() {
|
|||
&ResourceQuotaList{},
|
||||
&Namespace{},
|
||||
&NamespaceList{},
|
||||
&ServiceAccount{},
|
||||
&ServiceAccountList{},
|
||||
&Secret{},
|
||||
&SecretList{},
|
||||
&PersistentVolume{},
|
||||
|
@ -98,6 +100,8 @@ func (*ResourceQuota) IsAnAPIObject() {}
|
|||
func (*ResourceQuotaList) IsAnAPIObject() {}
|
||||
func (*Namespace) IsAnAPIObject() {}
|
||||
func (*NamespaceList) IsAnAPIObject() {}
|
||||
func (*ServiceAccount) IsAnAPIObject() {}
|
||||
func (*ServiceAccountList) IsAnAPIObject() {}
|
||||
func (*Secret) IsAnAPIObject() {}
|
||||
func (*SecretList) IsAnAPIObject() {}
|
||||
func (*PersistentVolume) IsAnAPIObject() {}
|
||||
|
|
|
@ -814,6 +814,10 @@ type PodSpec struct {
|
|||
// NodeSelector is a selector which must be true for the pod to fit on a node
|
||||
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
|
||||
|
||||
// ServiceAccount is the name of the ServiceAccount to use to run this pod
|
||||
// The pod will be allowed to use secrets referenced by the ServiceAccount
|
||||
ServiceAccount string `json:"serviceAccount"`
|
||||
|
||||
// Host is a request to schedule this pod onto a specific host. If it is non-empty,
|
||||
// the the scheduler simply schedules this pod onto that host, assuming that it fits
|
||||
// resource requirements.
|
||||
|
@ -1035,6 +1039,26 @@ type Service struct {
|
|||
Status ServiceStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceAccount binds together:
|
||||
// * a name, understood by users, and perhaps by peripheral systems, for an identity
|
||||
// * a principal that can be authenticated and authorized
|
||||
// * a set of secrets
|
||||
type ServiceAccount struct {
|
||||
TypeMeta `json:",inline"`
|
||||
ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Secrets is the list of secrets allowed to be used by pods running using this ServiceAccount
|
||||
Secrets []ObjectReference `json:"secrets"`
|
||||
}
|
||||
|
||||
// ServiceAccountList is a list of ServiceAccount objects
|
||||
type ServiceAccountList struct {
|
||||
TypeMeta `json:",inline"`
|
||||
ListMeta `json:"metadata,omitempty"`
|
||||
|
||||
Items []ServiceAccount `json:"items"`
|
||||
}
|
||||
|
||||
// Endpoints is a collection of endpoints that implement the actual service. Example:
|
||||
// Name: "mysvc",
|
||||
// Subsets: [
|
||||
|
|
|
@ -1878,6 +1878,7 @@ func init() {
|
|||
out.NodeSelector[key] = val
|
||||
}
|
||||
}
|
||||
out.ServiceAccount = in.ServiceAccount
|
||||
out.Host = in.Host
|
||||
out.HostNetwork = in.HostNetwork
|
||||
return nil
|
||||
|
@ -1911,6 +1912,7 @@ func init() {
|
|||
out.NodeSelector[key] = val
|
||||
}
|
||||
}
|
||||
out.ServiceAccount = in.ServiceAccount
|
||||
out.Host = in.Host
|
||||
out.HostNetwork = in.HostNetwork
|
||||
return nil
|
||||
|
@ -2475,6 +2477,74 @@ func init() {
|
|||
}
|
||||
return nil
|
||||
},
|
||||
func(in *ServiceAccount, out *newer.ServiceAccount, s conversion.Scope) error {
|
||||
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Secrets != nil {
|
||||
out.Secrets = make([]newer.ObjectReference, len(in.Secrets))
|
||||
for i := range in.Secrets {
|
||||
if err := s.Convert(&in.Secrets[i], &out.Secrets[i], 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
func(in *newer.ServiceAccount, out *ServiceAccount, s conversion.Scope) error {
|
||||
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Secrets != nil {
|
||||
out.Secrets = make([]ObjectReference, len(in.Secrets))
|
||||
for i := range in.Secrets {
|
||||
if err := s.Convert(&in.Secrets[i], &out.Secrets[i], 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
func(in *ServiceAccountList, out *newer.ServiceAccountList, s conversion.Scope) error {
|
||||
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
out.Items = make([]newer.ServiceAccount, len(in.Items))
|
||||
for i := range in.Items {
|
||||
if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
func(in *newer.ServiceAccountList, out *ServiceAccountList, s conversion.Scope) error {
|
||||
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
out.Items = make([]ServiceAccount, len(in.Items))
|
||||
for i := range in.Items {
|
||||
if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
func(in *ServiceList, out *newer.ServiceList, s conversion.Scope) error {
|
||||
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
|
||||
return err
|
||||
|
|
|
@ -52,6 +52,8 @@ func init() {
|
|||
&NamespaceList{},
|
||||
&Secret{},
|
||||
&SecretList{},
|
||||
&ServiceAccount{},
|
||||
&ServiceAccountList{},
|
||||
&PersistentVolume{},
|
||||
&PersistentVolumeList{},
|
||||
&PersistentVolumeClaim{},
|
||||
|
@ -97,6 +99,8 @@ func (*Namespace) IsAnAPIObject() {}
|
|||
func (*NamespaceList) IsAnAPIObject() {}
|
||||
func (*Secret) IsAnAPIObject() {}
|
||||
func (*SecretList) IsAnAPIObject() {}
|
||||
func (*ServiceAccount) IsAnAPIObject() {}
|
||||
func (*ServiceAccountList) IsAnAPIObject() {}
|
||||
func (*PersistentVolume) IsAnAPIObject() {}
|
||||
func (*PersistentVolumeList) IsAnAPIObject() {}
|
||||
func (*PersistentVolumeClaim) IsAnAPIObject() {}
|
||||
|
|
|
@ -816,6 +816,9 @@ type PodSpec struct {
|
|||
// NodeSelector is a selector which must be true for the pod to fit on a node
|
||||
NodeSelector map[string]string `json:"nodeSelector,omitempty" description:"selector which must match a node's labels for the pod to be scheduled on that node"`
|
||||
|
||||
// ServiceAccount is the name of the ServiceAccount to use to run this pod
|
||||
ServiceAccount string `json:"serviceAccount" description:"name of the ServiceAccount to use to run this pod"`
|
||||
|
||||
// Host is a request to schedule this pod onto a specific host. If it is non-empty,
|
||||
// the the scheduler simply schedules this pod onto that host, assuming that it fits
|
||||
// resource requirements.
|
||||
|
@ -1036,6 +1039,26 @@ type ServiceList struct {
|
|||
Items []Service `json:"items" description:"list of services"`
|
||||
}
|
||||
|
||||
// ServiceAccount binds together:
|
||||
// * a name, understood by users, and perhaps by peripheral systems, for an identity
|
||||
// * a principal that can be authenticated and authorized
|
||||
// * a set of secrets
|
||||
type ServiceAccount struct {
|
||||
TypeMeta `json:",inline"`
|
||||
ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"`
|
||||
|
||||
// Secrets is the list of secrets allowed to be used by pods running using this ServiceAccount
|
||||
Secrets []ObjectReference `json:"secrets" description:"list of secrets that can be used by pods running as this service account" patchStrategy:"merge" patchMergeKey:"name"`
|
||||
}
|
||||
|
||||
// ServiceAccountList is a list of ServiceAccount objects
|
||||
type ServiceAccountList struct {
|
||||
TypeMeta `json:",inline"`
|
||||
ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"`
|
||||
|
||||
Items []ServiceAccount `json:"items" description:"list of ServiceAccounts"`
|
||||
}
|
||||
|
||||
// Endpoints is a collection of endpoints that implement the actual service. Example:
|
||||
// Name: "mysvc",
|
||||
// Subsets: [
|
||||
|
|
|
@ -377,6 +377,7 @@ func init() {
|
|||
}
|
||||
out.DesiredState.Host = in.Spec.Host
|
||||
out.CurrentState.Host = in.Spec.Host
|
||||
out.ServiceAccount = in.Spec.ServiceAccount
|
||||
if err := s.Convert(&in.Status, &out.CurrentState, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -399,6 +400,7 @@ func init() {
|
|||
return err
|
||||
}
|
||||
out.Spec.Host = in.DesiredState.Host
|
||||
out.Spec.ServiceAccount = in.ServiceAccount
|
||||
if err := s.Convert(&in.CurrentState, &out.Status, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -503,6 +505,7 @@ func init() {
|
|||
return err
|
||||
}
|
||||
out.DesiredState.Host = in.Spec.Host
|
||||
out.ServiceAccount = in.Spec.ServiceAccount
|
||||
if err := s.Convert(&in.Spec.NodeSelector, &out.NodeSelector, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -519,6 +522,7 @@ func init() {
|
|||
return err
|
||||
}
|
||||
out.Spec.Host = in.DesiredState.Host
|
||||
out.Spec.ServiceAccount = in.ServiceAccount
|
||||
if err := s.Convert(&in.NodeSelector, &out.Spec.NodeSelector, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1685,4 +1689,17 @@ func init() {
|
|||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
err = newer.Scheme.AddFieldLabelConversionFunc("v1beta1", "ServiceAccount",
|
||||
func(label, value string) (string, string, error) {
|
||||
switch label {
|
||||
case "name":
|
||||
return "metadata.name", value, nil
|
||||
default:
|
||||
return "", "", fmt.Errorf("field label not supported: %s", label)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ func init() {
|
|||
&NamespaceList{},
|
||||
&Secret{},
|
||||
&SecretList{},
|
||||
&ServiceAccount{},
|
||||
&ServiceAccountList{},
|
||||
&PersistentVolume{},
|
||||
&PersistentVolumeList{},
|
||||
&PersistentVolumeClaim{},
|
||||
|
@ -105,6 +107,8 @@ func (*Namespace) IsAnAPIObject() {}
|
|||
func (*NamespaceList) IsAnAPIObject() {}
|
||||
func (*Secret) IsAnAPIObject() {}
|
||||
func (*SecretList) IsAnAPIObject() {}
|
||||
func (*ServiceAccount) IsAnAPIObject() {}
|
||||
func (*ServiceAccountList) IsAnAPIObject() {}
|
||||
func (*PersistentVolume) IsAnAPIObject() {}
|
||||
func (*PersistentVolumeList) IsAnAPIObject() {}
|
||||
func (*PersistentVolumeClaim) IsAnAPIObject() {}
|
||||
|
|
|
@ -755,6 +755,8 @@ type Pod struct {
|
|||
Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize pods; may match selectors of replication controllers and services"`
|
||||
DesiredState PodState `json:"desiredState,omitempty" description:"specification of the desired state of the pod"`
|
||||
CurrentState PodState `json:"currentState,omitempty" description:"current state of the pod; populated by the system, read-only"`
|
||||
// ServiceAccount is the name of the ServiceAccount to use to run this pod
|
||||
ServiceAccount string `json:"serviceAccount,omitempty" description:"the name of the ServiceAccount to use to run this pod"`
|
||||
// NodeSelector is a selector which must be true for the pod to fit on a node
|
||||
NodeSelector map[string]string `json:"nodeSelector,omitempty" description:"selector which must match a node's labels for the pod to be scheduled on that node"`
|
||||
}
|
||||
|
@ -782,10 +784,11 @@ type ReplicationController struct {
|
|||
|
||||
// PodTemplate holds the information used for creating pods.
|
||||
type PodTemplate struct {
|
||||
DesiredState PodState `json:"desiredState,omitempty" description:"specification of the desired state of pods created from this template"`
|
||||
NodeSelector map[string]string `json:"nodeSelector,omitempty" description:"a selector which must be true for the pod to fit on a node"`
|
||||
Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize the pods created from the template; must match the selector of the replication controller to which the template belongs; may match selectors of services"`
|
||||
Annotations map[string]string `json:"annotations,omitempty" description:"map of string keys and values that can be used by external tooling to store and retrieve arbitrary metadata about pods created from the template"`
|
||||
DesiredState PodState `json:"desiredState,omitempty" description:"specification of the desired state of pods created from this template"`
|
||||
ServiceAccount string `json:"serviceAccount,omitempty" description:"the name of the ServiceAccount to use to run this pod"`
|
||||
NodeSelector map[string]string `json:"nodeSelector,omitempty" description:"a selector which must be true for the pod to fit on a node"`
|
||||
Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize the pods created from the template; must match the selector of the replication controller to which the template belongs; may match selectors of services"`
|
||||
Annotations map[string]string `json:"annotations,omitempty" description:"map of string keys and values that can be used by external tooling to store and retrieve arbitrary metadata about pods created from the template"`
|
||||
}
|
||||
|
||||
// Session Affinity Type string
|
||||
|
@ -884,6 +887,24 @@ type ServicePort struct {
|
|||
ContainerPort util.IntOrString `json:"containerPort" description:"the port to access on the containers belonging to pods targeted by the service; defaults to the service port"`
|
||||
}
|
||||
|
||||
// ServiceAccount binds together:
|
||||
// * a name, understood by users, and perhaps by peripheral systems, for an identity
|
||||
// * a principal that can be authenticated and authorized
|
||||
// * a set of secrets
|
||||
type ServiceAccount struct {
|
||||
TypeMeta `json:",inline"`
|
||||
|
||||
// Secrets is the list of secrets allowed to be used by pods running using this ServiceAccount
|
||||
Secrets []ObjectReference `json:"secrets" description:"list of secrets that can be used by pods running as this service account" patchStrategy:"merge" patchMergeKey:"name"`
|
||||
}
|
||||
|
||||
// ServiceAccountList is a list of ServiceAccount objects
|
||||
type ServiceAccountList struct {
|
||||
TypeMeta `json:",inline"`
|
||||
|
||||
Items []ServiceAccount `json:"items" description:"list of ServiceAccounts"`
|
||||
}
|
||||
|
||||
// EndpointObjectReference is a reference to an object exposing the endpoint
|
||||
type EndpointObjectReference struct {
|
||||
Endpoint string `json:"endpoint" description:"endpoint exposed by the referenced object"`
|
||||
|
|
|
@ -180,6 +180,7 @@ func init() {
|
|||
}
|
||||
out.DesiredState.Host = in.Spec.Host
|
||||
out.CurrentState.Host = in.Spec.Host
|
||||
out.ServiceAccount = in.Spec.ServiceAccount
|
||||
if err := s.Convert(&in.Status, &out.CurrentState, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -201,6 +202,7 @@ func init() {
|
|||
if err := s.Convert(&in.DesiredState.Manifest, &out.Spec, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Spec.ServiceAccount = in.ServiceAccount
|
||||
out.Spec.Host = in.DesiredState.Host
|
||||
if err := s.Convert(&in.CurrentState, &out.Status, 0); err != nil {
|
||||
return err
|
||||
|
@ -282,6 +284,7 @@ func init() {
|
|||
return err
|
||||
}
|
||||
out.DesiredState.Host = in.Spec.Host
|
||||
out.ServiceAccount = in.Spec.ServiceAccount
|
||||
if err := s.Convert(&in.Spec.NodeSelector, &out.NodeSelector, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -298,6 +301,7 @@ func init() {
|
|||
return err
|
||||
}
|
||||
out.Spec.Host = in.DesiredState.Host
|
||||
out.Spec.ServiceAccount = in.ServiceAccount
|
||||
if err := s.Convert(&in.NodeSelector, &out.Spec.NodeSelector, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1601,4 +1605,17 @@ func init() {
|
|||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
err = newer.Scheme.AddFieldLabelConversionFunc("v1beta2", "ServiceAccount",
|
||||
func(label, value string) (string, string, error) {
|
||||
switch label {
|
||||
case "name":
|
||||
return "metadata.name", value, nil
|
||||
default:
|
||||
return "", "", fmt.Errorf("field label not supported: %s", label)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ func init() {
|
|||
&NamespaceList{},
|
||||
&Secret{},
|
||||
&SecretList{},
|
||||
&ServiceAccount{},
|
||||
&ServiceAccountList{},
|
||||
&PersistentVolume{},
|
||||
&PersistentVolumeList{},
|
||||
&PersistentVolumeClaim{},
|
||||
|
@ -105,6 +107,8 @@ func (*Namespace) IsAnAPIObject() {}
|
|||
func (*NamespaceList) IsAnAPIObject() {}
|
||||
func (*Secret) IsAnAPIObject() {}
|
||||
func (*SecretList) IsAnAPIObject() {}
|
||||
func (*ServiceAccount) IsAnAPIObject() {}
|
||||
func (*ServiceAccountList) IsAnAPIObject() {}
|
||||
func (*PersistentVolume) IsAnAPIObject() {}
|
||||
func (*PersistentVolumeList) IsAnAPIObject() {}
|
||||
func (*PersistentVolumeClaim) IsAnAPIObject() {}
|
||||
|
|
|
@ -756,6 +756,8 @@ type Pod struct {
|
|||
Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize pods; may match selectors of replication controllers and services"`
|
||||
DesiredState PodState `json:"desiredState,omitempty" description:"specification of the desired state of the pod"`
|
||||
CurrentState PodState `json:"currentState,omitempty" description:"current state of the pod; populated by the system, read-only"`
|
||||
// ServiceAccount is the name of the ServiceAccount to use to run this pod
|
||||
ServiceAccount string `json:"serviceAccount,omitempty" description:"the name of the ServiceAccount to use to run this pod"`
|
||||
// NodeSelector is a selector which must be true for the pod to fit on a node
|
||||
NodeSelector map[string]string `json:"nodeSelector,omitempty" description:"selector which must match a node's labels for the pod to be scheduled on that node"`
|
||||
}
|
||||
|
@ -787,10 +789,11 @@ type ReplicationController struct {
|
|||
//
|
||||
// http://docs.k8s.io/replication-controller.md#pod-template
|
||||
type PodTemplate struct {
|
||||
DesiredState PodState `json:"desiredState,omitempty" description:"specification of the desired state of pods created from this template"`
|
||||
NodeSelector map[string]string `json:"nodeSelector,omitempty" description:"a selector which must be true for the pod to fit on a node"`
|
||||
Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize the pods created from the template; must match the selector of the replication controller to which the template belongs; may match selectors of services"`
|
||||
Annotations map[string]string `json:"annotations,omitempty" description:"map of string keys and values that can be used by external tooling to store and retrieve arbitrary metadata about pods created from the template"`
|
||||
DesiredState PodState `json:"desiredState,omitempty" description:"specification of the desired state of pods created from this template"`
|
||||
ServiceAccount string `json:"serviceAccount,omitempty" description:"the name of the ServiceAccount to use to run this pod"`
|
||||
NodeSelector map[string]string `json:"nodeSelector,omitempty" description:"a selector which must be true for the pod to fit on a node"`
|
||||
Labels map[string]string `json:"labels,omitempty" description:"map of string keys and values that can be used to organize and categorize the pods created from the template; must match the selector of the replication controller to which the template belongs; may match selectors of services"`
|
||||
Annotations map[string]string `json:"annotations,omitempty" description:"map of string keys and values that can be used by external tooling to store and retrieve arbitrary metadata about pods created from the template"`
|
||||
}
|
||||
|
||||
// Session Affinity Type string
|
||||
|
@ -891,6 +894,24 @@ type ServicePort struct {
|
|||
ContainerPort util.IntOrString `json:"containerPort" description:"the port to access on the containers belonging to pods targeted by the service; defaults to the service port"`
|
||||
}
|
||||
|
||||
// ServiceAccount binds together:
|
||||
// * a name, understood by users, and perhaps by peripheral systems, for an identity
|
||||
// * a principal that can be authenticated and authorized
|
||||
// * a set of secrets
|
||||
type ServiceAccount struct {
|
||||
TypeMeta `json:",inline"`
|
||||
|
||||
// Secrets is the list of secrets allowed to be used by pods running using this ServiceAccount
|
||||
Secrets []ObjectReference `json:"secrets" description:"list of secrets that can be used by pods running as this service account" patchStrategy:"merge" patchMergeKey:"name"`
|
||||
}
|
||||
|
||||
// ServiceAccountList is a list of ServiceAccount objects
|
||||
type ServiceAccountList struct {
|
||||
TypeMeta `json:",inline"`
|
||||
|
||||
Items []ServiceAccount `json:"items" description:"list of ServiceAccounts"`
|
||||
}
|
||||
|
||||
// EndpointObjectReference is a reference to an object exposing the endpoint
|
||||
type EndpointObjectReference struct {
|
||||
Endpoint string `json:"endpoint" description:"endpoint exposed by the referenced object"`
|
||||
|
|
|
@ -128,6 +128,19 @@ func init() {
|
|||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
err = newer.Scheme.AddFieldLabelConversionFunc("v1beta3", "ServiceAccount",
|
||||
func(label, value string) (string, string, error) {
|
||||
switch label {
|
||||
case "metadata.name":
|
||||
return label, value, nil
|
||||
default:
|
||||
return "", "", fmt.Errorf("field label not supported: %s", label)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func convert_v1beta3_Container_To_api_Container(in *Container, out *newer.Container, s conversion.Scope) error {
|
||||
|
|
|
@ -2637,6 +2637,7 @@ func convert_v1beta3_PodSpec_To_api_PodSpec(in *PodSpec, out *newer.PodSpec, s c
|
|||
} else {
|
||||
out.NodeSelector = nil
|
||||
}
|
||||
out.ServiceAccount = in.ServiceAccount
|
||||
out.Host = in.Host
|
||||
out.HostNetwork = in.HostNetwork
|
||||
return nil
|
||||
|
@ -2682,6 +2683,7 @@ func convert_api_PodSpec_To_v1beta3_PodSpec(in *newer.PodSpec, out *PodSpec, s c
|
|||
} else {
|
||||
out.NodeSelector = nil
|
||||
}
|
||||
out.ServiceAccount = in.ServiceAccount
|
||||
out.Host = in.Host
|
||||
out.HostNetwork = in.HostNetwork
|
||||
return nil
|
||||
|
@ -3623,6 +3625,98 @@ func convert_api_Service_To_v1beta3_Service(in *newer.Service, out *Service, s c
|
|||
return nil
|
||||
}
|
||||
|
||||
func convert_v1beta3_ServiceAccount_To_api_ServiceAccount(in *ServiceAccount, out *newer.ServiceAccount, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*ServiceAccount))(in)
|
||||
}
|
||||
if err := convert_v1beta3_TypeMeta_To_api_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := convert_v1beta3_ObjectMeta_To_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Secrets != nil {
|
||||
out.Secrets = make([]newer.ObjectReference, len(in.Secrets))
|
||||
for i := range in.Secrets {
|
||||
if err := convert_v1beta3_ObjectReference_To_api_ObjectReference(&in.Secrets[i], &out.Secrets[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Secrets = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convert_api_ServiceAccount_To_v1beta3_ServiceAccount(in *newer.ServiceAccount, out *ServiceAccount, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*newer.ServiceAccount))(in)
|
||||
}
|
||||
if err := convert_api_TypeMeta_To_v1beta3_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := convert_api_ObjectMeta_To_v1beta3_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Secrets != nil {
|
||||
out.Secrets = make([]ObjectReference, len(in.Secrets))
|
||||
for i := range in.Secrets {
|
||||
if err := convert_api_ObjectReference_To_v1beta3_ObjectReference(&in.Secrets[i], &out.Secrets[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Secrets = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convert_v1beta3_ServiceAccountList_To_api_ServiceAccountList(in *ServiceAccountList, out *newer.ServiceAccountList, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*ServiceAccountList))(in)
|
||||
}
|
||||
if err := convert_v1beta3_TypeMeta_To_api_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := convert_v1beta3_ListMeta_To_api_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
out.Items = make([]newer.ServiceAccount, len(in.Items))
|
||||
for i := range in.Items {
|
||||
if err := convert_v1beta3_ServiceAccount_To_api_ServiceAccount(&in.Items[i], &out.Items[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convert_api_ServiceAccountList_To_v1beta3_ServiceAccountList(in *newer.ServiceAccountList, out *ServiceAccountList, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*newer.ServiceAccountList))(in)
|
||||
}
|
||||
if err := convert_api_TypeMeta_To_v1beta3_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := convert_api_ListMeta_To_v1beta3_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
out.Items = make([]ServiceAccount, len(in.Items))
|
||||
for i := range in.Items {
|
||||
if err := convert_api_ServiceAccount_To_v1beta3_ServiceAccount(&in.Items[i], &out.Items[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convert_v1beta3_ServiceList_To_api_ServiceList(in *ServiceList, out *newer.ServiceList, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*ServiceList))(in)
|
||||
|
@ -4242,6 +4336,8 @@ func init() {
|
|||
convert_api_Secret_To_v1beta3_Secret,
|
||||
convert_api_SecurityContext_To_v1beta3_SecurityContext,
|
||||
convert_api_SerializedReference_To_v1beta3_SerializedReference,
|
||||
convert_api_ServiceAccountList_To_v1beta3_ServiceAccountList,
|
||||
convert_api_ServiceAccount_To_v1beta3_ServiceAccount,
|
||||
convert_api_ServiceList_To_v1beta3_ServiceList,
|
||||
convert_api_ServicePort_To_v1beta3_ServicePort,
|
||||
convert_api_ServiceSpec_To_v1beta3_ServiceSpec,
|
||||
|
@ -4348,6 +4444,8 @@ func init() {
|
|||
convert_v1beta3_Secret_To_api_Secret,
|
||||
convert_v1beta3_SecurityContext_To_api_SecurityContext,
|
||||
convert_v1beta3_SerializedReference_To_api_SerializedReference,
|
||||
convert_v1beta3_ServiceAccountList_To_api_ServiceAccountList,
|
||||
convert_v1beta3_ServiceAccount_To_api_ServiceAccount,
|
||||
convert_v1beta3_ServiceList_To_api_ServiceList,
|
||||
convert_v1beta3_ServicePort_To_api_ServicePort,
|
||||
convert_v1beta3_ServiceSpec_To_api_ServiceSpec,
|
||||
|
|
|
@ -52,6 +52,8 @@ func init() {
|
|||
&NamespaceList{},
|
||||
&Secret{},
|
||||
&SecretList{},
|
||||
&ServiceAccount{},
|
||||
&ServiceAccountList{},
|
||||
&PersistentVolume{},
|
||||
&PersistentVolumeList{},
|
||||
&PersistentVolumeClaim{},
|
||||
|
@ -97,6 +99,8 @@ func (*Namespace) IsAnAPIObject() {}
|
|||
func (*NamespaceList) IsAnAPIObject() {}
|
||||
func (*Secret) IsAnAPIObject() {}
|
||||
func (*SecretList) IsAnAPIObject() {}
|
||||
func (*ServiceAccount) IsAnAPIObject() {}
|
||||
func (*ServiceAccountList) IsAnAPIObject() {}
|
||||
func (*PersistentVolume) IsAnAPIObject() {}
|
||||
func (*PersistentVolumeList) IsAnAPIObject() {}
|
||||
func (*PersistentVolumeClaim) IsAnAPIObject() {}
|
||||
|
|
|
@ -816,6 +816,9 @@ type PodSpec struct {
|
|||
// NodeSelector is a selector which must be true for the pod to fit on a node
|
||||
NodeSelector map[string]string `json:"nodeSelector,omitempty" description:"selector which must match a node's labels for the pod to be scheduled on that node"`
|
||||
|
||||
// ServiceAccount is the name of the ServiceAccount to use to run this pod
|
||||
ServiceAccount string `json:"serviceAccount" description:"name of the ServiceAccount to use to run this pod"`
|
||||
|
||||
// Host is a request to schedule this pod onto a specific host. If it is non-empty,
|
||||
// the the scheduler simply schedules this pod onto that host, assuming that it fits
|
||||
// resource requirements.
|
||||
|
@ -1036,6 +1039,26 @@ type ServiceList struct {
|
|||
Items []Service `json:"items" description:"list of services"`
|
||||
}
|
||||
|
||||
// ServiceAccount binds together:
|
||||
// * a name, understood by users, and perhaps by peripheral systems, for an identity
|
||||
// * a principal that can be authenticated and authorized
|
||||
// * a set of secrets
|
||||
type ServiceAccount struct {
|
||||
TypeMeta `json:",inline"`
|
||||
ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see http://docs.k8s.io/api-conventions.md#metadata"`
|
||||
|
||||
// Secrets is the list of secrets allowed to be used by pods running using this ServiceAccount
|
||||
Secrets []ObjectReference `json:"secrets" description:"list of secrets that can be used by pods running as this service account" patchStrategy:"merge" patchMergeKey:"name"`
|
||||
}
|
||||
|
||||
// ServiceAccountList is a list of ServiceAccount objects
|
||||
type ServiceAccountList struct {
|
||||
TypeMeta `json:",inline"`
|
||||
ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://docs.k8s.io/api-conventions.md#metadata"`
|
||||
|
||||
Items []ServiceAccount `json:"items" description:"list of ServiceAccounts"`
|
||||
}
|
||||
|
||||
// Endpoints is a collection of endpoints that implement the actual service. Example:
|
||||
// Name: "mysvc",
|
||||
// Subsets: [
|
||||
|
|
|
@ -153,6 +153,13 @@ func ValidateSecretName(name string, prefix bool) (bool, string) {
|
|||
return nameIsDNSSubdomain(name, prefix)
|
||||
}
|
||||
|
||||
// ValidateServiceAccountName can be used to check whether the given service account name is valid.
|
||||
// Prefix indicates this name will be used as part of generation, in which case
|
||||
// trailing dashes are allowed.
|
||||
func ValidateServiceAccountName(name string, prefix bool) (bool, string) {
|
||||
return nameIsDNSSubdomain(name, prefix)
|
||||
}
|
||||
|
||||
// ValidateEndpointsName can be used to check whether the given endpoints name is valid.
|
||||
// Prefix indicates this name will be used as part of generation, in which case
|
||||
// trailing dashes are allowed.
|
||||
|
@ -1225,6 +1232,21 @@ func ValidateLimitRange(limitRange *api.LimitRange) errs.ValidationErrorList {
|
|||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateServiceAccount tests if required fields in the ServiceAccount are set.
|
||||
func ValidateServiceAccount(serviceAccount *api.ServiceAccount) errs.ValidationErrorList {
|
||||
allErrs := errs.ValidationErrorList{}
|
||||
allErrs = append(allErrs, ValidateObjectMeta(&serviceAccount.ObjectMeta, true, ValidateServiceAccountName).Prefix("metadata")...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateServiceAccountUpdate tests if required fields in the ServiceAccount are set.
|
||||
func ValidateServiceAccountUpdate(oldServiceAccount, newServiceAccount *api.ServiceAccount) errs.ValidationErrorList {
|
||||
allErrs := errs.ValidationErrorList{}
|
||||
allErrs = append(allErrs, ValidateObjectMetaUpdate(&oldServiceAccount.ObjectMeta, &newServiceAccount.ObjectMeta).Prefix("metadata")...)
|
||||
allErrs = append(allErrs, ValidateServiceAccount(newServiceAccount)...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateSecret tests if required fields in the Secret are set.
|
||||
func ValidateSecret(secret *api.Secret) errs.ValidationErrorList {
|
||||
allErrs := errs.ValidationErrorList{}
|
||||
|
|
|
@ -39,6 +39,7 @@ type Interface interface {
|
|||
EventNamespacer
|
||||
LimitRangesNamespacer
|
||||
ResourceQuotasNamespacer
|
||||
ServiceAccountsNamespacer
|
||||
SecretsNamespacer
|
||||
NamespacesInterface
|
||||
PersistentVolumesInterface
|
||||
|
@ -77,6 +78,10 @@ func (c *Client) ResourceQuotas(namespace string) ResourceQuotaInterface {
|
|||
return newResourceQuotas(c, namespace)
|
||||
}
|
||||
|
||||
func (c *Client) ServiceAccounts(namespace string) ServiceAccountsInterface {
|
||||
return newServiceAccounts(c, namespace)
|
||||
}
|
||||
|
||||
func (c *Client) Secrets(namespace string) SecretsInterface {
|
||||
return newSecrets(c, namespace)
|
||||
}
|
||||
|
|
|
@ -310,6 +310,9 @@ var fieldMappings = versionToResourceToFieldMapping{
|
|||
"secrets": clientFieldNameToAPIVersionFieldName{
|
||||
SecretType: "type",
|
||||
},
|
||||
"serviceAccounts": clientFieldNameToAPIVersionFieldName{
|
||||
ObjectNameField: "name",
|
||||
},
|
||||
},
|
||||
"v1beta2": resourceTypeToFieldMapping{
|
||||
"nodes": clientFieldNameToAPIVersionFieldName{
|
||||
|
@ -326,6 +329,9 @@ var fieldMappings = versionToResourceToFieldMapping{
|
|||
"secrets": clientFieldNameToAPIVersionFieldName{
|
||||
SecretType: "type",
|
||||
},
|
||||
"serviceAccounts": clientFieldNameToAPIVersionFieldName{
|
||||
ObjectNameField: "name",
|
||||
},
|
||||
},
|
||||
"v1beta3": resourceTypeToFieldMapping{
|
||||
"nodes": clientFieldNameToAPIVersionFieldName{
|
||||
|
@ -342,6 +348,9 @@ var fieldMappings = versionToResourceToFieldMapping{
|
|||
"secrets": clientFieldNameToAPIVersionFieldName{
|
||||
SecretType: "type",
|
||||
},
|
||||
"serviceAccounts": clientFieldNameToAPIVersionFieldName{
|
||||
ObjectNameField: "metadata.name",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
)
|
||||
|
||||
type ServiceAccountsNamespacer interface {
|
||||
ServiceAccounts(namespace string) ServiceAccountsInterface
|
||||
}
|
||||
|
||||
type ServiceAccountsInterface interface {
|
||||
Create(serviceAccount *api.ServiceAccount) (*api.ServiceAccount, error)
|
||||
Update(serviceAccount *api.ServiceAccount) (*api.ServiceAccount, error)
|
||||
Delete(name string) error
|
||||
List(label labels.Selector, field fields.Selector) (*api.ServiceAccountList, error)
|
||||
Get(name string) (*api.ServiceAccount, error)
|
||||
Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
|
||||
}
|
||||
|
||||
// serviceAccounts implements ServiceAccounts interface
|
||||
type serviceAccounts struct {
|
||||
client *Client
|
||||
namespace string
|
||||
}
|
||||
|
||||
// newServiceAccounts returns a new serviceAccounts object.
|
||||
func newServiceAccounts(c *Client, ns string) ServiceAccountsInterface {
|
||||
return &serviceAccounts{
|
||||
client: c,
|
||||
namespace: ns,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *serviceAccounts) Create(serviceAccount *api.ServiceAccount) (*api.ServiceAccount, error) {
|
||||
result := &api.ServiceAccount{}
|
||||
err := s.client.Post().
|
||||
Namespace(s.namespace).
|
||||
Resource("serviceAccounts").
|
||||
Body(serviceAccount).
|
||||
Do().
|
||||
Into(result)
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// List returns a list of serviceAccounts matching the selectors.
|
||||
func (s *serviceAccounts) List(label labels.Selector, field fields.Selector) (*api.ServiceAccountList, error) {
|
||||
result := &api.ServiceAccountList{}
|
||||
|
||||
err := s.client.Get().
|
||||
Namespace(s.namespace).
|
||||
Resource("serviceAccounts").
|
||||
LabelsSelectorParam(label).
|
||||
FieldsSelectorParam(field).
|
||||
Do().
|
||||
Into(result)
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Get returns the given serviceAccount, or an error.
|
||||
func (s *serviceAccounts) Get(name string) (*api.ServiceAccount, error) {
|
||||
result := &api.ServiceAccount{}
|
||||
err := s.client.Get().
|
||||
Namespace(s.namespace).
|
||||
Resource("serviceAccounts").
|
||||
Name(name).
|
||||
Do().
|
||||
Into(result)
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Watch starts watching for serviceAccounts matching the given selectors.
|
||||
func (s *serviceAccounts) Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
|
||||
return s.client.Get().
|
||||
Prefix("watch").
|
||||
Namespace(s.namespace).
|
||||
Resource("serviceAccounts").
|
||||
Param("resourceVersion", resourceVersion).
|
||||
LabelsSelectorParam(label).
|
||||
FieldsSelectorParam(field).
|
||||
Watch()
|
||||
}
|
||||
|
||||
func (s *serviceAccounts) Delete(name string) error {
|
||||
return s.client.Delete().
|
||||
Namespace(s.namespace).
|
||||
Resource("serviceAccounts").
|
||||
Name(name).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
func (s *serviceAccounts) Update(serviceAccount *api.ServiceAccount) (result *api.ServiceAccount, err error) {
|
||||
result = &api.ServiceAccount{}
|
||||
err = s.client.Put().
|
||||
Namespace(s.namespace).
|
||||
Resource("serviceAccounts").
|
||||
Name(serviceAccount.Name).
|
||||
Body(serviceAccount).
|
||||
Do().
|
||||
Into(result)
|
||||
|
||||
return
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testclient
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
)
|
||||
|
||||
// FakeServiceAccounts implements ServiceAccountsInterface. Meant to be embedded into a struct to get a default
|
||||
// implementation. This makes faking out just the method you want to test easier.
|
||||
type FakeServiceAccounts struct {
|
||||
Fake *Fake
|
||||
Namespace string
|
||||
}
|
||||
|
||||
func (c *FakeServiceAccounts) List(labels labels.Selector, field fields.Selector) (*api.ServiceAccountList, error) {
|
||||
obj, err := c.Fake.Invokes(FakeAction{Action: "list-serviceaccounts"}, &api.ServiceAccountList{})
|
||||
return obj.(*api.ServiceAccountList), err
|
||||
}
|
||||
|
||||
func (c *FakeServiceAccounts) Get(name string) (*api.ServiceAccount, error) {
|
||||
obj, err := c.Fake.Invokes(FakeAction{Action: "get-serviceaccount", Value: name}, &api.ServiceAccount{})
|
||||
return obj.(*api.ServiceAccount), err
|
||||
}
|
||||
|
||||
func (c *FakeServiceAccounts) Create(serviceAccount *api.ServiceAccount) (*api.ServiceAccount, error) {
|
||||
obj, err := c.Fake.Invokes(FakeAction{Action: "create-serviceaccount", Value: serviceAccount}, &api.ServiceAccount{})
|
||||
return obj.(*api.ServiceAccount), err
|
||||
}
|
||||
|
||||
func (c *FakeServiceAccounts) Update(serviceAccount *api.ServiceAccount) (*api.ServiceAccount, error) {
|
||||
obj, err := c.Fake.Invokes(FakeAction{Action: "update-serviceaccount", Value: serviceAccount}, &api.ServiceAccount{})
|
||||
return obj.(*api.ServiceAccount), err
|
||||
}
|
||||
|
||||
func (c *FakeServiceAccounts) Delete(name string) error {
|
||||
_, err := c.Fake.Invokes(FakeAction{Action: "delete-serviceaccount", Value: name}, &api.ServiceAccount{})
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *FakeServiceAccounts) Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
|
||||
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "watch-serviceAccounts", Value: resourceVersion})
|
||||
return c.Fake.Watch, c.Fake.Err
|
||||
}
|
|
@ -107,6 +107,10 @@ func (c *Fake) Services(namespace string) client.ServiceInterface {
|
|||
return &FakeServices{Fake: c, Namespace: namespace}
|
||||
}
|
||||
|
||||
func (c *Fake) ServiceAccounts(namespace string) client.ServiceAccountsInterface {
|
||||
return &FakeServiceAccounts{Fake: c, Namespace: namespace}
|
||||
}
|
||||
|
||||
func (c *Fake) Secrets(namespace string) client.SecretsInterface {
|
||||
return &FakeSecrets{Fake: c, Namespace: namespace}
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ func describerMap(c *client.Client) map[string]Describer {
|
|||
"ReplicationController": &ReplicationControllerDescriber{c},
|
||||
"Secret": &SecretDescriber{c},
|
||||
"Service": &ServiceDescriber{c},
|
||||
"ServiceAccount": &ServiceAccountDescriber{c},
|
||||
"Minion": &NodeDescriber{c},
|
||||
"Node": &NodeDescriber{c},
|
||||
"LimitRange": &LimitRangeDescriber{c},
|
||||
|
@ -510,6 +511,67 @@ func describeService(service *api.Service, endpoints *api.Endpoints, events *api
|
|||
})
|
||||
}
|
||||
|
||||
// ServiceAccountDescriber generates information about a service.
|
||||
type ServiceAccountDescriber struct {
|
||||
client.Interface
|
||||
}
|
||||
|
||||
func (d *ServiceAccountDescriber) Describe(namespace, name string) (string, error) {
|
||||
c := d.ServiceAccounts(namespace)
|
||||
|
||||
serviceAccount, err := c.Get(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tokens := []api.Secret{}
|
||||
|
||||
tokenSelector := fields.SelectorFromSet(map[string]string{client.SecretType: string(api.SecretTypeServiceAccountToken)})
|
||||
secrets, err := d.Secrets(namespace).List(labels.Everything(), tokenSelector)
|
||||
if err == nil {
|
||||
for _, s := range secrets.Items {
|
||||
name, _ := s.Annotations[api.ServiceAccountNameKey]
|
||||
uid, _ := s.Annotations[api.ServiceAccountUIDKey]
|
||||
if name == serviceAccount.Name && uid == string(serviceAccount.UID) {
|
||||
tokens = append(tokens, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return describeServiceAccount(serviceAccount, tokens)
|
||||
}
|
||||
|
||||
func describeServiceAccount(serviceAccount *api.ServiceAccount, tokens []api.Secret) (string, error) {
|
||||
return tabbedString(func(out io.Writer) error {
|
||||
fmt.Fprintf(out, "Name:\t%s\n", serviceAccount.Name)
|
||||
fmt.Fprintf(out, "Labels:\t%s\n", formatLabels(serviceAccount.Labels))
|
||||
|
||||
if len(serviceAccount.Secrets) == 0 {
|
||||
fmt.Fprintf(out, "Secrets:\t<none>\n")
|
||||
} else {
|
||||
prefix := "Secrets:"
|
||||
for _, s := range serviceAccount.Secrets {
|
||||
fmt.Fprintf(out, "%s\t%s\n", prefix, s)
|
||||
prefix = " "
|
||||
}
|
||||
fmt.Fprintln(out)
|
||||
}
|
||||
|
||||
if len(tokens) == 0 {
|
||||
fmt.Fprintf(out, "Tokens: \t<none>\n")
|
||||
} else {
|
||||
prefix := "Tokens: "
|
||||
for _, t := range tokens {
|
||||
fmt.Fprintf(out, "%s\t%s\n", prefix, t.Name)
|
||||
prefix = " "
|
||||
}
|
||||
fmt.Fprintln(out)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// NodeDescriber generates information about a node.
|
||||
type NodeDescriber struct {
|
||||
client.Interface
|
||||
|
|
|
@ -255,6 +255,7 @@ var limitRangeColumns = []string{"NAME"}
|
|||
var resourceQuotaColumns = []string{"NAME"}
|
||||
var namespaceColumns = []string{"NAME", "LABELS", "STATUS"}
|
||||
var secretColumns = []string{"NAME", "TYPE", "DATA"}
|
||||
var serviceAccountColumns = []string{"NAME", "SECRETS"}
|
||||
var persistentVolumeColumns = []string{"NAME", "LABELS", "CAPACITY", "ACCESSMODES", "STATUS", "CLAIM"}
|
||||
var persistentVolumeClaimColumns = []string{"NAME", "LABELS", "STATUS", "VOLUME"}
|
||||
var componentStatusColumns = []string{"NAME", "STATUS", "MESSAGE", "ERROR"}
|
||||
|
@ -283,6 +284,8 @@ func (h *HumanReadablePrinter) addDefaultHandlers() {
|
|||
h.Handler(namespaceColumns, printNamespaceList)
|
||||
h.Handler(secretColumns, printSecret)
|
||||
h.Handler(secretColumns, printSecretList)
|
||||
h.Handler(serviceAccountColumns, printServiceAccount)
|
||||
h.Handler(serviceAccountColumns, printServiceAccountList)
|
||||
h.Handler(persistentVolumeClaimColumns, printPersistentVolumeClaim)
|
||||
h.Handler(persistentVolumeClaimColumns, printPersistentVolumeClaimList)
|
||||
h.Handler(persistentVolumeColumns, printPersistentVolume)
|
||||
|
@ -596,6 +599,21 @@ func printSecretList(list *api.SecretList, w io.Writer) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func printServiceAccount(item *api.ServiceAccount, w io.Writer) error {
|
||||
_, err := fmt.Fprintf(w, "%s\t%d\n", item.Name, len(item.Secrets))
|
||||
return err
|
||||
}
|
||||
|
||||
func printServiceAccountList(list *api.ServiceAccountList, w io.Writer) error {
|
||||
for _, item := range list.Items {
|
||||
if err := printServiceAccount(&item, w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func printNode(node *api.Node, w io.Writer) error {
|
||||
conditionMap := make(map[api.NodeConditionType]*api.NodeCondition)
|
||||
NodeAllConditions := []api.NodeConditionType{api.NodeReady}
|
||||
|
|
|
@ -65,6 +65,7 @@ import (
|
|||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/service"
|
||||
ipallocator "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/service/ipallocator"
|
||||
etcdipallocator "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/service/ipallocator/etcd"
|
||||
serviceaccountetcd "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/serviceaccount/etcd"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/ui"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
|
@ -398,6 +399,7 @@ func (m *Master) init(c *Config) {
|
|||
|
||||
resourceQuotaStorage, resourceQuotaStatusStorage := resourcequotaetcd.NewStorage(c.EtcdHelper)
|
||||
secretStorage := secretetcd.NewStorage(c.EtcdHelper)
|
||||
serviceAccountStorage := serviceaccountetcd.NewStorage(c.EtcdHelper)
|
||||
persistentVolumeStorage, persistentVolumeStatusStorage := pvetcd.NewStorage(c.EtcdHelper)
|
||||
persistentVolumeClaimStorage, persistentVolumeClaimStatusStorage := pvcetcd.NewStorage(c.EtcdHelper)
|
||||
|
||||
|
@ -449,6 +451,7 @@ func (m *Master) init(c *Config) {
|
|||
"namespaces/status": namespaceStatusStorage,
|
||||
"namespaces/finalize": namespaceFinalizeStorage,
|
||||
"secrets": secretStorage,
|
||||
"serviceAccounts": serviceAccountStorage,
|
||||
"persistentVolumes": persistentVolumeStorage,
|
||||
"persistentVolumes/status": persistentVolumeStatusStorage,
|
||||
"persistentVolumeClaims": persistentVolumeClaimStorage,
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package serviceaccount provides a Registry interface and a strategy
|
||||
// implementation for storing ServiceAccount API objects.
|
||||
package serviceaccount
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
|
||||
etcdgeneric "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic/etcd"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/serviceaccount"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||
)
|
||||
|
||||
// REST implements a RESTStorage for service accounts against etcd
|
||||
type REST struct {
|
||||
*etcdgeneric.Etcd
|
||||
}
|
||||
|
||||
const Prefix = "/serviceaccounts"
|
||||
|
||||
// NewStorage returns a RESTStorage object that will work against service accounts objects.
|
||||
func NewStorage(h tools.EtcdHelper) *REST {
|
||||
store := &etcdgeneric.Etcd{
|
||||
NewFunc: func() runtime.Object { return &api.ServiceAccount{} },
|
||||
NewListFunc: func() runtime.Object { return &api.ServiceAccountList{} },
|
||||
KeyRootFunc: func(ctx api.Context) string {
|
||||
return etcdgeneric.NamespaceKeyRootFunc(ctx, Prefix)
|
||||
},
|
||||
KeyFunc: func(ctx api.Context, name string) (string, error) {
|
||||
return etcdgeneric.NamespaceKeyFunc(ctx, Prefix, name)
|
||||
},
|
||||
ObjectNameFunc: func(obj runtime.Object) (string, error) {
|
||||
return obj.(*api.ServiceAccount).Name, nil
|
||||
},
|
||||
PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher {
|
||||
return serviceaccount.Matcher(label, field)
|
||||
},
|
||||
EndpointName: "serviceaccounts",
|
||||
|
||||
Helper: h,
|
||||
}
|
||||
|
||||
store.CreateStrategy = serviceaccount.Strategy
|
||||
store.UpdateStrategy = serviceaccount.Strategy
|
||||
store.ReturnDeletedObject = true
|
||||
|
||||
return &REST{store}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest/resttest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
|
||||
)
|
||||
|
||||
func newHelper(t *testing.T) (*tools.FakeEtcdClient, tools.EtcdHelper) {
|
||||
fakeEtcdClient := tools.NewFakeEtcdClient(t)
|
||||
fakeEtcdClient.TestIndex = true
|
||||
helper := tools.NewEtcdHelper(fakeEtcdClient, testapi.Codec(), etcdtest.PathPrefix())
|
||||
return fakeEtcdClient, helper
|
||||
}
|
||||
|
||||
func validNewServiceAccount(name string) *api.ServiceAccount {
|
||||
return &api.ServiceAccount{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Secrets: []api.ObjectReference{},
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
fakeEtcdClient, helper := newHelper(t)
|
||||
storage := NewStorage(helper)
|
||||
test := resttest.New(t, storage, fakeEtcdClient.SetError)
|
||||
serviceAccount := validNewServiceAccount("foo")
|
||||
serviceAccount.Name = ""
|
||||
serviceAccount.GenerateName = "foo-"
|
||||
test.TestCreate(
|
||||
// valid
|
||||
serviceAccount,
|
||||
// invalid
|
||||
&api.ServiceAccount{},
|
||||
&api.ServiceAccount{
|
||||
ObjectMeta: api.ObjectMeta{Name: "name with spaces"},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
fakeEtcdClient, helper := newHelper(t)
|
||||
storage := NewStorage(helper)
|
||||
test := resttest.New(t, storage, fakeEtcdClient.SetError)
|
||||
key := etcdtest.AddPrefix("serviceaccounts/default/foo")
|
||||
|
||||
fakeEtcdClient.ExpectNotFoundGet(key)
|
||||
fakeEtcdClient.ChangeIndex = 2
|
||||
serviceAccount := validNewServiceAccount("foo")
|
||||
existing := validNewServiceAccount("exists")
|
||||
obj, err := storage.Create(api.NewDefaultContext(), existing)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create object: %v", err)
|
||||
}
|
||||
older := obj.(*api.ServiceAccount)
|
||||
older.ResourceVersion = "1"
|
||||
|
||||
test.TestUpdate(
|
||||
serviceAccount,
|
||||
existing,
|
||||
older,
|
||||
)
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package serviceaccount
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
)
|
||||
|
||||
// Registry is an interface implemented by things that know how to store ServiceAccount objects.
|
||||
type Registry interface {
|
||||
// ListServiceAccounts obtains a list of ServiceAccounts having labels which match selector.
|
||||
ListServiceAccounts(ctx api.Context, selector labels.Selector) (*api.ServiceAccountList, error)
|
||||
// Watch for new/changed/deleted service accounts
|
||||
WatchServiceAccounts(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
|
||||
// Get a specific ServiceAccount
|
||||
GetServiceAccount(ctx api.Context, name string) (*api.ServiceAccount, error)
|
||||
// Create a ServiceAccount based on a specification.
|
||||
CreateServiceAccount(ctx api.Context, ServiceAccount *api.ServiceAccount) error
|
||||
// Update an existing ServiceAccount
|
||||
UpdateServiceAccount(ctx api.Context, ServiceAccount *api.ServiceAccount) error
|
||||
// Delete an existing ServiceAccount
|
||||
DeleteServiceAccount(ctx api.Context, name string) error
|
||||
}
|
||||
|
||||
// storage puts strong typing around storage calls
|
||||
type storage struct {
|
||||
rest.StandardStorage
|
||||
}
|
||||
|
||||
// NewRegistry returns a new Registry interface for the given Storage. Any mismatched
|
||||
// types will panic.
|
||||
func NewRegistry(s rest.StandardStorage) Registry {
|
||||
return &storage{s}
|
||||
}
|
||||
|
||||
func (s *storage) ListServiceAccounts(ctx api.Context, label labels.Selector) (*api.ServiceAccountList, error) {
|
||||
obj, err := s.List(ctx, label, fields.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*api.ServiceAccountList), nil
|
||||
}
|
||||
|
||||
func (s *storage) WatchServiceAccounts(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
|
||||
return s.Watch(ctx, label, field, resourceVersion)
|
||||
}
|
||||
|
||||
func (s *storage) GetServiceAccount(ctx api.Context, name string) (*api.ServiceAccount, error) {
|
||||
obj, err := s.Get(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*api.ServiceAccount), nil
|
||||
}
|
||||
|
||||
func (s *storage) CreateServiceAccount(ctx api.Context, serviceAccount *api.ServiceAccount) error {
|
||||
_, err := s.Create(ctx, serviceAccount)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *storage) UpdateServiceAccount(ctx api.Context, serviceAccount *api.ServiceAccount) error {
|
||||
_, _, err := s.Update(ctx, serviceAccount)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *storage) DeleteServiceAccount(ctx api.Context, name string) error {
|
||||
_, err := s.Delete(ctx, name, nil)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package serviceaccount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/fielderrors"
|
||||
)
|
||||
|
||||
// strategy implements behavior for ServiceAccount objects
|
||||
type strategy struct {
|
||||
runtime.ObjectTyper
|
||||
api.NameGenerator
|
||||
}
|
||||
|
||||
// Strategy is the default logic that applies when creating and updating ServiceAccount
|
||||
// objects via the REST API.
|
||||
var Strategy = strategy{api.Scheme, api.SimpleNameGenerator}
|
||||
|
||||
func (strategy) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (strategy) PrepareForCreate(obj runtime.Object) {
|
||||
cleanSecretReferences(obj.(*api.ServiceAccount))
|
||||
}
|
||||
|
||||
func (strategy) Validate(ctx api.Context, obj runtime.Object) fielderrors.ValidationErrorList {
|
||||
return validation.ValidateServiceAccount(obj.(*api.ServiceAccount))
|
||||
}
|
||||
|
||||
func (strategy) AllowCreateOnUpdate() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (strategy) PrepareForUpdate(obj, old runtime.Object) {
|
||||
cleanSecretReferences(obj.(*api.ServiceAccount))
|
||||
}
|
||||
|
||||
func cleanSecretReferences(serviceAccount *api.ServiceAccount) {
|
||||
for i, secret := range serviceAccount.Secrets {
|
||||
serviceAccount.Secrets[i] = api.ObjectReference{Name: secret.Name}
|
||||
}
|
||||
}
|
||||
|
||||
func (strategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) fielderrors.ValidationErrorList {
|
||||
return validation.ValidateServiceAccountUpdate(old.(*api.ServiceAccount), obj.(*api.ServiceAccount))
|
||||
}
|
||||
|
||||
// Matcher returns a generic matcher for a given label and field selector.
|
||||
func Matcher(label labels.Selector, field fields.Selector) generic.Matcher {
|
||||
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) {
|
||||
sa, ok := obj.(*api.ServiceAccount)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("not a serviceaccount")
|
||||
}
|
||||
fields := SelectableFields(sa)
|
||||
return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil
|
||||
})
|
||||
}
|
||||
|
||||
// SelectableFields returns a label set that represents the object
|
||||
func SelectableFields(obj *api.ServiceAccount) labels.Set {
|
||||
return labels.Set{
|
||||
"metadata.name": obj.Name,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue