diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 8ba27ae6f54..6778ec7e0de 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -77,7 +77,7 @@ go.sum @ajm188 @deepthi @harshit-gangal @mattlord @rohit-nayak-ps @systay @froui /go/vt/vttablet/*tmclient* @ajm188 @GuptaManan100 @rohit-nayak-ps @shlomi-noach /go/vt/vttablet/vexec @mattlord @rohit-nayak-ps @shlomi-noach /go/vt/wrangler @deepthi @mattlord @rohit-nayak-ps -/go/vt/workflow @mattlord @rohit-nayak-ps +/go/vt/vtctl/workflow @mattlord @rohit-nayak-ps /proto/ @deepthi @harshit-gangal /proto/vtadmin.proto @ajm188 @notfelineit @mattlord /proto/vtctldata.proto @ajm188 @notfelineit @mattlord diff --git a/go/vt/vtctl/workflow/server.go b/go/vt/vtctl/workflow/server.go index c247ed91e9a..a61f31a8241 100644 --- a/go/vt/vtctl/workflow/server.go +++ b/go/vt/vtctl/workflow/server.go @@ -29,6 +29,7 @@ import ( "text/template" "time" + "github.com/google/uuid" "golang.org/x/exp/maps" "golang.org/x/sync/errgroup" "golang.org/x/sync/semaphore" @@ -1837,6 +1838,16 @@ func (s *Server) VDiffCreate(ctx context.Context, req *vtctldatapb.VDiffCreateRe span.Annotate("auto_start", req.GetAutoStart()) } + var err error + req.Uuid = strings.TrimSpace(req.Uuid) + if req.Uuid == "" { // Generate a UUID + req.Uuid = uuid.New().String() + } else { // Validate UUID if provided + if err = uuid.Validate(req.Uuid); err != nil { + return nil, vterrors.Wrapf(err, "invalid UUID provided: %s", req.Uuid) + } + } + tabletTypesStr := discovery.BuildTabletTypesString(req.TabletTypes, req.TabletSelectionPreference) // This is a pointer so there's no ZeroValue in the message diff --git a/go/vt/vtctl/workflow/server_test.go b/go/vt/vtctl/workflow/server_test.go index 5d35b205ed3..8b1f09b8fde 100644 --- a/go/vt/vtctl/workflow/server_test.go +++ b/go/vt/vtctl/workflow/server_test.go @@ -36,7 +36,6 @@ import ( "vitess.io/vitess/go/test/utils" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/topo" - "vitess.io/vitess/go/vt/topo/memorytopo" "vitess.io/vitess/go/vt/topo/topoproto" "vitess.io/vitess/go/vt/topotools" "vitess.io/vitess/go/vt/vtenv" @@ -182,9 +181,17 @@ func TestCheckReshardingJournalExistsOnTablet(t *testing.T) { // to ensure that it behaves as expected given a specific request. func TestVDiffCreate(t *testing.T) { ctx := context.Background() - ts := memorytopo.NewServer(ctx, "cell") - tmc := &fakeTMC{} - s := NewServer(vtenv.NewTestEnv(), ts, tmc) + workflowName := "wf1" + sourceKeyspace := &testKeyspace{ + KeyspaceName: "source", + ShardNames: []string{"0"}, + } + targetKeyspace := &testKeyspace{ + KeyspaceName: "target", + ShardNames: []string{"-80", "80-"}, + } + env := newTestEnv(t, ctx, defaultCellName, sourceKeyspace, targetKeyspace) + defer env.close() tests := []struct { name string @@ -197,17 +204,32 @@ func TestVDiffCreate(t *testing.T) { // We did not provide any keyspace or shard. wantErr: "FindAllShardsInKeyspace() invalid keyspace name: UnescapeID err: invalid input identifier ''", }, + { + name: "generated UUID", + req: &vtctldatapb.VDiffCreateRequest{ + TargetKeyspace: targetKeyspace.KeyspaceName, + Workflow: workflowName, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := s.VDiffCreate(ctx, tt.req) + if tt.wantErr == "" { + env.tmc.expectVRQueryResultOnKeyspaceTablets(targetKeyspace.KeyspaceName, &queryResult{ + query: "select vrepl_id, table_name, lastpk from _vt.copy_state where vrepl_id in (1) and id in (select max(id) from _vt.copy_state where vrepl_id in (1) group by vrepl_id, table_name)", + result: &querypb.QueryResult{}, + }) + } + got, err := env.ws.VDiffCreate(ctx, tt.req) if tt.wantErr != "" { require.EqualError(t, err, tt.wantErr) return } require.NoError(t, err) require.NotNil(t, got) - require.NotEmpty(t, got.UUID) + // Ensure that we always use a valid UUID. + err = uuid.Validate(got.UUID) + require.NoError(t, err) }) } }