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