From 8f229057484453bd1b820d00c940efbbc56addc5 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Fri, 5 May 2023 11:31:03 -0400 Subject: [PATCH] [refactor] refactoring flags and options in Expose cmd This PR decouples the command options from the input flags. The input flags from the command are then translated to options which are further used while running the command. Signed-off-by: Varsha Prasad Narsing --- .../k8s.io/kubectl/pkg/cmd/expose/expose.go | 148 ++++++++++++------ 1 file changed, 102 insertions(+), 46 deletions(-) diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/expose/expose.go b/staging/src/k8s.io/kubectl/pkg/cmd/expose/expose.go index 0351cd560ea..9c8af8a078a 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/expose/expose.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/expose/expose.go @@ -135,10 +135,33 @@ type ExposeServiceOptions struct { genericiooptions.IOStreams } -// NewExposeServiceOptions creates a new ExposeServiceOptions and return a pointer to the -// struct -func NewExposeServiceOptions(ioStreams genericiooptions.IOStreams) *ExposeServiceOptions { - return &ExposeServiceOptions{ +// exposeServiceFlags is a struct that contains the user input flags to the command. +type ExposeServiceFlags struct { + cmdutil.OverrideOptions + PrintFlags *genericclioptions.PrintFlags + RecordFlags *genericclioptions.RecordFlags + + fieldManager string + Protocol string + + // Port will be used if a user specifies --port OR the exposed object as one port + Port string + Type string + LoadBalancerIP string + Selector string + Labels string + TargetPort string + ExternalIP string + Name string + SessionAffinity string + ClusterIP string + Recorder genericclioptions.Recorder + FilenameOptions resource.FilenameOptions + genericiooptions.IOStreams +} + +func NewExposeFlags(ioStreams genericiooptions.IOStreams) *ExposeServiceFlags { + return &ExposeServiceFlags{ RecordFlags: genericclioptions.NewRecordFlags(), PrintFlags: genericclioptions.NewPrintFlags("exposed").WithTypeSetter(scheme.Scheme), @@ -149,7 +172,7 @@ func NewExposeServiceOptions(ioStreams genericiooptions.IOStreams) *ExposeServic // NewCmdExposeService is a command to expose the service from user's input func NewCmdExposeService(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { - o := NewExposeServiceOptions(streams) + flags := NewExposeFlags(streams) validArgs := []string{} resources := regexp.MustCompile(`\s*,`).Split(exposeResources, -1) @@ -165,55 +188,89 @@ func NewCmdExposeService(f cmdutil.Factory, streams genericiooptions.IOStreams) Example: exposeExample, ValidArgsFunction: completion.SpecifiedResourceTypeAndNameCompletionFunc(f, validArgs), Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd)) + o, err := flags.ToOptions(cmd, args) + cmdutil.CheckErr(err) + cmdutil.CheckErr(o.Complete(f)) cmdutil.CheckErr(o.RunExpose(cmd, args)) }, } - o.RecordFlags.AddFlags(cmd) - o.PrintFlags.AddFlags(cmd) - - cmd.Flags().StringVar(&o.Protocol, "protocol", o.Protocol, i18n.T("The network protocol for the service to be created. Default is 'TCP'.")) - cmd.Flags().StringVar(&o.Port, "port", o.Port, i18n.T("The port that the service should serve on. Copied from the resource being exposed, if unspecified")) - cmd.Flags().StringVar(&o.Type, "type", o.Type, i18n.T("Type for this service: ClusterIP, NodePort, LoadBalancer, or ExternalName. Default is 'ClusterIP'.")) - cmd.Flags().StringVar(&o.LoadBalancerIP, "load-balancer-ip", o.LoadBalancerIP, i18n.T("IP to assign to the LoadBalancer. If empty, an ephemeral IP will be created and used (cloud-provider specific).")) - cmd.Flags().StringVar(&o.Selector, "selector", o.Selector, i18n.T("A label selector to use for this service. Only equality-based selector requirements are supported. If empty (the default) infer the selector from the replication controller or replica set.)")) - cmd.Flags().StringVarP(&o.Labels, "labels", "l", o.Labels, "Labels to apply to the service created by this call.") - cmd.Flags().StringVar(&o.TargetPort, "target-port", o.TargetPort, i18n.T("Name or number for the port on the container that the service should direct traffic to. Optional.")) - cmd.Flags().StringVar(&o.ExternalIP, "external-ip", o.ExternalIP, i18n.T("Additional external IP address (not managed by Kubernetes) to accept for the service. If this IP is routed to a node, the service can be accessed by this IP in addition to its generated service IP.")) - cmd.Flags().StringVar(&o.Name, "name", o.Name, i18n.T("The name for the newly created object.")) - cmd.Flags().StringVar(&o.SessionAffinity, "session-affinity", o.SessionAffinity, i18n.T("If non-empty, set the session affinity for the service to this; legal values: 'None', 'ClientIP'")) - cmd.Flags().StringVar(&o.ClusterIP, "cluster-ip", o.ClusterIP, i18n.T("ClusterIP to be assigned to the service. Leave empty to auto-allocate, or set to 'None' to create a headless service.")) - cmdutil.AddFieldManagerFlagVar(cmd, &o.fieldManager, "kubectl-expose") - o.AddOverrideFlags(cmd) - - usage := "identifying the resource to expose a service" - cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage) - cmdutil.AddDryRunFlag(cmd) - cmdutil.AddApplyAnnotationFlags(cmd) + flags.AddFlags(cmd) return cmd } +func (flags *ExposeServiceFlags) AddFlags(cmd *cobra.Command) { + flags.PrintFlags.AddFlags(cmd) + flags.RecordFlags.AddFlags(cmd) + + cmd.Flags().StringVar(&flags.Protocol, "protocol", flags.Protocol, i18n.T("The network protocol for the service to be created. Default is 'TCP'.")) + cmd.Flags().StringVar(&flags.Port, "port", flags.Port, i18n.T("The port that the service should serve on. Copied from the resource being exposed, if unspecified")) + cmd.Flags().StringVar(&flags.Type, "type", flags.Type, i18n.T("Type for this service: ClusterIP, NodePort, LoadBalancer, or ExternalName. Default is 'ClusterIP'.")) + cmd.Flags().StringVar(&flags.LoadBalancerIP, "load-balancer-ip", flags.LoadBalancerIP, i18n.T("IP to assign to the LoadBalancer. If empty, an ephemeral IP will be created and used (cloud-provider specific).")) + cmd.Flags().StringVar(&flags.Selector, "selector", flags.Selector, i18n.T("A label selector to use for this service. Only equality-based selector requirements are supported. If empty (the default) infer the selector from the replication controller or replica set.)")) + cmd.Flags().StringVarP(&flags.Labels, "labels", "l", flags.Labels, "Labels to apply to the service created by this call.") + cmd.Flags().StringVar(&flags.TargetPort, "target-port", flags.TargetPort, i18n.T("Name or number for the port on the container that the service should direct traffic to. Optional.")) + cmd.Flags().StringVar(&flags.ExternalIP, "external-ip", flags.ExternalIP, i18n.T("Additional external IP address (not managed by Kubernetes) to accept for the service. If this IP is routed to a node, the service can be accessed by this IP in addition to its generated service IP.")) + cmd.Flags().StringVar(&flags.Name, "name", flags.Name, i18n.T("The name for the newly created object.")) + cmd.Flags().StringVar(&flags.SessionAffinity, "session-affinity", flags.SessionAffinity, i18n.T("If non-empty, set the session affinity for the service to this; legal values: 'None', 'ClientIP'")) + cmd.Flags().StringVar(&flags.ClusterIP, "cluster-ip", flags.ClusterIP, i18n.T("ClusterIP to be assigned to the service. Leave empty to auto-allocate, or set to 'None' to create a headless service.")) + + cmdutil.AddFieldManagerFlagVar(cmd, &flags.fieldManager, "kubectl-expose") + flags.AddOverrideFlags(cmd) + + cmdutil.AddDryRunFlag(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) + + usage := "identifying the resource to expose a service" + cmdutil.AddFilenameOptionFlags(cmd, &flags.FilenameOptions, usage) +} + +func (flags *ExposeServiceFlags) ToOptions(cmd *cobra.Command, args []string) (*ExposeServiceOptions, error) { + dryRunStratergy, err := cmdutil.GetDryRunStrategy(cmd) + if err != nil { + return nil, err + } + + cmdutil.PrintFlagsWithDryRunStrategy(flags.PrintFlags, dryRunStratergy) + printer, err := flags.PrintFlags.ToPrinter() + if err != nil { + return nil, err + } + + flags.RecordFlags.Complete(cmd) + recorder, err := flags.RecordFlags.ToRecorder() + if err != nil { + return nil, err + } + + e := &ExposeServiceOptions{ + DryRunStrategy: dryRunStratergy, + PrintObj: printer.PrintObj, + Recorder: recorder, + IOStreams: flags.IOStreams, + fieldManager: flags.fieldManager, + PrintFlags: flags.PrintFlags, + RecordFlags: flags.RecordFlags, + FilenameOptions: flags.FilenameOptions, + Protocol: flags.Protocol, + Port: flags.Port, + Type: flags.Type, + LoadBalancerIP: flags.LoadBalancerIP, + Selector: flags.Selector, + Labels: flags.Labels, + TargetPort: flags.TargetPort, + ExternalIP: flags.ExternalIP, + Name: flags.Name, + SessionAffinity: flags.SessionAffinity, + ClusterIP: flags.ClusterIP, + OverrideOptions: flags.OverrideOptions, + } + return e, nil +} + // Complete loads data from the command line environment -func (o *ExposeServiceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { +func (o *ExposeServiceOptions) Complete(f cmdutil.Factory) error { var err error - o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd) - if err != nil { - return err - } - - cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) - printer, err := o.PrintFlags.ToPrinter() - if err != nil { - return err - } - o.PrintObj = printer.PrintObj - - o.RecordFlags.Complete(cmd) - o.Recorder, err = o.RecordFlags.ToRecorder() - if err != nil { - return err - } o.Builder = f.NewBuilder() o.ClientForMapping = f.ClientForMapping @@ -368,7 +425,6 @@ func (o *ExposeServiceOptions) RunExpose(cmd *cobra.Command, args []string) erro if err != nil { return err } - return o.PrintObj(actualObject, o.Out) }) return err