add exec option to API TmpfsOptions and the related volume functions
Signed-off-by: Arash Deshmeh <adeshmeh@ca.ibm.com>
This commit is contained in:
parent
d25b0bd7ea
commit
964c49a69e
5 changed files with 96 additions and 1 deletions
|
@ -442,6 +442,9 @@ definitions:
|
|||
Mode:
|
||||
description: "The permission mode for the tmpfs mount in an integer."
|
||||
type: "integer"
|
||||
Options:
|
||||
description: "The list of options to be passed to the tmpfs mount in a string."
|
||||
type: "string"
|
||||
|
||||
RestartPolicy:
|
||||
description: |
|
||||
|
|
|
@ -119,7 +119,8 @@ type TmpfsOptions struct {
|
|||
SizeBytes int64 `json:",omitempty"`
|
||||
// Mode of the tmpfs upon creation
|
||||
Mode os.FileMode `json:",omitempty"`
|
||||
|
||||
// Options passed directly to the tmpfs mount
|
||||
Options string `json:",omitempty"`
|
||||
// TODO(stevvooe): There are several more tmpfs flags, specified in the
|
||||
// daemon, that are accepted. Only the most basic are added for now.
|
||||
//
|
||||
|
|
|
@ -312,6 +312,7 @@ keywords: "API, Docker, rcli, REST, documentation"
|
|||
* `GET /services/{id}` now returns `Ulimits` as part of `ContainerSpec`.
|
||||
* `POST /services/create` now accepts `Ulimits` as part of `ContainerSpec`.
|
||||
* `POST /services/{id}/update` now accepts `Ulimits` as part of `ContainerSpec`.
|
||||
* `POST /containers/create` now takes `Options` as part of `HostConfig.Mounts` to set options for tmpfs mounts.
|
||||
|
||||
## v1.40 API changes
|
||||
|
||||
|
|
|
@ -204,6 +204,22 @@ func linuxValidMountMode(mode string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
var validTmpfsOptions = map[string]bool{
|
||||
"exec": true,
|
||||
"noexec": true,
|
||||
}
|
||||
|
||||
func validateTmpfsOptions(rawOptions string) ([]string, error) {
|
||||
var options []string
|
||||
for _, opt := range strings.Split(rawOptions, ",") {
|
||||
if _, ok := validTmpfsOptions[opt]; !ok {
|
||||
return nil, errors.New("invalid option: " + opt)
|
||||
}
|
||||
options = append(options, opt)
|
||||
}
|
||||
return options, nil
|
||||
}
|
||||
|
||||
func (p *linuxParser) ReadWrite(mode string) bool {
|
||||
if !linuxValidMountMode(mode) {
|
||||
return false
|
||||
|
@ -406,6 +422,15 @@ func (p *linuxParser) ConvertTmpfsOptions(opt *mount.TmpfsOptions, readOnly bool
|
|||
|
||||
rawOpts = append(rawOpts, fmt.Sprintf("size=%d%s", size, suffix))
|
||||
}
|
||||
|
||||
if opt != nil && len(opt.Options) > 0 {
|
||||
tmpfsOpts, err := validateTmpfsOptions(opt.Options)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
rawOpts = append(rawOpts, tmpfsOpts...)
|
||||
}
|
||||
|
||||
return strings.Join(rawOpts, ","), nil
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package mounts // import "github.com/docker/docker/volume/mounts"
|
|||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
|
@ -9,6 +10,70 @@ import (
|
|||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
type parseMountRawTestSet struct {
|
||||
valid []string
|
||||
invalid map[string]string
|
||||
}
|
||||
|
||||
func TestConvertTmpfsOptions(t *testing.T) {
|
||||
type testCase struct {
|
||||
opt mount.TmpfsOptions
|
||||
readOnly bool
|
||||
expectedSubstrings []string
|
||||
unexpectedSubstrings []string
|
||||
err bool
|
||||
}
|
||||
cases := []testCase{
|
||||
{
|
||||
opt: mount.TmpfsOptions{SizeBytes: 1024 * 1024, Mode: 0700},
|
||||
readOnly: false,
|
||||
expectedSubstrings: []string{"size=1m", "mode=700"},
|
||||
unexpectedSubstrings: []string{"ro"},
|
||||
},
|
||||
{
|
||||
opt: mount.TmpfsOptions{},
|
||||
readOnly: true,
|
||||
expectedSubstrings: []string{"ro"},
|
||||
unexpectedSubstrings: []string{},
|
||||
},
|
||||
{
|
||||
opt: mount.TmpfsOptions{Options: "exec"},
|
||||
readOnly: true,
|
||||
expectedSubstrings: []string{"ro", "exec"},
|
||||
unexpectedSubstrings: []string{"noexec"},
|
||||
},
|
||||
{
|
||||
opt: mount.TmpfsOptions{Options: "INVALID"},
|
||||
err: true,
|
||||
},
|
||||
}
|
||||
p := &linuxParser{}
|
||||
for _, c := range cases {
|
||||
data, err := p.ConvertTmpfsOptions(&c.opt, c.readOnly)
|
||||
if c.err {
|
||||
if err == nil {
|
||||
t.Fatalf("expected error for %+v, got nil", c.opt)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("could not convert %+v (readOnly: %v) to string: %v",
|
||||
c.opt, c.readOnly, err)
|
||||
}
|
||||
t.Logf("data=%q", data)
|
||||
for _, s := range c.expectedSubstrings {
|
||||
if !strings.Contains(data, s) {
|
||||
t.Fatalf("expected substring: %s, got %v (case=%+v)", s, data, c)
|
||||
}
|
||||
}
|
||||
for _, s := range c.unexpectedSubstrings {
|
||||
if strings.Contains(data, s) {
|
||||
t.Fatalf("unexpected substring: %s, got %v (case=%+v)", s, data, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type mockFiProvider struct{}
|
||||
|
||||
func (mockFiProvider) fileInfo(path string) (exists, isDir bool, err error) {
|
||||
|
|
Loading…
Add table
Reference in a new issue