Skip to content

Commit dc63c00

Browse files
committed
add the --ephemeral server flag, use a proper cache directory for built-in postgres cache
1 parent 2913fe8 commit dc63c00

File tree

5 files changed

+75
-5
lines changed

5 files changed

+75
-5
lines changed

cli/server.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -391,14 +391,29 @@ 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+
cliui.Infof(inv.Stdout, "Using an ephemeral deployment (%s)", r.globalConfig)
397+
if err := os.MkdirAll(r.globalConfig, 0o700); err != nil {
398+
return xerrors.Errorf("create ephemeral deployment directory: %w", err)
399+
}
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+
pgURL, closeFunc, err := startBuiltinPostgres(ctx, config, logger, cacheDir)
402417
if err != nil {
403418
return err
404419
}
@@ -1202,7 +1217,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
12021217
ctx, cancel := inv.SignalNotifyContext(ctx, InterruptSignals...)
12031218
defer cancel()
12041219

1205-
url, closePg, err := startBuiltinPostgres(ctx, cfg, logger)
1220+
url, closePg, err := startBuiltinPostgres(ctx, cfg, logger, "")
12061221
if err != nil {
12071222
return err
12081223
}
@@ -1949,7 +1964,7 @@ func embeddedPostgresURL(cfg config.Root) (string, error) {
19491964
return fmt.Sprintf("postgres://coder@localhost:%s/coder?sslmode=disable&password=%s", pgPort, pgPassword), nil
19501965
}
19511966

1952-
func startBuiltinPostgres(ctx context.Context, cfg config.Root, logger slog.Logger) (string, func() error, error) {
1967+
func startBuiltinPostgres(ctx context.Context, cfg config.Root, logger slog.Logger, cacheDir string) (string, func() error, error) {
19531968
usr, err := user.Current()
19541969
if err != nil {
19551970
return "", nil, err
@@ -1976,14 +1991,18 @@ func startBuiltinPostgres(ctx context.Context, cfg config.Root, logger slog.Logg
19761991
return "", nil, xerrors.Errorf("parse postgres port: %w", err)
19771992
}
19781993

1994+
cachePath := filepath.Join(cfg.PostgresPath(), "cache")
1995+
if cacheDir != "" {
1996+
cachePath = filepath.Join(cacheDir, "postgres")
1997+
}
19791998
stdlibLogger := slog.Stdlib(ctx, logger.Named("postgres"), slog.LevelDebug)
19801999
ep := embeddedpostgres.NewDatabase(
19812000
embeddedpostgres.DefaultConfig().
19822001
Version(embeddedpostgres.V13).
19832002
BinariesPath(filepath.Join(cfg.PostgresPath(), "bin")).
19842003
DataPath(filepath.Join(cfg.PostgresPath(), "data")).
19852004
RuntimePath(filepath.Join(cfg.PostgresPath(), "runtime")).
1986-
CachePath(filepath.Join(cfg.PostgresPath(), "cache")).
2005+
CachePath(cachePath).
19872006
Username("coder").
19882007
Password(pgPassword).
19892008
Database("coder").

cli/server_createadminuser.go

Lines changed: 1 addition & 1 deletion
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

Lines changed: 37 additions & 0 deletions
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+
const superDuperLong = testutil.WaitSuperLong * 3
195+
ctx, cancelFunc := context.WithCancel(testutil.Context(t, superDuperLong))
196+
errCh := make(chan error, 1)
197+
go func() {
198+
errCh <- inv.WithContext(ctx).Run()
199+
}()
200+
pty.ExpectMatch("Using an ephemeral deployment")
201+
rootDirLine := pty.ReadLine(ctx)
202+
rootDir := strings.TrimPrefix(rootDirLine, "Using an ephemeral deployment")
203+
rootDir = strings.TrimSpace(rootDir)
204+
rootDir = strings.TrimPrefix(rootDir, "(")
205+
rootDir = strings.TrimSuffix(rootDir, ")")
206+
require.NotEmpty(t, rootDir)
207+
require.DirExists(t, rootDir)
208+
209+
pty.ExpectMatch("View the Web UI")
210+
211+
cancelFunc()
212+
<-errCh
213+
214+
require.NoDirExists(t, rootDir)
215+
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

Lines changed: 4 additions & 0 deletions
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])

codersdk/deployment.go

Lines changed: 10 additions & 0 deletions
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.",

0 commit comments

Comments
 (0)