Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bbe91ec

Browse files
hugodutkaSasSwart
authored andcommitted
chore: add the --ephemeral server flag (#16126)
Another PR to address #15109. Changes: - Introduces the `--ephemeral` flag, which changes the Coder config directory to a temporary location. The config directory is where the built-in PostgreSQL stores its data, so using a new one results in a deployment with a fresh state. The `--ephemeral` flag is set to replace the `--in-memory` flag once the in-memory database is removed.
1 parent 1fbe9ba commit bbe91ec

File tree

10 files changed

+95
-5
lines changed

10 files changed

+95
-5
lines changed

cli/server.go

+32-4
Original file line numberDiff line numberDiff line change
@@ -391,14 +391,38 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
391391
}
392392
defer httpServers.Close()
393393

394+
if vals.EphemeralDeployment.Value() {
395+
r.globalConfig = filepath.Join(os.TempDir(), fmt.Sprintf("coder_ephemeral_%d", time.Now().UnixMilli()))
396+
if err := os.MkdirAll(r.globalConfig, 0o700); err != nil {
397+
return xerrors.Errorf("create ephemeral deployment directory: %w", err)
398+
}
399+
cliui.Infof(inv.Stdout, "Using an ephemeral deployment directory (%s)", r.globalConfig)
400+
defer func() {
401+
cliui.Infof(inv.Stdout, "Removing ephemeral deployment directory...")
402+
if err := os.RemoveAll(r.globalConfig); err != nil {
403+
cliui.Errorf(inv.Stderr, "Failed to remove ephemeral deployment directory: %v", err)
404+
} else {
405+
cliui.Infof(inv.Stdout, "Removed ephemeral deployment directory")
406+
}
407+
}()
408+
}
394409
config := r.createConfig()
395410

396411
builtinPostgres := false
397412
// Only use built-in if PostgreSQL URL isn't specified!
398413
if !vals.InMemoryDatabase && vals.PostgresURL == "" {
399414
var closeFunc func() error
400415
cliui.Infof(inv.Stdout, "Using built-in PostgreSQL (%s)", config.PostgresPath())
401-
pgURL, closeFunc, err := startBuiltinPostgres(ctx, config, logger)
416+
customPostgresCacheDir := ""
417+
// By default, built-in PostgreSQL will use the Coder root directory
418+
// for its cache. However, when a deployment is ephemeral, the root
419+
// directory is wiped clean on shutdown, defeating the purpose of using
420+
// it as a cache. So here we use a cache directory that will not get
421+
// removed on restart.
422+
if vals.EphemeralDeployment.Value() {
423+
customPostgresCacheDir = cacheDir
424+
}
425+
pgURL, closeFunc, err := startBuiltinPostgres(ctx, config, logger, customPostgresCacheDir)
402426
if err != nil {
403427
return err
404428
}
@@ -1202,7 +1226,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
12021226
ctx, cancel := inv.SignalNotifyContext(ctx, InterruptSignals...)
12031227
defer cancel()
12041228

1205-
url, closePg, err := startBuiltinPostgres(ctx, cfg, logger)
1229+
url, closePg, err := startBuiltinPostgres(ctx, cfg, logger, "")
12061230
if err != nil {
12071231
return err
12081232
}
@@ -1949,7 +1973,7 @@ func embeddedPostgresURL(cfg config.Root) (string, error) {
19491973
return fmt.Sprintf("postgres://coder@localhost:%s/coder?sslmode=disable&password=%s", pgPort, pgPassword), nil
19501974
}
19511975

1952-
func startBuiltinPostgres(ctx context.Context, cfg config.Root, logger slog.Logger) (string, func() error, error) {
1976+
func startBuiltinPostgres(ctx context.Context, cfg config.Root, logger slog.Logger, customCacheDir string) (string, func() error, error) {
19531977
usr, err := user.Current()
19541978
if err != nil {
19551979
return "", nil, err
@@ -1976,14 +2000,18 @@ func startBuiltinPostgres(ctx context.Context, cfg config.Root, logger slog.Logg
19762000
return "", nil, xerrors.Errorf("parse postgres port: %w", err)
19772001
}
19782002

2003+
cachePath := filepath.Join(cfg.PostgresPath(), "cache")
2004+
if customCacheDir != "" {
2005+
cachePath = filepath.Join(customCacheDir, "postgres")
2006+
}
19792007
stdlibLogger := slog.Stdlib(ctx, logger.Named("postgres"), slog.LevelDebug)
19802008
ep := embeddedpostgres.NewDatabase(
19812009
embeddedpostgres.DefaultConfig().
19822010
Version(embeddedpostgres.V13).
19832011
BinariesPath(filepath.Join(cfg.PostgresPath(), "bin")).
19842012
DataPath(filepath.Join(cfg.PostgresPath(), "data")).
19852013
RuntimePath(filepath.Join(cfg.PostgresPath(), "runtime")).
1986-
CachePath(filepath.Join(cfg.PostgresPath(), "cache")).
2014+
CachePath(cachePath).
19872015
Username("coder").
19882016
Password(pgPassword).
19892017
Database("coder").

cli/server_createadminuser.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func (r *RootCmd) newCreateAdminUserCommand() *serpent.Command {
5454

5555
if newUserDBURL == "" {
5656
cliui.Infof(inv.Stdout, "Using built-in PostgreSQL (%s)", cfg.PostgresPath())
57-
url, closePg, err := startBuiltinPostgres(ctx, cfg, logger)
57+
url, closePg, err := startBuiltinPostgres(ctx, cfg, logger, "")
5858
if err != nil {
5959
return err
6060
}

cli/server_test.go

+37
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,43 @@ func TestServer(t *testing.T) {
177177
return err == nil && rawURL != ""
178178
}, superDuperLong, testutil.IntervalFast, "failed to get access URL")
179179
})
180+
t.Run("EphemeralDeployment", func(t *testing.T) {
181+
t.Parallel()
182+
if testing.Short() {
183+
t.SkipNow()
184+
}
185+
186+
inv, _ := clitest.New(t,
187+
"server",
188+
"--http-address", ":0",
189+
"--access-url", "http://example.com",
190+
"--ephemeral",
191+
)
192+
pty := ptytest.New(t).Attach(inv)
193+
194+
// Embedded postgres takes a while to fire up.
195+
const superDuperLong = testutil.WaitSuperLong * 3
196+
ctx, cancelFunc := context.WithCancel(testutil.Context(t, superDuperLong))
197+
errCh := make(chan error, 1)
198+
go func() {
199+
errCh <- inv.WithContext(ctx).Run()
200+
}()
201+
pty.ExpectMatch("Using an ephemeral deployment directory")
202+
rootDirLine := pty.ReadLine(ctx)
203+
rootDir := strings.TrimPrefix(rootDirLine, "Using an ephemeral deployment directory")
204+
rootDir = strings.TrimSpace(rootDir)
205+
rootDir = strings.TrimPrefix(rootDir, "(")
206+
rootDir = strings.TrimSuffix(rootDir, ")")
207+
require.NotEmpty(t, rootDir)
208+
require.DirExists(t, rootDir)
209+
210+
pty.ExpectMatchContext(ctx, "View the Web UI")
211+
212+
cancelFunc()
213+
<-errCh
214+
215+
require.NoDirExists(t, rootDir)
216+
})
180217
t.Run("BuiltinPostgresURL", func(t *testing.T) {
181218
t.Parallel()
182219
root, _ := clitest.New(t, "server", "postgres-builtin-url")

cli/testdata/server-config.yaml.golden

+4
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,10 @@ cacheDir: [cache dir]
446446
# Controls whether data will be stored in an in-memory database.
447447
# (default: <unset>, type: bool)
448448
inMemoryDatabase: false
449+
# Controls whether Coder data, including built-in Postgres, will be stored in a
450+
# temporary directory and deleted when the server is stopped.
451+
# (default: <unset>, type: bool)
452+
ephemeralDeployment: false
449453
# Type of auth to use when connecting to postgres. For AWS RDS, using IAM
450454
# authentication (awsiamrds) is recommended.
451455
# (default: password, type: enum[password\|awsiamrds])

coderd/apidoc/docs.go

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codersdk/deployment.go

+10
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ type DeploymentValues struct {
350350
ProxyTrustedOrigins serpent.StringArray `json:"proxy_trusted_origins,omitempty" typescript:",notnull"`
351351
CacheDir serpent.String `json:"cache_directory,omitempty" typescript:",notnull"`
352352
InMemoryDatabase serpent.Bool `json:"in_memory_database,omitempty" typescript:",notnull"`
353+
EphemeralDeployment serpent.Bool `json:"ephemeral_deployment,omitempty" typescript:",notnull"`
353354
PostgresURL serpent.String `json:"pg_connection_url,omitempty" typescript:",notnull"`
354355
PostgresAuth string `json:"pg_auth,omitempty" typescript:",notnull"`
355356
OAuth2 OAuth2Config `json:"oauth2,omitempty" typescript:",notnull"`
@@ -2282,6 +2283,15 @@ func (c *DeploymentValues) Options() serpent.OptionSet {
22822283
Value: &c.InMemoryDatabase,
22832284
YAML: "inMemoryDatabase",
22842285
},
2286+
{
2287+
Name: "Ephemeral Deployment",
2288+
Description: "Controls whether Coder data, including built-in Postgres, will be stored in a temporary directory and deleted when the server is stopped.",
2289+
Flag: "ephemeral",
2290+
Env: "CODER_EPHEMERAL",
2291+
Hidden: true,
2292+
Value: &c.EphemeralDeployment,
2293+
YAML: "ephemeralDeployment",
2294+
},
22852295
{
22862296
Name: "Postgres Connection URL",
22872297
Description: "URL of a PostgreSQL database. If empty, PostgreSQL binaries will be downloaded from Maven (https://repo1.maven.org/maven2) and store all data in the config root. Access the built-in database with \"coder server postgres-builtin-url\". Note that any special characters in the URL must be URL-encoded.",

docs/reference/api/general.md

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/api/schemas.md

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

site/src/api/typesGenerated.ts

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)