...

Source file src/k8s.io/kubectl/pkg/cmd/rollout/rollout_restart.go

Documentation: k8s.io/kubectl/pkg/cmd/rollout

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package rollout
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"github.com/spf13/cobra"
    23  
    24  	"k8s.io/apimachinery/pkg/types"
    25  	utilerrors "k8s.io/apimachinery/pkg/util/errors"
    26  	"k8s.io/cli-runtime/pkg/genericclioptions"
    27  	"k8s.io/cli-runtime/pkg/genericiooptions"
    28  	"k8s.io/cli-runtime/pkg/printers"
    29  	"k8s.io/cli-runtime/pkg/resource"
    30  	"k8s.io/kubectl/pkg/cmd/set"
    31  	cmdutil "k8s.io/kubectl/pkg/cmd/util"
    32  	"k8s.io/kubectl/pkg/polymorphichelpers"
    33  	"k8s.io/kubectl/pkg/scheme"
    34  	"k8s.io/kubectl/pkg/util/completion"
    35  	"k8s.io/kubectl/pkg/util/i18n"
    36  	"k8s.io/kubectl/pkg/util/templates"
    37  )
    38  
    39  // RestartOptions is the start of the data required to perform the operation.  As new fields are added, add them here instead of
    40  // referencing the cmd.Flags()
    41  type RestartOptions struct {
    42  	PrintFlags *genericclioptions.PrintFlags
    43  	ToPrinter  func(string) (printers.ResourcePrinter, error)
    44  
    45  	Resources []string
    46  
    47  	Builder          func() *resource.Builder
    48  	Restarter        polymorphichelpers.ObjectRestarterFunc
    49  	Namespace        string
    50  	EnforceNamespace bool
    51  	LabelSelector    string
    52  
    53  	resource.FilenameOptions
    54  	genericiooptions.IOStreams
    55  
    56  	fieldManager string
    57  }
    58  
    59  var (
    60  	restartLong = templates.LongDesc(i18n.T(`
    61  		Restart a resource.
    62  
    63  	        Resource rollout will be restarted.`))
    64  
    65  	restartExample = templates.Examples(`
    66  		# Restart all deployments in test-namespace namespace
    67  		kubectl rollout restart deployment -n test-namespace
    68  
    69  		# Restart a deployment
    70  		kubectl rollout restart deployment/nginx
    71  
    72  		# Restart a daemon set
    73  		kubectl rollout restart daemonset/abc
    74  
    75  		# Restart deployments with the app=nginx label
    76  		kubectl rollout restart deployment --selector=app=nginx`)
    77  )
    78  
    79  // NewRolloutRestartOptions returns an initialized RestartOptions instance
    80  func NewRolloutRestartOptions(streams genericiooptions.IOStreams) *RestartOptions {
    81  	return &RestartOptions{
    82  		PrintFlags: genericclioptions.NewPrintFlags("restarted").WithTypeSetter(scheme.Scheme),
    83  		IOStreams:  streams,
    84  	}
    85  }
    86  
    87  // NewCmdRolloutRestart returns a Command instance for 'rollout restart' sub command
    88  func NewCmdRolloutRestart(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command {
    89  	o := NewRolloutRestartOptions(streams)
    90  
    91  	validArgs := []string{"deployment", "daemonset", "statefulset"}
    92  
    93  	cmd := &cobra.Command{
    94  		Use:                   "restart RESOURCE",
    95  		DisableFlagsInUseLine: true,
    96  		Short:                 i18n.T("Restart a resource"),
    97  		Long:                  restartLong,
    98  		Example:               restartExample,
    99  		ValidArgsFunction:     completion.SpecifiedResourceTypeAndNameCompletionFunc(f, validArgs),
   100  		Run: func(cmd *cobra.Command, args []string) {
   101  			cmdutil.CheckErr(o.Complete(f, cmd, args))
   102  			cmdutil.CheckErr(o.Validate())
   103  			cmdutil.CheckErr(o.RunRestart())
   104  		},
   105  	}
   106  
   107  	usage := "identifying the resource to get from a server."
   108  	cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
   109  	cmdutil.AddFieldManagerFlagVar(cmd, &o.fieldManager, "kubectl-rollout")
   110  	cmdutil.AddLabelSelectorFlagVar(cmd, &o.LabelSelector)
   111  	o.PrintFlags.AddFlags(cmd)
   112  	return cmd
   113  }
   114  
   115  // Complete completes all the required options
   116  func (o *RestartOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
   117  	o.Resources = args
   118  
   119  	o.Restarter = polymorphichelpers.ObjectRestarterFn
   120  
   121  	var err error
   122  	o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
   123  	if err != nil {
   124  		return err
   125  	}
   126  
   127  	o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) {
   128  		o.PrintFlags.NamePrintFlags.Operation = operation
   129  		return o.PrintFlags.ToPrinter()
   130  	}
   131  
   132  	o.Builder = f.NewBuilder
   133  
   134  	return nil
   135  }
   136  
   137  func (o *RestartOptions) Validate() error {
   138  	if len(o.Resources) == 0 && cmdutil.IsFilenameSliceEmpty(o.Filenames, o.Kustomize) {
   139  		return fmt.Errorf("required resource not specified")
   140  	}
   141  	return nil
   142  }
   143  
   144  // RunRestart performs the execution of 'rollout restart' sub command
   145  func (o RestartOptions) RunRestart() error {
   146  	r := o.Builder().
   147  		WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
   148  		NamespaceParam(o.Namespace).DefaultNamespace().
   149  		FilenameParam(o.EnforceNamespace, &o.FilenameOptions).
   150  		LabelSelectorParam(o.LabelSelector).
   151  		ResourceTypeOrNameArgs(true, o.Resources...).
   152  		ContinueOnError().
   153  		Latest().
   154  		Flatten().
   155  		Do()
   156  	if err := r.Err(); err != nil {
   157  		return err
   158  	}
   159  
   160  	allErrs := []error{}
   161  	infos, err := r.Infos()
   162  	if err != nil {
   163  		// restore previous command behavior where
   164  		// an error caused by retrieving infos due to
   165  		// at least a single broken object did not result
   166  		// in an immediate return, but rather an overall
   167  		// aggregation of errors.
   168  		allErrs = append(allErrs, err)
   169  	}
   170  
   171  	patches := set.CalculatePatches(infos, scheme.DefaultJSONEncoder(), set.PatchFn(o.Restarter))
   172  
   173  	if len(patches) == 0 && len(allErrs) == 0 {
   174  		fmt.Fprintf(o.ErrOut, "No resources found in %s namespace.\n", o.Namespace)
   175  		return nil
   176  	}
   177  
   178  	for _, patch := range patches {
   179  		info := patch.Info
   180  
   181  		if patch.Err != nil {
   182  			resourceString := info.Mapping.Resource.Resource
   183  			if len(info.Mapping.Resource.Group) > 0 {
   184  				resourceString = resourceString + "." + info.Mapping.Resource.Group
   185  			}
   186  			allErrs = append(allErrs, fmt.Errorf("error: %s %q %v", resourceString, info.Name, patch.Err))
   187  			continue
   188  		}
   189  
   190  		if string(patch.Patch) == "{}" || len(patch.Patch) == 0 {
   191  			allErrs = append(allErrs, fmt.Errorf("failed to create patch for %v: if restart has already been triggered within the past second, please wait before attempting to trigger another", info.Name))
   192  			continue
   193  		}
   194  
   195  		obj, err := resource.NewHelper(info.Client, info.Mapping).
   196  			WithFieldManager(o.fieldManager).
   197  			Patch(info.Namespace, info.Name, types.StrategicMergePatchType, patch.Patch, nil)
   198  		if err != nil {
   199  			allErrs = append(allErrs, fmt.Errorf("failed to patch: %v", err))
   200  			continue
   201  		}
   202  
   203  		info.Refresh(obj, true)
   204  		printer, err := o.ToPrinter("restarted")
   205  		if err != nil {
   206  			allErrs = append(allErrs, err)
   207  			continue
   208  		}
   209  		if err = printer.PrintObj(info.Object, o.Out); err != nil {
   210  			allErrs = append(allErrs, err)
   211  		}
   212  	}
   213  
   214  	return utilerrors.NewAggregate(allErrs)
   215  }
   216  

View as plain text