-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdemon.slide
296 lines (184 loc) · 7.81 KB
/
demon.slide
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
Demon
A tool for running demos
18:00 16 May 2018
Tags: golang, demo, websocket, http
Michael Lore
Principal Architect, SAP Concur
@ancientlore
* About Me
- Central Architecture Team at SAP Concur
- Designed the booking engine powering Concur Travel
- Playing with Go since 2010 (see [[https://github.com/ancientlore/go-avltree][go-avltree]])
- Interested in concurrent applications in the travel space
- ...which explains my interest in Go
.image media/gopher.png
[[https://twitter.com/ancientlore][@ancientlore]]
.link https://github.com/ancientlore/demon
.background media/plane_bg.png
: Hello.
* The Idea
.background media/plane_bg.png
* The problem with demos
.image media/demo_pain.png 530 _
.background media/plane_bg.png
: Switching windows.
: Copy/paste commands, to the right window.
: Typos, missing steps...
: More stress while giving demo.
: Also more confusing for the audience trying to follow the steps.
* A solution
.image media/demo_solved_notes.png 550 _
.background media/plane_bg.png
: Show web pages in iframes.
: Websocket access to external processes like bash or kubectl exec.
: Demo script with commmands included.
: Demo script knows where to send commands!
: Less stress! Easier to follow!
* Can it be mostly done in two days?
- JSON config file - very easy in Go
- Go's `os/exec` package can be used to launch processes
- Using [[https://github.com/gorilla/websocket][github.com/gorilla/websocket]] for websockets, we can send commands to processes and receive the output
- Use Go's templates to render the HTML site
- Find/steal some decent CSS
- Write some simple JavaScript - less fun than Go, but unavoidable
.caption Let's go for it!
.background media/plane_bg.png
: Go provides a lot of what we need to do this quickly.
: External packages provide the rest.
* Try out the os/exec package
.background media/plane_bg.png
* Simple command execution
.play examples/output/output.go
.background media/plane_bg.png
: os package can be used to execute processes and connect pipes.
: os/exec was designed to make process execution easier.
: One-liner gets the result of executing bash.
* Combining stdout and stderr
.play examples/combinedOutput/combinedOutput.go
.background media/plane_bg.png
: Using CombinedOutput we can capture stdout and stderr in the same stream.
: os/exec makes sure writes are synchronized.
* Using a Command with stdin/stdout
.play examples/command/command.go
.background media/plane_bg.png
: For our project, we need to deal with streams, so let's try out streams.
: You can assign cmd.Stdin, cmd.Stdout, and cmd.Stderr.
: If they are actual os files, they are passed over as such.
: Otherwise, a pipe is automatically created, including a goroutine to read or write.
: cmd.Run() executes the command using the streams assigned.
* Running a Command in the background
.play examples/background/background.go
.background media/plane_bg.png
: We need to be able to run the command in the background, not all at once.
: For this, we use cmd.Start.
: Once the I/O is done (in this example there isn't any), we call cmd.Wait.
* Using pipes
.play examples/pipe/pipe.go /func main/,/^}/
.background media/plane_bg.png
: You can create a pipe directly and write to it like any stream.
: The pipe is closed when the command exits.
: Note that some commands require the input to be closed before they will exit.
* Orchestrate bash - setup Command
.code -numbers examples/bbash/bbash.go /func main/,/launch/
.background media/plane_bg.png
: Create command and create pipes to use.
: Make Stderr and Stdout the same writer!
: Note: If Stdout and Stderr are the same writer, and have a type that can be compared with ==, at most one goroutine at a time will call Write.
* Orchestrate bash - I/O and Wait
.play -numbers examples/bbash/bbash.go /launch/,/^}/
.background media/plane_bg.png
: Write commands, closing the input when done.
: Read the output.
: Then (and only then) call cmd.Wait.
: You must do all your reads before calling cmd.Wait.
* Coding the utility
.background media/plane_bg.png
* Config File - sites and processes
.code demo.json /^\{/,/^\s*"steps"/
.background media/plane_bg.png
: Sites are URLs to load into an iframe.
: Processes are external programs to run (like a bash shell).
: Each has a key name in the map that can be used later.
: The position specifies the order the windows are loaded.
* Config File - steps
.code demo.json /^\s*"steps"/,/"Get some XML"/
.background media/plane_bg.png
: Steps are basically your demo script.
: Each step can optionally include an input command to send to one of the processes.
: The id specifies which process to send the command to.
* Loading the Config File
.code config.go /^\s*type config/,/c\.Validate/
.background media/plane_bg.png
: JSON tags provide hints to the JSON marshaler.
: The configuration is read from a file and the config type is unmarshaled from JSON.
: Validation checks that the configuration is consistent.
* The process type
.code config.go /^\s*type process/,/^\}/
- Start() error
- Wait() error
- Write(b []byte) (int, error) // io.Writer
- Read(b []byte) (n int, err error) // io.Reader
See [[https://golang.org/pkg/os/exec/][golang.org/pkg/os/exec]]
.background media/plane_bg.png
: The process type doesn't know about websockets.
: Was written during testing before websockets were added.
: It allows you to start and stop the process.
: Use Write (implementing io.Writer) to write to stdin.
: Use Read (implementing io.Reader) to read the combined stdout/stderr.
* Starting a process
.code process.go /exec.Command/,/cmd.Start/
.background media/plane_bg.png
: Create the command.
: Assign the directory to run the command in.
: Create input and output pipes. (Could perhaps be done just assigning Stdin and Stdout.)
: Make stderr use the same output pipe.
: Start the command.
* Ending a process
.code process.go /p.stdin != nil/,/return nil/
.background media/plane_bg.png
: Close the input, optionally sending an exit command. This is typically used to get the shell to stop.
: Wait on the wait group - this waits for the reader to exit on EOF.
: Want on the command to finish.
* Websockets - Upgrading the connection
.code socket.go /ServeHTTP/,/p\.Wait/
.background media/plane_bg.png
: Websocket code borrowed largely from https://github.com/gorilla/websocket/tree/master/examples/command.
: Connection must be upgraded to a websocket.
: Start the process.
* Processing the websocket
.code socket.go /stdoutDone/,/^\}/
.background media/plane_bg.png
: Use goroutines to process output and input from websockets.
: Websocket is closed during graceful server shutdown.
* Client-side websocket
.code home.go /window\["WebSocket"\]/,/\} else \{/
.background media/plane_bg.png
: Messages received are added to the DOM.
* Client-side websocket - writes
.code home.go /submitters\[k\] = function/,/\};/
.background media/plane_bg.png
: Messages received are added to the DOM.
* Serving the templates
.code home.go /<body>/,/\{\{end\}\}/
The handler:
.code home.go /var tpl/,/^\}/
.background media/plane_bg.png
: Using html/template.
: THere is an outer loop that allows the elements to show up where sorted.
: The loop is a little confusing (too clever) but works nicely.
* Finishing up
.background media/plane_bg.png
* Demo
.iframe http://localhost:8080 600 1000
.background media/plane_bg.png
: Don't forget to start the program...
* Thoughts
- Pretty easy to "scratch your own itch" using Go.
- gorilla/websocket handles SIGINT, I'd rather be able to control it.
- os/exec: having both `.Stdin` and `.StdinPipe()` is a bit confusing.
- There is a bit of mismatch between `os/exec` and `gorilla/websocket`, but their examples are good.
- CSS is messy; beg, borrow, or steal if you need to move quickly.
- You can do a lot with JavaScript even without a fancy framework.
- Might not work in every browser.
.background media/plane_bg.png
: Finish.