sigs.k8s.io/cluster-api@v1.7.1/cmd/clusterctl/client/rollout.go (about)

     1  /*
     2  Copyright 2020 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 client
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"strings"
    23  
    24  	corev1 "k8s.io/api/core/v1"
    25  
    26  	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster"
    27  	"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/util"
    28  )
    29  
    30  // RolloutRestartOptions carries the options supported by RolloutRestart.
    31  type RolloutRestartOptions struct {
    32  	// Kubeconfig defines the kubeconfig to use for accessing the management cluster. If empty,
    33  	// default rules for kubeconfig discovery will be used.
    34  	Kubeconfig Kubeconfig
    35  
    36  	// Resources for the rollout command
    37  	Resources []string
    38  
    39  	// Namespace where the resource(s) live. If unspecified, the namespace name will be inferred
    40  	// from the current configuration.
    41  	Namespace string
    42  }
    43  
    44  // RolloutPauseOptions carries the options supported by RolloutPause.
    45  type RolloutPauseOptions struct {
    46  	// Kubeconfig defines the kubeconfig to use for accessing the management cluster. If empty,
    47  	// default rules for kubeconfig discovery will be used.
    48  	Kubeconfig Kubeconfig
    49  
    50  	// Resources for the rollout command
    51  	Resources []string
    52  
    53  	// Namespace where the resource(s) live. If unspecified, the namespace name will be inferred
    54  	// from the current configuration.
    55  	Namespace string
    56  }
    57  
    58  // RolloutResumeOptions carries the options supported by RolloutResume.
    59  type RolloutResumeOptions struct {
    60  	// Kubeconfig defines the kubeconfig to use for accessing the management cluster. If empty,
    61  	// default rules for kubeconfig discovery will be used.
    62  	Kubeconfig Kubeconfig
    63  
    64  	// Resources for the rollout command
    65  	Resources []string
    66  
    67  	// Namespace where the resource(s) live. If unspecified, the namespace name will be inferred
    68  	// from the current configuration.
    69  	Namespace string
    70  }
    71  
    72  // RolloutUndoOptions carries the options supported by RolloutUndo.
    73  type RolloutUndoOptions struct {
    74  	// Kubeconfig defines the kubeconfig to use for accessing the management cluster. If empty,
    75  	// default rules for kubeconfig discovery will be used.
    76  	Kubeconfig Kubeconfig
    77  
    78  	// Resources for the rollout command
    79  	Resources []string
    80  
    81  	// Namespace where the resource(s) live. If unspecified, the namespace name will be inferred
    82  	// from the current configuration.
    83  	Namespace string
    84  
    85  	// Revision number to rollback to when issuing the undo command.
    86  	ToRevision int64
    87  }
    88  
    89  func (c *clusterctlClient) RolloutRestart(ctx context.Context, options RolloutRestartOptions) error {
    90  	clusterClient, err := c.clusterClientFactory(ClusterClientFactoryInput{Kubeconfig: options.Kubeconfig})
    91  	if err != nil {
    92  		return err
    93  	}
    94  	objRefs, err := getObjectRefs(clusterClient, options.Namespace, options.Resources)
    95  	if err != nil {
    96  		return err
    97  	}
    98  	for _, ref := range objRefs {
    99  		if err := c.alphaClient.Rollout().ObjectRestarter(ctx, clusterClient.Proxy(), ref); err != nil {
   100  			return err
   101  		}
   102  	}
   103  	return nil
   104  }
   105  
   106  func (c *clusterctlClient) RolloutPause(ctx context.Context, options RolloutPauseOptions) error {
   107  	clusterClient, err := c.clusterClientFactory(ClusterClientFactoryInput{Kubeconfig: options.Kubeconfig})
   108  	if err != nil {
   109  		return err
   110  	}
   111  	objRefs, err := getObjectRefs(clusterClient, options.Namespace, options.Resources)
   112  	if err != nil {
   113  		return err
   114  	}
   115  	for _, ref := range objRefs {
   116  		if err := c.alphaClient.Rollout().ObjectPauser(ctx, clusterClient.Proxy(), ref); err != nil {
   117  			return err
   118  		}
   119  	}
   120  	return nil
   121  }
   122  
   123  func (c *clusterctlClient) RolloutResume(ctx context.Context, options RolloutResumeOptions) error {
   124  	clusterClient, err := c.clusterClientFactory(ClusterClientFactoryInput{Kubeconfig: options.Kubeconfig})
   125  	if err != nil {
   126  		return err
   127  	}
   128  	objRefs, err := getObjectRefs(clusterClient, options.Namespace, options.Resources)
   129  	if err != nil {
   130  		return err
   131  	}
   132  	for _, ref := range objRefs {
   133  		if err := c.alphaClient.Rollout().ObjectResumer(ctx, clusterClient.Proxy(), ref); err != nil {
   134  			return err
   135  		}
   136  	}
   137  	return nil
   138  }
   139  
   140  func (c *clusterctlClient) RolloutUndo(ctx context.Context, options RolloutUndoOptions) error {
   141  	clusterClient, err := c.clusterClientFactory(ClusterClientFactoryInput{Kubeconfig: options.Kubeconfig})
   142  	if err != nil {
   143  		return err
   144  	}
   145  	objRefs, err := getObjectRefs(clusterClient, options.Namespace, options.Resources)
   146  	if err != nil {
   147  		return err
   148  	}
   149  	for _, ref := range objRefs {
   150  		if err := c.alphaClient.Rollout().ObjectRollbacker(ctx, clusterClient.Proxy(), ref, options.ToRevision); err != nil {
   151  			return err
   152  		}
   153  	}
   154  	return nil
   155  }
   156  
   157  func getObjectRefs(clusterClient cluster.Client, namespace string, resources []string) ([]corev1.ObjectReference, error) {
   158  	// If the option specifying the Namespace is empty, try to detect it.
   159  	if namespace == "" {
   160  		currentNamespace, err := clusterClient.Proxy().CurrentNamespace()
   161  		if err != nil {
   162  			return []corev1.ObjectReference{}, err
   163  		}
   164  		namespace = currentNamespace
   165  	}
   166  
   167  	if len(resources) == 0 {
   168  		return []corev1.ObjectReference{}, fmt.Errorf("required resource not specified")
   169  	}
   170  	normalized := normalizeResources(resources)
   171  	objRefs, err := util.GetObjectReferences(namespace, normalized...)
   172  	if err != nil {
   173  		return []corev1.ObjectReference{}, err
   174  	}
   175  	return objRefs, nil
   176  }
   177  
   178  func normalizeResources(input []string) []string {
   179  	normalized := make([]string, 0, len(input))
   180  	for _, in := range input {
   181  		normalized = append(normalized, strings.ToLower(in))
   182  	}
   183  	return normalized
   184  }