From 3dd5b9337627c8334dfbfa660a1e445bf2337b89 Mon Sep 17 00:00:00 2001 From: avallete Date: Mon, 9 Sep 2024 12:10:00 +0200 Subject: [PATCH 1/5] fix(db): reset command attempting to restart disabled services Fixes https://github.com/supabase/cli/issues/2658 --- internal/db/reset/reset.go | 32 +++++++++++++++++++++------ internal/db/reset/reset_test.go | 38 +++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/internal/db/reset/reset.go b/internal/db/reset/reset.go index be4802fb7..8369fd389 100644 --- a/internal/db/reset/reset.go +++ b/internal/db/reset/reset.go @@ -54,11 +54,13 @@ func Run(ctx context.Context, version string, config pgconn.Config, fsys afero.F return err } // Seed objects from supabase/buckets directory - if err := start.WaitForHealthyService(ctx, 30*time.Second, utils.StorageId); err != nil { - return err - } - if err := buckets.Run(ctx, "", false, fsys); err != nil { - return err + if utils.Config.Storage.Enabled { + if err := start.WaitForHealthyService(ctx, 30*time.Second, utils.StorageId); err != nil { + return err + } + if err := buckets.Run(ctx, "", false, fsys); err != nil { + return err + } } branch := keys.GetGitBranch(fsys) fmt.Fprintln(os.Stderr, "Finished "+utils.Aqua("supabase db reset")+" on branch "+utils.Aqua(branch)+".") @@ -204,8 +206,11 @@ func RestartDatabase(ctx context.Context, w io.Writer) error { } func restartServices(ctx context.Context) error { + debug := utils.GetDebugLogger() // No need to restart PostgREST because it automatically reconnects and listens for schema changes services := listServicesToRestart() + fmt.Fprintf(debug, "Enabled services to restart: %v\n", services) + result := utils.WaitAll(services, func(id string) error { if err := utils.Docker.ContainerRestart(ctx, id, container.StopOptions{}); err != nil && !errdefs.IsNotFound(err) { return errors.Errorf("Failed to restart %s: %w", id, err) @@ -217,7 +222,22 @@ func restartServices(ctx context.Context) error { } func listServicesToRestart() []string { - return []string{utils.StorageId, utils.GotrueId, utils.RealtimeId, utils.PoolerId} + var services []string + + if utils.Config.Storage.Enabled { + services = append(services, utils.StorageId) + } + if utils.Config.Realtime.Enabled { + services = append(services, utils.RealtimeId) + } + if utils.Config.Db.Pooler.Enabled { + services = append(services, utils.PoolerId) + } + if utils.Config.Auth.Enabled { + services = append(services, utils.GotrueId) + } + + return services } func resetRemote(ctx context.Context, version string, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error { diff --git a/internal/db/reset/reset_test.go b/internal/db/reset/reset_test.go index 38fef4b96..d5576ad82 100644 --- a/internal/db/reset/reset_test.go +++ b/internal/db/reset/reset_test.go @@ -321,6 +321,44 @@ func TestRestartDatabase(t *testing.T) { assert.ErrorContains(t, err, "test-reset container is not running: exited") assert.Empty(t, apitest.ListUnmatchedRequests()) }) + t.Run("restarts only enabled services", func(t *testing.T) { + utils.DbId = "test-reset" + utils.Config.Storage.Enabled = false + utils.Config.Auth.Enabled = true + utils.Config.Realtime.Enabled = true + utils.Config.Db.Pooler.Enabled = false + // Setup mock docker + require.NoError(t, apitest.MockDocker(utils.Docker)) + defer gock.OffAll() + // Restarts postgres + gock.New(utils.Docker.DaemonHost()). + Post("/v" + utils.Docker.ClientVersion() + "/containers/" + utils.DbId + "/restart"). + Reply(http.StatusOK) + gock.New(utils.Docker.DaemonHost()). + Get("/v" + utils.Docker.ClientVersion() + "/containers/" + utils.DbId + "/json"). + Reply(http.StatusOK). + JSON(types.ContainerJSON{ContainerJSONBase: &types.ContainerJSONBase{ + State: &types.ContainerState{ + Running: true, + Health: &types.Health{Status: "healthy"}, + }, + }}) + // Restarts enabled services + utils.StorageId = "test-storage" + utils.PoolerId = "test-pooler" + utils.GotrueId = "test-auth" + utils.RealtimeId = "test-realtime" + for _, container := range []string{utils.GotrueId, utils.RealtimeId} { + gock.New(utils.Docker.DaemonHost()). + Post("/v" + utils.Docker.ClientVersion() + "/containers/" + container + "/restart"). + Reply(http.StatusOK) + } + // Run test + err := RestartDatabase(context.Background(), io.Discard) + // Check error + assert.NoError(t, err) + assert.Empty(t, apitest.ListUnmatchedRequests()) + }) } var escapedSchemas = append(migration.ManagedSchemas, "extensions", "public") From 4e3898e4567853c05ae22c3c223384a2c16ed13d Mon Sep 17 00:00:00 2001 From: avallete Date: Mon, 9 Sep 2024 12:15:50 +0200 Subject: [PATCH 2/5] chore: cleanup debug log --- internal/db/reset/reset.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/db/reset/reset.go b/internal/db/reset/reset.go index 8369fd389..20ef26755 100644 --- a/internal/db/reset/reset.go +++ b/internal/db/reset/reset.go @@ -206,10 +206,8 @@ func RestartDatabase(ctx context.Context, w io.Writer) error { } func restartServices(ctx context.Context) error { - debug := utils.GetDebugLogger() // No need to restart PostgREST because it automatically reconnects and listens for schema changes services := listServicesToRestart() - fmt.Fprintf(debug, "Enabled services to restart: %v\n", services) result := utils.WaitAll(services, func(id string) error { if err := utils.Docker.ContainerRestart(ctx, id, container.StopOptions{}); err != nil && !errdefs.IsNotFound(err) { From 5e29d4c7f50e2948a4bc1d6f8cdb20cac52d8f8f Mon Sep 17 00:00:00 2001 From: avallete Date: Mon, 9 Sep 2024 12:27:39 +0200 Subject: [PATCH 3/5] chore: test config declaration order --- internal/db/reset/reset_test.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/internal/db/reset/reset_test.go b/internal/db/reset/reset_test.go index d5576ad82..d6d8b24e4 100644 --- a/internal/db/reset/reset_test.go +++ b/internal/db/reset/reset_test.go @@ -261,6 +261,9 @@ func TestRestartDatabase(t *testing.T) { utils.GotrueId = "test-auth" utils.RealtimeId = "test-realtime" utils.PoolerId = "test-pooler" + utils.Config.Storage.Enabled = true + utils.Config.Auth.Enabled = true + utils.Config.Realtime.Enabled = true for _, container := range []string{utils.StorageId, utils.GotrueId, utils.RealtimeId} { gock.New(utils.Docker.DaemonHost()). Post("/v" + utils.Docker.ClientVersion() + "/containers/" + container + "/restart"). @@ -323,10 +326,6 @@ func TestRestartDatabase(t *testing.T) { }) t.Run("restarts only enabled services", func(t *testing.T) { utils.DbId = "test-reset" - utils.Config.Storage.Enabled = false - utils.Config.Auth.Enabled = true - utils.Config.Realtime.Enabled = true - utils.Config.Db.Pooler.Enabled = false // Setup mock docker require.NoError(t, apitest.MockDocker(utils.Docker)) defer gock.OffAll() @@ -348,11 +347,20 @@ func TestRestartDatabase(t *testing.T) { utils.PoolerId = "test-pooler" utils.GotrueId = "test-auth" utils.RealtimeId = "test-realtime" + utils.Config.Auth.Enabled = true + utils.Config.Realtime.Enabled = true + utils.Config.Db.Pooler.Enabled = false + utils.Config.Storage.Enabled = false for _, container := range []string{utils.GotrueId, utils.RealtimeId} { gock.New(utils.Docker.DaemonHost()). Post("/v" + utils.Docker.ClientVersion() + "/containers/" + container + "/restart"). Reply(http.StatusOK) } + for _, container := range []string{utils.StorageId, utils.PoolerId} { + gock.New(utils.Docker.DaemonHost()). + Post("/v" + utils.Docker.ClientVersion() + "/containers/" + container + "/restart"). + Reply(http.StatusServiceUnavailable) + } // Run test err := RestartDatabase(context.Background(), io.Discard) // Check error From 5e1f197b700454f436bdd1ce066fafce06ea77c9 Mon Sep 17 00:00:00 2001 From: avallete Date: Mon, 9 Sep 2024 16:06:28 +0200 Subject: [PATCH 4/5] chore: apply PR suggestions --- internal/db/reset/reset.go | 17 +----------- internal/db/reset/reset_test.go | 46 --------------------------------- 2 files changed, 1 insertion(+), 62 deletions(-) diff --git a/internal/db/reset/reset.go b/internal/db/reset/reset.go index 20ef26755..967b7ebbe 100644 --- a/internal/db/reset/reset.go +++ b/internal/db/reset/reset.go @@ -220,22 +220,7 @@ func restartServices(ctx context.Context) error { } func listServicesToRestart() []string { - var services []string - - if utils.Config.Storage.Enabled { - services = append(services, utils.StorageId) - } - if utils.Config.Realtime.Enabled { - services = append(services, utils.RealtimeId) - } - if utils.Config.Db.Pooler.Enabled { - services = append(services, utils.PoolerId) - } - if utils.Config.Auth.Enabled { - services = append(services, utils.GotrueId) - } - - return services + return []string{utils.StorageId, utils.GotrueId, utils.RealtimeId, utils.PoolerId} } func resetRemote(ctx context.Context, version string, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error { diff --git a/internal/db/reset/reset_test.go b/internal/db/reset/reset_test.go index d6d8b24e4..38fef4b96 100644 --- a/internal/db/reset/reset_test.go +++ b/internal/db/reset/reset_test.go @@ -261,9 +261,6 @@ func TestRestartDatabase(t *testing.T) { utils.GotrueId = "test-auth" utils.RealtimeId = "test-realtime" utils.PoolerId = "test-pooler" - utils.Config.Storage.Enabled = true - utils.Config.Auth.Enabled = true - utils.Config.Realtime.Enabled = true for _, container := range []string{utils.StorageId, utils.GotrueId, utils.RealtimeId} { gock.New(utils.Docker.DaemonHost()). Post("/v" + utils.Docker.ClientVersion() + "/containers/" + container + "/restart"). @@ -324,49 +321,6 @@ func TestRestartDatabase(t *testing.T) { assert.ErrorContains(t, err, "test-reset container is not running: exited") assert.Empty(t, apitest.ListUnmatchedRequests()) }) - t.Run("restarts only enabled services", func(t *testing.T) { - utils.DbId = "test-reset" - // Setup mock docker - require.NoError(t, apitest.MockDocker(utils.Docker)) - defer gock.OffAll() - // Restarts postgres - gock.New(utils.Docker.DaemonHost()). - Post("/v" + utils.Docker.ClientVersion() + "/containers/" + utils.DbId + "/restart"). - Reply(http.StatusOK) - gock.New(utils.Docker.DaemonHost()). - Get("/v" + utils.Docker.ClientVersion() + "/containers/" + utils.DbId + "/json"). - Reply(http.StatusOK). - JSON(types.ContainerJSON{ContainerJSONBase: &types.ContainerJSONBase{ - State: &types.ContainerState{ - Running: true, - Health: &types.Health{Status: "healthy"}, - }, - }}) - // Restarts enabled services - utils.StorageId = "test-storage" - utils.PoolerId = "test-pooler" - utils.GotrueId = "test-auth" - utils.RealtimeId = "test-realtime" - utils.Config.Auth.Enabled = true - utils.Config.Realtime.Enabled = true - utils.Config.Db.Pooler.Enabled = false - utils.Config.Storage.Enabled = false - for _, container := range []string{utils.GotrueId, utils.RealtimeId} { - gock.New(utils.Docker.DaemonHost()). - Post("/v" + utils.Docker.ClientVersion() + "/containers/" + container + "/restart"). - Reply(http.StatusOK) - } - for _, container := range []string{utils.StorageId, utils.PoolerId} { - gock.New(utils.Docker.DaemonHost()). - Post("/v" + utils.Docker.ClientVersion() + "/containers/" + container + "/restart"). - Reply(http.StatusServiceUnavailable) - } - // Run test - err := RestartDatabase(context.Background(), io.Discard) - // Check error - assert.NoError(t, err) - assert.Empty(t, apitest.ListUnmatchedRequests()) - }) } var escapedSchemas = append(migration.ManagedSchemas, "extensions", "public") From ec946b1774196209650a40605d982554a8a97ca1 Mon Sep 17 00:00:00 2001 From: avallete Date: Mon, 9 Sep 2024 16:11:07 +0200 Subject: [PATCH 5/5] chore: remove unnecessary newline --- internal/db/reset/reset.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/db/reset/reset.go b/internal/db/reset/reset.go index 967b7ebbe..62c3d3350 100644 --- a/internal/db/reset/reset.go +++ b/internal/db/reset/reset.go @@ -208,7 +208,6 @@ func RestartDatabase(ctx context.Context, w io.Writer) error { func restartServices(ctx context.Context) error { // No need to restart PostgREST because it automatically reconnects and listens for schema changes services := listServicesToRestart() - result := utils.WaitAll(services, func(id string) error { if err := utils.Docker.ContainerRestart(ctx, id, container.StopOptions{}); err != nil && !errdefs.IsNotFound(err) { return errors.Errorf("Failed to restart %s: %w", id, err)