github.com/christopherobin/docker@v1.6.2/daemon/execdriver/lxc/lxc_template.go (about)

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