Skip to content

Commit 401e839

Browse files
committed
vtctld: add VDiff CLI commands
Add the vdiff subcommand group with create, show, stop, resume, and delete operations. These allow managing VDiff operations on Vitess branches through the CLI. Signed-off-by: Nick Van Wiggeren <nick@planetscale.com>
1 parent 8172bd9 commit 401e839

4 files changed

Lines changed: 546 additions & 0 deletions

File tree

Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
package vtctld
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/planetscale/cli/internal/cmdutil"
7+
"github.com/planetscale/cli/internal/printer"
8+
ps "github.com/planetscale/planetscale-go/planetscale"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
func VDiffCmd(ch *cmdutil.Helper) *cobra.Command {
13+
cmd := &cobra.Command{
14+
Use: "vdiff <command>",
15+
Short: "Manage VDiff operations",
16+
}
17+
18+
cmd.AddCommand(VDiffCreateCmd(ch))
19+
cmd.AddCommand(VDiffShowCmd(ch))
20+
cmd.AddCommand(VDiffStopCmd(ch))
21+
cmd.AddCommand(VDiffResumeCmd(ch))
22+
cmd.AddCommand(VDiffDeleteCmd(ch))
23+
24+
return cmd
25+
}
26+
27+
func VDiffCreateCmd(ch *cmdutil.Helper) *cobra.Command {
28+
var flags struct {
29+
workflow string
30+
targetKeyspace string
31+
autoRetry bool
32+
autoStart bool
33+
debugQuery bool
34+
onlyPKs bool
35+
updateTableStats bool
36+
verbose bool
37+
tables []string
38+
tabletTypes []string
39+
tabletSelectionPreference string
40+
filteredReplicationWaitTime int
41+
maxReportSampleRows int
42+
maxExtraRowsToCompare int
43+
rowDiffColumnTruncateAt int
44+
limit int
45+
}
46+
47+
cmd := &cobra.Command{
48+
Use: "create <database> <branch>",
49+
Short: "Create a VDiff",
50+
Args: cmdutil.RequiredArgs("database", "branch"),
51+
RunE: func(cmd *cobra.Command, args []string) error {
52+
ctx := cmd.Context()
53+
database, branch := args[0], args[1]
54+
55+
client, err := ch.Client()
56+
if err != nil {
57+
return err
58+
}
59+
60+
end := ch.Printer.PrintProgress(
61+
fmt.Sprintf("Creating VDiff for workflow %s on %s/%s\u2026",
62+
printer.BoldBlue(flags.workflow), printer.BoldBlue(database), printer.BoldBlue(branch)))
63+
defer end()
64+
65+
req := &ps.VDiffCreateRequest{
66+
Organization: ch.Config.Organization,
67+
Database: database,
68+
Branch: branch,
69+
Workflow: flags.workflow,
70+
TargetKeyspace: flags.targetKeyspace,
71+
DebugQuery: flags.debugQuery,
72+
OnlyPKs: flags.onlyPKs,
73+
UpdateTableStats: flags.updateTableStats,
74+
Verbose: flags.verbose,
75+
Tables: flags.tables,
76+
TabletTypes: flags.tabletTypes,
77+
TabletSelectionPreference: flags.tabletSelectionPreference,
78+
}
79+
80+
if cmd.Flags().Changed("auto-retry") {
81+
req.AutoRetry = &flags.autoRetry
82+
}
83+
if cmd.Flags().Changed("auto-start") {
84+
req.AutoStart = &flags.autoStart
85+
}
86+
if cmd.Flags().Changed("filtered-replication-wait-time") {
87+
req.FilteredReplicationWaitTime = &flags.filteredReplicationWaitTime
88+
}
89+
if cmd.Flags().Changed("max-report-sample-rows") {
90+
req.MaxReportSampleRows = &flags.maxReportSampleRows
91+
}
92+
if cmd.Flags().Changed("max-extra-rows-to-compare") {
93+
req.MaxExtraRowsToCompare = &flags.maxExtraRowsToCompare
94+
}
95+
if cmd.Flags().Changed("row-diff-column-truncate-at") {
96+
req.RowDiffColumnTruncateAt = &flags.rowDiffColumnTruncateAt
97+
}
98+
if cmd.Flags().Changed("limit") {
99+
req.Limit = &flags.limit
100+
}
101+
102+
data, err := client.VDiff.Create(ctx, req)
103+
if err != nil {
104+
return cmdutil.HandleError(err)
105+
}
106+
107+
end()
108+
return ch.Printer.PrettyPrintJSON(data)
109+
},
110+
}
111+
112+
cmd.Flags().StringVar(&flags.workflow, "workflow", "", "Name of the workflow")
113+
cmd.Flags().StringVar(&flags.targetKeyspace, "target-keyspace", "", "Target keyspace")
114+
cmd.Flags().BoolVar(&flags.autoRetry, "auto-retry", false, "Automatically retry on error")
115+
cmd.Flags().BoolVar(&flags.autoStart, "auto-start", true, "Automatically start the VDiff")
116+
cmd.Flags().BoolVar(&flags.debugQuery, "debug-query", false, "Log the queries used for the VDiff")
117+
cmd.Flags().BoolVar(&flags.onlyPKs, "only-pks", false, "Only compare primary keys")
118+
cmd.Flags().BoolVar(&flags.updateTableStats, "update-table-stats", false, "Update table statistics before the VDiff")
119+
cmd.Flags().BoolVar(&flags.verbose, "verbose", false, "Verbose output")
120+
cmd.Flags().StringSliceVar(&flags.tables, "tables", nil, "Tables to compare (comma-separated)")
121+
cmd.Flags().StringSliceVar(&flags.tabletTypes, "tablet-types", nil, "Tablet types to use (comma-separated)")
122+
cmd.Flags().StringVar(&flags.tabletSelectionPreference, "tablet-selection-preference", "", "Tablet selection preference")
123+
cmd.Flags().IntVar(&flags.filteredReplicationWaitTime, "filtered-replication-wait-time", 0, "Filtered replication wait time in seconds")
124+
cmd.Flags().IntVar(&flags.maxReportSampleRows, "max-report-sample-rows", 0, "Maximum number of sample rows in report")
125+
cmd.Flags().IntVar(&flags.maxExtraRowsToCompare, "max-extra-rows-to-compare", 0, "Maximum extra rows to compare")
126+
cmd.Flags().IntVar(&flags.rowDiffColumnTruncateAt, "row-diff-column-truncate-at", 0, "Truncate column values at this length in the report")
127+
cmd.Flags().IntVar(&flags.limit, "limit", 0, "Maximum number of rows to compare")
128+
cmd.MarkFlagRequired("workflow") // nolint:errcheck
129+
cmd.MarkFlagRequired("target-keyspace") // nolint:errcheck
130+
131+
return cmd
132+
}
133+
134+
func VDiffShowCmd(ch *cmdutil.Helper) *cobra.Command {
135+
var flags struct {
136+
workflow string
137+
uuid string
138+
targetKeyspace string
139+
}
140+
141+
cmd := &cobra.Command{
142+
Use: "show <database> <branch>",
143+
Short: "Show details of a VDiff",
144+
Args: cmdutil.RequiredArgs("database", "branch"),
145+
RunE: func(cmd *cobra.Command, args []string) error {
146+
ctx := cmd.Context()
147+
database, branch := args[0], args[1]
148+
149+
client, err := ch.Client()
150+
if err != nil {
151+
return err
152+
}
153+
154+
end := ch.Printer.PrintProgress(
155+
fmt.Sprintf("Fetching VDiff %s on %s/%s\u2026",
156+
printer.BoldBlue(flags.uuid), printer.BoldBlue(database), printer.BoldBlue(branch)))
157+
defer end()
158+
159+
data, err := client.VDiff.Show(ctx, &ps.VDiffShowRequest{
160+
Organization: ch.Config.Organization,
161+
Database: database,
162+
Branch: branch,
163+
Workflow: flags.workflow,
164+
UUID: flags.uuid,
165+
TargetKeyspace: flags.targetKeyspace,
166+
})
167+
if err != nil {
168+
return cmdutil.HandleError(err)
169+
}
170+
171+
end()
172+
return ch.Printer.PrettyPrintJSON(data)
173+
},
174+
}
175+
176+
cmd.Flags().StringVar(&flags.workflow, "workflow", "", "Name of the workflow")
177+
cmd.Flags().StringVar(&flags.uuid, "uuid", "", "UUID of the VDiff")
178+
cmd.Flags().StringVar(&flags.targetKeyspace, "target-keyspace", "", "Target keyspace")
179+
cmd.MarkFlagRequired("workflow") // nolint:errcheck
180+
cmd.MarkFlagRequired("uuid") // nolint:errcheck
181+
cmd.MarkFlagRequired("target-keyspace") // nolint:errcheck
182+
183+
return cmd
184+
}
185+
186+
func VDiffStopCmd(ch *cmdutil.Helper) *cobra.Command {
187+
var flags struct {
188+
workflow string
189+
uuid string
190+
targetKeyspace string
191+
targetShards []string
192+
}
193+
194+
cmd := &cobra.Command{
195+
Use: "stop <database> <branch>",
196+
Short: "Stop a VDiff",
197+
Args: cmdutil.RequiredArgs("database", "branch"),
198+
RunE: func(cmd *cobra.Command, args []string) error {
199+
ctx := cmd.Context()
200+
database, branch := args[0], args[1]
201+
202+
client, err := ch.Client()
203+
if err != nil {
204+
return err
205+
}
206+
207+
end := ch.Printer.PrintProgress(
208+
fmt.Sprintf("Stopping VDiff %s on %s/%s\u2026",
209+
printer.BoldBlue(flags.uuid), printer.BoldBlue(database), printer.BoldBlue(branch)))
210+
defer end()
211+
212+
data, err := client.VDiff.Stop(ctx, &ps.VDiffStopRequest{
213+
Organization: ch.Config.Organization,
214+
Database: database,
215+
Branch: branch,
216+
Workflow: flags.workflow,
217+
UUID: flags.uuid,
218+
TargetKeyspace: flags.targetKeyspace,
219+
TargetShards: flags.targetShards,
220+
})
221+
if err != nil {
222+
return cmdutil.HandleError(err)
223+
}
224+
225+
end()
226+
return ch.Printer.PrettyPrintJSON(data)
227+
},
228+
}
229+
230+
cmd.Flags().StringVar(&flags.workflow, "workflow", "", "Name of the workflow")
231+
cmd.Flags().StringVar(&flags.uuid, "uuid", "", "UUID of the VDiff")
232+
cmd.Flags().StringVar(&flags.targetKeyspace, "target-keyspace", "", "Target keyspace")
233+
cmd.Flags().StringSliceVar(&flags.targetShards, "target-shards", nil, "Target shards to stop (comma-separated)")
234+
cmd.MarkFlagRequired("workflow") // nolint:errcheck
235+
cmd.MarkFlagRequired("uuid") // nolint:errcheck
236+
cmd.MarkFlagRequired("target-keyspace") // nolint:errcheck
237+
238+
return cmd
239+
}
240+
241+
func VDiffResumeCmd(ch *cmdutil.Helper) *cobra.Command {
242+
var flags struct {
243+
workflow string
244+
uuid string
245+
targetKeyspace string
246+
targetShards []string
247+
}
248+
249+
cmd := &cobra.Command{
250+
Use: "resume <database> <branch>",
251+
Short: "Resume a stopped VDiff",
252+
Args: cmdutil.RequiredArgs("database", "branch"),
253+
RunE: func(cmd *cobra.Command, args []string) error {
254+
ctx := cmd.Context()
255+
database, branch := args[0], args[1]
256+
257+
client, err := ch.Client()
258+
if err != nil {
259+
return err
260+
}
261+
262+
end := ch.Printer.PrintProgress(
263+
fmt.Sprintf("Resuming VDiff %s on %s/%s\u2026",
264+
printer.BoldBlue(flags.uuid), printer.BoldBlue(database), printer.BoldBlue(branch)))
265+
defer end()
266+
267+
data, err := client.VDiff.Resume(ctx, &ps.VDiffResumeRequest{
268+
Organization: ch.Config.Organization,
269+
Database: database,
270+
Branch: branch,
271+
Workflow: flags.workflow,
272+
UUID: flags.uuid,
273+
TargetKeyspace: flags.targetKeyspace,
274+
TargetShards: flags.targetShards,
275+
})
276+
if err != nil {
277+
return cmdutil.HandleError(err)
278+
}
279+
280+
end()
281+
return ch.Printer.PrettyPrintJSON(data)
282+
},
283+
}
284+
285+
cmd.Flags().StringVar(&flags.workflow, "workflow", "", "Name of the workflow")
286+
cmd.Flags().StringVar(&flags.uuid, "uuid", "", "UUID of the VDiff")
287+
cmd.Flags().StringVar(&flags.targetKeyspace, "target-keyspace", "", "Target keyspace")
288+
cmd.Flags().StringSliceVar(&flags.targetShards, "target-shards", nil, "Target shards to resume (comma-separated)")
289+
cmd.MarkFlagRequired("workflow") // nolint:errcheck
290+
cmd.MarkFlagRequired("uuid") // nolint:errcheck
291+
cmd.MarkFlagRequired("target-keyspace") // nolint:errcheck
292+
293+
return cmd
294+
}
295+
296+
func VDiffDeleteCmd(ch *cmdutil.Helper) *cobra.Command {
297+
var flags struct {
298+
workflow string
299+
uuid string
300+
targetKeyspace string
301+
}
302+
303+
cmd := &cobra.Command{
304+
Use: "delete <database> <branch>",
305+
Short: "Delete a VDiff",
306+
Args: cmdutil.RequiredArgs("database", "branch"),
307+
RunE: func(cmd *cobra.Command, args []string) error {
308+
ctx := cmd.Context()
309+
database, branch := args[0], args[1]
310+
311+
client, err := ch.Client()
312+
if err != nil {
313+
return err
314+
}
315+
316+
end := ch.Printer.PrintProgress(
317+
fmt.Sprintf("Deleting VDiff %s on %s/%s\u2026",
318+
printer.BoldBlue(flags.uuid), printer.BoldBlue(database), printer.BoldBlue(branch)))
319+
defer end()
320+
321+
data, err := client.VDiff.Delete(ctx, &ps.VDiffDeleteRequest{
322+
Organization: ch.Config.Organization,
323+
Database: database,
324+
Branch: branch,
325+
Workflow: flags.workflow,
326+
UUID: flags.uuid,
327+
TargetKeyspace: flags.targetKeyspace,
328+
})
329+
if err != nil {
330+
return cmdutil.HandleError(err)
331+
}
332+
333+
end()
334+
return ch.Printer.PrettyPrintJSON(data)
335+
},
336+
}
337+
338+
cmd.Flags().StringVar(&flags.workflow, "workflow", "", "Name of the workflow")
339+
cmd.Flags().StringVar(&flags.uuid, "uuid", "", "UUID of the VDiff")
340+
cmd.Flags().StringVar(&flags.targetKeyspace, "target-keyspace", "", "Target keyspace")
341+
cmd.MarkFlagRequired("workflow") // nolint:errcheck
342+
cmd.MarkFlagRequired("uuid") // nolint:errcheck
343+
cmd.MarkFlagRequired("target-keyspace") // nolint:errcheck
344+
345+
return cmd
346+
}

0 commit comments

Comments
 (0)