mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: Add built-in PostgreSQL for simple production setup (#2345)
* feat: Add built-in PostgreSQL for simple production setup Fixes #2321. * Use fork of embedded-postgres for cache path
This commit is contained in:
+24
-113
@@ -9,7 +9,6 @@ import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -25,7 +24,6 @@ import (
|
||||
"go.uber.org/goleak"
|
||||
|
||||
"github.com/coder/coder/cli/clitest"
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
"github.com/coder/coder/coderd/database/postgres"
|
||||
"github.com/coder/coder/codersdk"
|
||||
)
|
||||
@@ -34,8 +32,6 @@ import (
|
||||
// nolint:paralleltest
|
||||
func TestServer(t *testing.T) {
|
||||
t.Run("Production", func(t *testing.T) {
|
||||
// postgres.Open() seems to be creating race conditions when run in parallel.
|
||||
// t.Parallel()
|
||||
if runtime.GOOS != "linux" || testing.Short() {
|
||||
// Skip on non-Linux because it spawns a PostgreSQL instance.
|
||||
t.SkipNow()
|
||||
@@ -71,99 +67,32 @@ func TestServer(t *testing.T) {
|
||||
cancelFunc()
|
||||
require.ErrorIs(t, <-errC, context.Canceled)
|
||||
})
|
||||
|
||||
t.Run("Development", func(t *testing.T) {
|
||||
t.Run("BuiltinPostgres", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
|
||||
wantEmail := "admin@coder.com"
|
||||
|
||||
root, cfg := clitest.New(t, "server", "--dev", "--tunnel=false", "--address", ":0")
|
||||
var buf strings.Builder
|
||||
errC := make(chan error)
|
||||
root.SetOutput(&buf)
|
||||
go func() {
|
||||
errC <- root.ExecuteContext(ctx)
|
||||
}()
|
||||
|
||||
var token string
|
||||
require.Eventually(t, func() bool {
|
||||
var err error
|
||||
token, err = cfg.Session().Read()
|
||||
return err == nil && token != ""
|
||||
}, 15*time.Second, 25*time.Millisecond)
|
||||
|
||||
// Verify that authentication was properly set in dev-mode.
|
||||
accessURL, err := cfg.URL().Read()
|
||||
require.NoError(t, err)
|
||||
parsed, err := url.Parse(accessURL)
|
||||
require.NoError(t, err)
|
||||
|
||||
client := codersdk.New(parsed)
|
||||
client.SessionToken = token
|
||||
_, err = client.User(ctx, codersdk.Me)
|
||||
require.NoError(t, err, "token:", token)
|
||||
|
||||
cancelFunc()
|
||||
require.ErrorIs(t, <-errC, context.Canceled)
|
||||
|
||||
// Verify that credentials were output to the terminal.
|
||||
assert.Contains(t, buf.String(), fmt.Sprintf("email: %s", wantEmail), "expected output %q; got no match", wantEmail)
|
||||
// Check that the password line is output and that it's non-empty.
|
||||
if _, after, found := strings.Cut(buf.String(), "password: "); found {
|
||||
before, _, _ := strings.Cut(after, "\n")
|
||||
before = strings.Trim(before, "\r") // Ensure no control character is left.
|
||||
assert.NotEmpty(t, before, "expected non-empty password; got empty")
|
||||
} else {
|
||||
t.Error("expected password line output; got no match")
|
||||
if testing.Short() {
|
||||
t.SkipNow()
|
||||
}
|
||||
|
||||
// Verify that we warned the user about the default access URL possibly not being what they want.
|
||||
assert.Contains(t, buf.String(), "coder/coder/issues/1528")
|
||||
})
|
||||
|
||||
// Duplicated test from "Development" above to test setting email/password via env.
|
||||
// Cannot run parallel due to os.Setenv.
|
||||
//nolint:paralleltest
|
||||
t.Run("Development with email and password from env", func(t *testing.T) {
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
|
||||
wantEmail := "myadmin@coder.com"
|
||||
wantPassword := "testpass42"
|
||||
t.Setenv("CODER_DEV_ADMIN_EMAIL", wantEmail)
|
||||
t.Setenv("CODER_DEV_ADMIN_PASSWORD", wantPassword)
|
||||
|
||||
root, cfg := clitest.New(t, "server", "--dev", "--tunnel=false", "--address", ":0")
|
||||
var buf strings.Builder
|
||||
root.SetOutput(&buf)
|
||||
root, cfg := clitest.New(t, "server", "--address", ":0")
|
||||
errC := make(chan error)
|
||||
go func() {
|
||||
errC <- root.ExecuteContext(ctx)
|
||||
}()
|
||||
|
||||
var token string
|
||||
require.Eventually(t, func() bool {
|
||||
var err error
|
||||
token, err = cfg.Session().Read()
|
||||
_, err := cfg.URL().Read()
|
||||
return err == nil
|
||||
}, 15*time.Second, 25*time.Millisecond)
|
||||
// Verify that authentication was properly set in dev-mode.
|
||||
accessURL, err := cfg.URL().Read()
|
||||
require.NoError(t, err)
|
||||
parsed, err := url.Parse(accessURL)
|
||||
require.NoError(t, err)
|
||||
client := codersdk.New(parsed)
|
||||
client.SessionToken = token
|
||||
_, err = client.User(ctx, codersdk.Me)
|
||||
require.NoError(t, err)
|
||||
|
||||
}, time.Minute, 25*time.Millisecond)
|
||||
cancelFunc()
|
||||
require.ErrorIs(t, <-errC, context.Canceled)
|
||||
// Verify that credentials were output to the terminal.
|
||||
assert.Contains(t, buf.String(), fmt.Sprintf("email: %s", wantEmail), "expected output %q; got no match", wantEmail)
|
||||
assert.Contains(t, buf.String(), fmt.Sprintf("password: %s", wantPassword), "expected output %q; got no match", wantPassword)
|
||||
})
|
||||
t.Run("BuiltinPostgresURL", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
root, _ := clitest.New(t, "server", "postgres-builtin-url")
|
||||
var buf strings.Builder
|
||||
root.SetOutput(&buf)
|
||||
err := root.Execute()
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, buf.String(), "psql")
|
||||
})
|
||||
|
||||
t.Run("NoWarningWithRemoteAccessURL", func(t *testing.T) {
|
||||
@@ -171,7 +100,7 @@ func TestServer(t *testing.T) {
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
|
||||
root, cfg := clitest.New(t, "server", "--dev", "--tunnel=false", "--address", ":0", "--access-url", "http://1.2.3.4:3000/")
|
||||
root, cfg := clitest.New(t, "server", "--in-memory", "--address", ":0", "--access-url", "http://1.2.3.4:3000/")
|
||||
var buf strings.Builder
|
||||
errC := make(chan error)
|
||||
root.SetOutput(&buf)
|
||||
@@ -189,14 +118,14 @@ func TestServer(t *testing.T) {
|
||||
cancelFunc()
|
||||
require.ErrorIs(t, <-errC, context.Canceled)
|
||||
|
||||
assert.NotContains(t, buf.String(), "coder/coder/issues/1528")
|
||||
assert.NotContains(t, buf.String(), "Workspaces must be able to reach Coder from this URL")
|
||||
})
|
||||
|
||||
t.Run("TLSBadVersion", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
root, _ := clitest.New(t, "server", "--dev", "--tunnel=false", "--address", ":0",
|
||||
root, _ := clitest.New(t, "server", "--in-memory", "--address", ":0",
|
||||
"--tls-enable", "--tls-min-version", "tls9")
|
||||
err := root.ExecuteContext(ctx)
|
||||
require.Error(t, err)
|
||||
@@ -205,7 +134,7 @@ func TestServer(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
root, _ := clitest.New(t, "server", "--dev", "--tunnel=false", "--address", ":0",
|
||||
root, _ := clitest.New(t, "server", "--in-memory", "--address", ":0",
|
||||
"--tls-enable", "--tls-client-auth", "something")
|
||||
err := root.ExecuteContext(ctx)
|
||||
require.Error(t, err)
|
||||
@@ -214,7 +143,7 @@ func TestServer(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
root, _ := clitest.New(t, "server", "--dev", "--tunnel=false", "--address", ":0",
|
||||
root, _ := clitest.New(t, "server", "--in-memory", "--address", ":0",
|
||||
"--tls-enable")
|
||||
err := root.ExecuteContext(ctx)
|
||||
require.Error(t, err)
|
||||
@@ -225,7 +154,7 @@ func TestServer(t *testing.T) {
|
||||
defer cancelFunc()
|
||||
|
||||
certPath, keyPath := generateTLSCertificate(t)
|
||||
root, cfg := clitest.New(t, "server", "--dev", "--tunnel=false", "--address", ":0",
|
||||
root, cfg := clitest.New(t, "server", "--in-memory", "--address", ":0",
|
||||
"--tls-enable", "--tls-cert-file", certPath, "--tls-key-file", keyPath)
|
||||
errC := make(chan error)
|
||||
go func() {
|
||||
@@ -266,36 +195,18 @@ func TestServer(t *testing.T) {
|
||||
}
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
root, cfg := clitest.New(t, "server", "--dev", "--tunnel=false", "--address", ":0", "--provisioner-daemons", "1")
|
||||
root, cfg := clitest.New(t, "server", "--in-memory", "--address", ":0", "--provisioner-daemons", "1")
|
||||
serverErr := make(chan error)
|
||||
go func() {
|
||||
err := root.ExecuteContext(ctx)
|
||||
serverErr <- err
|
||||
}()
|
||||
var token string
|
||||
require.Eventually(t, func() bool {
|
||||
var err error
|
||||
token, err = cfg.Session().Read()
|
||||
_, err = cfg.URL().Read()
|
||||
return err == nil
|
||||
}, 15*time.Second, 25*time.Millisecond)
|
||||
// Verify that authentication was properly set in dev-mode.
|
||||
accessURL, err := cfg.URL().Read()
|
||||
require.NoError(t, err)
|
||||
parsed, err := url.Parse(accessURL)
|
||||
require.NoError(t, err)
|
||||
client := codersdk.New(parsed)
|
||||
client.SessionToken = token
|
||||
orgs, err := client.OrganizationsByUser(ctx, codersdk.Me)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a workspace so the cleanup occurs!
|
||||
version := coderdtest.CreateTemplateVersion(t, client, orgs[0].ID, nil)
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
template := coderdtest.CreateTemplate(t, client, orgs[0].ID, version.ID)
|
||||
workspace := coderdtest.CreateWorkspace(t, client, orgs[0].ID, template.ID)
|
||||
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
|
||||
|
||||
require.NoError(t, err)
|
||||
currentProcess, err := os.FindProcess(os.Getpid())
|
||||
require.NoError(t, err)
|
||||
err = currentProcess.Signal(os.Interrupt)
|
||||
@@ -313,7 +224,7 @@ func TestServer(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
root, _ := clitest.New(t, "server", "--dev", "--tunnel=false", "--address", ":0", "--trace=true")
|
||||
root, _ := clitest.New(t, "server", "--in-memory", "--address", ":0", "--trace=true")
|
||||
errC := make(chan error)
|
||||
go func() {
|
||||
errC <- root.ExecuteContext(ctx)
|
||||
|
||||
Reference in New Issue
Block a user