@@ -23,6 +23,7 @@ import (
2323 "io"
2424 "log"
2525 "os"
26+ "path/filepath"
2627 "strings"
2728 "time"
2829
@@ -49,8 +50,13 @@ func main() {
4950 vol := flag .String ("vol" , "" , "Share volume into container, example: /home/:/home_shared" )
5051 image := flag .String ("image" , "" , "Force image to be executed" )
5152 cmd := flag .String ("cmd" , "" , "Execute cmd after login, example: ls" )
53+ exportFolder := flag .String ("export" , "" , "Before removing, export container contents to specified directory, example: /tmp/" )
5254 flag .Parse ()
5355
56+ if * exportFolder != "" {
57+ * exportFolder = filepath .Clean (* exportFolder )
58+ }
59+
5460 ssh .Handle (func (sess ssh.Session ) {
5561 InfoPrint ("Connection from: [%s]" , sess .RemoteAddr ())
5662 var defaultImage = sess .User ()
@@ -93,7 +99,7 @@ func main() {
9399 CgroupnsMode : "host" ,
94100 SecurityOpt : []string {"apparmor=unconfined" },
95101 }
96- status , cleanup , err := dockerRun (cfg , hostcfg , sess , * cmd )
102+ status , cleanup , err := dockerRun (cfg , hostcfg , sess , * cmd , * exportFolder )
97103 defer cleanup ()
98104 if err != nil {
99105 fmt .Fprintln (sess , err )
@@ -106,7 +112,11 @@ func main() {
106112 log .Fatal (ssh .ListenAndServe (* bindAddress , nil ))
107113}
108114
109- func imageExistsLocally (ctx context.Context , imageName string , cli * client.Client ) bool {
115+ func imageExistsLocally (
116+ ctx context.Context ,
117+ imageName string ,
118+ cli * client.Client ,
119+ ) bool {
110120 images , err := cli .ImageList (ctx , image.ListOptions {})
111121 if err != nil {
112122 ErrorPrint ("Error listing images: %v" , err )
@@ -124,7 +134,13 @@ func imageExistsLocally(ctx context.Context, imageName string, cli *client.Clien
124134 return false
125135}
126136
127- func waitForContainerReady (ctx context.Context , sess ssh.Session , cli * client.Client , containerID string , timeout time.Duration ) error {
137+ func waitForContainerReady (
138+ ctx context.Context ,
139+ sess ssh.Session ,
140+ cli * client.Client ,
141+ containerID string ,
142+ timeout time.Duration ,
143+ ) error {
128144 deadline := time .Now ().Add (timeout )
129145
130146 for time .Now ().Before (deadline ) {
@@ -156,7 +172,13 @@ func waitForContainerReady(ctx context.Context, sess ssh.Session, cli *client.Cl
156172
157173 return fmt .Errorf ("timeout waiting for container to be ready" )
158174}
159- func dockerRun (cfg * container.Config , hostcfg * container.HostConfig , sess ssh.Session , cmd string ) (status int , cleanup func (), err error ) {
175+ func dockerRun (
176+ cfg * container.Config ,
177+ hostcfg * container.HostConfig ,
178+ sess ssh.Session ,
179+ cmd string ,
180+ exportFolder string ,
181+ ) (status int , cleanup func (), err error ) {
160182 docker , err := client .NewClientWithOpts (client .FromEnv , client .WithAPIVersionNegotiation ())
161183 if err != nil {
162184 panic (err )
@@ -275,14 +297,26 @@ func dockerRun(cfg *container.Config, hostcfg *container.HostConfig, sess ssh.Se
275297
276298 select {
277299 case <- outputErr :
278-
279300 execInspect , ierr := docker .ContainerExecInspect (ctx , execResp .ID )
280301 if ierr != nil {
281302 WarnPrint ("Unable to inspect command exit code: %s" , err .Error ())
282303 }
283304 status = execInspect .ExitCode
284305 InfoPrint ("Exit code from specified command: %d" , status )
285-
306+ if exportFolder != "" {
307+ InfoPrint ("Exporting container to : [%s/%s.tar]" , exportFolder , resp .ID )
308+ stream , eErr := docker .ContainerExport (ctx , resp .ID )
309+ if eErr != nil {
310+ WarnPrint ("Unable to create export context for container %s: %s" , resp .ID , eErr .Error ())
311+ }
312+ targetFile , fErr := os .Create (exportFolder + "/" + resp .ID + ".tar" )
313+ if fErr != nil {
314+ WarnPrint ("Unable to create export file for container %s: %s" , resp .ID , fErr .Error ())
315+ }
316+ io .Copy (targetFile , stream )
317+ targetFile .Close ()
318+ stream .Close ()
319+ }
286320 cleanup = func () {
287321 InfoPrint ("Killing container: %s" , resp .ID )
288322 docker .ContainerKill (ctx , resp .ID , "9" )
0 commit comments