github.com/clintkitson/docker@v1.9.1/daemon/execdriver/lxc/lxc_template.go (about)

     1  // +build linux
     2  
     3  package lxc
     4  
     5  import (
     6  	"fmt"
     7  	"os"
     8  	"strings"
     9  	"text/template"
    10  
    11  	"github.com/Sirupsen/logrus"
    12  	"github.com/docker/docker/daemon/execdriver"
    13  	nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template"
    14  	"github.com/docker/docker/pkg/stringutils"
    15  	"github.com/opencontainers/runc/libcontainer/label"
    16  )
    17  
    18  // LxcTemplate is the template for lxc driver, it's used
    19  // to configure LXC.
    20  const LxcTemplate = `
    21  lxc.network.type = none
    22  # root filesystem
    23  {{$ROOTFS := .Rootfs}}
    24  lxc.rootfs = {{$ROOTFS}}
    25  
    26  # use a dedicated pts for the container (and limit the number of pseudo terminal
    27  # available)
    28  lxc.pts = 1024
    29  
    30  # disable the main console
    31  lxc.console = none
    32  
    33  # no controlling tty at all
    34  lxc.tty = 1
    35  
    36  {{if .ProcessConfig.Privileged}}
    37  lxc.cgroup.devices.allow = a
    38  {{else}}
    39  # no implicit access to devices
    40  lxc.cgroup.devices.deny = a
    41  #Allow the devices passed to us in the AllowedDevices list.
    42  {{range $allowedDevice := .AllowedDevices}}
    43  lxc.cgroup.devices.allow = {{$allowedDevice.CgroupString}}
    44  {{end}}
    45  {{end}}
    46  
    47  # standard mount point
    48  # Use mnt.putold as per https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/986385
    49  lxc.pivotdir = lxc_putold
    50  
    51  # lxc.autodev is not compatible with lxc --device switch
    52  lxc.autodev = 0
    53  
    54  # NOTICE: These mounts must be applied within the namespace
    55  {{if .ProcessConfig.Privileged}}
    56  # WARNING: mounting procfs and/or sysfs read-write is a known attack vector.
    57  # See e.g. http://blog.zx2c4.com/749 and https://bit.ly/T9CkqJ
    58  # We mount them read-write here, but later, dockerinit will call the Restrict() function to remount them read-only.
    59  # We cannot mount them directly read-only, because that would prevent loading AppArmor profiles.
    60  lxc.mount.entry = proc {{escapeFstabSpaces $ROOTFS}}/proc proc nosuid,nodev,noexec 0 0
    61  lxc.mount.entry = sysfs {{escapeFstabSpaces $ROOTFS}}/sys sysfs nosuid,nodev,noexec 0 0
    62  	{{if .AppArmor}}
    63  lxc.aa_profile = unconfined
    64  	{{end}}
    65  {{else}}
    66  # In non-privileged mode, lxc will automatically mount /proc and /sys in readonly mode
    67  # for security. See: http://man7.org/linux/man-pages/man5/lxc.container.conf.5.html
    68  lxc.mount.auto = proc sys
    69  	{{if .AppArmorProfile}}
    70  lxc.aa_profile = {{.AppArmorProfile}}
    71  	{{end}}
    72  {{end}}
    73  
    74  {{if .ProcessConfig.Tty}}
    75  lxc.mount.entry = {{.ProcessConfig.Console}} {{escapeFstabSpaces $ROOTFS}}/dev/console none bind,rw,create=file 0 0
    76  {{end}}
    77  
    78  lxc.mount.entry = devpts {{escapeFstabSpaces $ROOTFS}}/dev/pts devpts {{formatMountLabel "newinstance,ptmxmode=0666,nosuid,noexec,create=dir" ""}} 0 0
    79  lxc.mount.entry = shm {{escapeFstabSpaces $ROOTFS}}/dev/shm tmpfs {{formatMountLabel "size=65536k,nosuid,nodev,noexec,create=dir" ""}} 0 0
    80  
    81  {{range $value := .Mounts}}
    82  {{$createVal := isDirectory $value.Source}}
    83  {{if $value.Writable}}
    84  lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabSpaces $value.Destination}} none rbind,rw,create={{$createVal}} 0 0
    85  {{else}}
    86  lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabSpaces $value.Destination}} none rbind,ro,create={{$createVal}} 0 0
    87  {{end}}
    88  {{end}}
    89  
    90  # limits
    91  {{if .Resources}}
    92  {{if .Resources.Memory}}
    93  lxc.cgroup.memory.limit_in_bytes = {{.Resources.Memory}}
    94  {{end}}
    95  {{if gt .Resources.MemorySwap 0}}
    96  lxc.cgroup.memory.memsw.limit_in_bytes = {{.Resources.MemorySwap}}
    97  {{end}}
    98  {{if gt .Resources.MemoryReservation 0}}
    99  lxc.cgroup.memory.soft_limit_in_bytes = {{.Resources.MemoryReservation}}
   100  {{end}}
   101  {{if gt .Resources.KernelMemory 0}}
   102  lxc.cgroup.memory.kmem.limit_in_bytes = {{.Resources.KernelMemory}}
   103  {{end}}
   104  {{if .Resources.CPUShares}}
   105  lxc.cgroup.cpu.shares = {{.Resources.CPUShares}}
   106  {{end}}
   107  {{if .Resources.CPUPeriod}}
   108  lxc.cgroup.cpu.cfs_period_us = {{.Resources.CPUPeriod}}
   109  {{end}}
   110  {{if .Resources.CpusetCpus}}
   111  lxc.cgroup.cpuset.cpus = {{.Resources.CpusetCpus}}
   112  {{end}}
   113  {{if .Resources.CpusetMems}}
   114  lxc.cgroup.cpuset.mems = {{.Resources.CpusetMems}}
   115  {{end}}
   116  {{if .Resources.CPUQuota}}
   117  lxc.cgroup.cpu.cfs_quota_us = {{.Resources.CPUQuota}}
   118  {{end}}
   119  {{if .Resources.BlkioWeight}}
   120  lxc.cgroup.blkio.weight = {{.Resources.BlkioWeight}}
   121  {{end}}
   122  {{if .Resources.OomKillDisable}}
   123  lxc.cgroup.memory.oom_control = {{.Resources.OomKillDisable}}
   124  {{end}}
   125  {{if gt .Resources.MemorySwappiness 0}}
   126  lxc.cgroup.memory.swappiness = {{.Resources.MemorySwappiness}}
   127  {{end}}
   128  {{end}}
   129  
   130  {{if .LxcConfig}}
   131  {{range $value := .LxcConfig}}
   132  lxc.{{$value}}
   133  {{end}}
   134  {{end}}
   135  
   136  {{if .ProcessConfig.Env}}
   137  lxc.utsname = {{getHostname .ProcessConfig.Env}}
   138  {{end}}
   139  
   140  {{if .ProcessConfig.Privileged}}
   141  # No cap values are needed, as lxc is starting in privileged mode
   142  {{else}}
   143  	{{ with keepCapabilities .CapAdd .CapDrop }}
   144  		{{range .}}
   145  lxc.cap.keep = {{.}}
   146  		{{end}}
   147  	{{else}}
   148  		{{ with dropList .CapDrop }}
   149  		{{range .}}
   150  lxc.cap.drop = {{.}}
   151  		{{end}}
   152  		{{end}}
   153  	{{end}}
   154  {{end}}
   155  `
   156  
   157  var lxcTemplateCompiled *template.Template
   158  
   159  // Escape spaces in strings according to the fstab documentation, which is the
   160  // format for "lxc.mount.entry" lines in lxc.conf. See also "man 5 fstab".
   161  func escapeFstabSpaces(field string) string {
   162  	return strings.Replace(field, " ", "\\040", -1)
   163  }
   164  
   165  func keepCapabilities(adds []string, drops []string) ([]string, error) {
   166  	container := nativeTemplate.New()
   167  	logrus.Debugf("adds %s drops %s\n", adds, drops)
   168  	caps, err := execdriver.TweakCapabilities(container.Capabilities, adds, drops)
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  	var newCaps []string
   173  	for _, cap := range caps {
   174  		logrus.Debugf("cap %s\n", cap)
   175  		realCap := execdriver.GetCapability(cap)
   176  		numCap := fmt.Sprintf("%d", realCap.Value)
   177  		newCaps = append(newCaps, numCap)
   178  	}
   179  
   180  	return newCaps, nil
   181  }
   182  
   183  func dropList(drops []string) ([]string, error) {
   184  	if stringutils.InSlice(drops, "all") {
   185  		var newCaps []string
   186  		for _, capName := range execdriver.GetAllCapabilities() {
   187  			cap := execdriver.GetCapability(capName)
   188  			logrus.Debugf("drop cap %s\n", cap.Key)
   189  			numCap := fmt.Sprintf("%d", cap.Value)
   190  			newCaps = append(newCaps, numCap)
   191  		}
   192  		return newCaps, nil
   193  	}
   194  	return []string{}, nil
   195  }
   196  
   197  func isDirectory(source string) string {
   198  	f, err := os.Stat(source)
   199  	logrus.Debugf("dir: %s\n", source)
   200  	if err != nil {
   201  		if os.IsNotExist(err) {
   202  			return "dir"
   203  		}
   204  		return ""
   205  	}
   206  	if f.IsDir() {
   207  		return "dir"
   208  	}
   209  	return "file"
   210  }
   211  
   212  func getLabel(c map[string][]string, name string) string {
   213  	label := c["label"]
   214  	for _, l := range label {
   215  		parts := strings.SplitN(l, "=", 2)
   216  		if strings.TrimSpace(parts[0]) == name {
   217  			return strings.TrimSpace(parts[1])
   218  		}
   219  	}
   220  	return ""
   221  }
   222  
   223  func getHostname(env []string) string {
   224  	for _, kv := range env {
   225  		parts := strings.SplitN(kv, "=", 2)
   226  		if parts[0] == "HOSTNAME" && len(parts) == 2 {
   227  			return parts[1]
   228  		}
   229  	}
   230  	return ""
   231  }
   232  
   233  func init() {
   234  	var err error
   235  	funcMap := template.FuncMap{
   236  		"escapeFstabSpaces": escapeFstabSpaces,
   237  		"formatMountLabel":  label.FormatMountLabel,
   238  		"isDirectory":       isDirectory,
   239  		"keepCapabilities":  keepCapabilities,
   240  		"dropList":          dropList,
   241  		"getHostname":       getHostname,
   242  	}
   243  	lxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate)
   244  	if err != nil {
   245  		panic(err)
   246  	}
   247  }