Skip to content

chore: improve coder server ux #14761

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cli/cliui/cliui.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Styles struct {
DateTimeStamp,
Error,
Field,
Hyperlink,
Keyword,
Placeholder,
Prompt,
Expand Down Expand Up @@ -149,6 +150,10 @@ func init() {
pretty.Wrap("> ", ""),
pretty.FgColor(brightBlue),
},
Hyperlink: pretty.Style{
pretty.FgColor(magenta),
pretty.Underline(),
},
Keyword: pretty.Style{
pretty.FgColor(green),
},
Expand Down
3 changes: 3 additions & 0 deletions cli/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,9 @@ func isWSL() (bool, error) {

// openURL opens the provided URL via user's default browser
func openURL(inv *serpent.Invocation, urlToOpen string) error {
if !isTTYOut(inv) {
return xerrors.New("skipping browser open in non-interactive mode")
}
noOpen, err := inv.ParsedFlags().GetBool(varNoOpen)
if err != nil {
panic(err)
Expand Down
9 changes: 1 addition & 8 deletions cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -695,14 +695,7 @@ func namedWorkspace(ctx context.Context, client *codersdk.Client, identifier str
func initAppearance(client *codersdk.Client, outConfig *codersdk.AppearanceConfig) serpent.MiddlewareFunc {
return func(next serpent.HandlerFunc) serpent.HandlerFunc {
return func(inv *serpent.Invocation) error {
var err error
cfg, err := client.Appearance(inv.Context())
if err != nil {
var sdkErr *codersdk.Error
if !(xerrors.As(err, &sdkErr) && sdkErr.StatusCode() == http.StatusNotFound) {
return err
}
}
cfg, _ := client.Appearance(inv.Context())
if cfg.DocsURL == "" {
cfg.DocsURL = codersdk.DefaultDocsURL()
}
Expand Down
17 changes: 13 additions & 4 deletions cli/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"sync/atomic"
"time"

"github.com/charmbracelet/lipgloss"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/coreos/go-systemd/daemon"
embeddedpostgres "github.com/fergusstrange/embedded-postgres"
Expand Down Expand Up @@ -483,8 +484,15 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
)
}

// A newline is added before for visibility in terminal output.
cliui.Infof(inv.Stdout, "\nView the Web UI: %s", vals.AccessURL.String())
accessURL := vals.AccessURL.String()
cliui.Infof(inv.Stdout, lipgloss.NewStyle().
Border(lipgloss.DoubleBorder()).
Align(lipgloss.Center).
Padding(0, 3).
BorderForeground(lipgloss.Color("12")).
Render(fmt.Sprintf("View the Web UI:\n%s",
pretty.Sprint(cliui.DefaultStyles.Hyperlink, accessURL))))
_ = openURL(inv, accessURL)

// Used for zero-trust instance identity with Google Cloud.
googleTokenValidator, err := idtoken.NewValidator(ctx, option.WithoutAuthentication())
Expand Down Expand Up @@ -1438,6 +1446,7 @@ func newProvisionerDaemon(

// Omit any duplicates
provisionerTypes = slice.Unique(provisionerTypes)
provisionerLogger := logger.Named(fmt.Sprintf("provisionerd-%s", name))

// Populate the connector with the supported types.
connector := provisionerd.LocalProvisioners{}
Expand Down Expand Up @@ -1494,7 +1503,7 @@ func newProvisionerDaemon(
err := terraform.Serve(ctx, &terraform.ServeOptions{
ServeOptions: &provisionersdk.ServeOptions{
Listener: terraformServer,
Logger: logger.Named("terraform"),
Logger: provisionerLogger,
WorkDirectory: workDir,
},
CachePath: tfDir,
Expand All @@ -1519,7 +1528,7 @@ func newProvisionerDaemon(
// in provisionerdserver.go to learn more!
return coderAPI.CreateInMemoryProvisionerDaemon(dialCtx, name, provisionerTypes)
}, &provisionerd.Options{
Logger: logger.Named(fmt.Sprintf("provisionerd-%s", name)),
Logger: provisionerLogger,
UpdateInterval: time.Second,
ForceCancelInterval: cfg.Provisioner.ForceCancelInterval.Value(),
Connector: connector,
Expand Down
9 changes: 6 additions & 3 deletions cli/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,8 @@ func TestServer(t *testing.T) {
_ = waitAccessURL(t, cfg)

pty.ExpectMatch("this may cause unexpected problems when creating workspaces")
pty.ExpectMatch("View the Web UI: http://localhost:3000/")
pty.ExpectMatch("View the Web UI:")
pty.ExpectMatch("http://localhost:3000/")
})

// Validate that an https scheme is prepended to a remote access URL
Expand All @@ -244,7 +245,8 @@ func TestServer(t *testing.T) {
_ = waitAccessURL(t, cfg)

pty.ExpectMatch("this may cause unexpected problems when creating workspaces")
pty.ExpectMatch("View the Web UI: https://foobarbaz.mydomain")
pty.ExpectMatch("View the Web UI:")
pty.ExpectMatch("https://foobarbaz.mydomain")
})

t.Run("NoWarningWithRemoteAccessURL", func(t *testing.T) {
Expand All @@ -262,7 +264,8 @@ func TestServer(t *testing.T) {
// Just wait for startup
_ = waitAccessURL(t, cfg)

pty.ExpectMatch("View the Web UI: https://google.com")
pty.ExpectMatch("View the Web UI:")
pty.ExpectMatch("https://google.com")
})

t.Run("NoSchemeAccessURL", func(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion coderd/coderd.go
Original file line number Diff line number Diff line change
Expand Up @@ -1505,7 +1505,7 @@ func (api *API) CreateInMemoryTaggedProvisionerDaemon(dialCtx context.Context, n
}

mux := drpcmux.New()
api.Logger.Info(dialCtx, "starting in-memory provisioner daemon", slog.F("name", name))
api.Logger.Debug(dialCtx, "starting in-memory provisioner daemon", slog.F("name", name))
logger := api.Logger.Named(fmt.Sprintf("inmem-provisionerd-%s", name))
srv, err := provisionerdserver.NewServer(
api.ctx, // use the same ctx as the API
Expand Down
8 changes: 4 additions & 4 deletions coderd/database/pubsub/pubsub.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,15 +413,15 @@ func (d logDialer) DialContext(ctx context.Context, network, address string) (ne

logger := d.logger.With(slog.F("network", network), slog.F("address", address), slog.F("timeout_ms", timeoutMS))

logger.Info(ctx, "pubsub dialing postgres")
logger.Debug(ctx, "pubsub dialing postgres")
start := time.Now()
conn, err := d.d.DialContext(ctx, network, address)
if err != nil {
logger.Error(ctx, "pubsub failed to dial postgres")
return nil, err
}
elapsed := time.Since(start)
logger.Info(ctx, "pubsub postgres TCP connection established", slog.F("elapsed_ms", elapsed.Milliseconds()))
logger.Debug(ctx, "pubsub postgres TCP connection established", slog.F("elapsed_ms", elapsed.Milliseconds()))
return conn, nil
}

Expand Down Expand Up @@ -466,7 +466,7 @@ func (p *PGPubsub) startListener(ctx context.Context, connectURL string) error {
Listener: pq.NewConnectorListener(connector, connectURL, time.Second, time.Minute, func(t pq.ListenerEventType, err error) {
switch t {
case pq.ListenerEventConnected:
p.logger.Info(ctx, "pubsub connected to postgres")
p.logger.Debug(ctx, "pubsub connected to postgres")
p.connected.Set(1.0)
case pq.ListenerEventDisconnected:
p.logger.Error(ctx, "pubsub disconnected from postgres", slog.Error(err))
Expand Down Expand Up @@ -618,7 +618,7 @@ func New(startCtx context.Context, logger slog.Logger, db *sql.DB, connectURL st
return nil, err
}
go p.listen()
logger.Info(startCtx, "pubsub has started")
logger.Debug(startCtx, "pubsub has started")
return p, nil
}

Expand Down
12 changes: 10 additions & 2 deletions enterprise/cli/proxyserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
rpprof "runtime/pprof"
"time"

"github.com/charmbracelet/lipgloss"
"github.com/coreos/go-systemd/daemon"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
Expand All @@ -29,6 +30,7 @@ import (
"github.com/coder/coder/v2/coderd/workspaceapps/appurl"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/enterprise/wsproxy"
"github.com/coder/pretty"
"github.com/coder/serpent"
)

Expand Down Expand Up @@ -202,8 +204,14 @@ func (r *RootCmd) proxyServer() *serpent.Command {
headerTransport.Transport = httpClient.Transport
httpClient.Transport = headerTransport

// A newline is added before for visibility in terminal output.
cliui.Infof(inv.Stdout, "\nView the Web UI: %s", cfg.AccessURL.String())
accessURL := cfg.AccessURL.String()
cliui.Infof(inv.Stdout, lipgloss.NewStyle().
Border(lipgloss.DoubleBorder()).
Align(lipgloss.Center).
Padding(0, 3).
BorderForeground(lipgloss.Color("12")).
Render(fmt.Sprintf("View the Web UI:\n%s",
pretty.Sprint(cliui.DefaultStyles.Hyperlink, accessURL))))

var appHostnameRegex *regexp.Regexp
appHostname := cfg.WildcardAccessURL.String()
Expand Down
6 changes: 3 additions & 3 deletions tailnet/configmaps.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,22 +147,22 @@ func (c *configMaps) configLoop() {
if c.derpMapDirty {
derpMap := c.derpMapLocked()
actions = append(actions, func() {
c.logger.Info(context.Background(), "updating engine DERP map", slog.F("derp_map", (*derpMapStringer)(derpMap)))
c.logger.Debug(context.Background(), "updating engine DERP map", slog.F("derp_map", (*derpMapStringer)(derpMap)))
c.engine.SetDERPMap(derpMap)
})
}
if c.netmapDirty {
nm := c.netMapLocked()
actions = append(actions, func() {
c.logger.Info(context.Background(), "updating engine network map", slog.F("network_map", nm))
c.logger.Debug(context.Background(), "updating engine network map", slog.F("network_map", nm))
c.engine.SetNetworkMap(nm)
c.reconfig(nm)
})
}
if c.filterDirty {
f := c.filterLocked()
actions = append(actions, func() {
c.logger.Info(context.Background(), "updating engine filter", slog.F("filter", f))
c.logger.Debug(context.Background(), "updating engine filter", slog.F("filter", f))
c.engine.SetFilter(f)
})
}
Expand Down
Loading