Skip to content

Commit e086599

Browse files
author
Christian Weichel
committed
[supervisor] Add annotations to terminals
1 parent 2e2f001 commit e086599

File tree

6 files changed

+274
-134
lines changed

6 files changed

+274
-134
lines changed

components/supervisor-api/go/terminal.pb.go

Lines changed: 168 additions & 128 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/supervisor-api/terminal.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ service TerminalService {
4848
}
4949

5050
message OpenTerminalRequest {
51+
reserved 1;
5152
map<string, string> env = 2;
53+
map<string, string> annotations = 3;
5254
}
5355
message OpenTerminalResponse {
5456
string alias = 1;
@@ -70,6 +72,7 @@ message ListTerminalsResponse {
7072
repeated string command = 2;
7173
string title = 3;
7274
int64 pid = 4;
75+
map<string, string> annotations = 5;
7376
}
7477

7578
repeated Terminal terminals = 1;

components/supervisor/cmd/terminal-list.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"context"
99
"fmt"
1010
"os"
11+
"sort"
1112
"strings"
1213
"text/tabwriter"
1314
"time"
@@ -34,9 +35,14 @@ var terminalListCmd = &cobra.Command{
3435
tw := tabwriter.NewWriter(os.Stdout, 2, 4, 1, ' ', 0)
3536
defer tw.Flush()
3637

37-
fmt.Fprintf(tw, "ALIAS\tPID\tCOMMAND\n")
38+
fmt.Fprintf(tw, "ALIAS\tPID\tCOMMAND\tANNOTATIONS\n")
3839
for _, term := range resp.Terminals {
39-
fmt.Fprintf(tw, "%s\t%d\t%s\n", term.Alias, term.Pid, strings.Join(term.Command, " "))
40+
annotations := make([]string, 0, len(term.Annotations))
41+
for k, v := range term.Annotations {
42+
annotations = append(annotations, fmt.Sprintf("%s=%s", k, v))
43+
}
44+
sort.Slice(annotations, func(i, j int) bool { return annotations[i] < annotations[j] })
45+
fmt.Fprintf(tw, "%s\t%d\t%s\t%s\n", term.Alias, term.Pid, strings.Join(term.Command, " "), strings.Join(annotations, ","))
4046
}
4147
},
4248
}

components/supervisor/pkg/terminal/service.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,22 @@ func (srv *MuxTerminalService) RegisterREST(mux *runtime.ServeMux, grpcEndpoint
6565
func (srv *MuxTerminalService) Open(ctx context.Context, req *api.OpenTerminalRequest) (*api.OpenTerminalResponse, error) {
6666
return srv.OpenWithOptions(ctx, req, TermOptions{
6767
ReadTimeout: 5 * time.Second,
68+
Annotations: req.Annotations,
6869
})
6970
}
7071

71-
// OpenWithOptions opens a new terminal running the shell with given options
72+
// OpenWithOptions opens a new terminal running the shell with given options.
73+
// req.Annotations override options.Annotations.
7274
func (srv *MuxTerminalService) OpenWithOptions(ctx context.Context, req *api.OpenTerminalRequest, options TermOptions) (*api.OpenTerminalResponse, error) {
7375
cmd := exec.Command(srv.DefaultShell)
7476
cmd.Dir = srv.DefaultWorkdir
7577
cmd.Env = append(srv.Env, "TERM=xterm-color")
7678
for key, value := range req.Env {
7779
cmd.Env = append(cmd.Env, key+"="+value)
7880
}
81+
for k, v := range req.Annotations {
82+
options.Annotations[k] = v
83+
}
7984
alias, err := srv.Mux.Start(cmd, options)
8085
if err != nil {
8186
return nil, status.Error(codes.Internal, err.Error())
@@ -116,9 +121,10 @@ func (srv *MuxTerminalService) List(ctx context.Context, req *api.ListTerminalsR
116121
}
117122

118123
res = append(res, &api.ListTerminalsResponse_Terminal{
119-
Alias: alias,
120-
Command: term.Command.Args,
121-
Pid: pid,
124+
Alias: alias,
125+
Command: term.Command.Args,
126+
Pid: pid,
127+
Annotations: term.Annotations,
122128
})
123129
}
124130

components/supervisor/pkg/terminal/terminal.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ func newTerm(pty *os.File, cmd *exec.Cmd, options TermOptions) (*Term, error) {
192192
listener: make(map[*multiWriterListener]struct{}),
193193
recorder: recorder,
194194
},
195+
Annotations: options.Annotations,
195196

196197
StarterToken: token.String(),
197198

@@ -205,6 +206,9 @@ func newTerm(pty *os.File, cmd *exec.Cmd, options TermOptions) (*Term, error) {
205206
type TermOptions struct {
206207
// timeout after which a listener is dropped. Use 0 for no timeout.
207208
ReadTimeout time.Duration
209+
210+
// Annotations are user-defined metadata that's attached to a terminal
211+
Annotations map[string]string
208212
}
209213

210214
// Term is a pseudo-terminal
@@ -213,6 +217,7 @@ type Term struct {
213217
Command *exec.Cmd
214218
Title string
215219
StarterToken string
220+
Annotations map[string]string
216221

217222
Stdout *multiWriter
218223

components/supervisor/pkg/terminal/terminal_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,86 @@ import (
1818
"golang.org/x/sync/errgroup"
1919
)
2020

21+
func TestAnnotations(t *testing.T) {
22+
tests := []struct {
23+
Desc string
24+
Req *api.OpenTerminalRequest
25+
Opts *TermOptions
26+
Expectation map[string]string
27+
}{
28+
{
29+
Desc: "no annotations",
30+
Req: &api.OpenTerminalRequest{
31+
Annotations: map[string]string{},
32+
},
33+
Expectation: map[string]string{},
34+
},
35+
{
36+
Desc: "request annotation",
37+
Req: &api.OpenTerminalRequest{
38+
Annotations: map[string]string{
39+
"hello": "world",
40+
},
41+
},
42+
Expectation: map[string]string{
43+
"hello": "world",
44+
},
45+
},
46+
{
47+
Desc: "option annotation",
48+
Req: &api.OpenTerminalRequest{
49+
Annotations: map[string]string{
50+
"hello": "world",
51+
},
52+
},
53+
Opts: &TermOptions{
54+
Annotations: map[string]string{
55+
"hello": "foo",
56+
"bar": "baz",
57+
},
58+
},
59+
Expectation: map[string]string{
60+
"hello": "world",
61+
"bar": "baz",
62+
},
63+
},
64+
}
65+
66+
for _, test := range tests {
67+
t.Run(test.Desc, func(t *testing.T) {
68+
mux := NewMux()
69+
defer mux.Close()
70+
71+
terminalService := NewMuxTerminalService(mux)
72+
var err error
73+
if test.Opts == nil {
74+
_, err = terminalService.Open(context.Background(), test.Req)
75+
} else {
76+
_, err = terminalService.OpenWithOptions(context.Background(), test.Req, *test.Opts)
77+
}
78+
if err != nil {
79+
t.Fatal(err)
80+
return
81+
}
82+
83+
lr, err := terminalService.List(context.Background(), &api.ListTerminalsRequest{})
84+
if err != nil {
85+
t.Fatal(err)
86+
return
87+
}
88+
if len(lr.Terminals) != 1 {
89+
t.Fatalf("expected exactly one terminal, got %d", len(lr.Terminals))
90+
return
91+
}
92+
93+
if diff := cmp.Diff(test.Expectation, lr.Terminals[0].Annotations); diff != "" {
94+
t.Errorf("unexpected output (-want +got):\n%s", diff)
95+
}
96+
})
97+
98+
}
99+
}
100+
21101
func TestTerminals(t *testing.T) {
22102
tests := []struct {
23103
Desc string

0 commit comments

Comments
 (0)