lxc_template.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. package lxc
  2. import (
  3. "github.com/docker/docker/daemon/execdriver"
  4. nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template"
  5. "github.com/docker/libcontainer/label"
  6. "os"
  7. "strings"
  8. "text/template"
  9. )
  10. const LxcTemplate = `
  11. {{if .Network.Interface}}
  12. # network configuration
  13. lxc.network.type = veth
  14. lxc.network.link = {{.Network.Interface.Bridge}}
  15. lxc.network.name = eth0
  16. lxc.network.mtu = {{.Network.Mtu}}
  17. lxc.network.flags = up
  18. {{else if .Network.HostNetworking}}
  19. lxc.network.type = none
  20. {{else}}
  21. # network is disabled (-n=false)
  22. lxc.network.type = empty
  23. lxc.network.flags = up
  24. lxc.network.mtu = {{.Network.Mtu}}
  25. {{end}}
  26. # root filesystem
  27. {{$ROOTFS := .Rootfs}}
  28. lxc.rootfs = {{$ROOTFS}}
  29. # use a dedicated pts for the container (and limit the number of pseudo terminal
  30. # available)
  31. lxc.pts = 1024
  32. # disable the main console
  33. lxc.console = none
  34. # no controlling tty at all
  35. lxc.tty = 1
  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.GetCgroupAllowString}}
  44. {{end}}
  45. {{end}}
  46. # standard mount point
  47. # Use mnt.putold as per https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/986385
  48. lxc.pivotdir = lxc_putold
  49. # NOTICE: These mounts must be applied within the namespace
  50. # WARNING: mounting procfs and/or sysfs read-write is a known attack vector.
  51. # See e.g. http://blog.zx2c4.com/749 and http://bit.ly/T9CkqJ
  52. # We mount them read-write here, but later, dockerinit will call the Restrict() function to remount them read-only.
  53. # We cannot mount them directly read-only, because that would prevent loading AppArmor profiles.
  54. lxc.mount.entry = proc {{escapeFstabSpaces $ROOTFS}}/proc proc nosuid,nodev,noexec 0 0
  55. lxc.mount.entry = sysfs {{escapeFstabSpaces $ROOTFS}}/sys sysfs nosuid,nodev,noexec 0 0
  56. {{if .ProcessConfig.Tty}}
  57. lxc.mount.entry = {{.ProcessConfig.Console}} {{escapeFstabSpaces $ROOTFS}}/dev/console none bind,rw 0 0
  58. {{end}}
  59. lxc.mount.entry = devpts {{escapeFstabSpaces $ROOTFS}}/dev/pts devpts {{formatMountLabel "newinstance,ptmxmode=0666,nosuid,noexec" ""}} 0 0
  60. lxc.mount.entry = shm {{escapeFstabSpaces $ROOTFS}}/dev/shm tmpfs {{formatMountLabel "size=65536k,nosuid,nodev,noexec" ""}} 0 0
  61. {{range $value := .Mounts}}
  62. {{$createVal := isDirectory $value.Source}}
  63. {{if $value.Writable}}
  64. lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabSpaces $value.Destination}} none rbind,rw,create={{$createVal}} 0 0
  65. {{else}}
  66. lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabSpaces $value.Destination}} none rbind,ro,create={{$createVal}} 0 0
  67. {{end}}
  68. {{end}}
  69. {{if .ProcessConfig.Privileged}}
  70. {{if .AppArmor}}
  71. lxc.aa_profile = unconfined
  72. {{else}}
  73. # Let AppArmor normal confinement take place (i.e., not unconfined)
  74. {{end}}
  75. {{end}}
  76. # limits
  77. {{if .Resources}}
  78. {{if .Resources.Memory}}
  79. lxc.cgroup.memory.limit_in_bytes = {{.Resources.Memory}}
  80. lxc.cgroup.memory.soft_limit_in_bytes = {{.Resources.Memory}}
  81. {{with $memSwap := getMemorySwap .Resources}}
  82. lxc.cgroup.memory.memsw.limit_in_bytes = {{$memSwap}}
  83. {{end}}
  84. {{end}}
  85. {{if .Resources.CpuShares}}
  86. lxc.cgroup.cpu.shares = {{.Resources.CpuShares}}
  87. {{end}}
  88. {{if .Resources.Cpuset}}
  89. lxc.cgroup.cpuset.cpus = {{.Resources.Cpuset}}
  90. {{end}}
  91. {{end}}
  92. {{if .LxcConfig}}
  93. {{range $value := .LxcConfig}}
  94. lxc.{{$value}}
  95. {{end}}
  96. {{end}}
  97. {{if .Network.Interface}}
  98. {{if .Network.Interface.IPAddress}}
  99. lxc.network.ipv4 = {{.Network.Interface.IPAddress}}/{{.Network.Interface.IPPrefixLen}}
  100. {{end}}
  101. {{if .Network.Interface.Gateway}}
  102. lxc.network.ipv4.gateway = {{.Network.Interface.Gateway}}
  103. {{end}}
  104. {{if .ProcessConfig.Env}}
  105. lxc.utsname = {{getHostname .ProcessConfig.Env}}
  106. {{end}}
  107. {{if .ProcessConfig.Privileged}}
  108. # No cap values are needed, as lxc is starting in privileged mode
  109. {{else}}
  110. {{range $value := keepCapabilities .CapAdd .CapDrop}}
  111. lxc.cap.keep = {{$value}}
  112. {{end}}
  113. {{end}}
  114. {{end}}
  115. `
  116. var LxcTemplateCompiled *template.Template
  117. // Escape spaces in strings according to the fstab documentation, which is the
  118. // format for "lxc.mount.entry" lines in lxc.conf. See also "man 5 fstab".
  119. func escapeFstabSpaces(field string) string {
  120. return strings.Replace(field, " ", "\\040", -1)
  121. }
  122. func keepCapabilities(adds []string, drops []string) []string {
  123. container := nativeTemplate.New()
  124. caps, err := execdriver.TweakCapabilities(container.Capabilities, adds, drops)
  125. var newCaps []string
  126. for _, cap := range caps {
  127. newCaps = append(newCaps, strings.ToLower(cap))
  128. }
  129. if err != nil {
  130. return []string{}
  131. }
  132. return newCaps
  133. }
  134. func isDirectory(source string) string {
  135. f, err := os.Stat(source)
  136. if err != nil {
  137. if os.IsNotExist(err) {
  138. return "dir"
  139. }
  140. return ""
  141. }
  142. if f.IsDir() {
  143. return "dir"
  144. }
  145. return "file"
  146. }
  147. func getMemorySwap(v *execdriver.Resources) int64 {
  148. // By default, MemorySwap is set to twice the size of RAM.
  149. // If you want to omit MemorySwap, set it to `-1'.
  150. if v.MemorySwap < 0 {
  151. return 0
  152. }
  153. return v.Memory * 2
  154. }
  155. func getLabel(c map[string][]string, name string) string {
  156. label := c["label"]
  157. for _, l := range label {
  158. parts := strings.SplitN(l, "=", 2)
  159. if strings.TrimSpace(parts[0]) == name {
  160. return strings.TrimSpace(parts[1])
  161. }
  162. }
  163. return ""
  164. }
  165. func getHostname(env []string) string {
  166. for _, kv := range env {
  167. parts := strings.SplitN(kv, "=", 2)
  168. if parts[0] == "HOSTNAME" && len(parts) == 2 {
  169. return parts[1]
  170. }
  171. }
  172. return ""
  173. }
  174. func init() {
  175. var err error
  176. funcMap := template.FuncMap{
  177. "getMemorySwap": getMemorySwap,
  178. "escapeFstabSpaces": escapeFstabSpaces,
  179. "formatMountLabel": label.FormatMountLabel,
  180. "isDirectory": isDirectory,
  181. "keepCapabilities": keepCapabilities,
  182. "getHostname": getHostname,
  183. }
  184. LxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate)
  185. if err != nil {
  186. panic(err)
  187. }
  188. }