From 73833ecf5567680b5bd130d4179141dc9c6514b8 Mon Sep 17 00:00:00 2001 From: Elom Gomez Date: Tue, 29 Sep 2026 14:58:08 -0500 Subject: [PATCH] Add --ignore-source-keyspace to move-tables complete and cancel Lets you finish or cancel a MoveTables workflow after its source keyspace has been deleted or become unavailable. Co-Authored-By: Claude Opus 5.5 (1M context) --- AGENTS.md | 2 +- internal/cmd/branch/vtctld/move_tables.go | 33 ++++++++++++++------- internal/planetscale/vtctld_move_tables.go | 34 ++++++++++++---------- 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 57565f8e..0d75f75b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -508,7 +508,7 @@ pscale branch vtctld move-tables cancel --org --format --workflow --target-keyspace --keep-data=false --keep-routing-rules=false ``` -On `complete`, `--keep-data=true` keeps the source tables and `--keep-data=false` drops them. Always use `--keep-data=true` when the source is an external keyspace, since those tables are in the user's own database. +On `complete`, `--keep-data=true` keeps the source tables and `--keep-data=false` drops them. Always use `--keep-data=true` when the source is an external keyspace, since those tables are in the user's own database. If the source keyspace has been deleted or is unreachable, `complete` and `cancel` take `--ignore-source-keyspace` to finish without touching it; only use it after confirming the source is gone. Ask the user before `switch-traffic` with `PRIMARY`, `complete` without `--dry-run`, and `cancel`. diff --git a/internal/cmd/branch/vtctld/move_tables.go b/internal/cmd/branch/vtctld/move_tables.go index 17d4a06c..639cbfde 100644 --- a/internal/cmd/branch/vtctld/move_tables.go +++ b/internal/cmd/branch/vtctld/move_tables.go @@ -552,10 +552,11 @@ func MoveTablesReverseTrafficCmd(ch *cmdutil.Helper) *cobra.Command { func MoveTablesCancelCmd(ch *cmdutil.Helper) *cobra.Command { var flags struct { - workflow string - targetKeyspace string - keepData bool - keepRoutingRules bool + workflow string + targetKeyspace string + keepData bool + keepRoutingRules bool + ignoreSourceKeyspace bool } cmd := &cobra.Command{ @@ -590,6 +591,9 @@ func MoveTablesCancelCmd(ch *cmdutil.Helper) *cobra.Command { if cmd.Flags().Changed("keep-routing-rules") { req.KeepRoutingRules = &flags.keepRoutingRules } + if cmd.Flags().Changed("ignore-source-keyspace") { + req.IgnoreSourceKeyspace = &flags.ignoreSourceKeyspace + } operation, err := client.MoveTables.Cancel(ctx, req) if err != nil { @@ -610,6 +614,7 @@ func MoveTablesCancelCmd(ch *cmdutil.Helper) *cobra.Command { cmd.Flags().StringVar(&flags.targetKeyspace, "target-keyspace", "", "Target keyspace") cmd.Flags().BoolVar(&flags.keepData, "keep-data", false, "Keep the data copied into the target keyspace instead of deleting it") cmd.Flags().BoolVar(&flags.keepRoutingRules, "keep-routing-rules", false, "Keep the routing rules") + cmd.Flags().BoolVar(&flags.ignoreSourceKeyspace, "ignore-source-keyspace", false, "Cancel without touching the source keyspace. Only use this when the source keyspace has been deleted or is unavailable") cmd.MarkFlagRequired("workflow") // nolint:errcheck cmd.MarkFlagRequired("target-keyspace") // nolint:errcheck cmd.MarkFlagRequired("keep-data") // nolint:errcheck @@ -620,12 +625,13 @@ func MoveTablesCancelCmd(ch *cmdutil.Helper) *cobra.Command { func MoveTablesCompleteCmd(ch *cmdutil.Helper) *cobra.Command { var flags struct { - workflow string - targetKeyspace string - keepData bool - keepRoutingRules bool - renameTables bool - dryRun bool + workflow string + targetKeyspace string + keepData bool + keepRoutingRules bool + renameTables bool + ignoreSourceKeyspace bool + dryRun bool } cmd := &cobra.Command{ @@ -663,6 +669,9 @@ func MoveTablesCompleteCmd(ch *cmdutil.Helper) *cobra.Command { if cmd.Flags().Changed("rename-tables") { req.RenameTables = &flags.renameTables } + if cmd.Flags().Changed("ignore-source-keyspace") { + req.IgnoreSourceKeyspace = &flags.ignoreSourceKeyspace + } if cmd.Flags().Changed("dry-run") { req.DryRun = &flags.dryRun } @@ -686,6 +695,9 @@ func MoveTablesCompleteCmd(ch *cmdutil.Helper) *cobra.Command { if flags.renameTables { nextFlags = append(nextFlags, "--rename-tables") } + if flags.ignoreSourceKeyspace { + nextFlags = append(nextFlags, "--ignore-source-keyspace") + } return printWorkflowJSON(ch.Printer, data, []workflowNextStep{{ Command: moveTablesCommand( ch.Config.Organization, @@ -708,6 +720,7 @@ func MoveTablesCompleteCmd(ch *cmdutil.Helper) *cobra.Command { cmd.Flags().BoolVar(&flags.keepData, "keep-data", false, "Keep the source tables instead of dropping them. Use this when the source is an external keyspace") cmd.Flags().BoolVar(&flags.keepRoutingRules, "keep-routing-rules", false, "Keep the routing rules") cmd.Flags().BoolVar(&flags.renameTables, "rename-tables", false, "Rename source tables instead of dropping them") + cmd.Flags().BoolVar(&flags.ignoreSourceKeyspace, "ignore-source-keyspace", false, "Complete without touching the source keyspace. Only use this when the source keyspace has been deleted or is unavailable") cmd.Flags().BoolVar(&flags.dryRun, "dry-run", false, "Only show what would be done") cmd.MarkFlagRequired("workflow") // nolint:errcheck cmd.MarkFlagRequired("target-keyspace") // nolint:errcheck diff --git a/internal/planetscale/vtctld_move_tables.go b/internal/planetscale/vtctld_move_tables.go index c39f5b12..00936aae 100644 --- a/internal/planetscale/vtctld_move_tables.go +++ b/internal/planetscale/vtctld_move_tables.go @@ -120,26 +120,28 @@ type MoveTablesReverseTrafficRequest struct { // MoveTablesCancelRequest is a request for canceling a MoveTables workflow. type MoveTablesCancelRequest struct { - Organization string `json:"-"` - Database string `json:"-"` - Branch string `json:"-"` - Workflow string `json:"-"` - TargetKeyspace string `json:"target_keyspace"` - KeepData *bool `json:"keep_data,omitempty"` - KeepRoutingRules *bool `json:"keep_routing_rules,omitempty"` + Organization string `json:"-"` + Database string `json:"-"` + Branch string `json:"-"` + Workflow string `json:"-"` + TargetKeyspace string `json:"target_keyspace"` + KeepData *bool `json:"keep_data,omitempty"` + KeepRoutingRules *bool `json:"keep_routing_rules,omitempty"` + IgnoreSourceKeyspace *bool `json:"ignore_source_keyspace,omitempty"` } // MoveTablesCompleteRequest is a request for completing a MoveTables workflow. type MoveTablesCompleteRequest struct { - Organization string `json:"-"` - Database string `json:"-"` - Branch string `json:"-"` - Workflow string `json:"-"` - TargetKeyspace string `json:"target_keyspace"` - KeepData *bool `json:"keep_data,omitempty"` - KeepRoutingRules *bool `json:"keep_routing_rules,omitempty"` - RenameTables *bool `json:"rename_tables,omitempty"` - DryRun *bool `json:"dry_run,omitempty"` + Organization string `json:"-"` + Database string `json:"-"` + Branch string `json:"-"` + Workflow string `json:"-"` + TargetKeyspace string `json:"target_keyspace"` + KeepData *bool `json:"keep_data,omitempty"` + KeepRoutingRules *bool `json:"keep_routing_rules,omitempty"` + RenameTables *bool `json:"rename_tables,omitempty"` + IgnoreSourceKeyspace *bool `json:"ignore_source_keyspace,omitempty"` + DryRun *bool `json:"dry_run,omitempty"` } type moveTablesService struct {