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 }