@@ -2,13 +2,18 @@ package docker
22
33import (
44 "context"
5+ "fmt"
6+ "github.com/Wing924/shellwords"
57 "github.com/discourse/discourse_docker/launcher_go/v2/config"
68 "github.com/discourse/discourse_docker/launcher_go/v2/utils"
79 "golang.org/x/sys/unix"
810 "io"
911 "os"
1012 "os/exec"
13+ "runtime"
14+ "strings"
1115 "syscall"
16+ "time"
1217)
1318
1419type DockerBuilder struct {
@@ -52,3 +57,197 @@ func (r *DockerBuilder) Run() error {
5257 }
5358 return nil
5459}
60+
61+ type DockerRunner struct {
62+ Config * config.Config
63+ Ctx * context.Context
64+ ExtraEnv []string
65+ ExtraFlags []string
66+ Rm bool
67+ ContainerId string
68+ CustomImage string
69+ Cmd []string
70+ Stdin io.Reader
71+ SkipPorts bool
72+ DryRun bool
73+ Restart bool
74+ Detatch bool
75+ Hostname string
76+ }
77+
78+ func (r * DockerRunner ) Run () error {
79+ cmd := exec .CommandContext (* r .Ctx , utils .DockerPath , "run" )
80+
81+ // Detatch signifies we do not want to supervise
82+ if ! r .Detatch {
83+ cmd .SysProcAttr = & syscall.SysProcAttr {Setpgid : true }
84+ cmd .Cancel = func () error {
85+ if runtime .GOOS == "darwin" {
86+ runCtx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
87+ stopCmd := exec .CommandContext (runCtx , utils .DockerPath , "stop" , r .ContainerId )
88+ utils .CmdRunner (stopCmd ).Run ()
89+ cancel ()
90+ }
91+ return unix .Kill (- cmd .Process .Pid , unix .SIGINT )
92+ }
93+ }
94+ cmd .Env = r .Config .EnvArray (true )
95+
96+ if r .DryRun {
97+ // multi-line env doesn't work super great from CLI, but we can print out the rest.
98+ for k , v := range r .Config .Env {
99+ if ! strings .Contains (v , "\n " ) {
100+ cmd .Args = append (cmd .Args , "--env" )
101+ cmd .Args = append (cmd .Args , k + "=" + shellwords .Escape (v ))
102+ }
103+ }
104+ } else {
105+ for k , _ := range r .Config .Env {
106+ cmd .Args = append (cmd .Args , "--env" )
107+ cmd .Args = append (cmd .Args , k )
108+ }
109+ }
110+
111+ // Order is important here, we add extra env after config's env to override anything set in env.
112+ for _ , e := range r .ExtraEnv {
113+ cmd .Args = append (cmd .Args , "--env" )
114+ cmd .Args = append (cmd .Args , e )
115+ }
116+ for k , v := range r .Config .Labels {
117+ cmd .Args = append (cmd .Args , "--label" )
118+ cmd .Args = append (cmd .Args , k + "=" + v )
119+ }
120+ if ! r .SkipPorts {
121+ for _ , v := range r .Config .Expose {
122+ if strings .Contains (v , ":" ) {
123+ cmd .Args = append (cmd .Args , "-p" )
124+ cmd .Args = append (cmd .Args , v )
125+ } else {
126+ cmd .Args = append (cmd .Args , "--expose" )
127+ cmd .Args = append (cmd .Args , v )
128+ }
129+ }
130+ }
131+ for _ , v := range r .Config .Volumes {
132+ cmd .Args = append (cmd .Args , "-v" )
133+ cmd .Args = append (cmd .Args , v .Volume .Host + ":" + v .Volume .Guest )
134+ }
135+ for _ , v := range r .Config .Links {
136+ cmd .Args = append (cmd .Args , "--link" )
137+ cmd .Args = append (cmd .Args , v .Link .Name + ":" + v .Link .Alias )
138+ }
139+ cmd .Args = append (cmd .Args , "--shm-size=512m" )
140+ if r .Rm {
141+ cmd .Args = append (cmd .Args , "--rm" )
142+ }
143+ if r .Restart {
144+ cmd .Args = append (cmd .Args , "--restart=always" )
145+ } else {
146+ cmd .Args = append (cmd .Args , "--restart=no" )
147+ }
148+ if r .Detatch {
149+ cmd .Args = append (cmd .Args , "-d" )
150+ }
151+ cmd .Args = append (cmd .Args , "-i" )
152+
153+ // Docker args override settings above
154+ for _ , f := range r .Config .DockerArgs () {
155+ cmd .Args = append (cmd .Args , f )
156+ }
157+ for _ , f := range r .ExtraFlags {
158+ cmd .Args = append (cmd .Args , f )
159+ }
160+ cmd .Args = append (cmd .Args , "-h" )
161+ cmd .Args = append (cmd .Args , r .Hostname )
162+ cmd .Args = append (cmd .Args , "--name" )
163+ cmd .Args = append (cmd .Args , r .ContainerId )
164+ if len (r .CustomImage ) > 0 {
165+ cmd .Args = append (cmd .Args , r .CustomImage )
166+ } else {
167+ cmd .Args = append (cmd .Args , r .Config .RunImage ())
168+ }
169+
170+ for _ , c := range r .Cmd {
171+ cmd .Args = append (cmd .Args , c )
172+ }
173+
174+ if ! r .Detatch {
175+ cmd .Stdout = os .Stdout
176+ cmd .Stderr = os .Stderr
177+ cmd .Stdin = r .Stdin
178+ }
179+ runner := utils .CmdRunner (cmd )
180+ if r .DryRun {
181+ fmt .Println (cmd )
182+ } else {
183+ if err := runner .Run (); err != nil {
184+ return err
185+ }
186+ }
187+ return nil
188+ }
189+
190+ type DockerPupsRunner struct {
191+ Config * config.Config
192+ PupsArgs string
193+ SavedImageName string
194+ ExtraEnv []string
195+ Ctx * context.Context
196+ ContainerId string
197+ }
198+
199+ func (r * DockerPupsRunner ) Run () error {
200+ rm := false
201+ // remove : in case docker tag is blank, and use default latest tag
202+ r .SavedImageName = strings .TrimRight (r .SavedImageName , ":" )
203+ if r .SavedImageName == "" {
204+ rm = true
205+ }
206+ defer func (rm bool ) {
207+ if ! rm {
208+ time .Sleep (utils .CommitWait )
209+ runCtx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
210+ cmd := exec .CommandContext (runCtx , utils .DockerPath , "rm" , "-f" , r .ContainerId )
211+ utils .CmdRunner (cmd ).Run ()
212+ cancel ()
213+ }
214+ }(rm )
215+ commands := []string {"/bin/bash" ,
216+ "-c" ,
217+ "/usr/local/bin/pups --stdin " + r .PupsArgs }
218+
219+ runner := DockerRunner {Config : r .Config ,
220+ Ctx : r .Ctx ,
221+ ExtraEnv : r .ExtraEnv ,
222+ Rm : rm ,
223+ ContainerId : r .ContainerId ,
224+ Cmd : commands ,
225+ Stdin : strings .NewReader (r .Config .Yaml ()),
226+ SkipPorts : true , //pups runs don't need to expose ports
227+ }
228+
229+ if err := runner .Run (); err != nil {
230+ return err
231+ }
232+
233+ if len (r .SavedImageName ) > 0 {
234+ time .Sleep (utils .CommitWait )
235+ cmd := exec .Command ("docker" ,
236+ "commit" ,
237+ "--change" ,
238+ "LABEL org.opencontainers.image.created=\" " + time .Now ().Format (time .RFC3339 )+ "\" " ,
239+ "--change" ,
240+ "CMD [\" " + r .Config .BootCommand ()+ "\" ]" ,
241+ r .ContainerId ,
242+ r .SavedImageName ,
243+ )
244+ cmd .Stdout = os .Stdout
245+ cmd .Stderr = os .Stderr
246+
247+ fmt .Fprintln (utils .Out , cmd )
248+ if err := utils .CmdRunner (cmd ).Run (); err != nil {
249+ return err
250+ }
251+ }
252+ return nil
253+ }
0 commit comments