From 7a183594dda6c663c60a2c646f2929a600925d4a Mon Sep 17 00:00:00 2001 From: Oscar Utbult Date: Tue, 2 Aug 2022 11:52:02 +0200 Subject: [PATCH] clusterctl: Add move --to-directory and --from-directory flags These flags perform the same actions clusterctl backup and restore commands. Also adds deprecation warning to clusterctl backup and restore. --- cmd/clusterctl/client/client.go | 2 + cmd/clusterctl/client/cluster/mover.go | 52 +++++--- cmd/clusterctl/client/cluster/mover_test.go | 12 +- cmd/clusterctl/client/cluster/objectgraph.go | 6 +- cmd/clusterctl/client/move.go | 124 +++++++++++------- cmd/clusterctl/client/move_test.go | 61 ++++++++- cmd/clusterctl/cmd/backup.go | 5 +- cmd/clusterctl/cmd/move.go | 29 +++- cmd/clusterctl/cmd/restore.go | 7 +- .../commands/additional-commands.md | 4 + docs/book/src/clusterctl/commands/commands.md | 42 +++--- .../src/developer/providers/v1.2-to-v1.3.md | 4 + 12 files changed, 239 insertions(+), 109 deletions(-) diff --git a/cmd/clusterctl/client/client.go b/cmd/clusterctl/client/client.go index 2425ad8460f8..f7eb88272e12 100644 --- a/cmd/clusterctl/client/client.go +++ b/cmd/clusterctl/client/client.go @@ -55,9 +55,11 @@ type Client interface { Move(options MoveOptions) error // Backup saves all the Cluster API objects existing in a namespace (or from all the namespaces if empty) to a target management cluster. + // Deprecated: This will be dropped in a future release. Please use Move. Backup(options BackupOptions) error // Restore restores all the Cluster API objects existing in a configured directory based on a glob to a target management cluster. + // Deprecated: This will be dropped in a future release. Please use Move. Restore(options RestoreOptions) error // PlanUpgrade returns a set of suggested Upgrade plans for the cluster, and more specifically: diff --git a/cmd/clusterctl/client/cluster/mover.go b/cmd/clusterctl/client/cluster/mover.go index a4717d0fc449..c09dcf9ad38f 100644 --- a/cmd/clusterctl/client/cluster/mover.go +++ b/cmd/clusterctl/client/cluster/mover.go @@ -45,9 +45,19 @@ import ( type ObjectMover interface { // Move moves all the Cluster API objects existing in a namespace (or from all the namespaces if empty) to a target management cluster. Move(namespace string, toCluster Client, dryRun bool) error - // Backup saves all the Cluster API objects existing in a namespace (or from all the namespaces if empty) to a target management cluster. + + // ToDirectory writes all the Cluster API objects existing in a namespace (or from all the namespaces if empty) to a target directory. + ToDirectory(namespace string, directory string) error + + // FromDirectory reads all the Cluster API objects existing in a configured directory to a target management cluster. + FromDirectory(toCluster Client, directory string) error + + // Backup saves all the Cluster API objects existing in a namespace (or from all the namespaces if empty) to a target directory. + // Deprecated: This will be dropped in a future release. Please use ToDirectory. Backup(namespace string, directory string) error + // Restore restores all the Cluster API objects existing in a configured directory to a target management cluster. + // Deprecated: This will be dropped in a future release. Please use FromDirectory. Restore(toCluster Client, directory string) error } @@ -94,21 +104,33 @@ func (o *objectMover) Move(namespace string, toCluster Client, dryRun bool) erro func (o *objectMover) Backup(namespace string, directory string) error { log := logf.Log - log.Info("Performing backup...") + log.V(5).Info("Deprecated: This function will be dropped in a future release. Please use ToDirectory instead of Backup.") + return o.ToDirectory(namespace, directory) +} + +func (o *objectMover) ToDirectory(namespace string, directory string) error { + log := logf.Log + log.Info("Moving to directory...") objectGraph, err := o.getObjectGraph(namespace) if err != nil { return errors.Wrap(err, "failed to get object graph") } - return o.backup(objectGraph, directory) + return o.toDirectory(objectGraph, directory) } func (o *objectMover) Restore(toCluster Client, directory string) error { log := logf.Log - log.Info("Performing restore...") + log.V(5).Info("Deprecated: This function will be dropped in a future release. Please use FromDirectory instead of Restore.") + return o.FromDirectory(toCluster, directory) +} - // Build an empty object graph used for the restore sequence not tied to a specific namespace +func (o *objectMover) FromDirectory(toCluster Client, directory string) error { + log := logf.Log + log.Info("Moving from directory...") + + // Build an empty object graph used for the fromDirectory sequence not tied to a specific namespace objectGraph := newObjectGraph(o.fromProxy, o.fromProviderInventory) // Gets all the types defined by the CRDs installed by clusterctl plus the ConfigMap/Secret core types. @@ -135,13 +157,13 @@ func (o *objectMover) Restore(toCluster Client, directory string) error { // Completes the graph by setting for each node the list of tenants the node belongs to. objectGraph.setTenants() - // Check whether nodes are not included in GVK considered for restore. + // Check whether nodes are not included in GVK considered for fromDirectory. objectGraph.checkVirtualNode() // Restore the objects to the target cluster. proxy := toCluster.Proxy() - return o.restore(objectGraph, proxy) + return o.fromDirectory(objectGraph, proxy) } func (o *objectMover) filesToObjs(dir string) ([]unstructured.Unstructured, error) { @@ -191,7 +213,7 @@ func (o *objectMover) getObjectGraph(namespace string) (*objectGraph, error) { return nil, errors.Wrap(err, "failed to discover the object graph") } - // Checks if Cluster API has already completed the provisioning of the infrastructure for the objects involved in the move/backup operation. + // Checks if Cluster API has already completed the provisioning of the infrastructure for the objects involved in the move/toDirectory operation. // This is required because if the infrastructure is provisioned, then we can reasonably assume that the objects we are moving/backing up are // not currently waiting for long-running reconciliation loops, and so we can safely rely on the pause field on the Cluster object // for blocking any further object reconciliation on the source objects. @@ -354,7 +376,7 @@ func (o *objectMover) move(graph *objectGraph, toProxy Proxy) error { return err } } - + // Resume the ClusterClasses in the target management cluster, so the controllers start reconciling it. log.V(1).Info("Resuming the target ClusterClasses") if err := setClusterClassPause(toProxy, clusterClasses, false, o.dryRun); err != nil { @@ -366,11 +388,11 @@ func (o *objectMover) move(graph *objectGraph, toProxy Proxy) error { return setClusterPause(toProxy, clusters, false, o.dryRun) } -func (o *objectMover) backup(graph *objectGraph, directory string) error { +func (o *objectMover) toDirectory(graph *objectGraph, directory string) error { log := logf.Log clusters := graph.getClusters() - log.Info("Starting backup of Cluster API objects", "Clusters", len(clusters)) + log.Info("Starting move of Cluster API objects", "Clusters", len(clusters)) clusterClasses := graph.getClusterClasses() log.Info("Moving Cluster API objects", "ClusterClasses", len(clusterClasses)) @@ -412,7 +434,7 @@ func (o *objectMover) backup(graph *objectGraph, directory string) error { return setClusterPause(o.fromProxy, clusters, false, o.dryRun) } -func (o *objectMover) restore(graph *objectGraph, toProxy Proxy) error { +func (o *objectMover) fromDirectory(graph *objectGraph, toProxy Proxy) error { log := logf.Log // Get clusters from graph @@ -448,8 +470,8 @@ func (o *objectMover) restore(graph *objectGraph, toProxy Proxy) error { return errors.Wrap(err, "error resuming ClusterClasses") } - // Resume reconciling the Clusters after being restored from a backup. - // By default, during backup, Clusters are paused so they must be unpaused to be used again + // Resume reconciling the Clusters after being restored from a directory. + // By default, when moved to a directory , Clusters are paused, so they must be unpaused to be used again. log.V(1).Info("Resuming the target cluster") return setClusterPause(toProxy, clusters, false, o.dryRun) } @@ -972,7 +994,7 @@ func (o *objectMover) restoreTargetObject(nodeToCreate *node, toProxy Proxy) err existingTargetObj.SetAPIVersion(nodeToCreate.restoreObject.GetAPIVersion()) existingTargetObj.SetKind(nodeToCreate.restoreObject.GetKind()) if err := cTo.Get(ctx, objKey, existingTargetObj); err == nil { - log.V(5).Info("Object already exists, skipping restore", nodeToCreate.identity.Kind, nodeToCreate.identity.Name, "Namespace", nodeToCreate.identity.Namespace) + log.V(5).Info("Object already exists, skipping moving from directory", nodeToCreate.identity.Kind, nodeToCreate.identity.Name, "Namespace", nodeToCreate.identity.Namespace) // Update the nodes UID since it already exits. Any nodes owned by this existing node will be updated when the owner chain is rebuilt nodeToCreate.newUID = existingTargetObj.GetUID() diff --git a/cmd/clusterctl/client/cluster/mover_test.go b/cmd/clusterctl/client/cluster/mover_test.go index bcacf41b49fa..8b30c35b144d 100644 --- a/cmd/clusterctl/client/cluster/mover_test.go +++ b/cmd/clusterctl/client/cluster/mover_test.go @@ -706,7 +706,7 @@ func Test_objectMover_backupTargetObject(t *testing.T) { // Add delay so we ensure the file ModTime of updated files is different from old ones in the original files time.Sleep(time.Millisecond * 50) - // Running backupTargetObject should override any existing files since it represents a new backup + // Running backupTargetObject should override any existing files since it represents a new toDirectory err = mover.backupTargetObject(node, dir) if tt.wantErr { g.Expect(err).To(HaveOccurred()) @@ -855,7 +855,7 @@ func Test_objectMover_backup(t *testing.T) { // trigger discovery the content of the source cluster g.Expect(graph.Discovery("")).To(Succeed()) - // Run backup + // Run toDirectory mover := objectMover{ fromProxy: graph.proxy, } @@ -866,7 +866,7 @@ func Test_objectMover_backup(t *testing.T) { } defer os.RemoveAll(dir) - err = mover.backup(graph, dir) + err = mover.toDirectory(graph, dir) if tt.wantErr { g.Expect(err).To(HaveOccurred()) return @@ -996,7 +996,7 @@ func Test_objectMover_restore(t *testing.T) { // gets a fakeProxy to an empty cluster with all the required CRDs toProxy := getFakeProxyWithCRDs() - // Run restore + // Run fromDirectory mover := objectMover{ fromProxy: graph.proxy, } @@ -1018,14 +1018,14 @@ func Test_objectMover_restore(t *testing.T) { g.Expect(graph.addRestoredObj(&objs[i])).NotTo(HaveOccurred()) } - // restore works on the target cluster which does not yet have objs to discover + // fromDirectory works on the target cluster which does not yet have objs to discover // instead set the owners and tenants correctly on object graph like how ObjectMover.Restore does // https://github.com/kubernetes-sigs/cluster-api/blob/main/cmd/clusterctl/client/cluster/mover.go#L129-L132 graph.setSoftOwnership() graph.setTenants() graph.checkVirtualNode() - err = mover.restore(graph, toProxy) + err = mover.fromDirectory(graph, toProxy) if tt.wantErr { g.Expect(err).To(HaveOccurred()) return diff --git a/cmd/clusterctl/client/cluster/objectgraph.go b/cmd/clusterctl/client/cluster/objectgraph.go index dff48251b067..cedcb95c2a6f 100644 --- a/cmd/clusterctl/client/cluster/objectgraph.go +++ b/cmd/clusterctl/client/cluster/objectgraph.go @@ -82,7 +82,7 @@ type node struct { // the node is linked to a object indirectly in the OwnerReference chain. tenant map[*node]empty - // restoreObject holds the object that is referenced when creating a node during restore from file. + // restoreObject holds the object that is referenced when creating a node during fromDirectory from file. // the object can then be referenced latter when restoring objects to a target management cluster restoreObject *unstructured.Unstructured @@ -179,8 +179,8 @@ func (o *objectGraph) addObj(obj *unstructured.Unstructured) error { return nil } -// addRestoredObj adds a Kubernetes object to the object graph from file that is generated during a restore -// Populates the restoredObject field to be referenced during restore +// addRestoredObj adds a Kubernetes object to the object graph from file that is generated during a fromDirectory +// Populates the restoredObject field to be referenced during fromDirectory // During add, OwnerReferences are processed in order to create the dependency graph. func (o *objectGraph) addRestoredObj(obj *unstructured.Unstructured) error { // Add object to graph diff --git a/cmd/clusterctl/client/move.go b/cmd/clusterctl/client/move.go index c936f35c2f89..0db62e38426e 100644 --- a/cmd/clusterctl/client/move.go +++ b/cmd/clusterctl/client/move.go @@ -19,6 +19,8 @@ package client import ( "os" + "github.com/pkg/errors" + "sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster" ) @@ -36,11 +38,18 @@ type MoveOptions struct { // namespace will be used. Namespace string - // DryRun means the move action is a dry run, no real action will be performed + // FromDirectory apply configuration from directory. + FromDirectory string + + // ToDirectory save configuration to directory. + ToDirectory string + + // DryRun means the move action is a dry run, no real action will be performed. DryRun bool } // BackupOptions holds options supported by backup. +// Deprecated: This will be dropped in a future release. Please use MoveOptions. type BackupOptions struct { // FromKubeconfig defines the kubeconfig to use for accessing the source management cluster. If empty, // default rules for kubeconfig discovery will be used. @@ -55,6 +64,7 @@ type BackupOptions struct { } // RestoreOptions holds options supported by restore. +// Deprecated: This will be dropped in a future release. Please use MoveOptions. type RestoreOptions struct { // FromKubeconfig defines the kubeconfig to use for accessing the target management cluster. If empty, // default rules for kubeconfig discovery will be used. @@ -65,39 +75,32 @@ type RestoreOptions struct { } func (c *clusterctlClient) Move(options MoveOptions) error { - // Get the client for interacting with the source management cluster. - fromCluster, err := c.clusterClientFactory(ClusterClientFactoryInput{Kubeconfig: options.FromKubeconfig}) - if err != nil { - return err + // Both backup and restore makes no sense. It's a complete move. + if options.FromDirectory != "" && options.ToDirectory != "" { + return errors.Errorf("can't set both FromDirectory and ToDirectory") } - // Ensure this command only runs against management clusters with the current Cluster API contract. - if err := fromCluster.ProviderInventory().CheckCAPIContract(); err != nil { - return err + if !options.DryRun && + options.FromDirectory == "" && + options.ToDirectory == "" && + options.ToKubeconfig == (Kubeconfig{}) { + return errors.Errorf("at least one of FromDirectory, ToDirectory and ToKubeconfig must be set") } - // Ensures the custom resource definitions required by clusterctl are in place. - if err := fromCluster.ProviderInventory().EnsureCustomResourceDefinitions(); err != nil { - return err + if options.ToDirectory != "" { + return c.toDirectory(options) + } else if options.FromDirectory != "" { + return c.fromDirectory(options) + } else { + return c.move(options) } +} - var toCluster cluster.Client - if !options.DryRun { - // Get the client for interacting with the target management cluster. - toCluster, err = c.clusterClientFactory(ClusterClientFactoryInput{Kubeconfig: options.ToKubeconfig}) - if err != nil { - return err - } - - // Ensure this command only runs against management clusters with the current Cluster API contract. - if err := toCluster.ProviderInventory().CheckCAPIContract(); err != nil { - return err - } - - // Ensures the custom resource definitions required by clusterctl are in place - if err := toCluster.ProviderInventory().EnsureCustomResourceDefinitions(); err != nil { - return err - } +func (c *clusterctlClient) move(options MoveOptions) error { + // Get the client for interacting with the source management cluster. + fromCluster, err := c.getClusterClient(options.FromKubeconfig) + if err != nil { + return err } // If the option specifying the Namespace is empty, try to detect it. @@ -109,23 +112,33 @@ func (c *clusterctlClient) Move(options MoveOptions) error { options.Namespace = currentNamespace } + var toCluster cluster.Client + if !options.DryRun { + // Get the client for interacting with the target management cluster. + if toCluster, err = c.getClusterClient(options.ToKubeconfig); err != nil { + return err + } + } + return fromCluster.ObjectMover().Move(options.Namespace, toCluster, options.DryRun) } -func (c *clusterctlClient) Backup(options BackupOptions) error { - // Get the client for interacting with the source management cluster. - fromCluster, err := c.clusterClientFactory(ClusterClientFactoryInput{Kubeconfig: options.FromKubeconfig}) +func (c *clusterctlClient) fromDirectory(options MoveOptions) error { + toCluster, err := c.getClusterClient(options.ToKubeconfig) if err != nil { return err } - // Ensure this command only runs against management clusters with the current Cluster API contract. - if err := fromCluster.ProviderInventory().CheckCAPIContract(); err != nil { + if _, err := os.Stat(options.FromDirectory); os.IsNotExist(err) { return err } - // Ensures the custom resource definitions required by clusterctl are in place. - if err := fromCluster.ProviderInventory().EnsureCustomResourceDefinitions(); err != nil { + return toCluster.ObjectMover().FromDirectory(toCluster, options.FromDirectory) +} + +func (c *clusterctlClient) toDirectory(options MoveOptions) error { + fromCluster, err := c.getClusterClient(options.FromKubeconfig) + if err != nil { return err } @@ -138,33 +151,44 @@ func (c *clusterctlClient) Backup(options BackupOptions) error { options.Namespace = currentNamespace } - if _, err := os.Stat(options.Directory); os.IsNotExist(err) { + if _, err := os.Stat(options.ToDirectory); os.IsNotExist(err) { return err } - return fromCluster.ObjectMover().Backup(options.Namespace, options.Directory) + return fromCluster.ObjectMover().ToDirectory(options.Namespace, options.ToDirectory) } +// Deprecated: This will be dropped in a future release. Please use Move. +func (c *clusterctlClient) Backup(options BackupOptions) error { + return c.Move(MoveOptions{ + FromKubeconfig: options.FromKubeconfig, + ToDirectory: options.Directory, + Namespace: options.Namespace, + }) +} + +// Deprecated: This will be dropped in a future release. Please use Move. func (c *clusterctlClient) Restore(options RestoreOptions) error { - // Get the client for interacting with the source management cluster. - toCluster, err := c.clusterClientFactory(ClusterClientFactoryInput{Kubeconfig: options.ToKubeconfig}) + return c.Move(MoveOptions{ + ToKubeconfig: options.ToKubeconfig, + FromDirectory: options.Directory, + }) +} + +func (c *clusterctlClient) getClusterClient(kubeconfig Kubeconfig) (cluster.Client, error) { + cluster, err := c.clusterClientFactory(ClusterClientFactoryInput{Kubeconfig: kubeconfig}) if err != nil { - return err + return nil, err } // Ensure this command only runs against management clusters with the current Cluster API contract. - if err := toCluster.ProviderInventory().CheckCAPIContract(); err != nil { - return err + if err := cluster.ProviderInventory().CheckCAPIContract(); err != nil { + return nil, err } // Ensures the custom resource definitions required by clusterctl are in place. - if err := toCluster.ProviderInventory().EnsureCustomResourceDefinitions(); err != nil { - return err - } - - if _, err := os.Stat(options.Directory); os.IsNotExist(err) { - return err + if err := cluster.ProviderInventory().EnsureCustomResourceDefinitions(); err != nil { + return nil, err } - - return toCluster.ObjectMover().Restore(toCluster, options.Directory) + return cluster, nil } diff --git a/cmd/clusterctl/client/move_test.go b/cmd/clusterctl/client/move_test.go index e12555cb4451..8c2c82fbf449 100644 --- a/cmd/clusterctl/client/move_test.go +++ b/cmd/clusterctl/client/move_test.go @@ -80,6 +80,49 @@ func Test_clusterctlClient_Move(t *testing.T) { }, wantErr: true, }, + { + name: "returns an error if both move ToDirectory and FromDirectory is set", + fields: fields{ + client: fakeClientForMove(), + }, + args: args{ + options: MoveOptions{ + ToDirectory: "/var/cache/toDirectory", + FromDirectory: "/var/cache/fromDirectory", + }, + }, + wantErr: true, + }, + { + name: "returns an error if neither FromDirectory, ToDirectory, or ToKubeconfig is set", + fields: fields{ + client: fakeClientForMove(), + }, + args: args{ + options: MoveOptions{ + FromKubeconfig: Kubeconfig{Path: "kubeconfig", Context: "mgmt-context"}, + FromDirectory: "", + ToDirectory: "", + ToKubeconfig: Kubeconfig{}, + }, + }, + wantErr: true, + }, + { + name: "does not return an error if dryRun but neither FromDirectory, ToDirectory, or ToKubeconfig is set", + fields: fields{ + client: fakeClientForMove(), + }, + args: args{ + options: MoveOptions{ + FromKubeconfig: Kubeconfig{Path: "kubeconfig", Context: "mgmt-context"}, + FromDirectory: "", + ToKubeconfig: Kubeconfig{}, + DryRun: true, + }, + }, + wantErr: false, + }, } for _, tt := range tests { @@ -250,19 +293,27 @@ func fakeClientForMove() *fakeClient { } type fakeObjectMover struct { - moveErr error - backupErr error - restoerErr error + moveErr error + toDirectoryErr error + fromDirectoryErr error } func (f *fakeObjectMover) Move(namespace string, toCluster cluster.Client, dryRun bool) error { return f.moveErr } +func (f *fakeObjectMover) ToDirectory(namespace string, directory string) error { + return f.toDirectoryErr +} + func (f *fakeObjectMover) Backup(namespace string, directory string) error { - return f.backupErr + return f.toDirectoryErr +} + +func (f *fakeObjectMover) FromDirectory(toCluster cluster.Client, directory string) error { + return f.fromDirectoryErr } func (f *fakeObjectMover) Restore(toCluster cluster.Client, directory string) error { - return f.restoerErr + return f.fromDirectoryErr } diff --git a/cmd/clusterctl/cmd/backup.go b/cmd/clusterctl/cmd/backup.go index a5a1da0c7d9b..ad277a021f19 100644 --- a/cmd/clusterctl/cmd/backup.go +++ b/cmd/clusterctl/cmd/backup.go @@ -45,6 +45,7 @@ var backupCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) error { return runBackup() }, + Deprecated: "use 'clusterctl move --to-directory' instead.", } func init() { @@ -70,9 +71,9 @@ func runBackup() error { return err } - return c.Backup(client.BackupOptions{ + return c.Move(client.MoveOptions{ FromKubeconfig: client.Kubeconfig{Path: buo.fromKubeconfig, Context: buo.fromKubeconfigContext}, Namespace: buo.namespace, - Directory: buo.directory, + ToDirectory: buo.directory, }) } diff --git a/cmd/clusterctl/cmd/move.go b/cmd/clusterctl/cmd/move.go index 6e7823e2c30b..aea6a2dea738 100644 --- a/cmd/clusterctl/cmd/move.go +++ b/cmd/clusterctl/cmd/move.go @@ -29,6 +29,8 @@ type moveOptions struct { toKubeconfig string toKubeconfigContext string namespace string + fromDirectory string + toDirectory string dryRun bool } @@ -44,7 +46,14 @@ var moveCmd = &cobra.Command{ Example: Examples(` Move Cluster API objects and all dependencies between management clusters. - clusterctl move --to-kubeconfig=target-kubeconfig.yaml`), + clusterctl move --to-kubeconfig=target-kubeconfig.yaml + + Write Cluster API objects and all dependencies from a management cluster to directory. + clusterctl move --to-directory /tmp/backup-directory + + Read Cluster API objects and all dependencies from a directory into a management cluster. + clusterctl move --from-directory /tmp/backup-directory + `), Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { return runMove() @@ -64,14 +73,24 @@ func init() { "The namespace where the workload cluster is hosted. If unspecified, the current context's namespace is used.") moveCmd.Flags().BoolVar(&mo.dryRun, "dry-run", false, "Enable dry run, don't really perform the move actions") + moveCmd.Flags().StringVar(&mo.toDirectory, "to-directory", "", + "Write Cluster API objects and all dependencies from a management cluster to directory.") + moveCmd.Flags().StringVar(&mo.fromDirectory, "from-directory", "", + "Read Cluster API objects and all dependencies from a directory into a management cluster.") + + moveCmd.MarkFlagsMutuallyExclusive("to-directory", "to-kubeconfig") + moveCmd.MarkFlagsMutuallyExclusive("from-directory", "to-directory") + moveCmd.MarkFlagsMutuallyExclusive("from-directory", "kubeconfig") RootCmd.AddCommand(moveCmd) } func runMove() error { - // if no to kubeconfig provided and it's not a dry run, return error - if mo.toKubeconfig == "" && !mo.dryRun { - return errors.New("please specify a target cluster using the --to-kubeconfig flag") + if mo.toDirectory == "" && + mo.fromDirectory == "" && + mo.toKubeconfig == "" && + !mo.dryRun { + return errors.New("please specify a target cluster using the --to-kubeconfig flag when not using --dry-run, --to-directory or --from-directory") } c, err := client.New(cfgFile) @@ -82,6 +101,8 @@ func runMove() error { return c.Move(client.MoveOptions{ FromKubeconfig: client.Kubeconfig{Path: mo.fromKubeconfig, Context: mo.fromKubeconfigContext}, ToKubeconfig: client.Kubeconfig{Path: mo.toKubeconfig, Context: mo.toKubeconfigContext}, + FromDirectory: mo.fromDirectory, + ToDirectory: mo.toDirectory, Namespace: mo.namespace, DryRun: mo.dryRun, }) diff --git a/cmd/clusterctl/cmd/restore.go b/cmd/clusterctl/cmd/restore.go index 6b1c3d6b8e4e..5c12fdb053df 100644 --- a/cmd/clusterctl/cmd/restore.go +++ b/cmd/clusterctl/cmd/restore.go @@ -44,6 +44,7 @@ var restoreCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) error { return runRestore() }, + Deprecated: "use 'clusterctl move --from-directory' instead.", } func init() { @@ -67,8 +68,8 @@ func runRestore() error { return err } - return c.Restore(client.RestoreOptions{ - ToKubeconfig: client.Kubeconfig{Path: ro.toKubeconfig, Context: ro.toKubeconfigContext}, - Directory: ro.directory, + return c.Move(client.MoveOptions{ + ToKubeconfig: client.Kubeconfig{Path: ro.toKubeconfig, Context: ro.toKubeconfigContext}, + FromDirectory: ro.directory, }) } diff --git a/docs/book/src/clusterctl/commands/additional-commands.md b/docs/book/src/clusterctl/commands/additional-commands.md index 8c7432bbbb87..6a947842edfb 100644 --- a/docs/book/src/clusterctl/commands/additional-commands.md +++ b/docs/book/src/clusterctl/commands/additional-commands.md @@ -1,5 +1,7 @@ # clusterctl backup +**DEPRECATED. Please use `clusterctl move --to-directory` instead.** + Backup Cluster API objects and all dependencies from a management cluster. # clusterctl config repositories @@ -16,6 +18,8 @@ Simply type `clusterctl help [command]` for full details. # clusterctl restore +**DEPRECATED. Please use `clusterctl move --from-directory` instead.** + Restore Cluster API objects from file by glob. Object files are searched in the default config directory or in the provided directory. diff --git a/docs/book/src/clusterctl/commands/commands.md b/docs/book/src/clusterctl/commands/commands.md index ce538d059ced..4c0e2fd544bb 100644 --- a/docs/book/src/clusterctl/commands/commands.md +++ b/docs/book/src/clusterctl/commands/commands.md @@ -1,23 +1,23 @@ # clusterctl commands -| Command | Description | -|--------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------| -| [`clusterctl alpha rollout`](alpha-rollout.md) | Manages the rollout of Cluster API resources. For example: MachineDeployments. | -| [`clusterctl alpha topology plan`](alpha-topology-plan.md) | Describes the changes to a cluster topology for a given input. | -| [`clusterctl backup`](additional-commands.md#clusterctl-backup) | Backup Cluster API objects and all their dependencies from a management cluster. | -| [`clusterctl completion`](completion.md) | Output shell completion code for the specified shell (bash or zsh). | -| [`clusterctl config`](additional-commands.md#clusterctl-config-repositories) | Display clusterctl configuration. | -| [`clusterctl delete`](delete.md) | Delete one or more providers from the management cluster. | -| [`clusterctl describe cluster`](describe-cluster.md) | Describe workload clusters. | -| [`clusterctl generate cluster`](generate-cluster.md) | Generate templates for creating workload clusters. | -| [`clusterctl generate provider`](generate-provider.md) | Generate templates for provider components. | -| [`clusterctl generate yaml`](generate-yaml.md) | Process yaml using clusterctl's yaml processor. | -| [`clusterctl get kubeconfig`](get-kubeconfig.md) | Gets the kubeconfig file for accessing a workload cluster. | -| [`clusterctl help`](additional-commands.md#clusterctl-help) | Help about any command. | -| [`clusterctl init`](init.md) | Initialize a management cluster. | -| [`clusterctl init list-images`](additional-commands.md#clusterctl-init-list-images) | Lists the container images required for initializing the management cluster. | -| [`clusterctl move`](move.md) | Move Cluster API objects and all their dependencies between management clusters. | -| [`clusterctl restore`](additional-commands.md#clusterctl-restore) | Restore Cluster API objects from file by glob. | -| [`clusterctl upgrade plan`](upgrade.md#upgrade-plan) | Provide a list of recommended target versions for upgrading Cluster API providers in a management cluster. | -| [`clusterctl upgrade apply`](upgrade.md#upgrade-apply) | Apply new versions of Cluster API core and providers in a management cluster. | -| [`clusterctl version`](additional-commands.md#clusterctl-version) | Print clusterctl version. | +| Command | Description | +|------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| +| [`clusterctl alpha rollout`](alpha-rollout.md) | Manages the rollout of Cluster API resources. For example: MachineDeployments. | +| [`clusterctl alpha topology plan`](alpha-topology-plan.md) | Describes the changes to a cluster topology for a given input. | +| [`clusterctl backup`](additional-commands.md#clusterctl-backup) | Backup Cluster API objects and all their dependencies from a management cluster. **DEPRECATED. Please use `clusterctl move --to-directory` instead.** | +| [`clusterctl completion`](completion.md) | Output shell completion code for the specified shell (bash or zsh). | +| [`clusterctl config`](additional-commands.md#clusterctl-config-repositories) | Display clusterctl configuration. | +| [`clusterctl delete`](delete.md) | Delete one or more providers from the management cluster. | +| [`clusterctl describe cluster`](describe-cluster.md) | Describe workload clusters. | +| [`clusterctl generate cluster`](generate-cluster.md) | Generate templates for creating workload clusters. | +| [`clusterctl generate provider`](generate-provider.md) | Generate templates for provider components. | +| [`clusterctl generate yaml`](generate-yaml.md) | Process yaml using clusterctl's yaml processor. | +| [`clusterctl get kubeconfig`](get-kubeconfig.md) | Gets the kubeconfig file for accessing a workload cluster. | +| [`clusterctl help`](additional-commands.md#clusterctl-help) | Help about any command. | +| [`clusterctl init`](init.md) | Initialize a management cluster. | +| [`clusterctl init list-images`](additional-commands.md#clusterctl-init-list-images) | Lists the container images required for initializing the management cluster. | +| [`clusterctl move`](move.md) | Move Cluster API objects and all their dependencies between management clusters. | +| [`clusterctl restore`](additional-commands.md#clusterctl-restore) | Restore Cluster API objects from file by glob. **DEPRECATED. Please use `clusterctl move --from-directory` instead.** | +| [`clusterctl upgrade plan`](upgrade.md#upgrade-plan) | Provide a list of recommended target versions for upgrading Cluster API providers in a management cluster. | +| [`clusterctl upgrade apply`](upgrade.md#upgrade-apply) | Apply new versions of Cluster API core and providers in a management cluster. | +| [`clusterctl version`](additional-commands.md#clusterctl-version) | Print clusterctl version. | diff --git a/docs/book/src/developer/providers/v1.2-to-v1.3.md b/docs/book/src/developer/providers/v1.2-to-v1.3.md index 4fd14fd96527..e98f5b5da3da 100644 --- a/docs/book/src/developer/providers/v1.2-to-v1.3.md +++ b/docs/book/src/developer/providers/v1.2-to-v1.3.md @@ -20,6 +20,10 @@ in Cluster API are kept in sync with the versions used by `sigs.k8s.io/controlle - `sigs.k8s.io/cluster-api/controllers/external.CloneTemplate` has been deprecated and will be removed in a future release. Please use `sigs.k8s.io/cluster-api/controllers/external.CreateFromTemplate` instead. - `clusterctl init --list-images` has been deprecated and will be removed in a future release. Please use `clusterctl init list-images` instead. +- `clusterctl backup` has been deprecated. Please use `clusterctl move --to-directory` instead. +- `clusterctl restore` has been deprecated. Please use `clusterctl move --from-directory` instead. +- `Client` deprecates `Backup` and `Restore`. Please use `Move`. +- `ObjectMover` deprecates `Backup` and `Restore`. Adds replacements functions `ToDirectory` and `FromDirectory`. ### Removals