sigs.k8s.io/cluster-api@v1.7.1/cmd/clusterctl/client/move.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  	"os"
    22  
    23  	"github.com/pkg/errors"
    24  
    25  	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster"
    26  )
    27  
    28  // MoveOptions carries the options supported by move.
    29  type MoveOptions struct {
    30  	// FromKubeconfig defines the kubeconfig to use for accessing the source management cluster. If empty,
    31  	// default rules for kubeconfig discovery will be used.
    32  	FromKubeconfig Kubeconfig
    33  
    34  	// ToKubeconfig defines the kubeconfig to use for accessing the target management cluster. If empty,
    35  	// default rules for kubeconfig discovery will be used.
    36  	ToKubeconfig Kubeconfig
    37  
    38  	// Namespace where the objects describing the workload cluster exists. If unspecified, the current
    39  	// namespace will be used.
    40  	Namespace string
    41  
    42  	// ExperimentalResourceMutatorFn accepts any number of resource mutator functions that are applied on all resources being moved.
    43  	// This is an experimental feature and is exposed only from the library and not (yet) through the CLI.
    44  	ExperimentalResourceMutators []cluster.ResourceMutatorFunc
    45  
    46  	// FromDirectory apply configuration from directory.
    47  	FromDirectory string
    48  
    49  	// ToDirectory save configuration to directory.
    50  	ToDirectory string
    51  
    52  	// DryRun means the move action is a dry run, no real action will be performed.
    53  	DryRun bool
    54  }
    55  
    56  func (c *clusterctlClient) Move(ctx context.Context, options MoveOptions) error {
    57  	// Both backup and restore makes no sense. It's a complete move.
    58  	if options.FromDirectory != "" && options.ToDirectory != "" {
    59  		return errors.Errorf("can't set both FromDirectory and ToDirectory")
    60  	}
    61  
    62  	if !options.DryRun &&
    63  		options.FromDirectory == "" &&
    64  		options.ToDirectory == "" &&
    65  		options.ToKubeconfig == (Kubeconfig{}) {
    66  		return errors.Errorf("at least one of FromDirectory, ToDirectory and ToKubeconfig must be set")
    67  	}
    68  
    69  	if options.ToDirectory != "" {
    70  		return c.toDirectory(ctx, options)
    71  	} else if options.FromDirectory != "" {
    72  		return c.fromDirectory(ctx, options)
    73  	}
    74  
    75  	return c.move(ctx, options)
    76  }
    77  
    78  func (c *clusterctlClient) move(ctx context.Context, options MoveOptions) error {
    79  	// Get the client for interacting with the source management cluster.
    80  	fromCluster, err := c.getClusterClient(ctx, options.FromKubeconfig)
    81  	if err != nil {
    82  		return err
    83  	}
    84  
    85  	// If the option specifying the Namespace is empty, try to detect it.
    86  	if options.Namespace == "" {
    87  		currentNamespace, err := fromCluster.Proxy().CurrentNamespace()
    88  		if err != nil {
    89  			return err
    90  		}
    91  		options.Namespace = currentNamespace
    92  	}
    93  
    94  	var toCluster cluster.Client
    95  	if !options.DryRun {
    96  		// Get the client for interacting with the target management cluster.
    97  		if toCluster, err = c.getClusterClient(ctx, options.ToKubeconfig); err != nil {
    98  			return err
    99  		}
   100  	}
   101  
   102  	return fromCluster.ObjectMover().Move(ctx, options.Namespace, toCluster, options.DryRun, options.ExperimentalResourceMutators...)
   103  }
   104  
   105  func (c *clusterctlClient) fromDirectory(ctx context.Context, options MoveOptions) error {
   106  	toCluster, err := c.getClusterClient(ctx, options.ToKubeconfig)
   107  	if err != nil {
   108  		return err
   109  	}
   110  
   111  	if _, err := os.Stat(options.FromDirectory); os.IsNotExist(err) {
   112  		return err
   113  	}
   114  
   115  	return toCluster.ObjectMover().FromDirectory(ctx, toCluster, options.FromDirectory)
   116  }
   117  
   118  func (c *clusterctlClient) toDirectory(ctx context.Context, options MoveOptions) error {
   119  	fromCluster, err := c.getClusterClient(ctx, options.FromKubeconfig)
   120  	if err != nil {
   121  		return err
   122  	}
   123  
   124  	// If the option specifying the Namespace is empty, try to detect it.
   125  	if options.Namespace == "" {
   126  		currentNamespace, err := fromCluster.Proxy().CurrentNamespace()
   127  		if err != nil {
   128  			return err
   129  		}
   130  		options.Namespace = currentNamespace
   131  	}
   132  
   133  	if _, err := os.Stat(options.ToDirectory); os.IsNotExist(err) {
   134  		return err
   135  	}
   136  
   137  	return fromCluster.ObjectMover().ToDirectory(ctx, options.Namespace, options.ToDirectory)
   138  }
   139  
   140  func (c *clusterctlClient) getClusterClient(ctx context.Context, kubeconfig Kubeconfig) (cluster.Client, error) {
   141  	cluster, err := c.clusterClientFactory(ClusterClientFactoryInput{Kubeconfig: kubeconfig})
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  
   146  	// Ensure this command only runs against management clusters with the current Cluster API contract.
   147  	if err := cluster.ProviderInventory().CheckCAPIContract(ctx); err != nil {
   148  		return nil, err
   149  	}
   150  
   151  	// Ensures the custom resource definitions required by clusterctl are in place.
   152  	if err := cluster.ProviderInventory().EnsureCustomResourceDefinitions(ctx); err != nil {
   153  		return nil, err
   154  	}
   155  	return cluster, nil
   156  }