mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: refactor deployment config (#6347)
This commit is contained in:
+371
-160
@@ -12,6 +12,7 @@ import (
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
@@ -25,6 +26,7 @@ import (
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -40,7 +42,6 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"golang.org/x/mod/semver"
|
||||
"golang.org/x/oauth2"
|
||||
@@ -49,6 +50,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
"google.golang.org/api/idtoken"
|
||||
"google.golang.org/api/option"
|
||||
"gopkg.in/yaml.v3"
|
||||
"tailscale.com/tailcfg"
|
||||
|
||||
"cdr.dev/slog"
|
||||
@@ -56,9 +58,9 @@ import (
|
||||
"cdr.dev/slog/sloggers/slogjson"
|
||||
"cdr.dev/slog/sloggers/slogstackdriver"
|
||||
"github.com/coder/coder/buildinfo"
|
||||
"github.com/coder/coder/cli/clibase"
|
||||
"github.com/coder/coder/cli/cliui"
|
||||
"github.com/coder/coder/cli/config"
|
||||
"github.com/coder/coder/cli/deployment"
|
||||
"github.com/coder/coder/coderd"
|
||||
"github.com/coder/coder/coderd/autobuild/executor"
|
||||
"github.com/coder/coder/coderd/database"
|
||||
@@ -84,48 +86,221 @@ import (
|
||||
"github.com/coder/coder/tailnet"
|
||||
)
|
||||
|
||||
// ReadGitAuthProvidersFromEnv is provided for compatibility purposes with the
|
||||
// viper CLI.
|
||||
// DEPRECATED
|
||||
func ReadGitAuthProvidersFromEnv(environ []string) ([]codersdk.GitAuthConfig, error) {
|
||||
// The index numbers must be in-order.
|
||||
sort.Strings(environ)
|
||||
|
||||
var providers []codersdk.GitAuthConfig
|
||||
for _, v := range clibase.EnvsWithPrefix(environ, envPrefix+"GITAUTH_") {
|
||||
tokens := strings.SplitN(v.Name, "_", 2)
|
||||
if len(tokens) != 2 {
|
||||
return nil, xerrors.Errorf("invalid env var: %s", v.Name)
|
||||
}
|
||||
|
||||
providerNum, err := strconv.Atoi(tokens[0])
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse number: %s", v.Name)
|
||||
}
|
||||
|
||||
var provider codersdk.GitAuthConfig
|
||||
switch {
|
||||
case len(providers) < providerNum:
|
||||
return nil, xerrors.Errorf(
|
||||
"provider num %v skipped: %s",
|
||||
len(providers),
|
||||
v.Name,
|
||||
)
|
||||
case len(providers) == providerNum:
|
||||
// At the next next provider.
|
||||
providers = append(providers, provider)
|
||||
case len(providers) == providerNum+1:
|
||||
// At the current provider.
|
||||
provider = providers[providerNum]
|
||||
}
|
||||
|
||||
key := tokens[1]
|
||||
switch key {
|
||||
case "ID":
|
||||
provider.ID = v.Value
|
||||
case "TYPE":
|
||||
provider.Type = v.Value
|
||||
case "CLIENT_ID":
|
||||
provider.ClientID = v.Value
|
||||
case "CLIENT_SECRET":
|
||||
provider.ClientSecret = v.Value
|
||||
case "AUTH_URL":
|
||||
provider.AuthURL = v.Value
|
||||
case "TOKEN_URL":
|
||||
provider.TokenURL = v.Value
|
||||
case "VALIDATE_URL":
|
||||
provider.ValidateURL = v.Value
|
||||
case "REGEX":
|
||||
provider.Regex = v.Value
|
||||
case "NO_REFRESH":
|
||||
b, err := strconv.ParseBool(key)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse bool: %s", v.Value)
|
||||
}
|
||||
provider.NoRefresh = b
|
||||
case "SCOPES":
|
||||
provider.Scopes = strings.Split(v.Value, " ")
|
||||
}
|
||||
providers[providerNum] = provider
|
||||
}
|
||||
return providers, nil
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*coderd.API, io.Closer, error)) *cobra.Command {
|
||||
func Server(newAPI func(context.Context, *coderd.Options) (*coderd.API, io.Closer, error)) *cobra.Command {
|
||||
root := &cobra.Command{
|
||||
Use: "server",
|
||||
Short: "Start a Coder server",
|
||||
Use: "server",
|
||||
Short: "Start a Coder server",
|
||||
DisableFlagParsing: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// Main command context for managing cancellation of running
|
||||
// services.
|
||||
ctx, cancel := context.WithCancel(cmd.Context())
|
||||
defer cancel()
|
||||
|
||||
cfg := &codersdk.DeploymentValues{}
|
||||
cliOpts := cfg.Options()
|
||||
var configDir clibase.String
|
||||
// This is a hack to get around the fact that the Cobra-defined
|
||||
// flags are not available.
|
||||
cliOpts.Add(clibase.Option{
|
||||
Name: "Global Config",
|
||||
Flag: config.FlagName,
|
||||
Description: "Global Config is ignored in server mode.",
|
||||
Hidden: true,
|
||||
Default: config.DefaultDir(),
|
||||
Value: &configDir,
|
||||
})
|
||||
|
||||
err := cliOpts.SetDefaults()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("set defaults: %w", err)
|
||||
}
|
||||
|
||||
err = cliOpts.ParseEnv(envPrefix, os.Environ())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse env: %w", err)
|
||||
}
|
||||
|
||||
flagSet := cliOpts.FlagSet()
|
||||
// These parents and children will be moved once we convert the
|
||||
// rest of the `cli` package to clibase.
|
||||
flagSet.Usage = usageFn(cmd.ErrOrStderr(), &clibase.Cmd{
|
||||
Parent: &clibase.Cmd{
|
||||
Use: "coder",
|
||||
},
|
||||
Children: []*clibase.Cmd{
|
||||
{
|
||||
Use: "postgres-builtin-url",
|
||||
Short: "Output the connection URL for the built-in PostgreSQL deployment.",
|
||||
},
|
||||
{
|
||||
Use: "postgres-builtin-serve",
|
||||
Short: "Run the built-in PostgreSQL deployment.",
|
||||
},
|
||||
},
|
||||
Use: "server [flags]",
|
||||
Short: "Start a Coder server",
|
||||
Long: `
|
||||
The server provides the Coder dashboard, API, and provisioners.
|
||||
If no options are provided, the server will start with a built-in postgres
|
||||
and an access URL provided by Coder's cloud service.
|
||||
|
||||
Use the following command to print the built-in postgres URL:
|
||||
$ coder server postgres-builtin-url
|
||||
|
||||
Use the following command to manually run the built-in postgres:
|
||||
$ coder server postgres-builtin-serve
|
||||
|
||||
Options may be provided via environment variables prefixed with "CODER_",
|
||||
flags, and YAML configuration. The precedence is as follows:
|
||||
1. Defaults
|
||||
2. YAML configuration
|
||||
3. Environment variables
|
||||
4. Flags
|
||||
`,
|
||||
Options: cliOpts,
|
||||
})
|
||||
err = flagSet.Parse(args)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse flags: %w", err)
|
||||
}
|
||||
|
||||
if cfg.WriteConfig {
|
||||
// TODO: this should output to a file.
|
||||
n, err := cliOpts.ToYAML()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("generate yaml: %w", err)
|
||||
}
|
||||
enc := yaml.NewEncoder(cmd.ErrOrStderr())
|
||||
err = enc.Encode(n)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("encode yaml: %w", err)
|
||||
}
|
||||
err = enc.Close()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("close yaml encoder: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Print deprecation warnings.
|
||||
for _, opt := range cliOpts {
|
||||
if opt.UseInstead == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
warnStr := opt.Name + " is deprecated, please use "
|
||||
for i, use := range opt.UseInstead {
|
||||
warnStr += use.Name + " "
|
||||
if i != len(opt.UseInstead)-1 {
|
||||
warnStr += "and "
|
||||
}
|
||||
}
|
||||
warnStr += "instead.\n"
|
||||
|
||||
cmd.PrintErr(
|
||||
cliui.Styles.Warn.Render("WARN: ") + warnStr,
|
||||
)
|
||||
}
|
||||
|
||||
go dumpHandler(ctx)
|
||||
|
||||
cfg, err := deployment.Config(cmd.Flags(), vip)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting deployment config: %w", err)
|
||||
}
|
||||
|
||||
// Validate bind addresses.
|
||||
if cfg.Address.Value != "" {
|
||||
cmd.PrintErr(cliui.Styles.Warn.Render("WARN:") + " --address and -a are deprecated, please use --http-address and --tls-address instead")
|
||||
if cfg.TLS.Enable.Value {
|
||||
cfg.HTTPAddress.Value = ""
|
||||
cfg.TLS.Address.Value = cfg.Address.Value
|
||||
if cfg.Address.String() != "" {
|
||||
if cfg.TLS.Enable {
|
||||
cfg.HTTPAddress = ""
|
||||
cfg.TLS.Address = cfg.Address
|
||||
} else {
|
||||
cfg.HTTPAddress.Value = cfg.Address.Value
|
||||
cfg.TLS.Address.Value = ""
|
||||
_ = cfg.HTTPAddress.Set(cfg.Address.String())
|
||||
cfg.TLS.Address.Host = ""
|
||||
cfg.TLS.Address.Port = ""
|
||||
}
|
||||
}
|
||||
if cfg.TLS.Enable.Value && cfg.TLS.Address.Value == "" {
|
||||
if cfg.TLS.Enable && cfg.TLS.Address.String() == "" {
|
||||
return xerrors.Errorf("TLS address must be set if TLS is enabled")
|
||||
}
|
||||
if !cfg.TLS.Enable.Value && cfg.HTTPAddress.Value == "" {
|
||||
if !cfg.TLS.Enable && cfg.HTTPAddress.String() == "" {
|
||||
return xerrors.Errorf("TLS is disabled. Enable with --tls-enable or specify a HTTP address")
|
||||
}
|
||||
|
||||
if cfg.AccessURL.String() != "" && cfg.AccessURL.Scheme == "" {
|
||||
return xerrors.Errorf("access-url must include a scheme (e.g. 'http://' or 'https://)")
|
||||
}
|
||||
|
||||
// Disable rate limits if the `--dangerous-disable-rate-limits` flag
|
||||
// was specified.
|
||||
loginRateLimit := 60
|
||||
filesRateLimit := 12
|
||||
if cfg.RateLimit.DisableAll.Value {
|
||||
cfg.RateLimit.API.Value = -1
|
||||
if cfg.RateLimit.DisableAll {
|
||||
cfg.RateLimit.API = -1
|
||||
loginRateLimit = -1
|
||||
filesRateLimit = -1
|
||||
}
|
||||
@@ -137,6 +312,10 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
}
|
||||
defer logCloser()
|
||||
|
||||
// This line is helpful in tests.
|
||||
logger.Debug(ctx, "started debug logging")
|
||||
logger.Sync()
|
||||
|
||||
// Register signals early on so that graceful shutdown can't
|
||||
// be interrupted by additional signals. Note that we avoid
|
||||
// shadowing cancel() (from above) here because notifyStop()
|
||||
@@ -151,7 +330,7 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
defer notifyStop()
|
||||
|
||||
// Ensure we have a unique cache directory for this process.
|
||||
cacheDir := filepath.Join(cfg.CacheDirectory.Value, uuid.NewString())
|
||||
cacheDir := filepath.Join(cfg.CacheDir.String(), uuid.NewString())
|
||||
err = os.MkdirAll(cacheDir, 0o700)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create cache directory: %w", err)
|
||||
@@ -170,18 +349,18 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
|
||||
// Coder tracing should be disabled if telemetry is disabled unless
|
||||
// --telemetry-trace was explicitly provided.
|
||||
shouldCoderTrace := cfg.Telemetry.Enable.Value && !isTest()
|
||||
shouldCoderTrace := cfg.Telemetry.Enable.Value() && !isTest()
|
||||
// Only override if telemetryTraceEnable was specifically set.
|
||||
// By default we want it to be controlled by telemetryEnable.
|
||||
if cmd.Flags().Changed("telemetry-trace") {
|
||||
shouldCoderTrace = cfg.Telemetry.Trace.Value
|
||||
shouldCoderTrace = cfg.Telemetry.Trace.Value()
|
||||
}
|
||||
|
||||
if cfg.Trace.Enable.Value || shouldCoderTrace || cfg.Trace.HoneycombAPIKey.Value != "" {
|
||||
if cfg.Trace.Enable.Value() || shouldCoderTrace || cfg.Trace.HoneycombAPIKey != "" {
|
||||
sdkTracerProvider, closeTracing, err := tracing.TracerProvider(ctx, "coderd", tracing.TracerOpts{
|
||||
Default: cfg.Trace.Enable.Value,
|
||||
Default: cfg.Trace.Enable.Value(),
|
||||
Coder: shouldCoderTrace,
|
||||
Honeycomb: cfg.Trace.HoneycombAPIKey.Value,
|
||||
Honeycomb: cfg.Trace.HoneycombAPIKey.String(),
|
||||
})
|
||||
if err != nil {
|
||||
logger.Warn(ctx, "start telemetry exporter", slog.Error(err))
|
||||
@@ -202,13 +381,18 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
}
|
||||
}
|
||||
|
||||
config := createConfig(cmd)
|
||||
config := config.Root(configDir)
|
||||
builtinPostgres := false
|
||||
// Only use built-in if PostgreSQL URL isn't specified!
|
||||
if !cfg.InMemoryDatabase.Value && cfg.PostgresURL.Value == "" {
|
||||
if !cfg.InMemoryDatabase && cfg.PostgresURL == "" {
|
||||
var closeFunc func() error
|
||||
cmd.Printf("Using built-in PostgreSQL (%s)\n", config.PostgresPath())
|
||||
cfg.PostgresURL.Value, closeFunc, err = startBuiltinPostgres(ctx, config, logger)
|
||||
pgURL, closeFunc, err := startBuiltinPostgres(ctx, config, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = cfg.PostgresURL.Set(pgURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -228,10 +412,10 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
httpListener net.Listener
|
||||
httpURL *url.URL
|
||||
)
|
||||
if cfg.HTTPAddress.Value != "" {
|
||||
httpListener, err = net.Listen("tcp", cfg.HTTPAddress.Value)
|
||||
if cfg.HTTPAddress.String() != "" {
|
||||
httpListener, err = net.Listen("tcp", cfg.HTTPAddress.String())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("listen %q: %w", cfg.HTTPAddress.Value, err)
|
||||
return xerrors.Errorf("listen %q: %w", cfg.HTTPAddress.String(), err)
|
||||
}
|
||||
defer httpListener.Close()
|
||||
|
||||
@@ -240,7 +424,7 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
// httpListener.Addr().String() likes to return it as an ipv6
|
||||
// address (i.e. [::]:x). If the input ip is 0.0.0.0, try to
|
||||
// coerce the output back to ipv4 to make it less confusing.
|
||||
if strings.Contains(cfg.HTTPAddress.Value, "0.0.0.0") {
|
||||
if strings.Contains(cfg.HTTPAddress.String(), "0.0.0.0") {
|
||||
listenAddrStr = strings.ReplaceAll(listenAddrStr, "[::]", "0.0.0.0")
|
||||
}
|
||||
|
||||
@@ -267,8 +451,8 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
httpsListener net.Listener
|
||||
httpsURL *url.URL
|
||||
)
|
||||
if cfg.TLS.Enable.Value {
|
||||
if cfg.TLS.Address.Value == "" {
|
||||
if cfg.TLS.Enable {
|
||||
if cfg.TLS.Address.String() == "" {
|
||||
return xerrors.New("tls address must be set if tls is enabled")
|
||||
}
|
||||
|
||||
@@ -276,22 +460,22 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
// It made more sense to have the redirect be opt-in.
|
||||
if os.Getenv("CODER_TLS_REDIRECT_HTTP") == "true" || cmd.Flags().Changed("tls-redirect-http-to-https") {
|
||||
cmd.PrintErr(cliui.Styles.Warn.Render("WARN:") + " --tls-redirect-http-to-https is deprecated, please use --redirect-to-access-url instead\n")
|
||||
cfg.RedirectToAccessURL.Value = cfg.TLS.RedirectHTTP.Value
|
||||
cfg.RedirectToAccessURL = cfg.TLS.RedirectHTTP
|
||||
}
|
||||
|
||||
tlsConfig, err = configureTLS(
|
||||
cfg.TLS.MinVersion.Value,
|
||||
cfg.TLS.ClientAuth.Value,
|
||||
cfg.TLS.CertFiles.Value,
|
||||
cfg.TLS.KeyFiles.Value,
|
||||
cfg.TLS.ClientCAFile.Value,
|
||||
cfg.TLS.MinVersion.String(),
|
||||
cfg.TLS.ClientAuth.String(),
|
||||
cfg.TLS.CertFiles,
|
||||
cfg.TLS.KeyFiles,
|
||||
cfg.TLS.ClientCAFile.String(),
|
||||
)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("configure tls: %w", err)
|
||||
}
|
||||
httpsListenerInner, err := net.Listen("tcp", cfg.TLS.Address.Value)
|
||||
httpsListenerInner, err := net.Listen("tcp", cfg.TLS.Address.String())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("listen %q: %w", cfg.TLS.Address.Value, err)
|
||||
return xerrors.Errorf("listen %q: %w", cfg.TLS.Address.String(), err)
|
||||
}
|
||||
defer httpsListenerInner.Close()
|
||||
|
||||
@@ -304,7 +488,7 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
// an ipv6 address (i.e. [::]:x). If the input ip is 0.0.0.0,
|
||||
// try to coerce the output back to ipv4 to make it less
|
||||
// confusing.
|
||||
if strings.Contains(cfg.HTTPAddress.Value, "0.0.0.0") {
|
||||
if strings.Contains(cfg.HTTPAddress.String(), "0.0.0.0") {
|
||||
listenAddrStr = strings.ReplaceAll(listenAddrStr, "[::]", "0.0.0.0")
|
||||
}
|
||||
|
||||
@@ -340,9 +524,9 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
|
||||
ctx, httpClient, err := configureHTTPClient(
|
||||
ctx,
|
||||
cfg.TLS.ClientCertFile.Value,
|
||||
cfg.TLS.ClientKeyFile.Value,
|
||||
cfg.TLS.ClientCAFile.Value,
|
||||
cfg.TLS.ClientCertFile.String(),
|
||||
cfg.TLS.ClientKeyFile.String(),
|
||||
cfg.TLS.ClientCAFile.String(),
|
||||
)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("configure http client: %w", err)
|
||||
@@ -357,53 +541,60 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
|
||||
// If the access URL is empty, we attempt to run a reverse-proxy
|
||||
// tunnel to make the initial setup really simple.
|
||||
if cfg.AccessURL.Value == "" {
|
||||
if cfg.AccessURL.String() == "" {
|
||||
cmd.Printf("Opening tunnel so workspaces can connect to your deployment. For production scenarios, specify an external access URL\n")
|
||||
tunnel, tunnelErr, err = devtunnel.New(ctxTunnel, logger.Named("devtunnel"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create tunnel: %w", err)
|
||||
}
|
||||
cfg.AccessURL.Value = tunnel.URL
|
||||
err = cfg.AccessURL.Set(tunnel.URL)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("set access url: %w", err)
|
||||
}
|
||||
|
||||
if cfg.WildcardAccessURL.Value == "" {
|
||||
if cfg.WildcardAccessURL.String() == "" {
|
||||
u, err := parseURL(tunnel.URL)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse tunnel url: %w", err)
|
||||
}
|
||||
|
||||
// Suffixed wildcard access URL.
|
||||
cfg.WildcardAccessURL.Value = fmt.Sprintf("*--%s", u.Hostname())
|
||||
u, err = url.Parse(fmt.Sprintf("*--%s", u.Hostname()))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse wildcard url: %w", err)
|
||||
}
|
||||
cfg.WildcardAccessURL = clibase.URL(*u)
|
||||
}
|
||||
}
|
||||
|
||||
accessURLParsed, err := parseURL(cfg.AccessURL.Value)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse URL: %w", err)
|
||||
}
|
||||
accessURLPortRaw := accessURLParsed.Port()
|
||||
_, accessURLPortRaw, _ := net.SplitHostPort(cfg.AccessURL.Host)
|
||||
if accessURLPortRaw == "" {
|
||||
accessURLPortRaw = "80"
|
||||
if accessURLParsed.Scheme == "https" {
|
||||
if cfg.AccessURL.Scheme == "https" {
|
||||
accessURLPortRaw = "443"
|
||||
}
|
||||
}
|
||||
|
||||
accessURLPort, err := strconv.Atoi(accessURLPortRaw)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse access URL port: %w", err)
|
||||
}
|
||||
|
||||
// Warn the user if the access URL appears to be a loopback address.
|
||||
isLocal, err := isLocalURL(ctx, accessURLParsed)
|
||||
isLocal, err := isLocalURL(ctx, cfg.AccessURL.Value())
|
||||
if isLocal || err != nil {
|
||||
reason := "could not be resolved"
|
||||
if isLocal {
|
||||
reason = "isn't externally reachable"
|
||||
}
|
||||
cmd.Printf("%s The access URL %s %s, this may cause unexpected problems when creating workspaces. Generate a unique *.try.coder.app URL by not specifying an access URL.\n", cliui.Styles.Warn.Render("Warning:"), cliui.Styles.Field.Render(accessURLParsed.String()), reason)
|
||||
cmd.Printf(
|
||||
"%s The access URL %s %s, this may cause unexpected problems when creating workspaces. Generate a unique *.try.coder.app URL by not specifying an access URL.\n",
|
||||
cliui.Styles.Warn.Render("Warning:"), cliui.Styles.Field.Render(cfg.AccessURL.String()), reason,
|
||||
)
|
||||
}
|
||||
|
||||
// A newline is added before for visibility in terminal output.
|
||||
cmd.Printf("\nView the Web UI: %s\n", accessURLParsed.String())
|
||||
cmd.Printf("\nView the Web UI: %s\n", cfg.AccessURL.String())
|
||||
|
||||
// Used for zero-trust instance identity with Google Cloud.
|
||||
googleTokenValidator, err := idtoken.NewValidator(ctx, option.WithoutAuthentication())
|
||||
@@ -411,34 +602,37 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
return err
|
||||
}
|
||||
|
||||
sshKeygenAlgorithm, err := gitsshkey.ParseAlgorithm(cfg.SSHKeygenAlgorithm.Value)
|
||||
sshKeygenAlgorithm, err := gitsshkey.ParseAlgorithm(cfg.SSHKeygenAlgorithm.String())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse ssh keygen algorithm %s: %w", cfg.SSHKeygenAlgorithm.Value, err)
|
||||
return xerrors.Errorf("parse ssh keygen algorithm %s: %w", cfg.SSHKeygenAlgorithm, err)
|
||||
}
|
||||
|
||||
defaultRegion := &tailcfg.DERPRegion{
|
||||
EmbeddedRelay: true,
|
||||
RegionID: cfg.DERP.Server.RegionID.Value,
|
||||
RegionCode: cfg.DERP.Server.RegionCode.Value,
|
||||
RegionName: cfg.DERP.Server.RegionName.Value,
|
||||
RegionID: int(cfg.DERP.Server.RegionID.Value()),
|
||||
RegionCode: cfg.DERP.Server.RegionCode.String(),
|
||||
RegionName: cfg.DERP.Server.RegionName.String(),
|
||||
Nodes: []*tailcfg.DERPNode{{
|
||||
Name: fmt.Sprintf("%db", cfg.DERP.Server.RegionID.Value),
|
||||
RegionID: cfg.DERP.Server.RegionID.Value,
|
||||
HostName: accessURLParsed.Hostname(),
|
||||
Name: fmt.Sprintf("%db", cfg.DERP.Server.RegionID),
|
||||
RegionID: int(cfg.DERP.Server.RegionID.Value()),
|
||||
HostName: cfg.AccessURL.Host,
|
||||
DERPPort: accessURLPort,
|
||||
STUNPort: -1,
|
||||
ForceHTTP: accessURLParsed.Scheme == "http",
|
||||
ForceHTTP: cfg.AccessURL.Scheme == "http",
|
||||
}},
|
||||
}
|
||||
if !cfg.DERP.Server.Enable.Value {
|
||||
if !cfg.DERP.Server.Enable {
|
||||
defaultRegion = nil
|
||||
}
|
||||
derpMap, err := tailnet.NewDERPMap(ctx, defaultRegion, cfg.DERP.Server.STUNAddresses.Value, cfg.DERP.Config.URL.Value, cfg.DERP.Config.Path.Value)
|
||||
derpMap, err := tailnet.NewDERPMap(
|
||||
ctx, defaultRegion, cfg.DERP.Server.STUNAddresses,
|
||||
cfg.DERP.Config.URL.String(), cfg.DERP.Config.Path.String(),
|
||||
)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create derp map: %w", err)
|
||||
}
|
||||
|
||||
appHostname := strings.TrimSpace(cfg.WildcardAccessURL.Value)
|
||||
appHostname := cfg.WildcardAccessURL.String()
|
||||
var appHostnameRegex *regexp.Regexp
|
||||
if appHostname != "" {
|
||||
appHostnameRegex, err = httpapi.CompileHostnamePattern(appHostname)
|
||||
@@ -447,18 +641,32 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
}
|
||||
}
|
||||
|
||||
gitAuthConfigs, err := gitauth.ConvertConfig(cfg.GitAuth.Value, accessURLParsed)
|
||||
gitAuthEnv, err := ReadGitAuthProvidersFromEnv(os.Environ())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse git auth config: %w", err)
|
||||
return xerrors.Errorf("read git auth providers from env: %w", err)
|
||||
}
|
||||
|
||||
realIPConfig, err := httpmw.ParseRealIPConfig(cfg.ProxyTrustedHeaders.Value, cfg.ProxyTrustedOrigins.Value)
|
||||
gitAuthConfigs, err := gitauth.ConvertConfig(
|
||||
append(cfg.GitAuthProviders.Value, gitAuthEnv...),
|
||||
cfg.AccessURL.Value(),
|
||||
)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("convert git auth config: %w", err)
|
||||
}
|
||||
for _, c := range gitAuthConfigs {
|
||||
logger.Debug(
|
||||
ctx, "loaded git auth config",
|
||||
slog.F("id", c.ID),
|
||||
)
|
||||
}
|
||||
|
||||
realIPConfig, err := httpmw.ParseRealIPConfig(cfg.ProxyTrustedHeaders, cfg.ProxyTrustedOrigins)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse real ip config: %w", err)
|
||||
}
|
||||
|
||||
options := &coderd.Options{
|
||||
AccessURL: accessURLParsed,
|
||||
AccessURL: cfg.AccessURL.Value(),
|
||||
AppHostname: appHostname,
|
||||
AppHostnameRegex: appHostnameRegex,
|
||||
Logger: logger.Named("coderd"),
|
||||
@@ -469,15 +677,15 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
GoogleTokenValidator: googleTokenValidator,
|
||||
GitAuthConfigs: gitAuthConfigs,
|
||||
RealIPConfig: realIPConfig,
|
||||
SecureAuthCookie: cfg.SecureAuthCookie.Value,
|
||||
SecureAuthCookie: cfg.SecureAuthCookie.Value(),
|
||||
SSHKeygenAlgorithm: sshKeygenAlgorithm,
|
||||
TracerProvider: tracerProvider,
|
||||
Telemetry: telemetry.NewNoop(),
|
||||
MetricsCacheRefreshInterval: cfg.MetricsCacheRefreshInterval.Value,
|
||||
AgentStatsRefreshInterval: cfg.AgentStatRefreshInterval.Value,
|
||||
DeploymentConfig: cfg,
|
||||
MetricsCacheRefreshInterval: cfg.MetricsCacheRefreshInterval.Value(),
|
||||
AgentStatsRefreshInterval: cfg.AgentStatRefreshInterval.Value(),
|
||||
DeploymentValues: cfg,
|
||||
PrometheusRegistry: prometheus.NewRegistry(),
|
||||
APIRateLimit: cfg.RateLimit.API.Value,
|
||||
APIRateLimit: int(cfg.RateLimit.API.Value()),
|
||||
LoginRateLimit: loginRateLimit,
|
||||
FilesRateLimit: filesRateLimit,
|
||||
HTTPClient: httpClient,
|
||||
@@ -486,14 +694,16 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
options.TLSCertificates = tlsConfig.Certificates
|
||||
}
|
||||
|
||||
if cfg.StrictTransportSecurity.Value > 0 {
|
||||
options.StrictTransportSecurityCfg, err = httpmw.HSTSConfigOptions(cfg.StrictTransportSecurity.Value, cfg.StrictTransportSecurityOptions.Value)
|
||||
if cfg.StrictTransportSecurity > 0 {
|
||||
options.StrictTransportSecurityCfg, err = httpmw.HSTSConfigOptions(
|
||||
int(cfg.StrictTransportSecurity.Value()), cfg.StrictTransportSecurityOptions,
|
||||
)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("coderd: setting hsts header failed (options: %v): %w", cfg.StrictTransportSecurityOptions.Value, err)
|
||||
return xerrors.Errorf("coderd: setting hsts header failed (options: %v): %w", cfg.StrictTransportSecurityOptions, err)
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.UpdateCheck.Value {
|
||||
if cfg.UpdateCheck {
|
||||
options.UpdateCheckOptions = &updatecheck.Options{
|
||||
// Avoid spamming GitHub API checking for updates.
|
||||
Interval: 24 * time.Hour,
|
||||
@@ -512,67 +722,69 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.OAuth2.Github.ClientSecret.Value != "" {
|
||||
options.GithubOAuth2Config, err = configureGithubOAuth2(accessURLParsed,
|
||||
cfg.OAuth2.Github.ClientID.Value,
|
||||
cfg.OAuth2.Github.ClientSecret.Value,
|
||||
cfg.OAuth2.Github.AllowSignups.Value,
|
||||
cfg.OAuth2.Github.AllowEveryone.Value,
|
||||
cfg.OAuth2.Github.AllowedOrgs.Value,
|
||||
cfg.OAuth2.Github.AllowedTeams.Value,
|
||||
cfg.OAuth2.Github.EnterpriseBaseURL.Value,
|
||||
if cfg.OAuth2.Github.ClientSecret != "" {
|
||||
options.GithubOAuth2Config, err = configureGithubOAuth2(cfg.AccessURL.Value(),
|
||||
cfg.OAuth2.Github.ClientID.String(),
|
||||
cfg.OAuth2.Github.ClientSecret.String(),
|
||||
cfg.OAuth2.Github.AllowSignups.Value(),
|
||||
cfg.OAuth2.Github.AllowEveryone.Value(),
|
||||
cfg.OAuth2.Github.AllowedOrgs,
|
||||
cfg.OAuth2.Github.AllowedTeams,
|
||||
cfg.OAuth2.Github.EnterpriseBaseURL.String(),
|
||||
)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("configure github oauth2: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.OIDC.ClientSecret.Value != "" {
|
||||
if cfg.OIDC.ClientID.Value == "" {
|
||||
if cfg.OIDC.ClientSecret != "" {
|
||||
if cfg.OIDC.ClientID == "" {
|
||||
return xerrors.Errorf("OIDC client ID be set!")
|
||||
}
|
||||
if cfg.OIDC.IssuerURL.Value == "" {
|
||||
if cfg.OIDC.IssuerURL == "" {
|
||||
return xerrors.Errorf("OIDC issuer URL must be set!")
|
||||
}
|
||||
|
||||
if cfg.OIDC.IgnoreEmailVerified.Value {
|
||||
if cfg.OIDC.IgnoreEmailVerified {
|
||||
logger.Warn(ctx, "coder will not check email_verified for OIDC logins")
|
||||
}
|
||||
|
||||
oidcProvider, err := oidc.NewProvider(ctx, cfg.OIDC.IssuerURL.Value)
|
||||
oidcProvider, err := oidc.NewProvider(
|
||||
ctx, cfg.OIDC.IssuerURL.String(),
|
||||
)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("configure oidc provider: %w", err)
|
||||
}
|
||||
redirectURL, err := accessURLParsed.Parse("/api/v2/users/oidc/callback")
|
||||
redirectURL, err := cfg.AccessURL.Value().Parse("/api/v2/users/oidc/callback")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse oidc oauth callback url: %w", err)
|
||||
}
|
||||
options.OIDCConfig = &coderd.OIDCConfig{
|
||||
OAuth2Config: &oauth2.Config{
|
||||
ClientID: cfg.OIDC.ClientID.Value,
|
||||
ClientSecret: cfg.OIDC.ClientSecret.Value,
|
||||
ClientID: cfg.OIDC.ClientID.String(),
|
||||
ClientSecret: cfg.OIDC.ClientSecret.String(),
|
||||
RedirectURL: redirectURL.String(),
|
||||
Endpoint: oidcProvider.Endpoint(),
|
||||
Scopes: cfg.OIDC.Scopes.Value,
|
||||
Scopes: cfg.OIDC.Scopes,
|
||||
},
|
||||
Provider: oidcProvider,
|
||||
Verifier: oidcProvider.Verifier(&oidc.Config{
|
||||
ClientID: cfg.OIDC.ClientID.Value,
|
||||
ClientID: cfg.OIDC.ClientID.String(),
|
||||
}),
|
||||
EmailDomain: cfg.OIDC.EmailDomain.Value,
|
||||
AllowSignups: cfg.OIDC.AllowSignups.Value,
|
||||
UsernameField: cfg.OIDC.UsernameField.Value,
|
||||
SignInText: cfg.OIDC.SignInText.Value,
|
||||
IconURL: cfg.OIDC.IconURL.Value,
|
||||
IgnoreEmailVerified: cfg.OIDC.IgnoreEmailVerified.Value,
|
||||
EmailDomain: cfg.OIDC.EmailDomain,
|
||||
AllowSignups: cfg.OIDC.AllowSignups.Value(),
|
||||
UsernameField: cfg.OIDC.UsernameField.String(),
|
||||
SignInText: cfg.OIDC.SignInText.String(),
|
||||
IconURL: cfg.OIDC.IconURL.String(),
|
||||
IgnoreEmailVerified: cfg.OIDC.IgnoreEmailVerified.Value(),
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.InMemoryDatabase.Value {
|
||||
if cfg.InMemoryDatabase {
|
||||
options.Database = dbfake.New()
|
||||
options.Pubsub = database.NewPubsubInMemory()
|
||||
} else {
|
||||
sqlDB, err := connectToPostgres(ctx, logger, sqlDriver, cfg.PostgresURL.Value)
|
||||
sqlDB, err := connectToPostgres(ctx, logger, sqlDriver, cfg.PostgresURL.String())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("connect to postgres: %w", err)
|
||||
}
|
||||
@@ -581,7 +793,7 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
}()
|
||||
|
||||
options.Database = database.New(sqlDB)
|
||||
options.Pubsub, err = database.NewPubsub(ctx, sqlDB, cfg.PostgresURL.Value)
|
||||
options.Pubsub, err = database.NewPubsub(ctx, sqlDB, cfg.PostgresURL.String())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create pubsub: %w", err)
|
||||
}
|
||||
@@ -646,21 +858,13 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
return err
|
||||
}
|
||||
|
||||
// Disable telemetry if the in-memory database is used unless explicitly defined!
|
||||
if cfg.InMemoryDatabase.Value && !cmd.Flags().Changed(cfg.Telemetry.Enable.Flag) {
|
||||
cfg.Telemetry.Enable.Value = false
|
||||
}
|
||||
if cfg.Telemetry.Enable.Value {
|
||||
// Parse the raw telemetry URL!
|
||||
telemetryURL, err := parseURL(cfg.Telemetry.URL.Value)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse telemetry url: %w", err)
|
||||
}
|
||||
|
||||
if cfg.Telemetry.Enable {
|
||||
gitAuth := make([]telemetry.GitAuth, 0)
|
||||
// TODO:
|
||||
var gitAuthConfigs []codersdk.GitAuthConfig
|
||||
for _, cfg := range gitAuthConfigs {
|
||||
gitAuth = append(gitAuth, telemetry.GitAuth{
|
||||
Type: string(cfg.Type),
|
||||
Type: cfg.Type,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -669,15 +873,15 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
DeploymentID: deploymentID,
|
||||
Database: options.Database,
|
||||
Logger: logger.Named("telemetry"),
|
||||
URL: telemetryURL,
|
||||
Wildcard: cfg.WildcardAccessURL.Value != "",
|
||||
DERPServerRelayURL: cfg.DERP.Server.RelayURL.Value,
|
||||
URL: cfg.Telemetry.URL.Value(),
|
||||
Wildcard: cfg.WildcardAccessURL.String() != "",
|
||||
DERPServerRelayURL: cfg.DERP.Server.RelayURL.String(),
|
||||
GitAuth: gitAuth,
|
||||
GitHubOAuth: cfg.OAuth2.Github.ClientID.Value != "",
|
||||
OIDCAuth: cfg.OIDC.ClientID.Value != "",
|
||||
OIDCIssuerURL: cfg.OIDC.IssuerURL.Value,
|
||||
Prometheus: cfg.Prometheus.Enable.Value,
|
||||
STUN: len(cfg.DERP.Server.STUNAddresses.Value) != 0,
|
||||
GitHubOAuth: cfg.OAuth2.Github.ClientID != "",
|
||||
OIDCAuth: cfg.OIDC.ClientID != "",
|
||||
OIDCIssuerURL: cfg.OIDC.IssuerURL.String(),
|
||||
Prometheus: cfg.Prometheus.Enable.Value(),
|
||||
STUN: len(cfg.DERP.Server.STUNAddresses) != 0,
|
||||
Tunnel: tunnel != nil,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -688,11 +892,11 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
|
||||
// This prevents the pprof import from being accidentally deleted.
|
||||
_ = pprof.Handler
|
||||
if cfg.Pprof.Enable.Value {
|
||||
if cfg.Pprof.Enable {
|
||||
//nolint:revive
|
||||
defer serveHandler(ctx, logger, nil, cfg.Pprof.Address.Value, "pprof")()
|
||||
defer serveHandler(ctx, logger, nil, cfg.Pprof.Address.String(), "pprof")()
|
||||
}
|
||||
if cfg.Prometheus.Enable.Value {
|
||||
if cfg.Prometheus.Enable {
|
||||
options.PrometheusRegistry.MustRegister(collectors.NewGoCollector())
|
||||
options.PrometheusRegistry.MustRegister(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}))
|
||||
|
||||
@@ -711,11 +915,11 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
//nolint:revive
|
||||
defer serveHandler(ctx, logger, promhttp.InstrumentMetricHandler(
|
||||
options.PrometheusRegistry, promhttp.HandlerFor(options.PrometheusRegistry, promhttp.HandlerOpts{}),
|
||||
), cfg.Prometheus.Address.Value, "prometheus")()
|
||||
), cfg.Prometheus.Address.String(), "prometheus")()
|
||||
}
|
||||
|
||||
if cfg.Swagger.Enable.Value {
|
||||
options.SwaggerEndpoint = cfg.Swagger.Enable.Value
|
||||
if cfg.Swagger.Enable {
|
||||
options.SwaggerEndpoint = cfg.Swagger.Enable.Value()
|
||||
}
|
||||
|
||||
// We use a separate coderAPICloser so the Enterprise API
|
||||
@@ -742,7 +946,10 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
// This is helpful for tests, but can be silently ignored.
|
||||
// Coder may be ran as users that don't have permission to write in the homedir,
|
||||
// such as via the systemd service.
|
||||
_ = config.URL().Write(client.URL.String())
|
||||
err = config.URL().Write(client.URL.String())
|
||||
if err != nil && flag.Lookup("test.v") != nil {
|
||||
return xerrors.Errorf("write config url: %w", err)
|
||||
}
|
||||
|
||||
// Since errCh only has one buffered slot, all routines
|
||||
// sending on it must be wrapped in a select/default to
|
||||
@@ -759,7 +966,7 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
}
|
||||
}()
|
||||
provisionerdMetrics := provisionerd.NewMetrics(options.PrometheusRegistry)
|
||||
for i := 0; i < cfg.Provisioner.Daemons.Value; i++ {
|
||||
for i := int64(0); i < cfg.Provisioner.Daemons.Value(); i++ {
|
||||
daemonCacheDir := filepath.Join(cacheDir, fmt.Sprintf("provisioner-%d", i))
|
||||
daemon, err := newProvisionerDaemon(ctx, coderAPI, provisionerdMetrics, logger, cfg, daemonCacheDir, errCh, false)
|
||||
if err != nil {
|
||||
@@ -774,8 +981,8 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
// Wrap the server in middleware that redirects to the access URL if
|
||||
// the request is not to a local IP.
|
||||
var handler http.Handler = coderAPI.RootHandler
|
||||
if cfg.RedirectToAccessURL.Value {
|
||||
handler = redirectToAccessURL(handler, accessURLParsed, tunnel != nil, appHostnameRegex)
|
||||
if cfg.RedirectToAccessURL {
|
||||
handler = redirectToAccessURL(handler, cfg.AccessURL.Value(), tunnel != nil, appHostnameRegex)
|
||||
}
|
||||
|
||||
// ReadHeaderTimeout is purposefully not enabled. It caused some
|
||||
@@ -842,7 +1049,7 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
cmd.Println("\nFailed to check for the first user: " + err.Error())
|
||||
} else if !hasFirstUser {
|
||||
cmd.Println("\nGet started by creating the first user (in a new terminal):")
|
||||
cmd.Println(cliui.Styles.Code.Render("coder login " + accessURLParsed.String()))
|
||||
cmd.Println(cliui.Styles.Code.Render("coder login " + cfg.AccessURL.String()))
|
||||
}
|
||||
|
||||
cmd.Println("\n==> Logs will stream in below (press ctrl+c to gracefully exit):")
|
||||
@@ -853,7 +1060,7 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
return xerrors.Errorf("notify systemd: %w", err)
|
||||
}
|
||||
|
||||
autobuildPoller := time.NewTicker(cfg.AutobuildPollInterval.Value)
|
||||
autobuildPoller := time.NewTicker(cfg.AutobuildPollInterval.Value())
|
||||
defer autobuildPoller.Stop()
|
||||
autobuildExecutor := executor.New(ctx, options.Database, logger, autobuildPoller.C)
|
||||
autobuildExecutor.Run()
|
||||
@@ -1011,10 +1218,11 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
||||
postgresBuiltinServeCmd.Flags().BoolVar(&pgRawURL, "raw-url", false, "Output the raw connection URL instead of a psql command.")
|
||||
|
||||
createAdminUserCommand := newCreateAdminUserCommand()
|
||||
root.SetHelpFunc(func(cmd *cobra.Command, args []string) {
|
||||
// Help is handled by clibase in command body.
|
||||
})
|
||||
root.AddCommand(postgresBuiltinURLCmd, postgresBuiltinServeCmd, createAdminUserCommand)
|
||||
|
||||
deployment.AttachFlags(root.Flags(), vip, false)
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
@@ -1063,7 +1271,7 @@ func newProvisionerDaemon(
|
||||
coderAPI *coderd.API,
|
||||
metrics provisionerd.Metrics,
|
||||
logger slog.Logger,
|
||||
cfg *codersdk.DeploymentConfig,
|
||||
cfg *codersdk.DeploymentValues,
|
||||
cacheDir string,
|
||||
errCh chan error,
|
||||
dev bool,
|
||||
@@ -1140,11 +1348,11 @@ func newProvisionerDaemon(
|
||||
return coderAPI.CreateInMemoryProvisionerDaemon(ctx, debounce)
|
||||
}, &provisionerd.Options{
|
||||
Logger: logger,
|
||||
JobPollInterval: cfg.Provisioner.DaemonPollInterval.Value,
|
||||
JobPollJitter: cfg.Provisioner.DaemonPollJitter.Value,
|
||||
JobPollInterval: cfg.Provisioner.DaemonPollInterval.Value(),
|
||||
JobPollJitter: cfg.Provisioner.DaemonPollJitter.Value(),
|
||||
JobPollDebounce: debounce,
|
||||
UpdateInterval: 500 * time.Millisecond,
|
||||
ForceCancelInterval: cfg.Provisioner.ForceCancelInterval.Value,
|
||||
ForceCancelInterval: cfg.Provisioner.ForceCancelInterval.Value(),
|
||||
Provisioners: provisioners,
|
||||
WorkDirectory: tempDir,
|
||||
TracerProvider: coderAPI.TracerProvider,
|
||||
@@ -1172,7 +1380,11 @@ func loadCertificates(tlsCertFiles, tlsKeyFiles []string) ([]tls.Certificate, er
|
||||
certFile, keyFile := tlsCertFiles[i], tlsKeyFiles[i]
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("load TLS key pair %d (%q, %q): %w", i, certFile, keyFile, err)
|
||||
return nil, xerrors.Errorf(
|
||||
"load TLS key pair %d (%q, %q): %w\ncertFiles: %+v\nkeyFiles: %+v",
|
||||
i, certFile, keyFile, err,
|
||||
tlsCertFiles, tlsKeyFiles,
|
||||
)
|
||||
}
|
||||
|
||||
certs[i] = cert
|
||||
@@ -1554,7 +1766,7 @@ func isLocalhost(host string) bool {
|
||||
return host == "localhost" || host == "127.0.0.1" || host == "::1"
|
||||
}
|
||||
|
||||
func buildLogger(cmd *cobra.Command, cfg *codersdk.DeploymentConfig) (slog.Logger, func(), error) {
|
||||
func buildLogger(cmd *cobra.Command, cfg *codersdk.DeploymentValues) (slog.Logger, func(), error) {
|
||||
var (
|
||||
sinks = []slog.Sink{}
|
||||
closers = []func() error{}
|
||||
@@ -1575,32 +1787,31 @@ func buildLogger(cmd *cobra.Command, cfg *codersdk.DeploymentConfig) (slog.Logge
|
||||
if err != nil {
|
||||
return xerrors.Errorf("open log file %q: %w", loc, err)
|
||||
}
|
||||
|
||||
closers = append(closers, fi.Close)
|
||||
sinks = append(sinks, sinkFn(fi))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
err := addSinkIfProvided(sloghuman.Sink, cfg.Logging.Human.Value)
|
||||
err := addSinkIfProvided(sloghuman.Sink, cfg.Logging.Human.String())
|
||||
if err != nil {
|
||||
return slog.Logger{}, nil, xerrors.Errorf("add human sink: %w", err)
|
||||
}
|
||||
err = addSinkIfProvided(slogjson.Sink, cfg.Logging.JSON.Value)
|
||||
err = addSinkIfProvided(slogjson.Sink, cfg.Logging.JSON.String())
|
||||
if err != nil {
|
||||
return slog.Logger{}, nil, xerrors.Errorf("add json sink: %w", err)
|
||||
}
|
||||
err = addSinkIfProvided(slogstackdriver.Sink, cfg.Logging.Stackdriver.Value)
|
||||
err = addSinkIfProvided(slogstackdriver.Sink, cfg.Logging.Stackdriver.String())
|
||||
if err != nil {
|
||||
return slog.Logger{}, nil, xerrors.Errorf("add stackdriver sink: %w", err)
|
||||
}
|
||||
|
||||
if cfg.Trace.CaptureLogs.Value {
|
||||
if cfg.Trace.CaptureLogs {
|
||||
sinks = append(sinks, tracing.SlogSink{})
|
||||
}
|
||||
|
||||
level := slog.LevelInfo
|
||||
if ok, _ := cmd.Flags().GetBool(varVerbose); ok {
|
||||
if cfg.Verbose {
|
||||
level = slog.LevelDebug
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user