Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Apr 28, 2020. It is now read-only.

Commit bcf9063

Browse files
authored
Merge pull request #219 from cdr/on_open-label
Add on_start label for running a command every time the container starts
2 parents aa11bec + 3b747e9 commit bcf9063

File tree

5 files changed

+113
-2
lines changed

5 files changed

+113
-2
lines changed

hat-examples/on_start/Dockerfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
FROM codercom/ubuntu-dev
2+
3+
# The command in the on_start label will be run immediately after the
4+
# project starts. You could use this to reinstall dependencies or
5+
# perform any other bootstrapping tasks.
6+
LABEL on_start="touch did_on_start"

internal/dockutil/exec.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ func Exec(cntName, cmd string, args ...string) *exec.Cmd {
1111
return exec.Command("docker", args...)
1212
}
1313

14+
func ExecDir(cntName, dir, cmd string, args ...string) *exec.Cmd {
15+
args = append([]string{"exec", "-w", dir, "-i", cntName, cmd}, args...)
16+
return exec.Command("docker", args...)
17+
}
18+
1419
func ExecTTY(cntName, dir, cmd string, args ...string) *exec.Cmd {
1520
args = append([]string{"exec", "-w", dir, "-it", cntName, cmd}, args...)
1621
return exec.Command("docker", args...)
@@ -25,6 +30,11 @@ func DetachedExec(cntName, cmd string, args ...string) *exec.Cmd {
2530
return exec.Command("docker", args...)
2631
}
2732

33+
func DetachedExecDir(cntName, dir, cmd string, args ...string) *exec.Cmd {
34+
args = append([]string{"exec", "-dw", dir, cntName, cmd}, args...)
35+
return exec.Command("docker", args...)
36+
}
37+
2838
func ExecEnv(cntName string, envs []string, cmd string, args ...string) *exec.Cmd {
2939
args = append([]string{"exec", "-e", strings.Join(envs, ","), "-i", cntName, cmd}, args...)
3040
return exec.Command("docker", args...)

runner.go

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"golang.org/x/xerrors"
2222

2323
"go.coder.com/flog"
24+
"go.coder.com/sail/internal/dockutil"
2425
)
2526

2627
// containerLogPath is the location of the code-server log.
@@ -44,6 +45,12 @@ const (
4445
proxyURLLabel = sailLabel + ".proxy_url"
4546
)
4647

48+
// Docker labels for user configuration.
49+
const (
50+
onStartLabel = "on_start"
51+
projectRootLabel = "project_root"
52+
)
53+
4754
// runner holds all the information needed to assemble a new sail container.
4855
// The runner stores itself as state on the container.
4956
// It enables quick iteration on a container with small modifications to it's config.
@@ -68,6 +75,8 @@ type runner struct {
6875
// the container's root process.
6976
// We want code-server to be the root process as it gives us the nice guarantee that
7077
// the container is only online when code-server is working.
78+
// Additionally, runContainer also runs the image's `on_start` label as a bash
79+
// command inside of the project directory.
7180
func (r *runner) runContainer(image string) error {
7281
cli := dockerClient()
7382
defer cli.Close()
@@ -131,6 +140,11 @@ func (r *runner) runContainer(image string) error {
131140
return xerrors.Errorf("failed to start container: %w", err)
132141
}
133142

143+
err = r.runOnStart(image)
144+
if err != nil {
145+
return xerrors.Errorf("failed to run on_start label in container: %w", err)
146+
}
147+
134148
return nil
135149
}
136150

@@ -457,7 +471,7 @@ func (r *runner) projectDir(image string) (string, error) {
457471
return "", xerrors.Errorf("failed to inspect image: %w", err)
458472
}
459473

460-
proot, ok := img.Config.Labels["project_root"]
474+
proot, ok := img.Config.Labels[projectRootLabel]
461475
if ok {
462476
return filepath.Join(proot, r.projectName), nil
463477
}
@@ -491,6 +505,34 @@ func runnerFromContainer(name string) (*runner, error) {
491505
}, nil
492506
}
493507

508+
// runOnStart runs the image's `on_start` label in the container in the project directory.
509+
func (r *runner) runOnStart(image string) error {
510+
cli := dockerClient()
511+
defer cli.Close()
512+
513+
// Get project directory.
514+
projectDir, err := r.projectDir(image)
515+
if err != nil {
516+
return err
517+
}
518+
projectDir = resolvePath(containerHome, projectDir)
519+
520+
// Get on_start label from image.
521+
img, _, err := cli.ImageInspectWithRaw(context.Background(), image)
522+
if err != nil {
523+
return xerrors.Errorf("failed to inspect image: %w", err)
524+
}
525+
onStartCmd, ok := img.Config.Labels[onStartLabel]
526+
if !ok {
527+
// No on_start label, so we quit early.
528+
return nil
529+
}
530+
531+
// Execute the command detached in the container.
532+
cmd := dockutil.DetachedExecDir(r.cntName, projectDir, "/bin/bash", "-c", onStartCmd)
533+
return cmd.Run()
534+
}
535+
494536
func (r *runner) forkProxy() error {
495537
var err error
496538
r.proxyURL, err = forkProxy(r.cntName)

runner_test.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package main
22

33
import (
4+
"fmt"
45
"testing"
56

67
"github.com/stretchr/testify/assert"
78
"github.com/stretchr/testify/require"
9+
10+
"go.coder.com/sail/internal/dockutil"
811
)
912

1013
func Test_runner(t *testing.T) {
1114
// Ensure that the testing environment won't conflict with any running sail projects.
12-
requireProjectsNotRunning(t, "cdr/nbin", "cdr/flog", "cdr/bigdur", "cdr/sshcode")
15+
requireProjectsNotRunning(t, "cdr/nbin", "cdr/flog", "cdr/bigdur", "cdr/sshcode", "cdr/cli")
1316
requireUbuntuDevImage(t)
1417

1518
// labelChecker asserts that all of the correct labels
@@ -73,6 +76,23 @@ func Test_runner(t *testing.T) {
7376
})
7477
}
7578

79+
// containsFile ensures that a container contains a file.
80+
// This is used for testing the on_start label.
81+
containsFile := func(name, path string) func(*testing.T, *params) {
82+
return func(t *testing.T, p *params) {
83+
t.Run(name, func(t *testing.T) {
84+
cntDir, err := p.proj.containerDir()
85+
require.NoError(t, err)
86+
cntDir = resolvePath(containerHome, cntDir)
87+
88+
// Run the file existence check using /bin/sh.
89+
cmdStr := fmt.Sprintf(`[ -f "%s" ]`, path)
90+
err = dockutil.ExecDir(p.proj.cntName(), cntDir, "/bin/sh", "-c", cmdStr).Run()
91+
require.NoError(t, err)
92+
})
93+
}
94+
}
95+
7696
run(t, "BaseImageNoHat", "https://github.com/cdr/nbin", "",
7797
labelChecker,
7898
codeServerStarts,
@@ -96,4 +116,13 @@ func Test_runner(t *testing.T) {
96116
codeServerStarts,
97117
loadFromContainer,
98118
)
119+
120+
run(t, "ProjImageOnStartHat", "https://github.com/cdr/cli", "./hat-examples/on_start",
121+
labelChecker,
122+
codeServerStarts,
123+
loadFromContainer,
124+
125+
// ./hat-examples/on_start should create `did_on_start` in the project directory.
126+
containsFile("ContainsOnStartFile", "did_on_start"),
127+
)
99128
}

site/content/docs/concepts/labels.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,30 @@ LABEL project_root "~/go/src/"
2424

2525
Will bind mount the host directory `$project_root/<org>/<repo>` to `~/go/src/<repo>` in the container.
2626

27+
### On Start Labels
28+
29+
You can run a command in your sail container after it starts by specifying
30+
the `on_start` label. If you'd like to run multiple commands on launch, we
31+
recommend using a `.sh` file as your `on_start` label, as you cannot
32+
provide multiple `on_start` labels in your image.
33+
34+
The `on_start` label is run detached inside of `/bin/bash` as soon as the
35+
container is started, with the work directory set to your `project_root`
36+
(see the section above).
37+
38+
For example:
39+
```Dockerfile
40+
LABEL on_start "npm install"
41+
```
42+
```Dockerfile
43+
LABEL on_start "go get"
44+
```
45+
```Dockerfile
46+
LABEL on_start "./.sail/on_start.sh"
47+
```
48+
49+
Make sure any scripts you make are executable, otherwise sail will fail to
50+
launch.
2751

2852
### Share Labels
2953

0 commit comments

Comments
 (0)