mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
fn: fixup temp dir read/write permissions if tmp fs size is not set. (#1024)
When TmpFsSize is not set in a route, docker fails to create a /tmp mount that is writable. Forcing docker to explicitly to this if read-only root directory is enabled (default).
This commit is contained in:
committed by
Chad Arimura
parent
316940285d
commit
f97b63f878
@@ -632,10 +632,106 @@ func TestGetCallReturnsResourceImpossibility(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTmpFsSize(t *testing.T) {
|
//
|
||||||
// TODO it may be a good idea to mock out the http server and use a real
|
// Tmp directory should be RW by default.
|
||||||
// response writer with sync, and also test that this works with async + log
|
//
|
||||||
|
func TestTmpFsRW(t *testing.T) {
|
||||||
|
appName := "myapp"
|
||||||
|
path := "/hello"
|
||||||
|
url := "http://127.0.0.1:8080/r/" + appName + path
|
||||||
|
|
||||||
|
app := &models.App{Name: appName}
|
||||||
|
app.SetDefaults()
|
||||||
|
// we need to load in app & route so that FromRequest works
|
||||||
|
ds := datastore.NewMockInit(
|
||||||
|
[]*models.App{app},
|
||||||
|
[]*models.Route{
|
||||||
|
{
|
||||||
|
Path: path,
|
||||||
|
AppID: app.ID,
|
||||||
|
Image: "fnproject/fn-test-utils",
|
||||||
|
Type: "sync",
|
||||||
|
Format: "http", // this _is_ the test
|
||||||
|
Timeout: 5,
|
||||||
|
IdleTimeout: 10,
|
||||||
|
Memory: 64,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
a := New(NewDirectDataAccess(ds, ds, new(mqs.Mock)))
|
||||||
|
defer checkClose(t, a)
|
||||||
|
|
||||||
|
// Here we tell fn-test-utils to read file /proc/mounts and create a /tmp/salsa of 4MB
|
||||||
|
bodOne := `{"readFile":"/proc/mounts", "createFile":"/tmp/salsa", "createFileSize": 4194304, "isDebug": true}`
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", url, &dummyReader{Reader: strings.NewReader(bodOne)})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("unexpected error building request", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var out bytes.Buffer
|
||||||
|
callI, err := a.GetCall(FromRequest(a, app, path, req), WithWriter(&out))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Submit(callI)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("submit should not error:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// we're using http format so this will have written a whole http request
|
||||||
|
res, err := http.ReadResponse(bufio.NewReader(&out), nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
// Let's fetch read output and write results. See fn-test-utils AppResponse struct (data field)
|
||||||
|
var resp struct {
|
||||||
|
R struct {
|
||||||
|
MountsRead string `json:"/proc/mounts.read_output"`
|
||||||
|
CreateFile string `json:"/tmp/salsa.create_error"`
|
||||||
|
} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
json.NewDecoder(res.Body).Decode(&resp)
|
||||||
|
|
||||||
|
// Let's check what mounts are on...
|
||||||
|
mounts := strings.Split(resp.R.MountsRead, "\n")
|
||||||
|
isFound := false
|
||||||
|
isRootFound := false
|
||||||
|
for _, mnt := range mounts {
|
||||||
|
tokens := strings.Split(mnt, " ")
|
||||||
|
if len(tokens) < 3 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
point := tokens[1]
|
||||||
|
opts := tokens[3]
|
||||||
|
|
||||||
|
// tmp dir with RW and no other options (size, inodes, etc.)
|
||||||
|
if point == "/tmp" && opts == "rw,nosuid,nodev,noexec,relatime" {
|
||||||
|
// good
|
||||||
|
isFound = true
|
||||||
|
} else if point == "/" && strings.HasPrefix(opts, "ro,") {
|
||||||
|
// Read-only root, good...
|
||||||
|
isRootFound = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isFound || !isRootFound {
|
||||||
|
t.Fatal(`didn't get proper mounts for /tmp or /, got /proc/mounts content of:\n`, resp.R.MountsRead)
|
||||||
|
}
|
||||||
|
|
||||||
|
// write file should not have failed...
|
||||||
|
if resp.R.CreateFile != "" {
|
||||||
|
t.Fatal(`limited tmpfs should generate fs full error, but got output: `, resp.R.CreateFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTmpFsSize(t *testing.T) {
|
||||||
appName := "myapp"
|
appName := "myapp"
|
||||||
path := "/hello"
|
path := "/hello"
|
||||||
url := "http://127.0.0.1:8080/r/" + appName + path
|
url := "http://127.0.0.1:8080/r/" + appName + path
|
||||||
@@ -719,6 +815,7 @@ func TestTmpFsSize(t *testing.T) {
|
|||||||
point := tokens[1]
|
point := tokens[1]
|
||||||
opts := tokens[3]
|
opts := tokens[3]
|
||||||
|
|
||||||
|
// rw tmp dir with size and inode limits applied.
|
||||||
if point == "/tmp" && opts == "rw,nosuid,nodev,noexec,relatime,size=1024k,nr_inodes=1024" {
|
if point == "/tmp" && opts == "rw,nosuid,nodev,noexec,relatime,size=1024k,nr_inodes=1024" {
|
||||||
// good
|
// good
|
||||||
isFound = true
|
isFound = true
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ func (drv *DockerDriver) configureFs(log logrus.FieldLogger, container *docker.C
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (drv *DockerDriver) configureTmpFs(log logrus.FieldLogger, container *docker.CreateContainerOptions, task drivers.ContainerTask) {
|
func (drv *DockerDriver) configureTmpFs(log logrus.FieldLogger, container *docker.CreateContainerOptions, task drivers.ContainerTask) {
|
||||||
if task.TmpFsSize() == 0 {
|
if task.TmpFsSize() == 0 && !drv.conf.EnableReadOnlyRootFs {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,10 +228,12 @@ func (drv *DockerDriver) configureTmpFs(log logrus.FieldLogger, container *docke
|
|||||||
}
|
}
|
||||||
|
|
||||||
var tmpFsOption string
|
var tmpFsOption string
|
||||||
if drv.conf.MaxTmpFsInodes != 0 {
|
if task.TmpFsSize() != 0 {
|
||||||
tmpFsOption = fmt.Sprintf("size=%dm,nr_inodes=%d", task.TmpFsSize(), drv.conf.MaxTmpFsInodes)
|
if drv.conf.MaxTmpFsInodes != 0 {
|
||||||
} else {
|
tmpFsOption = fmt.Sprintf("size=%dm,nr_inodes=%d", task.TmpFsSize(), drv.conf.MaxTmpFsInodes)
|
||||||
tmpFsOption = fmt.Sprintf("size=%dm", task.TmpFsSize())
|
} else {
|
||||||
|
tmpFsOption = fmt.Sprintf("size=%dm", task.TmpFsSize())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
target := "/tmp"
|
target := "/tmp"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user