Skip to content

Commit b06b65c

Browse files
Process stderr for containers with stdin
1 parent a58529b commit b06b65c

File tree

2 files changed

+94
-81
lines changed

2 files changed

+94
-81
lines changed

src/docker.clj

Lines changed: 29 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
[babashka.fs :as fs]
55
[cheshire.core :as json]
66
[clojure.core.async :as async]
7-
[clojure.pprint :refer [pprint]]
87
[clojure.string :as string]
98
[creds]
109
jsonrpc
@@ -184,7 +183,7 @@
184183
(defn attach-container-stdout-logs [{:keys [Id]}]
185184
;; this assumes no Tty so the output will be multiplexed back
186185
(curl/post
187-
(format "http://localhost/containers/%s/attach?stdout=true&logs=true" Id)
186+
(format "http://localhost/containers/%s/attach?stdout=true&stderr=true&logs=true" Id)
188187
{:raw-args ["--unix-socket" "/var/run/docker.sock"]
189188
:as :bytes
190189
:throw false}))
@@ -234,12 +233,6 @@
234233
(def pull (comp (status? 200 "pull-image") pull-image))
235234
(def images (comp ->json list-images))
236235

237-
(def sample {:image "docker/lsp:latest"
238-
:entrypoint "/app/result/bin/docker-lsp"
239-
:command ["project-facts"
240-
"--vs-machine-id" "none"
241-
"--workspace" "/docker"]})
242-
243236
(defn- -pull [m]
244237
(pull (merge m
245238
{:serveraddress "https://index.docker.io/v1/"}
@@ -300,18 +293,6 @@
300293
:exit-code (-> info :State :ExitCode)
301294
:info info})))}))
302295

303-
(comment
304-
(async/thread
305-
(run-streaming-function-with-no-stdin
306-
{:image "vonwig/inotifywait:latest"
307-
:volumes ["docker-prompts:/prompts"]
308-
:command ["-e" "create" "-e" "modify" "-e" "delete" "-q" "-m" "/prompts"]
309-
:opts {:Tty true
310-
:StdinOnce false
311-
:OpenStdin false
312-
:AttachStdin false}}
313-
println)))
314-
315296
(defn run-background-function
316297
"run container function with no stdin, and no streaming output"
317298
[m]
@@ -375,19 +356,28 @@
375356
client))
376357
client))
377358

359+
(defn get-block [x-bytes start]
360+
(let [[type _ _ _ n1 n2 n3 n4] (Arrays/copyOfRange ^bytes x-bytes start (+ start 8))]
361+
(let [size (.getInt (ByteBuffer/wrap (Arrays/copyOfRange ^bytes x-bytes (+ start 4) (+ start 8))))]
362+
[(case type 0 :stdin 1 :stdout 2 :stderr)
363+
size
364+
(String. (Arrays/copyOfRange ^bytes x-bytes (+ start 8) (+ start 8 size)))])))
365+
366+
(defn process-bytes [x-bytes]
367+
(loop [agg {:stdout "" :stderr "" :stdin ""} start 0]
368+
(if (> (- (count x-bytes) start) 8)
369+
(let [[type size s] (get-block x-bytes start)]
370+
(recur
371+
(update agg type str s)
372+
(+ start size 8)))
373+
agg)))
374+
378375
(defn docker-stream-format->stdout [bytes]
379-
;; use xxd to look at the bytes
380-
#_(try
381-
(with-open [w (java.io.BufferedOutputStream.
382-
(java.io.FileOutputStream. "hey.txt"))]
383-
(.write w bytes))
384-
385-
(catch Throwable t
386-
(println t)))
387376
(try
388-
(String. ^bytes (Arrays/copyOfRange ^bytes bytes 8 (count bytes)))
377+
(let [{:keys [stdout stderr]} (process-bytes bytes)]
378+
(str stdout stderr))
389379
(catch Throwable t
390-
(logger/error "not a docker stream: " t)
380+
(logger/error "processing docker engine attach bytes: " t)
391381
"")))
392382

393383
(defn function-call-with-stdin
@@ -440,7 +430,15 @@
440430
{}))))
441431

442432
(defn run-with-stdin-content
443-
"run container with stdin read from a file"
433+
"run container with stdin read from file or from string
434+
this is several engine calls
435+
- create container
436+
- start container
437+
- write-stdin which creates a socket, upgrades the connection, and writes the bytes
438+
- closes the socket
439+
- wait for container to exit or kill it if there's a timeout
440+
- attaches to the container and downloads the bytes for both the stdout and stderr
441+
- deletes the container"
444442
[m]
445443
(let [x (docker/function-call-with-stdin
446444
(assoc m :content (or (-> m :stdin :content) (slurp (-> m :stdin :file)))))]
@@ -461,28 +459,6 @@
461459
:else
462460
(run-function m)))
463461

464-
(comment
465-
(run-container
466-
{:image "vonwig/websocat:latest",
467-
:stdin
468-
{:content
469-
"Page.navigate {\"url\":\"https://www.docker.com\"}"},
470-
:command
471-
["-n1"
472-
"--jsonrpc"
473-
"--jsonrpc-omit-jsonrpc"
474-
"http://host.docker.internal:9222/devtools/page/EF1106D0B121836079CE1582C85F6E9A"],
475-
:jsonrpc true,
476-
:host-dir "/Users/slim/docker/labs-ai-tools-for-devs",
477-
:debug true,
478-
:stream true,
479-
:jwt "xxxxxxx",
480-
:save-thread-volume true,
481-
:register [],
482-
:thread-id "thread",
483-
:user "jimclark106",
484-
:platform "darwin"}))
485-
486462
(defn get-login-info-from-desktop-backend
487463
"returns token or nil if not logged in or backend.sock is not available"
488464
[]
@@ -495,31 +471,3 @@
495471
(catch Throwable _))))
496472
(catch Throwable _)))
497473

498-
(comment
499-
500-
(is-logged-in? {})
501-
(get-token {})
502-
(get-login-info {})
503-
(get-login-info-from-desktop-backend)
504-
(images {})
505-
506-
(pprint
507-
(json/parse-string
508-
(run-container
509-
(assoc sample
510-
:host-dir "/Users/slim/docker/genai-stack"
511-
:user "jimclark106")) keyword))
512-
(docker/delete-image {:image "vonwig/go-linguist:latest"})
513-
(pprint
514-
(run-container {:image "vonwig/go-linguist:latest"
515-
:timeout 100
516-
:command ["-json"]
517-
:host-dir "/Users/slim/docker/labs-make-runbook"
518-
:user "jimclark106"}))
519-
(pprint
520-
(json/parse-string
521-
(run-container
522-
{:image "vonwig/extractor-node:latest"
523-
:host-dir "/Users/slim/docker/labs-make-runbook"})
524-
keyword)))
525-

test/run_container_t.clj

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
(ns run-container-t
2+
(:require
3+
[cheshire.core :as json]
4+
[clojure.edn :as edn]
5+
[clojure.pprint :refer [pprint]]
6+
[clojure.string :as string]
7+
[clojure.test :as t]
8+
[docker]))
9+
10+
(t/deftest run-container-with-stdin-tests
11+
(t/is (=
12+
(-> (docker/run-container
13+
{:image "docker/lsp:treesitter"
14+
:stdin {:content "---\ntools:\n---\n\n# okay\n\n"}})
15+
:pty-output
16+
(edn/read-string)
17+
first)
18+
"document"))
19+
(t/is
20+
(string/starts-with?
21+
(-> (docker/run-container
22+
{:image "vonwig/websocat:latest",
23+
:stdin
24+
{:content
25+
"Page.navigate {\"url\":\"https://www.docker.com\"}"},
26+
:command
27+
["-n1"
28+
"--jsonrpc"
29+
"--jsonrpc-omit-jsonrpc"
30+
"http://host.docker.internal:9222/devtools/page/A27C1705A771414EB6647777F1625F6A"]})
31+
:pty-output)
32+
"Specify ws:")))
33+
34+
(comment
35+
36+
(docker/is-logged-in? {})
37+
(docker/get-token {})
38+
(docker/get-login-info {})
39+
(docker/get-login-info-from-desktop-backend)
40+
(docker/images {})
41+
42+
(def sample {:image "docker/lsp:latest"
43+
:entrypoint "/app/result/bin/docker-lsp"
44+
:command ["project-facts"
45+
"--vs-machine-id" "none"
46+
"--workspace" "/docker"]})
47+
(pprint
48+
(json/parse-string
49+
(docker/run-container
50+
(assoc sample
51+
:host-dir "/Users/slim/docker/genai-stack"
52+
:user "jimclark106")) keyword))
53+
(docker/delete-image {:image "vonwig/go-linguist:latest"})
54+
(pprint
55+
(docker/run-container {:image "vonwig/go-linguist:latest"
56+
:timeout 10000
57+
:command ["-json"]
58+
:host-dir "/Users/slim/docker/labs-make-runbook"
59+
:user "jimclark106"}))
60+
(pprint
61+
(json/parse-string
62+
(docker/run-container
63+
{:image "vonwig/extractor-node:latest"
64+
:host-dir "/Users/slim/docker/labs-make-runbook"})
65+
keyword)))

0 commit comments

Comments
 (0)