Skip to content

Commit 2efad77

Browse files
arampricejfmyers9
authored andcommitted
allow arbitrary mounts into process's container
Recursive, read/write, bind mount paths specified by release-author into the process's container. The path inside the container will mirror the path on the host. [finishes #149683751] Signed-off-by: James Myers <jfmyers9@gmail.com>
1 parent c101e3a commit 2efad77

File tree

9 files changed

+83
-32
lines changed

9 files changed

+83
-32
lines changed

docs/config.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ limits:
2222
open_files: 100
2323

2424
volumes:
25-
- name: certificates
26-
- name: sockets
25+
- /var/vcap/data/certificates
2726

2827
hooks:
2928
pre_start: /var/vcap/job/program/bin/bpm-pre-start

docs/runtime.md

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -54,24 +54,6 @@ This storage area is shared between all processes in your job. It is your
5454
responsibility to make sure that the data saved by each of your job's processes
5555
does not collide.
5656

57-
### Shared Data
58-
59-
> **Note:** This feature has been added to enable support for older jobs which
60-
> use the file system to communicate with other jobs. It is preferable in nearly
61-
> all cases to use the network to communicate across job boundaries. Using the
62-
> network reduces scheduling constraints such that a job can be un-collocated
63-
> and allows more modern access control (key rotation, etc.) of the information
64-
> being transferred between your jobs.
65-
66-
If your job configuration lists shared volumes then these will be mounted
67-
under `/var/vcap/data/shared/[VOLUME NAME]`. These volumes will be mounted
68-
read-write. All collocated jobs which list a particular volume name will be
69-
given a volume they can all share. If your release already has a data stored
70-
in the `/var/vcap/data/shared` directory then it is your responsibility to
71-
move this data to a different path before using shared volumes.
72-
73-
Due to path collisions, job name of `shared` will be rejected.
74-
7557
### Persistent Data
7658

7759
TODO: Work out if there is anything complex about persistent data across

src/bpm/bpm/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type Config struct {
2929
Args []string `yaml:"args"`
3030
Env []string `yaml:"env"`
3131
Limits *Limits `yaml:"limits"`
32+
Volumes []string `yaml:"volumes"`
3233
Hooks *Hooks `yaml:"hooks"`
3334
}
3435

src/bpm/bpm/config_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ var _ = Describe("Config", func() {
4141
Expect(cfg.Env).To(ConsistOf("FOO=BAR", "BAZ=BUZZ"))
4242
Expect(cfg.Limits.Memory).To(Equal(&expectedMemoryLimit))
4343
Expect(cfg.Limits.OpenFiles).To(Equal(&expectedOpenFilesLimit))
44+
Expect(cfg.Volumes).To(ConsistOf("/var/vcap/data/program/foobar", "/var/vcap/data/alternate-program"))
4445
Expect(cfg.Hooks.PreStart).To(Equal("/var/vcap/jobs/program/bin/pre"))
4546
})
4647

src/bpm/bpm/fixtures/example.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,8 @@ env:
99
limits:
1010
memory: 100G
1111
open_files: 100
12+
volumes:
13+
- /var/vcap/data/program/foobar
14+
- /var/vcap/data/alternate-program
1215
hooks:
1316
pre_start: /var/vcap/jobs/program/bin/pre

src/bpm/runc/adapter/adapter.go

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ func NewRuncAdapter() *RuncAdapter {
3333
return &RuncAdapter{}
3434
}
3535

36-
func (a *RuncAdapter) CreateJobPrerequisites(systemRoot, jobName, procName string, user specs.User) (string, *os.File, *os.File, error) {
36+
func (a *RuncAdapter) CreateJobPrerequisites(
37+
systemRoot, jobName, procName string,
38+
cfg *bpm.Config,
39+
user specs.User,
40+
) (string, *os.File, *os.File, error) {
3741
bpmPidDir := filepath.Join(systemRoot, "sys", "run", "bpm", jobName)
3842
jobLogDir := filepath.Join(systemRoot, "sys", "log", jobName)
3943
stdoutFileLocation := filepath.Join(jobLogDir, fmt.Sprintf("%s.out.log", procName))
@@ -64,18 +68,30 @@ func (a *RuncAdapter) CreateJobPrerequisites(systemRoot, jobName, procName strin
6468
return "", nil, nil, err
6569
}
6670

67-
err = os.MkdirAll(dataDir, 0700)
71+
err = createDirFor(dataDir, int(user.UID), int(user.GID))
6872
if err != nil {
6973
return "", nil, nil, err
7074
}
71-
err = os.Chown(dataDir, int(user.UID), int(user.GID))
72-
if err != nil {
73-
return "", nil, nil, err
75+
76+
for _, vol := range cfg.Volumes {
77+
err := createDirFor(vol, int(user.UID), int(user.GID))
78+
if err != nil {
79+
return "", nil, nil, err
80+
}
7481
}
7582

7683
return bpmPidDir, stdout, stderr, nil
7784
}
7885

86+
func createDirFor(path string, uid, gid int) error {
87+
err := os.MkdirAll(path, 0700)
88+
if err != nil {
89+
return err
90+
}
91+
92+
return os.Chown(path, uid, gid)
93+
}
94+
7995
func createFileFor(path string, uid, gid int) (*os.File, error) {
8096
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
8197
if err != nil {
@@ -107,6 +123,7 @@ func (a *RuncAdapter) BuildSpec(
107123
mounts := defaultMounts()
108124
mounts = append(mounts, boshMounts(systemRoot, jobName, procName)...)
109125
mounts = append(mounts, systemIdentityMounts()...)
126+
mounts = append(mounts, userProvidedIdentityMounts(cfg.Volumes)...)
110127

111128
var resources *specs.LinuxResources
112129
if cfg.Limits != nil {
@@ -291,3 +308,18 @@ func systemIdentityMounts() []specs.Mount {
291308
},
292309
}
293310
}
311+
312+
func userProvidedIdentityMounts(volumes []string) []specs.Mount {
313+
var mnts []specs.Mount
314+
315+
for _, vol := range volumes {
316+
mnts = append(mnts, specs.Mount{
317+
Destination: vol,
318+
Type: "bind",
319+
Source: vol,
320+
Options: []string{"rbind", "rw"},
321+
})
322+
}
323+
324+
return mnts
325+
}

src/bpm/runc/adapter/adapter_test.go

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ var _ = Describe("RuncAdapter", func() {
4040
procName,
4141
systemRoot string
4242
user specs.User
43+
44+
cfg *bpm.Config
4345
)
4446

4547
BeforeEach(func() {
@@ -52,6 +54,13 @@ var _ = Describe("RuncAdapter", func() {
5254
var err error
5355
systemRoot, err = ioutil.TempDir("", "runc-adapter-system-files")
5456
Expect(err).NotTo(HaveOccurred())
57+
58+
cfg = &bpm.Config{
59+
Volumes: []string{
60+
filepath.Join(systemRoot, "some", "directory"),
61+
filepath.Join(systemRoot, "another", "location"),
62+
},
63+
}
5564
})
5665

5766
AfterEach(func() {
@@ -60,7 +69,7 @@ var _ = Describe("RuncAdapter", func() {
6069

6170
Describe("CreateJobPrerequisites", func() {
6271
It("creates the job prerequisites", func() {
63-
pidDir, stdout, stderr, err := runcAdapter.CreateJobPrerequisites(systemRoot, jobName, procName, user)
72+
pidDir, stdout, stderr, err := runcAdapter.CreateJobPrerequisites(systemRoot, jobName, procName, cfg, user)
6473
Expect(err).NotTo(HaveOccurred())
6574

6675
logDir := filepath.Join(systemRoot, "sys", "log", jobName)
@@ -100,12 +109,19 @@ var _ = Describe("RuncAdapter", func() {
100109
Expect(dataDirInfo.Mode() & os.ModePerm).To(Equal(os.FileMode(0700)))
101110
Expect(dataDirInfo.Sys().(*syscall.Stat_t).Uid).To(Equal(uint32(200)))
102111
Expect(dataDirInfo.Sys().(*syscall.Stat_t).Gid).To(Equal(uint32(300)))
112+
113+
//Volumes
114+
for _, vol := range cfg.Volumes {
115+
volDirInfo, err := os.Stat(vol)
116+
Expect(err).NotTo(HaveOccurred())
117+
Expect(volDirInfo.Mode() & os.ModePerm).To(Equal(os.FileMode(0700)))
118+
Expect(volDirInfo.Sys().(*syscall.Stat_t).Uid).To(Equal(uint32(200)))
119+
Expect(volDirInfo.Sys().(*syscall.Stat_t).Gid).To(Equal(uint32(300)))
120+
}
103121
})
104122
})
105123

106124
Describe("BuildSpec", func() {
107-
var cfg *bpm.Config
108-
109125
BeforeEach(func() {
110126
cfg = &bpm.Config{
111127
Executable: "/var/vcap/packages/example/bin/example",
@@ -117,6 +133,10 @@ var _ = Describe("RuncAdapter", func() {
117133
"RAVE=true",
118134
"ONE=two",
119135
},
136+
Volumes: []string{
137+
"/path/to/volume/1",
138+
"/path/to/volume/2",
139+
},
120140
}
121141
})
122142

@@ -246,6 +266,18 @@ var _ = Describe("RuncAdapter", func() {
246266
Source: filepath.Join(systemRoot, "sys", "log", jobName),
247267
Options: []string{"rbind", "rw"},
248268
},
269+
{
270+
Destination: "/path/to/volume/1",
271+
Type: "bind",
272+
Source: "/path/to/volume/1",
273+
Options: []string{"rbind", "rw"},
274+
},
275+
{
276+
Destination: "/path/to/volume/2",
277+
Type: "bind",
278+
Source: "/path/to/volume/2",
279+
Options: []string{"rbind", "rw"},
280+
},
249281
}))
250282

251283
Expect(spec.Linux.RootfsPropagation).To(Equal("private"))

src/bpm/runc/lifecycle/lifecycle.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ type CommandRunner interface {
5656
//go:generate counterfeiter . RuncAdapter
5757

5858
type RuncAdapter interface {
59-
CreateJobPrerequisites(systemRoot, jobName, procName string, user specs.User) (string, *os.File, *os.File, error)
59+
CreateJobPrerequisites(systemRoot, jobName, procName string, cfg *bpm.Config, user specs.User) (string, *os.File, *os.File, error)
6060
BuildSpec(systemRoot, jobName, procName string, cfg *bpm.Config, user specs.User) (specs.Spec, error)
6161
}
6262

@@ -106,7 +106,7 @@ func (j *RuncLifecycle) StartJob(jobName, procName string, cfg *bpm.Config) erro
106106
return err
107107
}
108108

109-
pidDir, stdout, stderr, err := j.runcAdapter.CreateJobPrerequisites(j.systemRoot, jobName, procName, user)
109+
pidDir, stdout, stderr, err := j.runcAdapter.CreateJobPrerequisites(j.systemRoot, jobName, procName, cfg, user)
110110
if err != nil {
111111
return fmt.Errorf("failed to create system files: %s", err.Error())
112112
}

src/bpm/runc/lifecycle/lifecycle_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,15 @@ var _ = Describe("RuncJobLifecycle", func() {
124124
Expect(fakeUserFinder.LookupArgsForCall(0)).To(Equal(usertools.VcapUser))
125125

126126
Expect(fakeRuncAdapter.CreateJobPrerequisitesCallCount()).To(Equal(1))
127-
systemRoot, jobName, procName, user := fakeRuncAdapter.CreateJobPrerequisitesArgsForCall(0)
127+
systemRoot, jobName, procName, cfg, user := fakeRuncAdapter.CreateJobPrerequisitesArgsForCall(0)
128128
Expect(systemRoot).To(Equal(expectedSystemRoot))
129129
Expect(jobName).To(Equal(expectedJobName))
130130
Expect(procName).To(Equal(expectedProcName))
131+
Expect(cfg).To(Equal(jobConfig))
131132
Expect(user).To(Equal(expectedUser))
132133

133134
Expect(fakeRuncAdapter.BuildSpecCallCount()).To(Equal(1))
134-
systemRoot, jobName, procName, cfg, user := fakeRuncAdapter.BuildSpecArgsForCall(0)
135+
systemRoot, jobName, procName, cfg, user = fakeRuncAdapter.BuildSpecArgsForCall(0)
135136
Expect(systemRoot).To(Equal(expectedSystemRoot))
136137
Expect(jobName).To(Equal(expectedJobName))
137138
Expect(procName).To(Equal(expectedProcName))

0 commit comments

Comments
 (0)