mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
chore: Export all functions used by server cmd (#7118)
* chore: Export all functions used by server cmd Required to make workspace proxy cmd * Factor out httpservers and tracer
This commit is contained in:
+236
-186
@@ -169,8 +169,8 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
Short: "Start a Coder server",
|
||||
Options: opts,
|
||||
Middleware: clibase.Chain(
|
||||
writeConfigMW(cfg),
|
||||
printDeprecatedOptions(),
|
||||
WriteConfigMW(cfg),
|
||||
PrintDeprecatedOptions(),
|
||||
clibase.RequireNArgs(0),
|
||||
),
|
||||
Handler: func(inv *clibase.Invocation) error {
|
||||
@@ -183,7 +183,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
cliui.Warnf(inv.Stderr, "YAML support is experimental and offers no compatibility guarantees.")
|
||||
}
|
||||
|
||||
go dumpHandler(ctx)
|
||||
go DumpHandler(ctx)
|
||||
|
||||
// Validate bind addresses.
|
||||
if cfg.Address.String() != "" {
|
||||
@@ -218,8 +218,8 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
filesRateLimit = -1
|
||||
}
|
||||
|
||||
printLogo(inv)
|
||||
logger, logCloser, err := buildLogger(inv, cfg)
|
||||
PrintLogo(inv)
|
||||
logger, logCloser, err := BuildLogger(inv, cfg)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("make logger: %w", err)
|
||||
}
|
||||
@@ -255,44 +255,12 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
// which is caught by goleaks.
|
||||
defer http.DefaultClient.CloseIdleConnections()
|
||||
|
||||
var (
|
||||
tracerProvider trace.TracerProvider
|
||||
sqlDriver = "postgres"
|
||||
)
|
||||
|
||||
// Coder tracing should be disabled if telemetry is disabled unless
|
||||
// --telemetry-trace was explicitly provided.
|
||||
shouldCoderTrace := cfg.Telemetry.Enable.Value() && !isTest()
|
||||
// Only override if telemetryTraceEnable was specifically set.
|
||||
// By default we want it to be controlled by telemetryEnable.
|
||||
if inv.ParsedFlags().Changed("telemetry-trace") {
|
||||
shouldCoderTrace = cfg.Telemetry.Trace.Value()
|
||||
}
|
||||
|
||||
if cfg.Trace.Enable.Value() || shouldCoderTrace || cfg.Trace.HoneycombAPIKey != "" {
|
||||
sdkTracerProvider, closeTracing, err := tracing.TracerProvider(ctx, "coderd", tracing.TracerOpts{
|
||||
Default: cfg.Trace.Enable.Value(),
|
||||
Coder: shouldCoderTrace,
|
||||
Honeycomb: cfg.Trace.HoneycombAPIKey.String(),
|
||||
})
|
||||
if err != nil {
|
||||
logger.Warn(ctx, "start telemetry exporter", slog.Error(err))
|
||||
} else {
|
||||
// allow time for traces to flush even if command context is canceled
|
||||
defer func() {
|
||||
_ = shutdownWithTimeout(closeTracing, 5*time.Second)
|
||||
}()
|
||||
|
||||
d, err := tracing.PostgresDriver(sdkTracerProvider, "coderd.database")
|
||||
if err != nil {
|
||||
logger.Warn(ctx, "start postgres tracing driver", slog.Error(err))
|
||||
} else {
|
||||
sqlDriver = d
|
||||
}
|
||||
|
||||
tracerProvider = sdkTracerProvider
|
||||
}
|
||||
tracerProvider, sqlDriver := ConfigureTraceProvider(ctx, logger, inv, cfg)
|
||||
httpServers, err := ConfigureHTTPServers(inv, cfg)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("configure http(s): %w", err)
|
||||
}
|
||||
defer httpServers.Close()
|
||||
|
||||
config := r.createConfig()
|
||||
|
||||
@@ -322,121 +290,13 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
}()
|
||||
}
|
||||
|
||||
var (
|
||||
httpListener net.Listener
|
||||
httpURL *url.URL
|
||||
)
|
||||
if cfg.HTTPAddress.String() != "" {
|
||||
httpListener, err = net.Listen("tcp", cfg.HTTPAddress.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer httpListener.Close()
|
||||
|
||||
listenAddrStr := httpListener.Addr().String()
|
||||
// For some reason if 0.0.0.0:x is provided as the http address,
|
||||
// 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.String(), "0.0.0.0") {
|
||||
listenAddrStr = strings.ReplaceAll(listenAddrStr, "[::]", "0.0.0.0")
|
||||
}
|
||||
|
||||
// We want to print out the address the user supplied, not the
|
||||
// loopback device.
|
||||
_, _ = fmt.Fprintf(inv.Stdout, "Started HTTP listener at %s\n", (&url.URL{Scheme: "http", Host: listenAddrStr}).String())
|
||||
|
||||
// Set the http URL we want to use when connecting to ourselves.
|
||||
tcpAddr, tcpAddrValid := httpListener.Addr().(*net.TCPAddr)
|
||||
if !tcpAddrValid {
|
||||
return xerrors.Errorf("invalid TCP address type %T", httpListener.Addr())
|
||||
}
|
||||
if tcpAddr.IP.IsUnspecified() {
|
||||
tcpAddr.IP = net.IPv4(127, 0, 0, 1)
|
||||
}
|
||||
httpURL = &url.URL{
|
||||
Scheme: "http",
|
||||
Host: tcpAddr.String(),
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
tlsConfig *tls.Config
|
||||
httpsListener net.Listener
|
||||
httpsURL *url.URL
|
||||
)
|
||||
if cfg.TLS.Enable {
|
||||
if cfg.TLS.Address.String() == "" {
|
||||
return xerrors.New("tls address must be set if tls is enabled")
|
||||
}
|
||||
|
||||
// DEPRECATED: This redirect used to default to true.
|
||||
// It made more sense to have the redirect be opt-in.
|
||||
if inv.Environ.Get("CODER_TLS_REDIRECT_HTTP") == "true" || inv.ParsedFlags().Changed("tls-redirect-http-to-https") {
|
||||
cliui.Warn(inv.Stderr, "--tls-redirect-http-to-https is deprecated, please use --redirect-to-access-url instead")
|
||||
cfg.RedirectToAccessURL = cfg.TLS.RedirectHTTP
|
||||
}
|
||||
|
||||
tlsConfig, err = configureTLS(
|
||||
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.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer httpsListenerInner.Close()
|
||||
|
||||
httpsListener = tls.NewListener(httpsListenerInner, tlsConfig)
|
||||
defer httpsListener.Close()
|
||||
|
||||
listenAddrStr := httpsListener.Addr().String()
|
||||
// For some reason if 0.0.0.0:x is provided as the https
|
||||
// address, httpsListener.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.String(), "0.0.0.0") {
|
||||
listenAddrStr = strings.ReplaceAll(listenAddrStr, "[::]", "0.0.0.0")
|
||||
}
|
||||
|
||||
// We want to print out the address the user supplied, not the
|
||||
// loopback device.
|
||||
_, _ = fmt.Fprintf(inv.Stdout, "Started TLS/HTTPS listener at %s\n", (&url.URL{Scheme: "https", Host: listenAddrStr}).String())
|
||||
|
||||
// Set the https URL we want to use when connecting to
|
||||
// ourselves.
|
||||
tcpAddr, tcpAddrValid := httpsListener.Addr().(*net.TCPAddr)
|
||||
if !tcpAddrValid {
|
||||
return xerrors.Errorf("invalid TCP address type %T", httpsListener.Addr())
|
||||
}
|
||||
if tcpAddr.IP.IsUnspecified() {
|
||||
tcpAddr.IP = net.IPv4(127, 0, 0, 1)
|
||||
}
|
||||
httpsURL = &url.URL{
|
||||
Scheme: "https",
|
||||
Host: tcpAddr.String(),
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity check that at least one listener was started.
|
||||
if httpListener == nil && httpsListener == nil {
|
||||
return xerrors.New("must listen on at least one address")
|
||||
}
|
||||
|
||||
// Prefer HTTP because it's less prone to TLS errors over localhost.
|
||||
localURL := httpsURL
|
||||
if httpURL != nil {
|
||||
localURL = httpURL
|
||||
localURL := httpServers.TLSUrl
|
||||
if httpServers.HTTPUrl != nil {
|
||||
localURL = httpServers.HTTPUrl
|
||||
}
|
||||
|
||||
ctx, httpClient, err := configureHTTPClient(
|
||||
ctx, httpClient, err := ConfigureHTTPClient(
|
||||
ctx,
|
||||
cfg.TLS.ClientCertFile.String(),
|
||||
cfg.TLS.ClientKeyFile.String(),
|
||||
@@ -486,7 +346,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
}
|
||||
|
||||
// Warn the user if the access URL appears to be a loopback address.
|
||||
isLocal, err := isLocalURL(ctx, cfg.AccessURL.Value())
|
||||
isLocal, err := IsLocalURL(ctx, cfg.AccessURL.Value())
|
||||
if isLocal || err != nil {
|
||||
reason := "could not be resolved"
|
||||
if isLocal {
|
||||
@@ -607,8 +467,8 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
SSHConfigOptions: configSSHOptions,
|
||||
},
|
||||
}
|
||||
if tlsConfig != nil {
|
||||
options.TLSCertificates = tlsConfig.Certificates
|
||||
if httpServers.TLSConfig != nil {
|
||||
options.TLSCertificates = httpServers.TLSConfig.Certificates
|
||||
}
|
||||
|
||||
if cfg.StrictTransportSecurity > 0 {
|
||||
@@ -826,7 +686,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
_ = pprof.Handler
|
||||
if cfg.Pprof.Enable {
|
||||
//nolint:revive
|
||||
defer serveHandler(ctx, logger, nil, cfg.Pprof.Address.String(), "pprof")()
|
||||
defer ServeHandler(ctx, logger, nil, cfg.Pprof.Address.String(), "pprof")()
|
||||
}
|
||||
if cfg.Prometheus.Enable {
|
||||
options.PrometheusRegistry.MustRegister(collectors.NewGoCollector())
|
||||
@@ -845,7 +705,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
defer closeWorkspacesFunc()
|
||||
|
||||
//nolint:revive
|
||||
defer serveHandler(ctx, logger, promhttp.InstrumentMetricHandler(
|
||||
defer ServeHandler(ctx, logger, promhttp.InstrumentMetricHandler(
|
||||
options.PrometheusRegistry, promhttp.HandlerFor(options.PrometheusRegistry, promhttp.HandlerOpts{}),
|
||||
), cfg.Prometheus.Address.String(), "prometheus")()
|
||||
}
|
||||
@@ -872,7 +732,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
}
|
||||
|
||||
client := codersdk.New(localURL)
|
||||
if localURL.Scheme == "https" && isLocalhost(localURL.Hostname()) {
|
||||
if localURL.Scheme == "https" && IsLocalhost(localURL.Hostname()) {
|
||||
// The certificate will likely be self-signed or for a different
|
||||
// hostname, so we need to skip verification.
|
||||
client.HTTPClient.Transport = &http.Transport{
|
||||
@@ -956,30 +816,17 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
// We call this in the routine so we can kill the other listeners if
|
||||
// one of them fails.
|
||||
closeListenersNow := func() {
|
||||
if httpListener != nil {
|
||||
_ = httpListener.Close()
|
||||
}
|
||||
if httpsListener != nil {
|
||||
_ = httpsListener.Close()
|
||||
}
|
||||
httpServers.Close()
|
||||
if tunnel != nil {
|
||||
_ = tunnel.Listener.Close()
|
||||
}
|
||||
}
|
||||
|
||||
eg := errgroup.Group{}
|
||||
if httpListener != nil {
|
||||
eg.Go(func() error {
|
||||
defer closeListenersNow()
|
||||
return httpServer.Serve(httpListener)
|
||||
})
|
||||
}
|
||||
if httpsListener != nil {
|
||||
eg.Go(func() error {
|
||||
defer closeListenersNow()
|
||||
return httpServer.Serve(httpsListener)
|
||||
})
|
||||
}
|
||||
eg.Go(func() error {
|
||||
defer closeListenersNow()
|
||||
return httpServers.Serve(httpServer)
|
||||
})
|
||||
if tunnel != nil {
|
||||
eg.Go(func() error {
|
||||
defer closeListenersNow()
|
||||
@@ -1186,7 +1033,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
|
||||
// printDeprecatedOptions loops through all command options, and prints
|
||||
// a warning for usage of deprecated options.
|
||||
func printDeprecatedOptions() clibase.MiddlewareFunc {
|
||||
func PrintDeprecatedOptions() clibase.MiddlewareFunc {
|
||||
return func(next clibase.HandlerFunc) clibase.HandlerFunc {
|
||||
return func(inv *clibase.Invocation) error {
|
||||
opts := inv.Command.Options
|
||||
@@ -1222,7 +1069,7 @@ func printDeprecatedOptions() clibase.MiddlewareFunc {
|
||||
// writeConfigMW will prevent the main command from running if the write-config
|
||||
// flag is set. Instead, it will marshal the command options to YAML and write
|
||||
// them to stdout.
|
||||
func writeConfigMW(cfg *codersdk.DeploymentValues) clibase.MiddlewareFunc {
|
||||
func WriteConfigMW(cfg *codersdk.DeploymentValues) clibase.MiddlewareFunc {
|
||||
return func(next clibase.HandlerFunc) clibase.HandlerFunc {
|
||||
return func(inv *clibase.Invocation) error {
|
||||
if !cfg.WriteConfig {
|
||||
@@ -1251,7 +1098,7 @@ func writeConfigMW(cfg *codersdk.DeploymentValues) clibase.MiddlewareFunc {
|
||||
|
||||
// isLocalURL returns true if the hostname of the provided URL appears to
|
||||
// resolve to a loopback address.
|
||||
func isLocalURL(ctx context.Context, u *url.URL) (bool, error) {
|
||||
func IsLocalURL(ctx context.Context, u *url.URL) (bool, error) {
|
||||
resolver := &net.Resolver{}
|
||||
ips, err := resolver.LookupIPAddr(ctx, u.Hostname())
|
||||
if err != nil {
|
||||
@@ -1377,7 +1224,7 @@ func newProvisionerDaemon(
|
||||
}
|
||||
|
||||
// nolint: revive
|
||||
func printLogo(inv *clibase.Invocation) {
|
||||
func PrintLogo(inv *clibase.Invocation) {
|
||||
// Only print the logo in TTYs.
|
||||
if !isTTYOut(inv) {
|
||||
return
|
||||
@@ -1723,7 +1570,7 @@ func startBuiltinPostgres(ctx context.Context, cfg config.Root, logger slog.Logg
|
||||
return connectionURL, ep.Stop, nil
|
||||
}
|
||||
|
||||
func configureHTTPClient(ctx context.Context, clientCertFile, clientKeyFile string, tlsClientCAFile string) (context.Context, *http.Client, error) {
|
||||
func ConfigureHTTPClient(ctx context.Context, clientCertFile, clientKeyFile string, tlsClientCAFile string) (context.Context, *http.Client, error) {
|
||||
if clientCertFile != "" && clientKeyFile != "" {
|
||||
certificates, err := loadCertificates([]string{clientCertFile}, []string{clientKeyFile})
|
||||
if err != nil {
|
||||
@@ -1783,13 +1630,13 @@ func redirectToAccessURL(handler http.Handler, accessURL *url.URL, tunnel bool,
|
||||
})
|
||||
}
|
||||
|
||||
// isLocalhost returns true if the host points to the local machine. Intended to
|
||||
// IsLocalhost returns true if the host points to the local machine. Intended to
|
||||
// be called with `u.Hostname()`.
|
||||
func isLocalhost(host string) bool {
|
||||
func IsLocalhost(host string) bool {
|
||||
return host == "localhost" || host == "127.0.0.1" || host == "::1"
|
||||
}
|
||||
|
||||
func buildLogger(inv *clibase.Invocation, cfg *codersdk.DeploymentValues) (slog.Logger, func(), error) {
|
||||
func BuildLogger(inv *clibase.Invocation, cfg *codersdk.DeploymentValues) (slog.Logger, func(), error) {
|
||||
var (
|
||||
sinks = []slog.Sink{}
|
||||
closers = []func() error{}
|
||||
@@ -1916,3 +1763,206 @@ func connectToPostgres(ctx context.Context, logger slog.Logger, driver string, d
|
||||
ok = true
|
||||
return sqlDB, nil
|
||||
}
|
||||
|
||||
type HTTPServers struct {
|
||||
HTTPUrl *url.URL
|
||||
HTTPListener net.Listener
|
||||
|
||||
// TLS
|
||||
TLSUrl *url.URL
|
||||
TLSListener net.Listener
|
||||
TLSConfig *tls.Config
|
||||
}
|
||||
|
||||
// Serve acts just like http.Serve. It is a blocking call until the server
|
||||
// is closed, and an error is returned if any underlying Serve call fails.
|
||||
func (s *HTTPServers) Serve(srv *http.Server) error {
|
||||
eg := errgroup.Group{}
|
||||
if s.HTTPListener != nil {
|
||||
eg.Go(func() error {
|
||||
defer s.Close() // close all listeners on error
|
||||
return srv.Serve(s.HTTPListener)
|
||||
})
|
||||
}
|
||||
if s.TLSListener != nil {
|
||||
eg.Go(func() error {
|
||||
defer s.Close() // close all listeners on error
|
||||
return srv.Serve(s.TLSListener)
|
||||
})
|
||||
}
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
func (s *HTTPServers) Close() {
|
||||
if s.HTTPListener != nil {
|
||||
_ = s.HTTPListener.Close()
|
||||
}
|
||||
if s.TLSListener != nil {
|
||||
_ = s.TLSListener.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func ConfigureTraceProvider(ctx context.Context, logger slog.Logger, inv *clibase.Invocation, cfg *codersdk.DeploymentValues) (trace.TracerProvider, string) {
|
||||
var (
|
||||
tracerProvider trace.TracerProvider
|
||||
sqlDriver = "postgres"
|
||||
)
|
||||
// Coder tracing should be disabled if telemetry is disabled unless
|
||||
// --telemetry-trace was explicitly provided.
|
||||
shouldCoderTrace := cfg.Telemetry.Enable.Value() && !isTest()
|
||||
// Only override if telemetryTraceEnable was specifically set.
|
||||
// By default we want it to be controlled by telemetryEnable.
|
||||
if inv.ParsedFlags().Changed("telemetry-trace") {
|
||||
shouldCoderTrace = cfg.Telemetry.Trace.Value()
|
||||
}
|
||||
|
||||
if cfg.Trace.Enable.Value() || shouldCoderTrace || cfg.Trace.HoneycombAPIKey != "" {
|
||||
sdkTracerProvider, closeTracing, err := tracing.TracerProvider(ctx, "coderd", tracing.TracerOpts{
|
||||
Default: cfg.Trace.Enable.Value(),
|
||||
Coder: shouldCoderTrace,
|
||||
Honeycomb: cfg.Trace.HoneycombAPIKey.String(),
|
||||
})
|
||||
if err != nil {
|
||||
logger.Warn(ctx, "start telemetry exporter", slog.Error(err))
|
||||
} else {
|
||||
// allow time for traces to flush even if command context is canceled
|
||||
defer func() {
|
||||
_ = shutdownWithTimeout(closeTracing, 5*time.Second)
|
||||
}()
|
||||
|
||||
d, err := tracing.PostgresDriver(sdkTracerProvider, "coderd.database")
|
||||
if err != nil {
|
||||
logger.Warn(ctx, "start postgres tracing driver", slog.Error(err))
|
||||
} else {
|
||||
sqlDriver = d
|
||||
}
|
||||
|
||||
tracerProvider = sdkTracerProvider
|
||||
}
|
||||
}
|
||||
return tracerProvider, sqlDriver
|
||||
}
|
||||
|
||||
func ConfigureHTTPServers(inv *clibase.Invocation, cfg *codersdk.DeploymentValues) (_ *HTTPServers, err error) {
|
||||
httpServers := &HTTPServers{}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
// Always close the listeners if we fail.
|
||||
httpServers.Close()
|
||||
}
|
||||
}()
|
||||
// Validate bind addresses.
|
||||
if cfg.Address.String() != "" {
|
||||
if cfg.TLS.Enable {
|
||||
cfg.HTTPAddress = ""
|
||||
cfg.TLS.Address = cfg.Address
|
||||
} else {
|
||||
_ = cfg.HTTPAddress.Set(cfg.Address.String())
|
||||
cfg.TLS.Address.Host = ""
|
||||
cfg.TLS.Address.Port = ""
|
||||
}
|
||||
}
|
||||
if cfg.TLS.Enable && cfg.TLS.Address.String() == "" {
|
||||
return nil, xerrors.Errorf("TLS address must be set if TLS is enabled")
|
||||
}
|
||||
if !cfg.TLS.Enable && cfg.HTTPAddress.String() == "" {
|
||||
return nil, xerrors.Errorf("TLS is disabled. Enable with --tls-enable or specify a HTTP address")
|
||||
}
|
||||
|
||||
if cfg.AccessURL.String() != "" &&
|
||||
!(cfg.AccessURL.Scheme == "http" || cfg.AccessURL.Scheme == "https") {
|
||||
return nil, xerrors.Errorf("access-url must include a scheme (e.g. 'http://' or 'https://)")
|
||||
}
|
||||
|
||||
addrString := func(l net.Listener) string {
|
||||
listenAddrStr := l.Addr().String()
|
||||
// For some reason if 0.0.0.0:x is provided as the https
|
||||
// address, httpsListener.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.String(), "0.0.0.0") {
|
||||
listenAddrStr = strings.ReplaceAll(listenAddrStr, "[::]", "0.0.0.0")
|
||||
}
|
||||
return listenAddrStr
|
||||
}
|
||||
|
||||
if cfg.HTTPAddress.String() != "" {
|
||||
httpServers.HTTPListener, err = net.Listen("tcp", cfg.HTTPAddress.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We want to print out the address the user supplied, not the
|
||||
// loopback device.
|
||||
_, _ = fmt.Fprintf(inv.Stdout, "Started HTTP listener at %s\n", (&url.URL{Scheme: "http", Host: addrString(httpServers.HTTPListener)}).String())
|
||||
|
||||
// Set the http URL we want to use when connecting to ourselves.
|
||||
tcpAddr, tcpAddrValid := httpServers.HTTPListener.Addr().(*net.TCPAddr)
|
||||
if !tcpAddrValid {
|
||||
return nil, xerrors.Errorf("invalid TCP address type %T", httpServers.HTTPListener.Addr())
|
||||
}
|
||||
if tcpAddr.IP.IsUnspecified() {
|
||||
tcpAddr.IP = net.IPv4(127, 0, 0, 1)
|
||||
}
|
||||
httpServers.HTTPUrl = &url.URL{
|
||||
Scheme: "http",
|
||||
Host: tcpAddr.String(),
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.TLS.Enable {
|
||||
if cfg.TLS.Address.String() == "" {
|
||||
return nil, xerrors.New("tls address must be set if tls is enabled")
|
||||
}
|
||||
|
||||
// DEPRECATED: This redirect used to default to true.
|
||||
// It made more sense to have the redirect be opt-in.
|
||||
if inv.Environ.Get("CODER_TLS_REDIRECT_HTTP") == "true" || inv.ParsedFlags().Changed("tls-redirect-http-to-https") {
|
||||
cliui.Warn(inv.Stderr, "--tls-redirect-http-to-https is deprecated, please use --redirect-to-access-url instead")
|
||||
cfg.RedirectToAccessURL = cfg.TLS.RedirectHTTP
|
||||
}
|
||||
|
||||
tlsConfig, err := configureTLS(
|
||||
cfg.TLS.MinVersion.String(),
|
||||
cfg.TLS.ClientAuth.String(),
|
||||
cfg.TLS.CertFiles,
|
||||
cfg.TLS.KeyFiles,
|
||||
cfg.TLS.ClientCAFile.String(),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("configure tls: %w", err)
|
||||
}
|
||||
httpsListenerInner, err := net.Listen("tcp", cfg.TLS.Address.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpServers.TLSConfig = tlsConfig
|
||||
httpServers.TLSListener = tls.NewListener(httpsListenerInner, tlsConfig)
|
||||
|
||||
// We want to print out the address the user supplied, not the
|
||||
// loopback device.
|
||||
_, _ = fmt.Fprintf(inv.Stdout, "Started TLS/HTTPS listener at %s\n", (&url.URL{Scheme: "https", Host: addrString(httpServers.TLSListener)}).String())
|
||||
|
||||
// Set the https URL we want to use when connecting to
|
||||
// ourselves.
|
||||
tcpAddr, tcpAddrValid := httpServers.TLSListener.Addr().(*net.TCPAddr)
|
||||
if !tcpAddrValid {
|
||||
return nil, xerrors.Errorf("invalid TCP address type %T", httpServers.TLSListener.Addr())
|
||||
}
|
||||
if tcpAddr.IP.IsUnspecified() {
|
||||
tcpAddr.IP = net.IPv4(127, 0, 0, 1)
|
||||
}
|
||||
httpServers.TLSUrl = &url.URL{
|
||||
Scheme: "https",
|
||||
Host: tcpAddr.String(),
|
||||
}
|
||||
}
|
||||
|
||||
if httpServers.HTTPListener == nil && httpServers.TLSListener == nil {
|
||||
return nil, xerrors.New("must listen on at least one address")
|
||||
}
|
||||
|
||||
return httpServers, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user