diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/praefect/subcmd_dataloss.go | 31 | ||||
-rw-r--r-- | cmd/praefect/subcmd_dataloss_test.go | 142 |
2 files changed, 74 insertions, 99 deletions
diff --git a/cmd/praefect/subcmd_dataloss.go b/cmd/praefect/subcmd_dataloss.go index f9c7f2d22..c66ca1a1b 100644 --- a/cmd/praefect/subcmd_dataloss.go +++ b/cmd/praefect/subcmd_dataloss.go @@ -74,27 +74,24 @@ func (cmd *datalossSubcommand) Exec(flags *flag.FlagSet, cfg config.Config) erro return fmt.Errorf("error checking: %v", err) } - mode := "write-enabled" - if resp.IsReadOnly { - mode = "read-only" - } - cmd.println(0, "Virtual storage: %s", vs) - cmd.println(1, "Current %s primary: %s", mode, resp.CurrentPrimary) - if resp.PreviousWritablePrimary == "" { - fmt.Fprintln(cmd.output, " No data loss as the virtual storage has not encountered a failover") - continue - } - - cmd.println(1, "Previous write-enabled primary: %s", resp.PreviousWritablePrimary) - if len(resp.OutdatedNodes) == 0 { - cmd.println(2, "No data loss from failing over from %s", resp.PreviousWritablePrimary) + cmd.println(1, "Primary: %s", resp.Primary) + if len(resp.Repositories) == 0 { + cmd.println(1, "All repositories are up to date!") continue } - cmd.println(2, "Nodes with data loss from failing over from %s:", resp.PreviousWritablePrimary) - for _, odn := range resp.OutdatedNodes { - cmd.println(3, "%s: %s", odn.RelativePath, strings.Join(odn.Nodes, ", ")) + cmd.println(1, "Outdated repositories:") + for _, r := range resp.Repositories { + cmd.println(2, "%s:", r.RelativePath) + for _, s := range r.Storages { + plural := "" + if s.BehindBy > 1 { + plural = "s" + } + + cmd.println(3, "%s is behind by %d change%s or less", s.Name, s.BehindBy, plural) + } } } diff --git a/cmd/praefect/subcmd_dataloss_test.go b/cmd/praefect/subcmd_dataloss_test.go index 569cf7caa..4c24741b9 100644 --- a/cmd/praefect/subcmd_dataloss_test.go +++ b/cmd/praefect/subcmd_dataloss_test.go @@ -5,9 +5,12 @@ import ( "context" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitaly/internal/praefect/config" + "gitlab.com/gitlab-org/gitaly/internal/praefect/datastore" + "gitlab.com/gitlab-org/gitaly/internal/praefect/nodes" + "gitlab.com/gitlab-org/gitaly/internal/praefect/service/info" + "gitlab.com/gitlab-org/gitaly/internal/testhelper" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" ) @@ -26,117 +29,92 @@ func (m mockPraefectInfoService) EnableWrites(ctx context.Context, r *gitalypb.E } func TestDatalossSubcommand(t *testing.T) { - mockSvc := &mockPraefectInfoService{} - ln, clean := listenAndServe(t, []svcRegistrar{registerPraefectInfoServer(mockSvc)}) + mgr := &nodes.MockManager{ + GetShardFunc: func(vs string) (nodes.Shard, error) { + var primary string + switch vs { + case "virtual-storage-1": + primary = "gitaly-1" + case "virtual-storage-2": + primary = "gitaly-4" + default: + t.Error("unexpected virtual storage") + } + + return nodes.Shard{Primary: &nodes.MockNode{StorageName: primary}}, nil + }, + } + + gs := datastore.NewMemoryRepositoryStore(map[string][]string{ + "virtual-storage-1": {"gitaly-1", "gitaly-2", "gitaly-3"}, + "virtual-storage-2": {"gitaly-4"}, + }) + + ctx, cancel := testhelper.Context() + defer cancel() + + require.NoError(t, gs.SetGeneration(ctx, "virtual-storage-1", "repository-1", "gitaly-1", 1)) + require.NoError(t, gs.SetGeneration(ctx, "virtual-storage-1", "repository-1", "gitaly-2", 0)) + + require.NoError(t, gs.SetGeneration(ctx, "virtual-storage-1", "repository-2", "gitaly-2", 0)) + require.NoError(t, gs.SetGeneration(ctx, "virtual-storage-1", "repository-2", "gitaly-3", 0)) + + ln, clean := listenAndServe(t, []svcRegistrar{ + registerPraefectInfoServer(info.NewServer(mgr, config.Config{}, nil, gs))}) defer clean() for _, tc := range []struct { desc string args []string virtualStorages []*config.VirtualStorage - datalossCheck func(context.Context, *gitalypb.DatalossCheckRequest) (*gitalypb.DatalossCheckResponse, error) output string error error }{ { desc: "positional arguments", - args: []string{"-virtual-storage=test-virtual-storage", "positional-arg"}, + args: []string{"-virtual-storage=virtual-storage-1", "positional-arg"}, error: UnexpectedPositionalArgsError{Command: "dataloss"}, }, { - desc: "no failover", - args: []string{"-virtual-storage=test-virtual-storage"}, - datalossCheck: func(ctx context.Context, req *gitalypb.DatalossCheckRequest) (*gitalypb.DatalossCheckResponse, error) { - assert.Equal(t, "test-virtual-storage", req.GetVirtualStorage()) - return &gitalypb.DatalossCheckResponse{ - CurrentPrimary: "test-current-primary", - }, nil - }, - output: `Virtual storage: test-virtual-storage - Current write-enabled primary: test-current-primary - No data loss as the virtual storage has not encountered a failover -`, - }, - { - desc: "no data loss", - args: []string{"-virtual-storage=test-virtual-storage"}, - datalossCheck: func(ctx context.Context, req *gitalypb.DatalossCheckRequest) (*gitalypb.DatalossCheckResponse, error) { - assert.Equal(t, "test-virtual-storage", req.GetVirtualStorage()) - return &gitalypb.DatalossCheckResponse{ - PreviousWritablePrimary: "test-previous-primary", - IsReadOnly: false, - CurrentPrimary: "test-current-primary", - }, nil - }, - output: `Virtual storage: test-virtual-storage - Current write-enabled primary: test-current-primary - Previous write-enabled primary: test-previous-primary - No data loss from failing over from test-previous-primary -`, - }, - { desc: "data loss", - args: []string{"-virtual-storage=test-virtual-storage"}, - datalossCheck: func(ctx context.Context, req *gitalypb.DatalossCheckRequest) (*gitalypb.DatalossCheckResponse, error) { - assert.Equal(t, "test-virtual-storage", req.GetVirtualStorage()) - return &gitalypb.DatalossCheckResponse{ - PreviousWritablePrimary: "test-previous-primary", - IsReadOnly: true, - CurrentPrimary: "test-current-primary", - OutdatedNodes: []*gitalypb.DatalossCheckResponse_Nodes{ - {RelativePath: "repository-1", Nodes: []string{"gitaly-2", "gitaly-3"}}, - {RelativePath: "repository-2", Nodes: []string{"gitaly-1"}}, - }, - }, nil - }, - output: `Virtual storage: test-virtual-storage - Current read-only primary: test-current-primary - Previous write-enabled primary: test-previous-primary - Nodes with data loss from failing over from test-previous-primary: - repository-1: gitaly-2, gitaly-3 - repository-2: gitaly-1 + args: []string{"-virtual-storage=virtual-storage-1"}, output: `Virtual storage: virtual-storage-1 + Primary: gitaly-1 + Outdated repositories: + repository-1: + gitaly-2 is behind by 1 change or less + gitaly-3 is behind by 2 changes or less + repository-2: + gitaly-1 is behind by 1 change or less `, }, { desc: "multiple virtual storages", - virtualStorages: []*config.VirtualStorage{{Name: "test-virtual-storage-2"}, {Name: "test-virtual-storage-1"}}, - datalossCheck: func(ctx context.Context, req *gitalypb.DatalossCheckRequest) (*gitalypb.DatalossCheckResponse, error) { - return &gitalypb.DatalossCheckResponse{ - PreviousWritablePrimary: "test-previous-primary", - IsReadOnly: true, - CurrentPrimary: "test-current-primary", - OutdatedNodes: []*gitalypb.DatalossCheckResponse_Nodes{ - {RelativePath: "repository-1", Nodes: []string{"gitaly-2", "gitaly-3"}}, - {RelativePath: "repository-2", Nodes: []string{"gitaly-1"}}, - }, - }, nil - }, - output: `Virtual storage: test-virtual-storage-1 - Current read-only primary: test-current-primary - Previous write-enabled primary: test-previous-primary - Nodes with data loss from failing over from test-previous-primary: - repository-1: gitaly-2, gitaly-3 - repository-2: gitaly-1 -Virtual storage: test-virtual-storage-2 - Current read-only primary: test-current-primary - Previous write-enabled primary: test-previous-primary - Nodes with data loss from failing over from test-previous-primary: - repository-1: gitaly-2, gitaly-3 - repository-2: gitaly-1 + virtualStorages: []*config.VirtualStorage{{Name: "virtual-storage-2"}, {Name: "virtual-storage-1"}}, + output: `Virtual storage: virtual-storage-1 + Primary: gitaly-1 + Outdated repositories: + repository-1: + gitaly-2 is behind by 1 change or less + gitaly-3 is behind by 2 changes or less + repository-2: + gitaly-1 is behind by 1 change or less +Virtual storage: virtual-storage-2 + Primary: gitaly-4 + All repositories are up to date! `, }, } { t.Run(tc.desc, func(t *testing.T) { - mockSvc.DatalossCheckFunc = tc.datalossCheck cmd := newDatalossSubcommand() output := &bytes.Buffer{} cmd.output = output fs := cmd.FlagSet() require.NoError(t, fs.Parse(tc.args)) - require.Equal(t, tc.error, cmd.Exec(fs, config.Config{ + err := cmd.Exec(fs, config.Config{ VirtualStorages: tc.virtualStorages, SocketPath: ln.Addr().String(), - })) + }) + require.Equal(t, tc.error, err, err) require.Equal(t, tc.output, output.String()) }) } |