refactor Factory make it interface

pull/6/head
AdoHe 2016-10-13 08:09:26 +08:00
parent 06c1f2ba2c
commit 593d8e0d7c
2 changed files with 639 additions and 587 deletions

View File

@ -77,87 +77,107 @@ const (
// TODO: make the functions interfaces // TODO: make the functions interfaces
// TODO: pass the various interfaces on the factory directly into the command constructors (so the // TODO: pass the various interfaces on the factory directly into the command constructors (so the
// commands are decoupled from the factory). // commands are decoupled from the factory).
type Factory struct { type Factory interface {
clients *ClientCache // Returns internal flagset
flags *pflag.FlagSet FlagSet() *pflag.FlagSet
// Returns interfaces for dealing with arbitrary runtime.Objects. // Returns interfaces for dealing with arbitrary runtime.Objects.
Object func() (meta.RESTMapper, runtime.ObjectTyper) Object() (meta.RESTMapper, runtime.ObjectTyper)
// Returns interfaces for dealing with arbitrary // Returns interfaces for dealing with arbitrary
// runtime.Unstructured. This performs API calls to discover types. // runtime.Unstructured. This performs API calls to discover types.
UnstructuredObject func() (meta.RESTMapper, runtime.ObjectTyper, error) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper, error)
// Returns interfaces for decoding objects - if toInternal is set, decoded objects will be converted // Returns interfaces for decoding objects - if toInternal is set, decoded objects will be converted
// into their internal form (if possible). Eventually the internal form will be removed as an option, // into their internal form (if possible). Eventually the internal form will be removed as an option,
// and only versioned objects will be returned. // and only versioned objects will be returned.
Decoder func(toInternal bool) runtime.Decoder Decoder(toInternal bool) runtime.Decoder
// Returns an encoder capable of encoding a provided object into JSON in the default desired version. // Returns an encoder capable of encoding a provided object into JSON in the default desired version.
JSONEncoder func() runtime.Encoder JSONEncoder() runtime.Encoder
// ClientSet gives you back an internal, generated clientset // ClientSet gives you back an internal, generated clientset
ClientSet func() (*internalclientset.Clientset, error) ClientSet() (*internalclientset.Clientset, error)
// Returns a RESTClient for accessing Kubernetes resources or an error. // Returns a RESTClient for accessing Kubernetes resources or an error.
RESTClient func() (*restclient.RESTClient, error) RESTClient() (*restclient.RESTClient, error)
// Returns a client.Config for accessing the Kubernetes server. // Returns a client.Config for accessing the Kubernetes server.
ClientConfig func() (*restclient.Config, error) ClientConfig() (*restclient.Config, error)
// Returns a RESTClient for working with the specified RESTMapping or an error. This is intended // Returns a RESTClient for working with the specified RESTMapping or an error. This is intended
// for working with arbitrary resources and is not guaranteed to point to a Kubernetes APIServer. // for working with arbitrary resources and is not guaranteed to point to a Kubernetes APIServer.
ClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error) ClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error)
// Returns a RESTClient for working with Unstructured objects. // Returns a RESTClient for working with Unstructured objects.
UnstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error) UnstructuredClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error)
// Returns a Describer for displaying the specified RESTMapping type or an error. // Returns a Describer for displaying the specified RESTMapping type or an error.
Describer func(mapping *meta.RESTMapping) (kubectl.Describer, error) Describer(mapping *meta.RESTMapping) (kubectl.Describer, error)
// Returns a Printer for formatting objects of the given type or an error. // Returns a Printer for formatting objects of the given type or an error.
Printer func(mapping *meta.RESTMapping, options kubectl.PrintOptions) (kubectl.ResourcePrinter, error) Printer(mapping *meta.RESTMapping, options kubectl.PrintOptions) (kubectl.ResourcePrinter, error)
// Returns a Scaler for changing the size of the specified RESTMapping type or an error // Returns a Scaler for changing the size of the specified RESTMapping type or an error
Scaler func(mapping *meta.RESTMapping) (kubectl.Scaler, error) Scaler(mapping *meta.RESTMapping) (kubectl.Scaler, error)
// Returns a Reaper for gracefully shutting down resources. // Returns a Reaper for gracefully shutting down resources.
Reaper func(mapping *meta.RESTMapping) (kubectl.Reaper, error) Reaper(mapping *meta.RESTMapping) (kubectl.Reaper, error)
// Returns a HistoryViewer for viewing change history // Returns a HistoryViewer for viewing change history
HistoryViewer func(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) HistoryViewer(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error)
// Returns a Rollbacker for changing the rollback version of the specified RESTMapping type or an error // Returns a Rollbacker for changing the rollback version of the specified RESTMapping type or an error
Rollbacker func(mapping *meta.RESTMapping) (kubectl.Rollbacker, error) Rollbacker(mapping *meta.RESTMapping) (kubectl.Rollbacker, error)
// Returns a StatusViewer for printing rollout status. // Returns a StatusViewer for printing rollout status.
StatusViewer func(mapping *meta.RESTMapping) (kubectl.StatusViewer, error) StatusViewer(mapping *meta.RESTMapping) (kubectl.StatusViewer, error)
// MapBasedSelectorForObject returns the map-based selector associated with the provided object. If a // MapBasedSelectorForObject returns the map-based selector associated with the provided object. If a
// new set-based selector is provided, an error is returned if the selector cannot be converted to a // new set-based selector is provided, an error is returned if the selector cannot be converted to a
// map-based selector // map-based selector
MapBasedSelectorForObject func(object runtime.Object) (string, error) MapBasedSelectorForObject(object runtime.Object) (string, error)
// PortsForObject returns the ports associated with the provided object // PortsForObject returns the ports associated with the provided object
PortsForObject func(object runtime.Object) ([]string, error) PortsForObject(object runtime.Object) ([]string, error)
// ProtocolsForObject returns the <port, protocol> mapping associated with the provided object // ProtocolsForObject returns the <port, protocol> mapping associated with the provided object
ProtocolsForObject func(object runtime.Object) (map[string]string, error) ProtocolsForObject(object runtime.Object) (map[string]string, error)
// LabelsForObject returns the labels associated with the provided object // LabelsForObject returns the labels associated with the provided object
LabelsForObject func(object runtime.Object) (map[string]string, error) LabelsForObject(object runtime.Object) (map[string]string, error)
// LogsForObject returns a request for the logs associated with the provided object // LogsForObject returns a request for the logs associated with the provided object
LogsForObject func(object, options runtime.Object) (*restclient.Request, error) LogsForObject(object, options runtime.Object) (*restclient.Request, error)
// PauseObject marks the provided object as paused ie. it will not be reconciled by its controller. // PauseObject marks the provided object as paused ie. it will not be reconciled by its controller.
PauseObject func(object runtime.Object) (bool, error) PauseObject(object runtime.Object) (bool, error)
// ResumeObject resumes a paused object ie. it will be reconciled by its controller. // ResumeObject resumes a paused object ie. it will be reconciled by its controller.
ResumeObject func(object runtime.Object) (bool, error) ResumeObject(object runtime.Object) (bool, error)
// Returns a schema that can validate objects stored on disk. // Returns a schema that can validate objects stored on disk.
Validator func(validate bool, cacheDir string) (validation.Schema, error) Validator(validate bool, cacheDir string) (validation.Schema, error)
// SwaggerSchema returns the schema declaration for the provided group version kind. // SwaggerSchema returns the schema declaration for the provided group version kind.
SwaggerSchema func(unversioned.GroupVersionKind) (*swagger.ApiDeclaration, error) SwaggerSchema(unversioned.GroupVersionKind) (*swagger.ApiDeclaration, error)
// Returns the default namespace to use in cases where no // Returns the default namespace to use in cases where no
// other namespace is specified and whether the namespace was // other namespace is specified and whether the namespace was
// overridden. // overridden.
DefaultNamespace func() (string, bool, error) DefaultNamespace() (string, bool, error)
// Generators returns the generators for the provided command // Generators returns the generators for the provided command
Generators func(cmdName string) map[string]kubectl.Generator Generators(cmdName string) map[string]kubectl.Generator
// Check whether the kind of resources could be exposed // Check whether the kind of resources could be exposed
CanBeExposed func(kind unversioned.GroupKind) error CanBeExposed(kind unversioned.GroupKind) error
// Check whether the kind of resources could be autoscaled // Check whether the kind of resources could be autoscaled
CanBeAutoscaled func(kind unversioned.GroupKind) error CanBeAutoscaled(kind unversioned.GroupKind) error
// AttachablePodForObject returns the pod to which to attach given an object. // AttachablePodForObject returns the pod to which to attach given an object.
AttachablePodForObject func(object runtime.Object) (*api.Pod, error) AttachablePodForObject(object runtime.Object) (*api.Pod, error)
// UpdatePodSpecForObject will call the provided function on the pod spec this object supports, // UpdatePodSpecForObject will call the provided function on the pod spec this object supports,
// return false if no pod spec is supported, or return an error. // return false if no pod spec is supported, or return an error.
UpdatePodSpecForObject func(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error) UpdatePodSpecForObject(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error)
// EditorEnvs returns a group of environment variables that the edit command // EditorEnvs returns a group of environment variables that the edit command
// can range over in order to determine if the user has specified an editor // can range over in order to determine if the user has specified an editor
// of their choice. // of their choice.
EditorEnvs func() []string EditorEnvs() []string
// PrintObjectSpecificMessage prints object-specific messages on the provided writer // PrintObjectSpecificMessage prints object-specific messages on the provided writer
PrintObjectSpecificMessage func(obj runtime.Object, out io.Writer) PrintObjectSpecificMessage(obj runtime.Object, out io.Writer)
// Command will stringify and return all environment arguments ie. a command run by a client
// using the factory.
Command() string
// BindFlags adds any flags that are common to all kubectl sub commands.
BindFlags(flags *pflag.FlagSet)
// BindExternalFlags adds any flags defined by external projects (not part of pflags)
BindExternalFlags(flags *pflag.FlagSet)
DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *kubectl.PrintOptions
// DefaultResourceFilterFunc returns a collection of FilterFuncs suitable for filtering specific resource types.
DefaultResourceFilterFunc() kubectl.Filters
// PrintObject prints an api object given command line flags to modify the output format
PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error
// PrinterForMapping returns a printer suitable for displaying the provided resource type.
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (kubectl.ResourcePrinter, error)
// One stop shopping for a Builder
NewBuilder() *resource.Builder
} }
const ( const (
@ -273,10 +293,17 @@ func makeInterfacesFor(versionList []unversioned.GroupVersion) func(version unve
} }
} }
type factory struct {
flags *pflag.FlagSet
clientConfig clientcmd.ClientConfig
clients *ClientCache
}
// NewFactory creates a factory with the default Kubernetes resources defined // NewFactory creates a factory with the default Kubernetes resources defined
// if optionalClientConfig is nil, then flags will be bound to a new clientcmd.ClientConfig. // if optionalClientConfig is nil, then flags will be bound to a new clientcmd.ClientConfig.
// if optionalClientConfig is not nil, then this factory will make use of it. // if optionalClientConfig is not nil, then this factory will make use of it.
func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory { func NewFactory(optionalClientConfig clientcmd.ClientConfig) Factory {
flags := pflag.NewFlagSet("", pflag.ContinueOnError) flags := pflag.NewFlagSet("", pflag.ContinueOnError)
flags.SetNormalizeFunc(utilflag.WarnWordSepNormalizeFunc) // Warn for "_" flags flags.SetNormalizeFunc(utilflag.WarnWordSepNormalizeFunc) // Warn for "_" flags
@ -286,13 +313,19 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
} }
clients := NewClientCache(clientConfig) clients := NewClientCache(clientConfig)
return &factory{
return &Factory{
clients: clients,
flags: flags, flags: flags,
clientConfig: clientConfig,
clients: clients,
}
}
Object: func() (meta.RESTMapper, runtime.ObjectTyper) { func (f *factory) FlagSet() *pflag.FlagSet {
cfg, err := clientConfig.ClientConfig() return f.flags
}
func (f *factory) Object() (meta.RESTMapper, runtime.ObjectTyper) {
cfg, err := f.clientConfig.ClientConfig()
checkErrWithPrefix("failed to get client config: ", err) checkErrWithPrefix("failed to get client config: ", err)
cmdApiVersion := unversioned.GroupVersion{} cmdApiVersion := unversioned.GroupVersion{}
if cfg.GroupVersion != nil { if cfg.GroupVersion != nil {
@ -329,9 +362,10 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
// wrap with output preferences // wrap with output preferences
mapper = kubectl.OutputVersionMapper{RESTMapper: mapper, OutputVersions: []unversioned.GroupVersion{cmdApiVersion}} mapper = kubectl.OutputVersionMapper{RESTMapper: mapper, OutputVersions: []unversioned.GroupVersion{cmdApiVersion}}
return mapper, api.Scheme return mapper, api.Scheme
}, }
UnstructuredObject: func() (meta.RESTMapper, runtime.ObjectTyper, error) {
cfg, err := clients.ClientConfigForVersion(nil) func (f *factory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper, error) {
cfg, err := f.clients.ClientConfigForVersion(nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -363,22 +397,26 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
typer := discovery.NewUnstructuredObjectTyper(groupResources) typer := discovery.NewUnstructuredObjectTyper(groupResources)
return NewShortcutExpander(mapper, dc), typer, nil return NewShortcutExpander(mapper, dc), typer, nil
}, }
RESTClient: func() (*restclient.RESTClient, error) {
clientConfig, err := clients.ClientConfigForVersion(nil) func (f *factory) RESTClient() (*restclient.RESTClient, error) {
clientConfig, err := f.clients.ClientConfigForVersion(nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return restclient.RESTClientFor(clientConfig) return restclient.RESTClientFor(clientConfig)
}, }
ClientSet: func() (*internalclientset.Clientset, error) {
return clients.ClientSetForVersion(nil) func (f *factory) ClientSet() (*internalclientset.Clientset, error) {
}, return f.clients.ClientSetForVersion(nil)
ClientConfig: func() (*restclient.Config, error) { }
return clients.ClientConfigForVersion(nil)
}, func (f *factory) ClientConfig() (*restclient.Config, error) {
ClientForMapping: func(mapping *meta.RESTMapping) (resource.RESTClient, error) { return f.clients.ClientConfigForVersion(nil)
cfg, err := clientConfig.ClientConfig() }
func (f *factory) ClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) {
cfg, err := f.clientConfig.ClientConfig()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -389,7 +427,7 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
switch gvk.Group { switch gvk.Group {
case federation.GroupName: case federation.GroupName:
mappingVersion := mapping.GroupVersionKind.GroupVersion() mappingVersion := mapping.GroupVersionKind.GroupVersion()
return clients.FederationClientForVersion(&mappingVersion) return f.clients.FederationClientForVersion(&mappingVersion)
case api.GroupName: case api.GroupName:
cfg.APIPath = "/api" cfg.APIPath = "/api"
default: default:
@ -401,9 +439,10 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
cfg.NegotiatedSerializer = thirdpartyresourcedata.NewNegotiatedSerializer(api.Codecs, gvk.Kind, gv, gv) cfg.NegotiatedSerializer = thirdpartyresourcedata.NewNegotiatedSerializer(api.Codecs, gvk.Kind, gv, gv)
} }
return restclient.RESTClientFor(cfg) return restclient.RESTClientFor(cfg)
}, }
UnstructuredClientForMapping: func(mapping *meta.RESTMapping) (resource.RESTClient, error) {
cfg, err := clientConfig.ClientConfig() func (f *factory) UnstructuredClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) {
cfg, err := f.clientConfig.ClientConfig()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -418,11 +457,12 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
cfg.ContentConfig = dynamic.ContentConfig() cfg.ContentConfig = dynamic.ContentConfig()
cfg.GroupVersion = &gv cfg.GroupVersion = &gv
return restclient.RESTClientFor(cfg) return restclient.RESTClientFor(cfg)
}, }
Describer: func(mapping *meta.RESTMapping) (kubectl.Describer, error) {
func (f *factory) Describer(mapping *meta.RESTMapping) (kubectl.Describer, error) {
mappingVersion := mapping.GroupVersionKind.GroupVersion() mappingVersion := mapping.GroupVersionKind.GroupVersion()
if mapping.GroupVersionKind.Group == federation.GroupName { if mapping.GroupVersionKind.Group == federation.GroupName {
fedClientSet, err := clients.FederationClientSetForVersion(&mappingVersion) fedClientSet, err := f.clients.FederationClientSetForVersion(&mappingVersion)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -430,7 +470,7 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
return &kubectl.ClusterDescriber{Interface: fedClientSet}, nil return &kubectl.ClusterDescriber{Interface: fedClientSet}, nil
} }
} }
clientset, err := clients.ClientSetForVersion(&mappingVersion) clientset, err := f.clients.ClientSetForVersion(&mappingVersion)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -438,8 +478,9 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
return describer, nil return describer, nil
} }
return nil, fmt.Errorf("no description has been implemented for %q", mapping.GroupVersionKind.Kind) return nil, fmt.Errorf("no description has been implemented for %q", mapping.GroupVersionKind.Kind)
}, }
Decoder: func(toInternal bool) runtime.Decoder {
func (f *factory) Decoder(toInternal bool) runtime.Decoder {
var decoder runtime.Decoder var decoder runtime.Decoder
if toInternal { if toInternal {
decoder = api.Codecs.UniversalDecoder() decoder = api.Codecs.UniversalDecoder()
@ -447,15 +488,17 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
decoder = api.Codecs.UniversalDeserializer() decoder = api.Codecs.UniversalDeserializer()
} }
return thirdpartyresourcedata.NewDecoder(decoder, "") return thirdpartyresourcedata.NewDecoder(decoder, "")
}
}, func (f *factory) JSONEncoder() runtime.Encoder {
JSONEncoder: func() runtime.Encoder {
return api.Codecs.LegacyCodec(registered.EnabledVersions()...) return api.Codecs.LegacyCodec(registered.EnabledVersions()...)
}, }
Printer: func(mapping *meta.RESTMapping, options kubectl.PrintOptions) (kubectl.ResourcePrinter, error) {
func (f *factory) Printer(mapping *meta.RESTMapping, options kubectl.PrintOptions) (kubectl.ResourcePrinter, error) {
return kubectl.NewHumanReadablePrinter(options), nil return kubectl.NewHumanReadablePrinter(options), nil
}, }
MapBasedSelectorForObject: func(object runtime.Object) (string, error) {
func (f *factory) MapBasedSelectorForObject(object runtime.Object) (string, error) {
// TODO: replace with a swagger schema based approach (identify pod selector via schema introspection) // TODO: replace with a swagger schema based approach (identify pod selector via schema introspection)
switch t := object.(type) { switch t := object.(type) {
case *api.ReplicationController: case *api.ReplicationController:
@ -491,8 +534,9 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
} }
return "", fmt.Errorf("cannot extract pod selector from %v", gvks[0]) return "", fmt.Errorf("cannot extract pod selector from %v", gvks[0])
} }
}, }
PortsForObject: func(object runtime.Object) ([]string, error) {
func (f *factory) PortsForObject(object runtime.Object) ([]string, error) {
// TODO: replace with a swagger schema based approach (identify pod selector via schema introspection) // TODO: replace with a swagger schema based approach (identify pod selector via schema introspection)
switch t := object.(type) { switch t := object.(type) {
case *api.ReplicationController: case *api.ReplicationController:
@ -512,8 +556,9 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
} }
return nil, fmt.Errorf("cannot extract ports from %v", gvks[0]) return nil, fmt.Errorf("cannot extract ports from %v", gvks[0])
} }
}, }
ProtocolsForObject: func(object runtime.Object) (map[string]string, error) {
func (f *factory) ProtocolsForObject(object runtime.Object) (map[string]string, error) {
// TODO: replace with a swagger schema based approach (identify pod selector via schema introspection) // TODO: replace with a swagger schema based approach (identify pod selector via schema introspection)
switch t := object.(type) { switch t := object.(type) {
case *api.ReplicationController: case *api.ReplicationController:
@ -533,12 +578,14 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
} }
return nil, fmt.Errorf("cannot extract protocols from %v", gvks[0]) return nil, fmt.Errorf("cannot extract protocols from %v", gvks[0])
} }
}, }
LabelsForObject: func(object runtime.Object) (map[string]string, error) {
func (f *factory) LabelsForObject(object runtime.Object) (map[string]string, error) {
return meta.NewAccessor().Labels(object) return meta.NewAccessor().Labels(object)
}, }
LogsForObject: func(object, options runtime.Object) (*restclient.Request, error) {
clientset, err := clients.ClientSetForVersion(nil) func (f *factory) LogsForObject(object, options runtime.Object) (*restclient.Request, error) {
clientset, err := f.clients.ClientSetForVersion(nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -595,9 +642,10 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
} }
return nil, fmt.Errorf("cannot get the logs from %v", gvks[0]) return nil, fmt.Errorf("cannot get the logs from %v", gvks[0])
} }
}, }
PauseObject: func(object runtime.Object) (bool, error) {
clientset, err := clients.ClientSetForVersion(nil) func (f *factory) PauseObject(object runtime.Object) (bool, error) {
clientset, err := f.clients.ClientSetForVersion(nil)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -617,9 +665,10 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
} }
return false, fmt.Errorf("cannot pause %v", gvks[0]) return false, fmt.Errorf("cannot pause %v", gvks[0])
} }
}, }
ResumeObject: func(object runtime.Object) (bool, error) {
clientset, err := clients.ClientSetForVersion(nil) func (f *factory) ResumeObject(object runtime.Object) (bool, error) {
clientset, err := f.clients.ClientSetForVersion(nil)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -639,50 +688,56 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
} }
return false, fmt.Errorf("cannot resume %v", gvks[0]) return false, fmt.Errorf("cannot resume %v", gvks[0])
} }
}, }
Scaler: func(mapping *meta.RESTMapping) (kubectl.Scaler, error) {
func (f *factory) Scaler(mapping *meta.RESTMapping) (kubectl.Scaler, error) {
mappingVersion := mapping.GroupVersionKind.GroupVersion() mappingVersion := mapping.GroupVersionKind.GroupVersion()
clientset, err := clients.ClientSetForVersion(&mappingVersion) clientset, err := f.clients.ClientSetForVersion(&mappingVersion)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return kubectl.ScalerFor(mapping.GroupVersionKind.GroupKind(), clientset) return kubectl.ScalerFor(mapping.GroupVersionKind.GroupKind(), clientset)
}, }
Reaper: func(mapping *meta.RESTMapping) (kubectl.Reaper, error) {
func (f *factory) Reaper(mapping *meta.RESTMapping) (kubectl.Reaper, error) {
mappingVersion := mapping.GroupVersionKind.GroupVersion() mappingVersion := mapping.GroupVersionKind.GroupVersion()
clientset, err := clients.ClientSetForVersion(&mappingVersion) clientset, err := f.clients.ClientSetForVersion(&mappingVersion)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return kubectl.ReaperFor(mapping.GroupVersionKind.GroupKind(), clientset) return kubectl.ReaperFor(mapping.GroupVersionKind.GroupKind(), clientset)
}, }
HistoryViewer: func(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) {
func (f *factory) HistoryViewer(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) {
mappingVersion := mapping.GroupVersionKind.GroupVersion() mappingVersion := mapping.GroupVersionKind.GroupVersion()
clientset, err := clients.ClientSetForVersion(&mappingVersion) clientset, err := f.clients.ClientSetForVersion(&mappingVersion)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return kubectl.HistoryViewerFor(mapping.GroupVersionKind.GroupKind(), clientset) return kubectl.HistoryViewerFor(mapping.GroupVersionKind.GroupKind(), clientset)
}, }
Rollbacker: func(mapping *meta.RESTMapping) (kubectl.Rollbacker, error) {
func (f *factory) Rollbacker(mapping *meta.RESTMapping) (kubectl.Rollbacker, error) {
mappingVersion := mapping.GroupVersionKind.GroupVersion() mappingVersion := mapping.GroupVersionKind.GroupVersion()
clientset, err := clients.ClientSetForVersion(&mappingVersion) clientset, err := f.clients.ClientSetForVersion(&mappingVersion)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return kubectl.RollbackerFor(mapping.GroupVersionKind.GroupKind(), clientset) return kubectl.RollbackerFor(mapping.GroupVersionKind.GroupKind(), clientset)
}, }
StatusViewer: func(mapping *meta.RESTMapping) (kubectl.StatusViewer, error) {
func (f *factory) StatusViewer(mapping *meta.RESTMapping) (kubectl.StatusViewer, error) {
mappingVersion := mapping.GroupVersionKind.GroupVersion() mappingVersion := mapping.GroupVersionKind.GroupVersion()
clientset, err := clients.ClientSetForVersion(&mappingVersion) clientset, err := f.clients.ClientSetForVersion(&mappingVersion)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return kubectl.StatusViewerFor(mapping.GroupVersionKind.GroupKind(), clientset) return kubectl.StatusViewerFor(mapping.GroupVersionKind.GroupKind(), clientset)
}, }
Validator: func(validate bool, cacheDir string) (validation.Schema, error) {
func (f *factory) Validator(validate bool, cacheDir string) (validation.Schema, error) {
if validate { if validate {
clientConfig, err := clients.ClientConfigForVersion(nil) clientConfig, err := f.clients.ClientConfigForVersion(nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -690,7 +745,7 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
if err != nil { if err != nil {
return nil, err return nil, err
} }
clientset, err := clients.ClientSetForVersion(nil) clientset, err := f.clients.ClientSetForVersion(nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -703,7 +758,7 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
dir = "" // disable caching as a fallback dir = "" // disable caching as a fallback
} }
} }
fedClient, err := clients.FederationClientForVersion(nil) fedClient, err := f.clients.FederationClientForVersion(nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -714,22 +769,26 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
}, nil }, nil
} }
return validation.NullSchema{}, nil return validation.NullSchema{}, nil
}, }
SwaggerSchema: func(gvk unversioned.GroupVersionKind) (*swagger.ApiDeclaration, error) {
func (f *factory) SwaggerSchema(gvk unversioned.GroupVersionKind) (*swagger.ApiDeclaration, error) {
version := gvk.GroupVersion() version := gvk.GroupVersion()
clientset, err := clients.ClientSetForVersion(&version) clientset, err := f.clients.ClientSetForVersion(&version)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return clientset.Discovery().SwaggerSchema(version) return clientset.Discovery().SwaggerSchema(version)
}, }
DefaultNamespace: func() (string, bool, error) {
return clientConfig.Namespace() func (f *factory) DefaultNamespace() (string, bool, error) {
}, return f.clientConfig.Namespace()
Generators: func(cmdName string) map[string]kubectl.Generator { }
func (f *factory) Generators(cmdName string) map[string]kubectl.Generator {
return DefaultGenerators(cmdName) return DefaultGenerators(cmdName)
}, }
CanBeExposed: func(kind unversioned.GroupKind) error {
func (f *factory) CanBeExposed(kind unversioned.GroupKind) error {
switch kind { switch kind {
case api.Kind("ReplicationController"), api.Kind("Service"), api.Kind("Pod"), extensions.Kind("Deployment"), extensions.Kind("ReplicaSet"): case api.Kind("ReplicationController"), api.Kind("Service"), api.Kind("Pod"), extensions.Kind("Deployment"), extensions.Kind("ReplicaSet"):
// nothing to do here // nothing to do here
@ -737,8 +796,9 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
return fmt.Errorf("cannot expose a %s", kind) return fmt.Errorf("cannot expose a %s", kind)
} }
return nil return nil
}, }
CanBeAutoscaled: func(kind unversioned.GroupKind) error {
func (f *factory) CanBeAutoscaled(kind unversioned.GroupKind) error {
switch kind { switch kind {
case api.Kind("ReplicationController"), extensions.Kind("Deployment"), extensions.Kind("ReplicaSet"): case api.Kind("ReplicationController"), extensions.Kind("Deployment"), extensions.Kind("ReplicaSet"):
// nothing to do here // nothing to do here
@ -746,9 +806,10 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
return fmt.Errorf("cannot autoscale a %v", kind) return fmt.Errorf("cannot autoscale a %v", kind)
} }
return nil return nil
}, }
AttachablePodForObject: func(object runtime.Object) (*api.Pod, error) {
clientset, err := clients.ClientSetForVersion(nil) func (f *factory) AttachablePodForObject(object runtime.Object) (*api.Pod, error) {
clientset, err := f.clients.ClientSetForVersion(nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -783,9 +844,9 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
} }
return nil, fmt.Errorf("cannot attach to %v: not implemented", gvks[0]) return nil, fmt.Errorf("cannot attach to %v: not implemented", gvks[0])
} }
}, }
// UpdatePodSpecForObject update the pod specification for the provided object
UpdatePodSpecForObject: func(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error) { func (f *factory) UpdatePodSpecForObject(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error) {
// TODO: replace with a swagger schema based approach (identify pod template via schema introspection) // TODO: replace with a swagger schema based approach (identify pod template via schema introspection)
switch t := obj.(type) { switch t := obj.(type) {
case *api.Pod: case *api.Pod:
@ -808,11 +869,13 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
default: default:
return false, fmt.Errorf("the object is not a pod or does not have a pod template") return false, fmt.Errorf("the object is not a pod or does not have a pod template")
} }
}, }
EditorEnvs: func() []string {
func (f *factory) EditorEnvs() []string {
return []string{"KUBE_EDITOR", "EDITOR"} return []string{"KUBE_EDITOR", "EDITOR"}
}, }
PrintObjectSpecificMessage: func(obj runtime.Object, out io.Writer) {
func (f *factory) PrintObjectSpecificMessage(obj runtime.Object, out io.Writer) {
switch obj := obj.(type) { switch obj := obj.(type) {
case *api.Service: case *api.Service:
if obj.Spec.Type == api.ServiceTypeNodePort { if obj.Spec.Type == api.ServiceTypeNodePort {
@ -838,8 +901,6 @@ See http://kubernetes.io/docs/user-guide/services-firewalls for more details.
out.Write([]byte(msg)) out.Write([]byte(msg))
} }
} }
},
}
} }
// GetFirstPod returns a pod matching the namespace and label selector // GetFirstPod returns a pod matching the namespace and label selector
@ -883,10 +944,8 @@ func GetFirstPod(client coreclient.PodsGetter, namespace string, selector labels
return pod, 1, nil return pod, 1, nil
} }
// Command will stringify and return all environment arguments ie. a command run by a client
// using the factory.
// TODO: We need to filter out stuff like secrets. // TODO: We need to filter out stuff like secrets.
func (f *Factory) Command() string { func (f *factory) Command() string {
if len(os.Args) == 0 { if len(os.Args) == 0 {
return "" return ""
} }
@ -895,8 +954,7 @@ func (f *Factory) Command() string {
return strings.Join(args, " ") return strings.Join(args, " ")
} }
// BindFlags adds any flags that are common to all kubectl sub commands. func (f *factory) BindFlags(flags *pflag.FlagSet) {
func (f *Factory) BindFlags(flags *pflag.FlagSet) {
// Merge factory's flags // Merge factory's flags
flags.AddFlagSet(f.flags) flags.AddFlagSet(f.flags)
@ -911,8 +969,7 @@ func (f *Factory) BindFlags(flags *pflag.FlagSet) {
flags.SetNormalizeFunc(utilflag.WordSepNormalizeFunc) flags.SetNormalizeFunc(utilflag.WordSepNormalizeFunc)
} }
// BindCommonFlags adds any flags defined by external projects (not part of pflags) func (f *factory) BindExternalFlags(flags *pflag.FlagSet) {
func (f *Factory) BindExternalFlags(flags *pflag.FlagSet) {
// any flags defined by external projects (not part of pflags) // any flags defined by external projects (not part of pflags)
flags.AddGoFlagSet(flag.CommandLine) flags.AddGoFlagSet(flag.CommandLine)
} }
@ -1179,7 +1236,7 @@ func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig {
return clientConfig return clientConfig
} }
func (f *Factory) DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *kubectl.PrintOptions { func (f *factory) DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *kubectl.PrintOptions {
columnLabel, err := cmd.Flags().GetStringSlice("label-columns") columnLabel, err := cmd.Flags().GetStringSlice("label-columns")
if err != nil { if err != nil {
columnLabel = []string{} columnLabel = []string{}
@ -1197,13 +1254,11 @@ func (f *Factory) DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace
return opts return opts
} }
// DefaultResourceFilterFunc returns a collection of FilterFuncs suitable for filtering specific resource types. func (f *factory) DefaultResourceFilterFunc() kubectl.Filters {
func (f *Factory) DefaultResourceFilterFunc() kubectl.Filters {
return kubectl.NewResourceFilter() return kubectl.NewResourceFilter()
} }
// PrintObject prints an api object given command line flags to modify the output format func (f *factory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error {
func (f *Factory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error {
gvks, _, err := api.Scheme.ObjectKinds(obj) gvks, _, err := api.Scheme.ObjectKinds(obj)
if err != nil { if err != nil {
return err return err
@ -1221,9 +1276,7 @@ func (f *Factory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, obj ru
return printer.PrintObj(obj, out) return printer.PrintObj(obj, out)
} }
// PrinterForMapping returns a printer suitable for displaying the provided resource type. func (f *factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (kubectl.ResourcePrinter, error) {
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
func (f *Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (kubectl.ResourcePrinter, error) {
printer, ok, err := PrinterForCommand(cmd) printer, ok, err := PrinterForCommand(cmd)
if err != nil { if err != nil {
return nil, err return nil, err
@ -1273,8 +1326,7 @@ func (f *Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMappin
return printer, nil return printer, nil
} }
// One stop shopping for a Builder func (f *factory) NewBuilder() *resource.Builder {
func (f *Factory) NewBuilder() *resource.Builder {
mapper, typer := f.Object() mapper, typer := f.Object()
return resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)) return resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true))

View File

@ -55,7 +55,7 @@ import (
func TestNewFactoryDefaultFlagBindings(t *testing.T) { func TestNewFactoryDefaultFlagBindings(t *testing.T) {
factory := NewFactory(nil) factory := NewFactory(nil)
if !factory.flags.HasFlags() { if !factory.FlagSet().HasFlags() {
t.Errorf("Expected flags, but didn't get any") t.Errorf("Expected flags, but didn't get any")
} }
} }
@ -64,8 +64,8 @@ func TestNewFactoryNoFlagBindings(t *testing.T) {
clientConfig := clientcmd.NewDefaultClientConfig(*clientcmdapi.NewConfig(), &clientcmd.ConfigOverrides{}) clientConfig := clientcmd.NewDefaultClientConfig(*clientcmdapi.NewConfig(), &clientcmd.ConfigOverrides{})
factory := NewFactory(clientConfig) factory := NewFactory(clientConfig)
if factory.flags.HasFlags() { if factory.FlagSet().HasFlags() {
t.Errorf("Expected zero flags, but got %v", factory.flags) t.Errorf("Expected zero flags, but got %v", factory.FlagSet())
} }
} }
@ -229,12 +229,12 @@ func TestCanBeExposed(t *testing.T) {
func TestFlagUnderscoreRenaming(t *testing.T) { func TestFlagUnderscoreRenaming(t *testing.T) {
factory := NewFactory(nil) factory := NewFactory(nil)
factory.flags.SetNormalizeFunc(flag.WordSepNormalizeFunc) factory.FlagSet().SetNormalizeFunc(flag.WordSepNormalizeFunc)
factory.flags.Bool("valid_flag", false, "bool value") factory.FlagSet().Bool("valid_flag", false, "bool value")
// In case of failure of this test check this PR: spf13/pflag#23 // In case of failure of this test check this PR: spf13/pflag#23
if factory.flags.Lookup("valid_flag").Name != "valid-flag" { if factory.FlagSet().Lookup("valid_flag").Name != "valid-flag" {
t.Fatalf("Expected flag name to be valid-flag, got %s", factory.flags.Lookup("valid_flag").Name) t.Fatalf("Expected flag name to be valid-flag, got %s", factory.FlagSet().Lookup("valid_flag").Name)
} }
} }