mirror of https://github.com/docker/docs.git
apply selinux labels volume patch on volumes refactor
Signed-off-by: Jessica Frazelle <princess@docker.com>
This commit is contained in:
parent
160dc79db0
commit
af7d17a6c9
|
@ -6,11 +6,14 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/pkg/chrootarchive"
|
"github.com/docker/docker/pkg/chrootarchive"
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
"github.com/docker/docker/volume"
|
"github.com/docker/docker/volume"
|
||||||
|
"github.com/docker/libcontainer/label"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mountPoint struct {
|
type mountPoint struct {
|
||||||
|
@ -50,7 +53,7 @@ func (m *mountPoint) Path() string {
|
||||||
return m.Source
|
return m.Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseBindMount(spec string, config *runconfig.Config) (*mountPoint, error) {
|
func parseBindMount(spec string, mountLabel string, config *runconfig.Config) (*mountPoint, error) {
|
||||||
bind := &mountPoint{
|
bind := &mountPoint{
|
||||||
RW: true,
|
RW: true,
|
||||||
}
|
}
|
||||||
|
@ -61,10 +64,17 @@ func parseBindMount(spec string, config *runconfig.Config) (*mountPoint, error)
|
||||||
bind.Destination = arr[1]
|
bind.Destination = arr[1]
|
||||||
case 3:
|
case 3:
|
||||||
bind.Destination = arr[1]
|
bind.Destination = arr[1]
|
||||||
if !validMountMode(arr[2]) {
|
mode := arr[2]
|
||||||
return nil, fmt.Errorf("invalid mode for volumes-from: %s", arr[2])
|
if !validMountMode(mode) {
|
||||||
|
return nil, fmt.Errorf("invalid mode for volumes-from: %s", mode)
|
||||||
|
}
|
||||||
|
bind.RW = rwModes[mode]
|
||||||
|
// check if we need to apply a SELinux label
|
||||||
|
if strings.ContainsAny(mode, "zZ") {
|
||||||
|
if err := label.Relabel(bind.Source, mountLabel, mode); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bind.RW = arr[2] == "rw"
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Invalid volume specification: %s", spec)
|
return nil, fmt.Errorf("Invalid volume specification: %s", spec)
|
||||||
}
|
}
|
||||||
|
@ -106,12 +116,28 @@ func parseVolumesFrom(spec string) (string, string, error) {
|
||||||
return id, mode, nil
|
return id, mode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// read-write modes
|
||||||
|
var rwModes = map[string]bool{
|
||||||
|
"rw": true,
|
||||||
|
"rw,Z": true,
|
||||||
|
"rw,z": true,
|
||||||
|
"z,rw": true,
|
||||||
|
"Z,rw": true,
|
||||||
|
"Z": true,
|
||||||
|
"z": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// read-only modes
|
||||||
|
var roModes = map[string]bool{
|
||||||
|
"ro": true,
|
||||||
|
"ro,Z": true,
|
||||||
|
"ro,z": true,
|
||||||
|
"z,ro": true,
|
||||||
|
"Z,ro": true,
|
||||||
|
}
|
||||||
|
|
||||||
func validMountMode(mode string) bool {
|
func validMountMode(mode string) bool {
|
||||||
validModes := map[string]bool{
|
return roModes[mode] || rwModes[mode]
|
||||||
"rw": true,
|
|
||||||
"ro": true,
|
|
||||||
}
|
|
||||||
return validModes[mode]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyExistingContents(source, destination string) error {
|
func copyExistingContents(source, destination string) error {
|
||||||
|
@ -177,10 +203,13 @@ func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lock for labels
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
// 3. Read bind mounts
|
// 3. Read bind mounts
|
||||||
for _, b := range hostConfig.Binds {
|
for _, b := range hostConfig.Binds {
|
||||||
// #10618
|
// #10618
|
||||||
bind, err := parseBindMount(b, container.Config)
|
bind, err := parseBindMount(b, container.MountLabel, container.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -190,11 +219,26 @@ func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runc
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(bind.Name) > 0 && len(bind.Driver) > 0 {
|
if len(bind.Name) > 0 && len(bind.Driver) > 0 {
|
||||||
|
// set the label
|
||||||
|
if err := label.SetFileCreateLabel(container.MountLabel); err != nil {
|
||||||
|
return fmt.Errorf("Unable to setup default labeling for volume creation %s: %v", bind.Source, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the volume
|
||||||
v, err := createVolume(bind.Name, bind.Driver)
|
v, err := createVolume(bind.Name, bind.Driver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// reset the label
|
||||||
|
if e := label.SetFileCreateLabel(""); e != nil {
|
||||||
|
logrus.Errorf("Unable to reset labeling for volume creation %s: %v", bind.Source, e)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
bind.Volume = v
|
bind.Volume = v
|
||||||
|
|
||||||
|
// reset the label
|
||||||
|
if err := label.SetFileCreateLabel(""); err != nil {
|
||||||
|
return fmt.Errorf("Unable to reset labeling for volume creation %s: %v", bind.Source, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binds[bind.Destination] = true
|
binds[bind.Destination] = true
|
||||||
|
@ -250,7 +294,6 @@ func (daemon *Daemon) verifyOldVolumesInfo(container *Container) error {
|
||||||
|
|
||||||
func createVolume(name, driverName string) (volume.Volume, error) {
|
func createVolume(name, driverName string) (volume.Volume, error) {
|
||||||
vd, err := getVolumeDriver(driverName)
|
vd, err := getVolumeDriver(driverName)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,28 +34,29 @@ func TestGetVolumeDriver(t *testing.T) {
|
||||||
|
|
||||||
func TestParseBindMount(t *testing.T) {
|
func TestParseBindMount(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
bind string
|
bind string
|
||||||
driver string
|
driver string
|
||||||
expDest string
|
expDest string
|
||||||
expSource string
|
expSource string
|
||||||
expName string
|
expName string
|
||||||
expDriver string
|
expDriver string
|
||||||
expRW bool
|
mountLabel string
|
||||||
fail bool
|
expRW bool
|
||||||
|
fail bool
|
||||||
}{
|
}{
|
||||||
{"/tmp:/tmp", "", "/tmp", "/tmp", "", "", true, false},
|
{"/tmp:/tmp", "", "/tmp", "/tmp", "", "", "", true, false},
|
||||||
{"/tmp:/tmp:ro", "", "/tmp", "/tmp", "", "", false, false},
|
{"/tmp:/tmp:ro", "", "/tmp", "/tmp", "", "", "", false, false},
|
||||||
{"/tmp:/tmp:rw", "", "/tmp", "/tmp", "", "", true, false},
|
{"/tmp:/tmp:rw", "", "/tmp", "/tmp", "", "", "", true, false},
|
||||||
{"/tmp:/tmp:foo", "", "/tmp", "/tmp", "", "", false, true},
|
{"/tmp:/tmp:foo", "", "/tmp", "/tmp", "", "", "", false, true},
|
||||||
{"name:/tmp", "", "/tmp", "", "name", "local", true, false},
|
{"name:/tmp", "", "/tmp", "", "name", "local", "", true, false},
|
||||||
{"name:/tmp", "external", "/tmp", "", "name", "external", true, false},
|
{"name:/tmp", "external", "/tmp", "", "name", "external", "", true, false},
|
||||||
{"name:/tmp:ro", "local", "/tmp", "", "name", "local", false, false},
|
{"name:/tmp:ro", "local", "/tmp", "", "name", "local", "", false, false},
|
||||||
{"local/name:/tmp:rw", "", "/tmp", "", "local/name", "local", true, false},
|
{"local/name:/tmp:rw", "", "/tmp", "", "local/name", "local", "", true, false},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
conf := &runconfig.Config{VolumeDriver: c.driver}
|
conf := &runconfig.Config{VolumeDriver: c.driver}
|
||||||
m, err := parseBindMount(c.bind, conf)
|
m, err := parseBindMount(c.bind, c.mountLabel, conf)
|
||||||
if c.fail {
|
if c.fail {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error, was nil, for spec %s\n", c.bind)
|
t.Fatalf("Expected error, was nil, for spec %s\n", c.bind)
|
||||||
|
|
|
@ -37,24 +37,25 @@ func TestGetVolumeDefaultDriver(t *testing.T) {
|
||||||
|
|
||||||
func TestParseBindMount(t *testing.T) {
|
func TestParseBindMount(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
bind string
|
bind string
|
||||||
expDest string
|
expDest string
|
||||||
expSource string
|
expSource string
|
||||||
expName string
|
expName string
|
||||||
expRW bool
|
mountLabel string
|
||||||
fail bool
|
expRW bool
|
||||||
|
fail bool
|
||||||
}{
|
}{
|
||||||
{"/tmp:/tmp", "/tmp", "/tmp", "", true, false},
|
{"/tmp:/tmp", "/tmp", "/tmp", "", "", true, false},
|
||||||
{"/tmp:/tmp:ro", "/tmp", "/tmp", "", false, false},
|
{"/tmp:/tmp:ro", "/tmp", "/tmp", "", "", false, false},
|
||||||
{"/tmp:/tmp:rw", "/tmp", "/tmp", "", true, false},
|
{"/tmp:/tmp:rw", "/tmp", "/tmp", "", "", true, false},
|
||||||
{"/tmp:/tmp:foo", "/tmp", "/tmp", "", false, true},
|
{"/tmp:/tmp:foo", "/tmp", "/tmp", "", "", false, true},
|
||||||
{"name:/tmp", "", "", "", false, true},
|
{"name:/tmp", "", "", "", "", false, true},
|
||||||
{"local/name:/tmp:rw", "", "", "", true, true},
|
{"local/name:/tmp:rw", "", "", "", "", true, true},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
conf := &runconfig.Config{}
|
conf := &runconfig.Config{}
|
||||||
m, err := parseBindMount(c.bind, conf)
|
m, err := parseBindMount(c.bind, c.mountLabel, conf)
|
||||||
if c.fail {
|
if c.fail {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected error, was nil, for spec %s\n", c.bind)
|
t.Fatalf("Expected error, was nil, for spec %s\n", c.bind)
|
||||||
|
|
Loading…
Reference in New Issue