Skip to content

Commit d62df8a

Browse files
authored
Merge branch 'main' into patch-2
2 parents 3d10720 + 370f0b9 commit d62df8a

File tree

116 files changed

+4533
-871
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+4533
-871
lines changed

agent/agent.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1357,7 +1357,7 @@ func (a *agent) runCoordinator(ctx context.Context, conn drpc.Conn, network *tai
13571357
defer close(errCh)
13581358
select {
13591359
case <-ctx.Done():
1360-
err := coordination.Close()
1360+
err := coordination.Close(a.hardCtx)
13611361
if err != nil {
13621362
a.logger.Warn(ctx, "failed to close remote coordination", slog.Error(err))
13631363
}

agent/agent_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,7 +1896,9 @@ func TestAgent_UpdatedDERP(t *testing.T) {
18961896
coordinator, conn)
18971897
t.Cleanup(func() {
18981898
t.Logf("closing coordination %s", name)
1899-
err := coordination.Close()
1899+
cctx, ccancel := context.WithTimeout(testCtx, testutil.WaitShort)
1900+
defer ccancel()
1901+
err := coordination.Close(cctx)
19001902
if err != nil {
19011903
t.Logf("error closing in-memory coordination: %s", err.Error())
19021904
}
@@ -2384,7 +2386,9 @@ func setupAgent(t *testing.T, metadata agentsdk.Manifest, ptyTimeout time.Durati
23842386
clientID, metadata.AgentID,
23852387
coordinator, conn)
23862388
t.Cleanup(func() {
2387-
err := coordination.Close()
2389+
cctx, ccancel := context.WithTimeout(testCtx, testutil.WaitShort)
2390+
defer ccancel()
2391+
err := coordination.Close(cctx)
23882392
if err != nil {
23892393
t.Logf("error closing in-mem coordination: %s", err.Error())
23902394
}

cli/cliui/cliui.go

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,21 @@ var (
3737
)
3838

3939
var (
40-
Green = Color("#04B575")
41-
Red = Color("#ED567A")
42-
Fuchsia = Color("#EE6FF8")
43-
Yellow = Color("#ECFD65")
44-
Blue = Color("#5000ff")
40+
// ANSI color codes
41+
red = Color("1")
42+
green = Color("2")
43+
yellow = Color("3")
44+
magenta = Color("5")
45+
white = Color("7")
46+
brightBlue = Color("12")
47+
brightMagenta = Color("13")
4548
)
4649

4750
// Color returns a color for the given string.
4851
func Color(s string) termenv.Color {
4952
colorOnce.Do(func() {
50-
color = termenv.NewOutput(os.Stdout).ColorProfile()
53+
color = termenv.NewOutput(os.Stdout).EnvColorProfile()
54+
5155
if flag.Lookup("test.v") != nil {
5256
// Use a consistent colorless profile in tests so that results
5357
// are deterministic.
@@ -123,42 +127,45 @@ func init() {
123127
DefaultStyles = Styles{
124128
Code: pretty.Style{
125129
ifTerm(pretty.XPad(1, 1)),
126-
pretty.FgColor(Red),
127-
pretty.BgColor(color.Color("#2c2c2c")),
130+
pretty.FgColor(Color("#ED567A")),
131+
pretty.BgColor(Color("#2C2C2C")),
128132
},
129133
DateTimeStamp: pretty.Style{
130-
pretty.FgColor(color.Color("#7571F9")),
134+
pretty.FgColor(brightBlue),
131135
},
132136
Error: pretty.Style{
133-
pretty.FgColor(Red),
137+
pretty.FgColor(red),
134138
},
135139
Field: pretty.Style{
136140
pretty.XPad(1, 1),
137-
pretty.FgColor(color.Color("#FFFFFF")),
138-
pretty.BgColor(color.Color("#2b2a2a")),
141+
pretty.FgColor(Color("#FFFFFF")),
142+
pretty.BgColor(Color("#2B2A2A")),
143+
},
144+
Fuchsia: pretty.Style{
145+
pretty.FgColor(brightMagenta),
146+
},
147+
FocusedPrompt: pretty.Style{
148+
pretty.FgColor(white),
149+
pretty.Wrap("> ", ""),
150+
pretty.FgColor(brightBlue),
139151
},
140152
Keyword: pretty.Style{
141-
pretty.FgColor(Green),
153+
pretty.FgColor(green),
142154
},
143155
Placeholder: pretty.Style{
144-
pretty.FgColor(color.Color("#4d46b3")),
156+
pretty.FgColor(magenta),
145157
},
146158
Prompt: pretty.Style{
147-
pretty.FgColor(color.Color("#5C5C5C")),
148-
pretty.Wrap("> ", ""),
159+
pretty.FgColor(white),
160+
pretty.Wrap(" ", ""),
149161
},
150162
Warn: pretty.Style{
151-
pretty.FgColor(Yellow),
163+
pretty.FgColor(yellow),
152164
},
153165
Wrap: pretty.Style{
154166
pretty.LineWrap(80),
155167
},
156168
}
157-
158-
DefaultStyles.FocusedPrompt = append(
159-
DefaultStyles.Prompt,
160-
pretty.FgColor(Blue),
161-
)
162169
}
163170

164171
// ValidateNotEmpty is a helper function to disallow empty inputs!

cli/cliui/select.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ func (m selectModel) View() string {
256256
if m.cursor == start+i {
257257
style = pretty.Style{
258258
pretty.Wrap("> ", ""),
259-
pretty.FgColor(Green),
259+
DefaultStyles.Keyword,
260260
}
261261
}
262262

@@ -481,13 +481,13 @@ func (m multiSelectModel) View() string {
481481
o := option.option
482482

483483
if m.cursor == i {
484-
cursor = pretty.Sprint(pretty.FgColor(Green), "> ")
485-
chosen = pretty.Sprint(pretty.FgColor(Green), "[ ]")
486-
o = pretty.Sprint(pretty.FgColor(Green), o)
484+
cursor = pretty.Sprint(DefaultStyles.Keyword, "> ")
485+
chosen = pretty.Sprint(DefaultStyles.Keyword, "[ ]")
486+
o = pretty.Sprint(DefaultStyles.Keyword, o)
487487
}
488488

489489
if option.chosen {
490-
chosen = pretty.Sprint(pretty.FgColor(Green), "[x]")
490+
chosen = pretty.Sprint(DefaultStyles.Keyword, "[x]")
491491
}
492492

493493
_, _ = s.WriteString(fmt.Sprintf(

cli/server.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,6 @@ func createOIDCConfig(ctx context.Context, logger slog.Logger, vals *codersdk.De
187187
EmailField: vals.OIDC.EmailField.String(),
188188
AuthURLParams: vals.OIDC.AuthURLParams.Value,
189189
IgnoreUserInfo: vals.OIDC.IgnoreUserInfo.Value(),
190-
UserRoleField: vals.OIDC.UserRoleField.String(),
191-
UserRoleMapping: vals.OIDC.UserRoleMapping.Value,
192-
UserRolesDefault: vals.OIDC.UserRolesDefault.GetSlice(),
193190
SignInText: vals.OIDC.SignInText.String(),
194191
SignupsDisabledText: vals.OIDC.SignupsDisabledText.String(),
195192
IconURL: vals.OIDC.IconURL.String(),

cli/ssh.go

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
"github.com/coder/coder/v2/codersdk/workspacesdk"
3838
"github.com/coder/coder/v2/cryptorand"
3939
"github.com/coder/coder/v2/pty"
40+
"github.com/coder/quartz"
4041
"github.com/coder/retry"
4142
"github.com/coder/serpent"
4243
)
@@ -48,6 +49,8 @@ const (
4849
var (
4950
workspacePollInterval = time.Minute
5051
autostopNotifyCountdown = []time.Duration{30 * time.Minute}
52+
// gracefulShutdownTimeout is the timeout, per item in the stack of things to close
53+
gracefulShutdownTimeout = 2 * time.Second
5154
)
5255

5356
func (r *RootCmd) ssh() *serpent.Command {
@@ -153,7 +156,7 @@ func (r *RootCmd) ssh() *serpent.Command {
153156
// log HTTP requests
154157
client.SetLogger(logger)
155158
}
156-
stack := newCloserStack(ctx, logger)
159+
stack := newCloserStack(ctx, logger, quartz.NewReal())
157160
defer stack.close(nil)
158161

159162
for _, remoteForward := range remoteForwards {
@@ -936,11 +939,18 @@ type closerStack struct {
936939
closed bool
937940
logger slog.Logger
938941
err error
939-
wg sync.WaitGroup
942+
allDone chan struct{}
943+
944+
// for testing
945+
clock quartz.Clock
940946
}
941947

942-
func newCloserStack(ctx context.Context, logger slog.Logger) *closerStack {
943-
cs := &closerStack{logger: logger}
948+
func newCloserStack(ctx context.Context, logger slog.Logger, clock quartz.Clock) *closerStack {
949+
cs := &closerStack{
950+
logger: logger,
951+
allDone: make(chan struct{}),
952+
clock: clock,
953+
}
944954
go cs.closeAfterContext(ctx)
945955
return cs
946956
}
@@ -954,20 +964,58 @@ func (c *closerStack) close(err error) {
954964
c.Lock()
955965
if c.closed {
956966
c.Unlock()
957-
c.wg.Wait()
967+
<-c.allDone
958968
return
959969
}
960970
c.closed = true
961971
c.err = err
962-
c.wg.Add(1)
963-
defer c.wg.Done()
964972
c.Unlock()
973+
defer close(c.allDone)
974+
if len(c.closers) == 0 {
975+
return
976+
}
965977

966-
for i := len(c.closers) - 1; i >= 0; i-- {
967-
cwn := c.closers[i]
968-
cErr := cwn.closer.Close()
969-
c.logger.Debug(context.Background(),
970-
"closed item from stack", slog.F("name", cwn.name), slog.Error(cErr))
978+
// We are going to work down the stack in order. If things close quickly, we trigger the
979+
// closers serially, in order. `done` is a channel that indicates the nth closer is done
980+
// closing, and we should trigger the (n-1) closer. However, if things take too long we don't
981+
// want to wait, so we also start a ticker that works down the stack and sends on `done` as
982+
// well.
983+
next := len(c.closers) - 1
984+
// here we make the buffer 2x the number of closers because we could write once for it being
985+
// actually done and once via the countdown for each closer
986+
done := make(chan int, len(c.closers)*2)
987+
startNext := func() {
988+
go func(i int) {
989+
defer func() { done <- i }()
990+
cwn := c.closers[i]
991+
cErr := cwn.closer.Close()
992+
c.logger.Debug(context.Background(),
993+
"closed item from stack", slog.F("name", cwn.name), slog.Error(cErr))
994+
}(next)
995+
next--
996+
}
997+
done <- len(c.closers) // kick us off right away
998+
999+
// start a ticking countdown in case we hang/don't close quickly
1000+
countdown := len(c.closers) - 1
1001+
ctx, cancel := context.WithCancel(context.Background())
1002+
defer cancel()
1003+
c.clock.TickerFunc(ctx, gracefulShutdownTimeout, func() error {
1004+
if countdown < 0 {
1005+
return nil
1006+
}
1007+
done <- countdown
1008+
countdown--
1009+
return nil
1010+
}, "closerStack")
1011+
1012+
for n := range done { // the nth closer is done
1013+
if n == 0 {
1014+
return
1015+
}
1016+
if n-1 == next {
1017+
startNext()
1018+
}
9711019
}
9721020
}
9731021

0 commit comments

Comments
 (0)