| ... | ... |
@@ -39,7 +39,7 @@ func main() {
|
| 39 | 39 |
flDefaultIp = flag.String([]string{"#ip", "-ip"}, "0.0.0.0", "Default IP address to use when binding container ports")
|
| 40 | 40 |
flInterContainerComm = flag.Bool([]string{"#icc", "-icc"}, true, "Enable inter-container communication")
|
| 41 | 41 |
flGraphDriver = flag.String([]string{"s", "-storage-driver"}, "", "Force the docker runtime to use a specific storage driver")
|
| 42 |
- flExecDriver = flag.String([]string{"e", "-exec-driver"}, "", "Force the docker runtime to use a specific exec driver")
|
|
| 42 |
+ flExecDriver = flag.String([]string{"e", "-exec-driver"}, "native", "Force the docker runtime to use a specific exec driver")
|
|
| 43 | 43 |
flHosts = opts.NewListOpts(api.ValidateHost) |
| 44 | 44 |
flMtu = flag.Int([]string{"#mtu", "-mtu"}, 0, "Set the containers network MTU; if no value is provided: default to the default route MTU or 1500 if no default route is available")
|
| 45 | 45 |
) |
| 46 | 46 |
deleted file mode 100644 |
| ... | ... |
@@ -1,41 +0,0 @@ |
| 1 |
-package docker |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "github.com/dotcloud/docker/pkg/cgroups" |
|
| 5 |
- "github.com/dotcloud/docker/pkg/libcontainer" |
|
| 6 |
-) |
|
| 7 |
- |
|
| 8 |
-// getDefaultTemplate returns the docker default for |
|
| 9 |
-// the libcontainer configuration file |
|
| 10 |
-func getDefaultTemplate() *libcontainer.Container {
|
|
| 11 |
- return &libcontainer.Container{
|
|
| 12 |
- Capabilities: libcontainer.Capabilities{
|
|
| 13 |
- libcontainer.CAP_SETPCAP, |
|
| 14 |
- libcontainer.CAP_SYS_MODULE, |
|
| 15 |
- libcontainer.CAP_SYS_RAWIO, |
|
| 16 |
- libcontainer.CAP_SYS_PACCT, |
|
| 17 |
- libcontainer.CAP_SYS_ADMIN, |
|
| 18 |
- libcontainer.CAP_SYS_NICE, |
|
| 19 |
- libcontainer.CAP_SYS_RESOURCE, |
|
| 20 |
- libcontainer.CAP_SYS_TIME, |
|
| 21 |
- libcontainer.CAP_SYS_TTY_CONFIG, |
|
| 22 |
- libcontainer.CAP_MKNOD, |
|
| 23 |
- libcontainer.CAP_AUDIT_WRITE, |
|
| 24 |
- libcontainer.CAP_AUDIT_CONTROL, |
|
| 25 |
- libcontainer.CAP_MAC_ADMIN, |
|
| 26 |
- libcontainer.CAP_MAC_OVERRIDE, |
|
| 27 |
- libcontainer.CAP_NET_ADMIN, |
|
| 28 |
- }, |
|
| 29 |
- Namespaces: libcontainer.Namespaces{
|
|
| 30 |
- libcontainer.CLONE_NEWIPC, |
|
| 31 |
- libcontainer.CLONE_NEWNET, |
|
| 32 |
- libcontainer.CLONE_NEWNS, |
|
| 33 |
- libcontainer.CLONE_NEWPID, |
|
| 34 |
- libcontainer.CLONE_NEWUTS, |
|
| 35 |
- }, |
|
| 36 |
- Cgroups: &cgroups.Cgroup{
|
|
| 37 |
- Parent: "docker", |
|
| 38 |
- DeviceAccess: false, |
|
| 39 |
- }, |
|
| 40 |
- } |
|
| 41 |
-} |
| 42 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,315 +0,0 @@ |
| 1 |
-package docker |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "encoding/json" |
|
| 5 |
- "errors" |
|
| 6 |
- "fmt" |
|
| 7 |
- "github.com/dotcloud/docker/execdriver" |
|
| 8 |
- "github.com/dotcloud/docker/execdriver/lxc" |
|
| 9 |
- "github.com/dotcloud/docker/pkg/cgroups" |
|
| 10 |
- "github.com/dotcloud/docker/pkg/libcontainer" |
|
| 11 |
- "github.com/dotcloud/docker/pkg/libcontainer/nsinit" |
|
| 12 |
- "io" |
|
| 13 |
- "io/ioutil" |
|
| 14 |
- "log" |
|
| 15 |
- "os" |
|
| 16 |
- "os/exec" |
|
| 17 |
- "path/filepath" |
|
| 18 |
- "strconv" |
|
| 19 |
- "strings" |
|
| 20 |
- "syscall" |
|
| 21 |
-) |
|
| 22 |
- |
|
| 23 |
-const ( |
|
| 24 |
- DriverName = "namespaces" |
|
| 25 |
- Version = "0.1" |
|
| 26 |
-) |
|
| 27 |
- |
|
| 28 |
-var ( |
|
| 29 |
- ErrNotSupported = errors.New("not supported")
|
|
| 30 |
- noOpLog = log.New(ioutil.Discard, "[nsinit] ", log.LstdFlags) |
|
| 31 |
-) |
|
| 32 |
- |
|
| 33 |
-func init() {
|
|
| 34 |
- execdriver.RegisterInitFunc(DriverName, func(args *execdriver.InitArgs) error {
|
|
| 35 |
- var container *libcontainer.Container |
|
| 36 |
- f, err := os.Open("container.json")
|
|
| 37 |
- if err != nil {
|
|
| 38 |
- return err |
|
| 39 |
- } |
|
| 40 |
- if err := json.NewDecoder(f).Decode(&container); err != nil {
|
|
| 41 |
- f.Close() |
|
| 42 |
- return err |
|
| 43 |
- } |
|
| 44 |
- f.Close() |
|
| 45 |
- |
|
| 46 |
- cwd, err := os.Getwd() |
|
| 47 |
- if err != nil {
|
|
| 48 |
- return err |
|
| 49 |
- } |
|
| 50 |
- syncPipe, err := nsinit.NewSyncPipeFromFd(0, uintptr(args.Pipe)) |
|
| 51 |
- if err != nil {
|
|
| 52 |
- return err |
|
| 53 |
- } |
|
| 54 |
- ns := nsinit.NewNsInit(noOpLog, "", &nsinit.DefaultCommandFactory{}, &nsinit.DefaultStateWriter{})
|
|
| 55 |
- if err := ns.Init(container, cwd, args.Console, syncPipe, args.Args); err != nil {
|
|
| 56 |
- return err |
|
| 57 |
- } |
|
| 58 |
- return nil |
|
| 59 |
- }) |
|
| 60 |
-} |
|
| 61 |
- |
|
| 62 |
-type driver struct {
|
|
| 63 |
- root string |
|
| 64 |
-} |
|
| 65 |
- |
|
| 66 |
-type info struct {
|
|
| 67 |
- ID string |
|
| 68 |
- driver *driver |
|
| 69 |
-} |
|
| 70 |
- |
|
| 71 |
-func (i *info) IsRunning() bool {
|
|
| 72 |
- p := filepath.Join(i.driver.root, "containers", i.ID, "root", ".nspid") |
|
| 73 |
- if _, err := os.Stat(p); err == nil {
|
|
| 74 |
- return true |
|
| 75 |
- } |
|
| 76 |
- return false |
|
| 77 |
-} |
|
| 78 |
- |
|
| 79 |
-func NewDriver(root string) (*driver, error) {
|
|
| 80 |
- return &driver{
|
|
| 81 |
- root: root, |
|
| 82 |
- }, nil |
|
| 83 |
-} |
|
| 84 |
- |
|
| 85 |
-func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
|
|
| 86 |
- var ( |
|
| 87 |
- term nsinit.Terminal |
|
| 88 |
- container = createContainer(c) |
|
| 89 |
- factory = &dockerCommandFactory{c}
|
|
| 90 |
- stateWriter = &dockerStateWriter{
|
|
| 91 |
- callback: startCallback, |
|
| 92 |
- c: c, |
|
| 93 |
- dsw: &nsinit.DefaultStateWriter{c.Rootfs},
|
|
| 94 |
- } |
|
| 95 |
- ) |
|
| 96 |
- ns := nsinit.NewNsInit(noOpLog, "", factory, stateWriter) |
|
| 97 |
- if c.Tty {
|
|
| 98 |
- term = &dockerTtyTerm{
|
|
| 99 |
- pipes: pipes, |
|
| 100 |
- } |
|
| 101 |
- } else {
|
|
| 102 |
- term = &dockerStdTerm{
|
|
| 103 |
- pipes: pipes, |
|
| 104 |
- } |
|
| 105 |
- } |
|
| 106 |
- c.Terminal = term |
|
| 107 |
- if err := writeContainerFile(container, c.Rootfs); err != nil {
|
|
| 108 |
- return -1, err |
|
| 109 |
- } |
|
| 110 |
- args := append([]string{c.Entrypoint}, c.Arguments...)
|
|
| 111 |
- return ns.Exec(container, term, args) |
|
| 112 |
-} |
|
| 113 |
- |
|
| 114 |
-func (d *driver) Kill(p *execdriver.Command, sig int) error {
|
|
| 115 |
- return syscall.Kill(p.Process.Pid, syscall.Signal(sig)) |
|
| 116 |
-} |
|
| 117 |
- |
|
| 118 |
-func (d *driver) Restore(c *execdriver.Command) error {
|
|
| 119 |
- var ( |
|
| 120 |
- nspid int |
|
| 121 |
- p = filepath.Join(d.root, "containers", c.ID, "root", ".nspid") |
|
| 122 |
- ) |
|
| 123 |
- f, err := os.Open(p) |
|
| 124 |
- if err != nil {
|
|
| 125 |
- return err |
|
| 126 |
- } |
|
| 127 |
- defer f.Close() |
|
| 128 |
- if _, err := fmt.Fscanf(f, "%d", &nspid); err != nil {
|
|
| 129 |
- return err |
|
| 130 |
- } |
|
| 131 |
- proc, err := os.FindProcess(nspid) |
|
| 132 |
- if err != nil {
|
|
| 133 |
- return err |
|
| 134 |
- } |
|
| 135 |
- _, err = proc.Wait() |
|
| 136 |
- return err |
|
| 137 |
-} |
|
| 138 |
- |
|
| 139 |
-func (d *driver) Info(id string) execdriver.Info {
|
|
| 140 |
- return &info{
|
|
| 141 |
- ID: id, |
|
| 142 |
- driver: d, |
|
| 143 |
- } |
|
| 144 |
-} |
|
| 145 |
- |
|
| 146 |
-func (d *driver) Name() string {
|
|
| 147 |
- return fmt.Sprintf("%s-%s", DriverName, Version)
|
|
| 148 |
-} |
|
| 149 |
- |
|
| 150 |
-func (d *driver) GetPidsForContainer(id string) ([]int, error) {
|
|
| 151 |
- pids := []int{}
|
|
| 152 |
- |
|
| 153 |
- subsystem := "devices" |
|
| 154 |
- cgroupRoot, err := cgroups.FindCgroupMountpoint(subsystem) |
|
| 155 |
- if err != nil {
|
|
| 156 |
- return pids, err |
|
| 157 |
- } |
|
| 158 |
- cgroupDir, err := cgroups.GetThisCgroupDir(subsystem) |
|
| 159 |
- if err != nil {
|
|
| 160 |
- return pids, err |
|
| 161 |
- } |
|
| 162 |
- |
|
| 163 |
- filename := filepath.Join(cgroupRoot, cgroupDir, id, "tasks") |
|
| 164 |
- if _, err := os.Stat(filename); os.IsNotExist(err) {
|
|
| 165 |
- filename = filepath.Join(cgroupRoot, cgroupDir, "docker", id, "tasks") |
|
| 166 |
- } |
|
| 167 |
- |
|
| 168 |
- output, err := ioutil.ReadFile(filename) |
|
| 169 |
- if err != nil {
|
|
| 170 |
- return pids, err |
|
| 171 |
- } |
|
| 172 |
- for _, p := range strings.Split(string(output), "\n") {
|
|
| 173 |
- if len(p) == 0 {
|
|
| 174 |
- continue |
|
| 175 |
- } |
|
| 176 |
- pid, err := strconv.Atoi(p) |
|
| 177 |
- if err != nil {
|
|
| 178 |
- return pids, fmt.Errorf("Invalid pid '%s': %s", p, err)
|
|
| 179 |
- } |
|
| 180 |
- pids = append(pids, pid) |
|
| 181 |
- } |
|
| 182 |
- return pids, nil |
|
| 183 |
-} |
|
| 184 |
- |
|
| 185 |
-func writeContainerFile(container *libcontainer.Container, rootfs string) error {
|
|
| 186 |
- data, err := json.Marshal(container) |
|
| 187 |
- if err != nil {
|
|
| 188 |
- return err |
|
| 189 |
- } |
|
| 190 |
- return ioutil.WriteFile(filepath.Join(rootfs, "container.json"), data, 0755) |
|
| 191 |
-} |
|
| 192 |
- |
|
| 193 |
-func getEnv(key string, env []string) string {
|
|
| 194 |
- for _, pair := range env {
|
|
| 195 |
- parts := strings.Split(pair, "=") |
|
| 196 |
- if parts[0] == key {
|
|
| 197 |
- return parts[1] |
|
| 198 |
- } |
|
| 199 |
- } |
|
| 200 |
- return "" |
|
| 201 |
-} |
|
| 202 |
- |
|
| 203 |
-type dockerCommandFactory struct {
|
|
| 204 |
- c *execdriver.Command |
|
| 205 |
-} |
|
| 206 |
- |
|
| 207 |
-// createCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces |
|
| 208 |
-// defined on the container's configuration and use the current binary as the init with the |
|
| 209 |
-// args provided |
|
| 210 |
-func (d *dockerCommandFactory) Create(container *libcontainer.Container, |
|
| 211 |
- console, logFile string, syncFd uintptr, args []string) *exec.Cmd {
|
|
| 212 |
- c := d.c |
|
| 213 |
- // we need to join the rootfs because nsinit will setup the rootfs and chroot |
|
| 214 |
- initPath := filepath.Join(c.Rootfs, c.InitPath) |
|
| 215 |
- |
|
| 216 |
- c.Path = initPath |
|
| 217 |
- c.Args = append([]string{
|
|
| 218 |
- initPath, |
|
| 219 |
- "-driver", DriverName, |
|
| 220 |
- "-console", console, |
|
| 221 |
- "-pipe", fmt.Sprint(syncFd), |
|
| 222 |
- "-log", logFile, |
|
| 223 |
- }, args...) |
|
| 224 |
- c.SysProcAttr = &syscall.SysProcAttr{
|
|
| 225 |
- Cloneflags: uintptr(nsinit.GetNamespaceFlags(container.Namespaces)), |
|
| 226 |
- } |
|
| 227 |
- c.Env = container.Env |
|
| 228 |
- c.Dir = c.Rootfs |
|
| 229 |
- |
|
| 230 |
- return &c.Cmd |
|
| 231 |
-} |
|
| 232 |
- |
|
| 233 |
-type dockerStateWriter struct {
|
|
| 234 |
- dsw nsinit.StateWriter |
|
| 235 |
- c *execdriver.Command |
|
| 236 |
- callback execdriver.StartCallback |
|
| 237 |
-} |
|
| 238 |
- |
|
| 239 |
-func (d *dockerStateWriter) WritePid(pid int) error {
|
|
| 240 |
- err := d.dsw.WritePid(pid) |
|
| 241 |
- if d.callback != nil {
|
|
| 242 |
- d.callback(d.c) |
|
| 243 |
- } |
|
| 244 |
- return err |
|
| 245 |
-} |
|
| 246 |
- |
|
| 247 |
-func (d *dockerStateWriter) DeletePid() error {
|
|
| 248 |
- return d.dsw.DeletePid() |
|
| 249 |
-} |
|
| 250 |
- |
|
| 251 |
-func createContainer(c *execdriver.Command) *libcontainer.Container {
|
|
| 252 |
- container := getDefaultTemplate() |
|
| 253 |
- |
|
| 254 |
- container.Hostname = getEnv("HOSTNAME", c.Env)
|
|
| 255 |
- container.Tty = c.Tty |
|
| 256 |
- container.User = c.User |
|
| 257 |
- container.WorkingDir = c.WorkingDir |
|
| 258 |
- container.Env = c.Env |
|
| 259 |
- |
|
| 260 |
- container.Env = append(container.Env, "container=docker") |
|
| 261 |
- |
|
| 262 |
- if c.Network != nil {
|
|
| 263 |
- container.Network = &libcontainer.Network{
|
|
| 264 |
- Mtu: c.Network.Mtu, |
|
| 265 |
- Address: fmt.Sprintf("%s/%d", c.Network.IPAddress, c.Network.IPPrefixLen),
|
|
| 266 |
- Gateway: c.Network.Gateway, |
|
| 267 |
- Type: "veth", |
|
| 268 |
- Context: libcontainer.Context{
|
|
| 269 |
- "prefix": "dock", |
|
| 270 |
- "bridge": c.Network.Bridge, |
|
| 271 |
- }, |
|
| 272 |
- } |
|
| 273 |
- } |
|
| 274 |
- container.Cgroups.Name = c.ID |
|
| 275 |
- if c.Privileged {
|
|
| 276 |
- container.Capabilities = nil |
|
| 277 |
- container.Cgroups.DeviceAccess = true |
|
| 278 |
- } |
|
| 279 |
- if c.Resources != nil {
|
|
| 280 |
- container.Cgroups.CpuShares = c.Resources.CpuShares |
|
| 281 |
- container.Cgroups.Memory = c.Resources.Memory |
|
| 282 |
- container.Cgroups.MemorySwap = c.Resources.MemorySwap |
|
| 283 |
- } |
|
| 284 |
- return container |
|
| 285 |
-} |
|
| 286 |
- |
|
| 287 |
-type dockerStdTerm struct {
|
|
| 288 |
- lxc.StdConsole |
|
| 289 |
- pipes *execdriver.Pipes |
|
| 290 |
-} |
|
| 291 |
- |
|
| 292 |
-func (d *dockerStdTerm) Attach(cmd *exec.Cmd) error {
|
|
| 293 |
- return d.AttachPipes(cmd, d.pipes) |
|
| 294 |
-} |
|
| 295 |
- |
|
| 296 |
-func (d *dockerStdTerm) SetMaster(master *os.File) {
|
|
| 297 |
- // do nothing |
|
| 298 |
-} |
|
| 299 |
- |
|
| 300 |
-type dockerTtyTerm struct {
|
|
| 301 |
- lxc.TtyConsole |
|
| 302 |
- pipes *execdriver.Pipes |
|
| 303 |
-} |
|
| 304 |
- |
|
| 305 |
-func (t *dockerTtyTerm) Attach(cmd *exec.Cmd) error {
|
|
| 306 |
- go io.Copy(t.pipes.Stdout, t.MasterPty) |
|
| 307 |
- if t.pipes.Stdin != nil {
|
|
| 308 |
- go io.Copy(t.MasterPty, t.pipes.Stdin) |
|
| 309 |
- } |
|
| 310 |
- return nil |
|
| 311 |
-} |
|
| 312 |
- |
|
| 313 |
-func (t *dockerTtyTerm) SetMaster(master *os.File) {
|
|
| 314 |
- t.MasterPty = master |
|
| 315 |
-} |
| 316 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,26 +0,0 @@ |
| 1 |
-package docker |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "github.com/dotcloud/docker/execdriver" |
|
| 5 |
- "github.com/dotcloud/docker/pkg/term" |
|
| 6 |
- "os" |
|
| 7 |
-) |
|
| 8 |
- |
|
| 9 |
-type NsinitTerm struct {
|
|
| 10 |
- master *os.File |
|
| 11 |
-} |
|
| 12 |
- |
|
| 13 |
-func NewTerm(pipes *execdriver.Pipes, master *os.File) *NsinitTerm {
|
|
| 14 |
- return &NsinitTerm{master}
|
|
| 15 |
-} |
|
| 16 |
- |
|
| 17 |
-func (t *NsinitTerm) Close() error {
|
|
| 18 |
- return t.master.Close() |
|
| 19 |
-} |
|
| 20 |
- |
|
| 21 |
-func (t *NsinitTerm) Resize(h, w int) error {
|
|
| 22 |
- if t.master != nil {
|
|
| 23 |
- return term.SetWinsize(t.master.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
|
|
| 24 |
- } |
|
| 25 |
- return nil |
|
| 26 |
-} |
| 27 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,41 @@ |
| 0 |
+package native |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "github.com/dotcloud/docker/pkg/cgroups" |
|
| 4 |
+ "github.com/dotcloud/docker/pkg/libcontainer" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+// getDefaultTemplate returns the docker default for |
|
| 8 |
+// the libcontainer configuration file |
|
| 9 |
+func getDefaultTemplate() *libcontainer.Container {
|
|
| 10 |
+ return &libcontainer.Container{
|
|
| 11 |
+ Capabilities: libcontainer.Capabilities{
|
|
| 12 |
+ libcontainer.CAP_SETPCAP, |
|
| 13 |
+ libcontainer.CAP_SYS_MODULE, |
|
| 14 |
+ libcontainer.CAP_SYS_RAWIO, |
|
| 15 |
+ libcontainer.CAP_SYS_PACCT, |
|
| 16 |
+ libcontainer.CAP_SYS_ADMIN, |
|
| 17 |
+ libcontainer.CAP_SYS_NICE, |
|
| 18 |
+ libcontainer.CAP_SYS_RESOURCE, |
|
| 19 |
+ libcontainer.CAP_SYS_TIME, |
|
| 20 |
+ libcontainer.CAP_SYS_TTY_CONFIG, |
|
| 21 |
+ libcontainer.CAP_MKNOD, |
|
| 22 |
+ libcontainer.CAP_AUDIT_WRITE, |
|
| 23 |
+ libcontainer.CAP_AUDIT_CONTROL, |
|
| 24 |
+ libcontainer.CAP_MAC_ADMIN, |
|
| 25 |
+ libcontainer.CAP_MAC_OVERRIDE, |
|
| 26 |
+ libcontainer.CAP_NET_ADMIN, |
|
| 27 |
+ }, |
|
| 28 |
+ Namespaces: libcontainer.Namespaces{
|
|
| 29 |
+ libcontainer.CLONE_NEWIPC, |
|
| 30 |
+ libcontainer.CLONE_NEWNET, |
|
| 31 |
+ libcontainer.CLONE_NEWNS, |
|
| 32 |
+ libcontainer.CLONE_NEWPID, |
|
| 33 |
+ libcontainer.CLONE_NEWUTS, |
|
| 34 |
+ }, |
|
| 35 |
+ Cgroups: &cgroups.Cgroup{
|
|
| 36 |
+ Parent: "docker", |
|
| 37 |
+ DeviceAccess: false, |
|
| 38 |
+ }, |
|
| 39 |
+ } |
|
| 40 |
+} |
| 0 | 41 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,315 @@ |
| 0 |
+package native |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "encoding/json" |
|
| 4 |
+ "errors" |
|
| 5 |
+ "fmt" |
|
| 6 |
+ "github.com/dotcloud/docker/execdriver" |
|
| 7 |
+ "github.com/dotcloud/docker/execdriver/lxc" |
|
| 8 |
+ "github.com/dotcloud/docker/pkg/cgroups" |
|
| 9 |
+ "github.com/dotcloud/docker/pkg/libcontainer" |
|
| 10 |
+ "github.com/dotcloud/docker/pkg/libcontainer/nsinit" |
|
| 11 |
+ "io" |
|
| 12 |
+ "io/ioutil" |
|
| 13 |
+ "log" |
|
| 14 |
+ "os" |
|
| 15 |
+ "os/exec" |
|
| 16 |
+ "path/filepath" |
|
| 17 |
+ "strconv" |
|
| 18 |
+ "strings" |
|
| 19 |
+ "syscall" |
|
| 20 |
+) |
|
| 21 |
+ |
|
| 22 |
+const ( |
|
| 23 |
+ DriverName = "namespaces" |
|
| 24 |
+ Version = "0.1" |
|
| 25 |
+) |
|
| 26 |
+ |
|
| 27 |
+var ( |
|
| 28 |
+ ErrNotSupported = errors.New("not supported")
|
|
| 29 |
+ noOpLog = log.New(ioutil.Discard, "[nsinit] ", log.LstdFlags) |
|
| 30 |
+) |
|
| 31 |
+ |
|
| 32 |
+func init() {
|
|
| 33 |
+ execdriver.RegisterInitFunc(DriverName, func(args *execdriver.InitArgs) error {
|
|
| 34 |
+ var container *libcontainer.Container |
|
| 35 |
+ f, err := os.Open("container.json")
|
|
| 36 |
+ if err != nil {
|
|
| 37 |
+ return err |
|
| 38 |
+ } |
|
| 39 |
+ if err := json.NewDecoder(f).Decode(&container); err != nil {
|
|
| 40 |
+ f.Close() |
|
| 41 |
+ return err |
|
| 42 |
+ } |
|
| 43 |
+ f.Close() |
|
| 44 |
+ |
|
| 45 |
+ cwd, err := os.Getwd() |
|
| 46 |
+ if err != nil {
|
|
| 47 |
+ return err |
|
| 48 |
+ } |
|
| 49 |
+ syncPipe, err := nsinit.NewSyncPipeFromFd(0, uintptr(args.Pipe)) |
|
| 50 |
+ if err != nil {
|
|
| 51 |
+ return err |
|
| 52 |
+ } |
|
| 53 |
+ ns := nsinit.NewNsInit(noOpLog, "", &nsinit.DefaultCommandFactory{}, &nsinit.DefaultStateWriter{})
|
|
| 54 |
+ if err := ns.Init(container, cwd, args.Console, syncPipe, args.Args); err != nil {
|
|
| 55 |
+ return err |
|
| 56 |
+ } |
|
| 57 |
+ return nil |
|
| 58 |
+ }) |
|
| 59 |
+} |
|
| 60 |
+ |
|
| 61 |
+type driver struct {
|
|
| 62 |
+ root string |
|
| 63 |
+} |
|
| 64 |
+ |
|
| 65 |
+type info struct {
|
|
| 66 |
+ ID string |
|
| 67 |
+ driver *driver |
|
| 68 |
+} |
|
| 69 |
+ |
|
| 70 |
+func (i *info) IsRunning() bool {
|
|
| 71 |
+ p := filepath.Join(i.driver.root, "containers", i.ID, "root", ".nspid") |
|
| 72 |
+ if _, err := os.Stat(p); err == nil {
|
|
| 73 |
+ return true |
|
| 74 |
+ } |
|
| 75 |
+ return false |
|
| 76 |
+} |
|
| 77 |
+ |
|
| 78 |
+func NewDriver(root string) (*driver, error) {
|
|
| 79 |
+ return &driver{
|
|
| 80 |
+ root: root, |
|
| 81 |
+ }, nil |
|
| 82 |
+} |
|
| 83 |
+ |
|
| 84 |
+func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
|
|
| 85 |
+ var ( |
|
| 86 |
+ term nsinit.Terminal |
|
| 87 |
+ container = createContainer(c) |
|
| 88 |
+ factory = &dockerCommandFactory{c}
|
|
| 89 |
+ stateWriter = &dockerStateWriter{
|
|
| 90 |
+ callback: startCallback, |
|
| 91 |
+ c: c, |
|
| 92 |
+ dsw: &nsinit.DefaultStateWriter{c.Rootfs},
|
|
| 93 |
+ } |
|
| 94 |
+ ) |
|
| 95 |
+ ns := nsinit.NewNsInit(noOpLog, "", factory, stateWriter) |
|
| 96 |
+ if c.Tty {
|
|
| 97 |
+ term = &dockerTtyTerm{
|
|
| 98 |
+ pipes: pipes, |
|
| 99 |
+ } |
|
| 100 |
+ } else {
|
|
| 101 |
+ term = &dockerStdTerm{
|
|
| 102 |
+ pipes: pipes, |
|
| 103 |
+ } |
|
| 104 |
+ } |
|
| 105 |
+ c.Terminal = term |
|
| 106 |
+ if err := writeContainerFile(container, c.Rootfs); err != nil {
|
|
| 107 |
+ return -1, err |
|
| 108 |
+ } |
|
| 109 |
+ args := append([]string{c.Entrypoint}, c.Arguments...)
|
|
| 110 |
+ return ns.Exec(container, term, args) |
|
| 111 |
+} |
|
| 112 |
+ |
|
| 113 |
+func (d *driver) Kill(p *execdriver.Command, sig int) error {
|
|
| 114 |
+ return syscall.Kill(p.Process.Pid, syscall.Signal(sig)) |
|
| 115 |
+} |
|
| 116 |
+ |
|
| 117 |
+func (d *driver) Restore(c *execdriver.Command) error {
|
|
| 118 |
+ var ( |
|
| 119 |
+ nspid int |
|
| 120 |
+ p = filepath.Join(d.root, "containers", c.ID, "root", ".nspid") |
|
| 121 |
+ ) |
|
| 122 |
+ f, err := os.Open(p) |
|
| 123 |
+ if err != nil {
|
|
| 124 |
+ return err |
|
| 125 |
+ } |
|
| 126 |
+ defer f.Close() |
|
| 127 |
+ if _, err := fmt.Fscanf(f, "%d", &nspid); err != nil {
|
|
| 128 |
+ return err |
|
| 129 |
+ } |
|
| 130 |
+ proc, err := os.FindProcess(nspid) |
|
| 131 |
+ if err != nil {
|
|
| 132 |
+ return err |
|
| 133 |
+ } |
|
| 134 |
+ _, err = proc.Wait() |
|
| 135 |
+ return err |
|
| 136 |
+} |
|
| 137 |
+ |
|
| 138 |
+func (d *driver) Info(id string) execdriver.Info {
|
|
| 139 |
+ return &info{
|
|
| 140 |
+ ID: id, |
|
| 141 |
+ driver: d, |
|
| 142 |
+ } |
|
| 143 |
+} |
|
| 144 |
+ |
|
| 145 |
+func (d *driver) Name() string {
|
|
| 146 |
+ return fmt.Sprintf("%s-%s", DriverName, Version)
|
|
| 147 |
+} |
|
| 148 |
+ |
|
| 149 |
+func (d *driver) GetPidsForContainer(id string) ([]int, error) {
|
|
| 150 |
+ pids := []int{}
|
|
| 151 |
+ |
|
| 152 |
+ subsystem := "devices" |
|
| 153 |
+ cgroupRoot, err := cgroups.FindCgroupMountpoint(subsystem) |
|
| 154 |
+ if err != nil {
|
|
| 155 |
+ return pids, err |
|
| 156 |
+ } |
|
| 157 |
+ cgroupDir, err := cgroups.GetThisCgroupDir(subsystem) |
|
| 158 |
+ if err != nil {
|
|
| 159 |
+ return pids, err |
|
| 160 |
+ } |
|
| 161 |
+ |
|
| 162 |
+ filename := filepath.Join(cgroupRoot, cgroupDir, id, "tasks") |
|
| 163 |
+ if _, err := os.Stat(filename); os.IsNotExist(err) {
|
|
| 164 |
+ filename = filepath.Join(cgroupRoot, cgroupDir, "docker", id, "tasks") |
|
| 165 |
+ } |
|
| 166 |
+ |
|
| 167 |
+ output, err := ioutil.ReadFile(filename) |
|
| 168 |
+ if err != nil {
|
|
| 169 |
+ return pids, err |
|
| 170 |
+ } |
|
| 171 |
+ for _, p := range strings.Split(string(output), "\n") {
|
|
| 172 |
+ if len(p) == 0 {
|
|
| 173 |
+ continue |
|
| 174 |
+ } |
|
| 175 |
+ pid, err := strconv.Atoi(p) |
|
| 176 |
+ if err != nil {
|
|
| 177 |
+ return pids, fmt.Errorf("Invalid pid '%s': %s", p, err)
|
|
| 178 |
+ } |
|
| 179 |
+ pids = append(pids, pid) |
|
| 180 |
+ } |
|
| 181 |
+ return pids, nil |
|
| 182 |
+} |
|
| 183 |
+ |
|
| 184 |
+func writeContainerFile(container *libcontainer.Container, rootfs string) error {
|
|
| 185 |
+ data, err := json.Marshal(container) |
|
| 186 |
+ if err != nil {
|
|
| 187 |
+ return err |
|
| 188 |
+ } |
|
| 189 |
+ return ioutil.WriteFile(filepath.Join(rootfs, "container.json"), data, 0755) |
|
| 190 |
+} |
|
| 191 |
+ |
|
| 192 |
+func getEnv(key string, env []string) string {
|
|
| 193 |
+ for _, pair := range env {
|
|
| 194 |
+ parts := strings.Split(pair, "=") |
|
| 195 |
+ if parts[0] == key {
|
|
| 196 |
+ return parts[1] |
|
| 197 |
+ } |
|
| 198 |
+ } |
|
| 199 |
+ return "" |
|
| 200 |
+} |
|
| 201 |
+ |
|
| 202 |
+type dockerCommandFactory struct {
|
|
| 203 |
+ c *execdriver.Command |
|
| 204 |
+} |
|
| 205 |
+ |
|
| 206 |
+// createCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces |
|
| 207 |
+// defined on the container's configuration and use the current binary as the init with the |
|
| 208 |
+// args provided |
|
| 209 |
+func (d *dockerCommandFactory) Create(container *libcontainer.Container, |
|
| 210 |
+ console, logFile string, syncFd uintptr, args []string) *exec.Cmd {
|
|
| 211 |
+ c := d.c |
|
| 212 |
+ // we need to join the rootfs because nsinit will setup the rootfs and chroot |
|
| 213 |
+ initPath := filepath.Join(c.Rootfs, c.InitPath) |
|
| 214 |
+ |
|
| 215 |
+ c.Path = initPath |
|
| 216 |
+ c.Args = append([]string{
|
|
| 217 |
+ initPath, |
|
| 218 |
+ "-driver", DriverName, |
|
| 219 |
+ "-console", console, |
|
| 220 |
+ "-pipe", fmt.Sprint(syncFd), |
|
| 221 |
+ "-log", logFile, |
|
| 222 |
+ }, args...) |
|
| 223 |
+ c.SysProcAttr = &syscall.SysProcAttr{
|
|
| 224 |
+ Cloneflags: uintptr(nsinit.GetNamespaceFlags(container.Namespaces)), |
|
| 225 |
+ } |
|
| 226 |
+ c.Env = container.Env |
|
| 227 |
+ c.Dir = c.Rootfs |
|
| 228 |
+ |
|
| 229 |
+ return &c.Cmd |
|
| 230 |
+} |
|
| 231 |
+ |
|
| 232 |
+type dockerStateWriter struct {
|
|
| 233 |
+ dsw nsinit.StateWriter |
|
| 234 |
+ c *execdriver.Command |
|
| 235 |
+ callback execdriver.StartCallback |
|
| 236 |
+} |
|
| 237 |
+ |
|
| 238 |
+func (d *dockerStateWriter) WritePid(pid int) error {
|
|
| 239 |
+ err := d.dsw.WritePid(pid) |
|
| 240 |
+ if d.callback != nil {
|
|
| 241 |
+ d.callback(d.c) |
|
| 242 |
+ } |
|
| 243 |
+ return err |
|
| 244 |
+} |
|
| 245 |
+ |
|
| 246 |
+func (d *dockerStateWriter) DeletePid() error {
|
|
| 247 |
+ return d.dsw.DeletePid() |
|
| 248 |
+} |
|
| 249 |
+ |
|
| 250 |
+func createContainer(c *execdriver.Command) *libcontainer.Container {
|
|
| 251 |
+ container := getDefaultTemplate() |
|
| 252 |
+ |
|
| 253 |
+ container.Hostname = getEnv("HOSTNAME", c.Env)
|
|
| 254 |
+ container.Tty = c.Tty |
|
| 255 |
+ container.User = c.User |
|
| 256 |
+ container.WorkingDir = c.WorkingDir |
|
| 257 |
+ container.Env = c.Env |
|
| 258 |
+ |
|
| 259 |
+ container.Env = append(container.Env, "container=docker") |
|
| 260 |
+ |
|
| 261 |
+ if c.Network != nil {
|
|
| 262 |
+ container.Network = &libcontainer.Network{
|
|
| 263 |
+ Mtu: c.Network.Mtu, |
|
| 264 |
+ Address: fmt.Sprintf("%s/%d", c.Network.IPAddress, c.Network.IPPrefixLen),
|
|
| 265 |
+ Gateway: c.Network.Gateway, |
|
| 266 |
+ Type: "veth", |
|
| 267 |
+ Context: libcontainer.Context{
|
|
| 268 |
+ "prefix": "dock", |
|
| 269 |
+ "bridge": c.Network.Bridge, |
|
| 270 |
+ }, |
|
| 271 |
+ } |
|
| 272 |
+ } |
|
| 273 |
+ container.Cgroups.Name = c.ID |
|
| 274 |
+ if c.Privileged {
|
|
| 275 |
+ container.Capabilities = nil |
|
| 276 |
+ container.Cgroups.DeviceAccess = true |
|
| 277 |
+ } |
|
| 278 |
+ if c.Resources != nil {
|
|
| 279 |
+ container.Cgroups.CpuShares = c.Resources.CpuShares |
|
| 280 |
+ container.Cgroups.Memory = c.Resources.Memory |
|
| 281 |
+ container.Cgroups.MemorySwap = c.Resources.MemorySwap |
|
| 282 |
+ } |
|
| 283 |
+ return container |
|
| 284 |
+} |
|
| 285 |
+ |
|
| 286 |
+type dockerStdTerm struct {
|
|
| 287 |
+ lxc.StdConsole |
|
| 288 |
+ pipes *execdriver.Pipes |
|
| 289 |
+} |
|
| 290 |
+ |
|
| 291 |
+func (d *dockerStdTerm) Attach(cmd *exec.Cmd) error {
|
|
| 292 |
+ return d.AttachPipes(cmd, d.pipes) |
|
| 293 |
+} |
|
| 294 |
+ |
|
| 295 |
+func (d *dockerStdTerm) SetMaster(master *os.File) {
|
|
| 296 |
+ // do nothing |
|
| 297 |
+} |
|
| 298 |
+ |
|
| 299 |
+type dockerTtyTerm struct {
|
|
| 300 |
+ lxc.TtyConsole |
|
| 301 |
+ pipes *execdriver.Pipes |
|
| 302 |
+} |
|
| 303 |
+ |
|
| 304 |
+func (t *dockerTtyTerm) Attach(cmd *exec.Cmd) error {
|
|
| 305 |
+ go io.Copy(t.pipes.Stdout, t.MasterPty) |
|
| 306 |
+ if t.pipes.Stdin != nil {
|
|
| 307 |
+ go io.Copy(t.MasterPty, t.pipes.Stdin) |
|
| 308 |
+ } |
|
| 309 |
+ return nil |
|
| 310 |
+} |
|
| 311 |
+ |
|
| 312 |
+func (t *dockerTtyTerm) SetMaster(master *os.File) {
|
|
| 313 |
+ t.MasterPty = master |
|
| 314 |
+} |
| 0 | 315 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,26 @@ |
| 0 |
+package native |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "github.com/dotcloud/docker/execdriver" |
|
| 4 |
+ "github.com/dotcloud/docker/pkg/term" |
|
| 5 |
+ "os" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+type NsinitTerm struct {
|
|
| 9 |
+ master *os.File |
|
| 10 |
+} |
|
| 11 |
+ |
|
| 12 |
+func NewTerm(pipes *execdriver.Pipes, master *os.File) *NsinitTerm {
|
|
| 13 |
+ return &NsinitTerm{master}
|
|
| 14 |
+} |
|
| 15 |
+ |
|
| 16 |
+func (t *NsinitTerm) Close() error {
|
|
| 17 |
+ return t.master.Close() |
|
| 18 |
+} |
|
| 19 |
+ |
|
| 20 |
+func (t *NsinitTerm) Resize(h, w int) error {
|
|
| 21 |
+ if t.master != nil {
|
|
| 22 |
+ return term.SetWinsize(t.master.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
|
|
| 23 |
+ } |
|
| 24 |
+ return nil |
|
| 25 |
+} |
| ... | ... |
@@ -7,8 +7,8 @@ import ( |
| 7 | 7 |
"github.com/dotcloud/docker/dockerversion" |
| 8 | 8 |
"github.com/dotcloud/docker/engine" |
| 9 | 9 |
"github.com/dotcloud/docker/execdriver" |
| 10 |
- "github.com/dotcloud/docker/execdriver/docker" |
|
| 11 | 10 |
"github.com/dotcloud/docker/execdriver/lxc" |
| 11 |
+ "github.com/dotcloud/docker/execdriver/native" |
|
| 12 | 12 |
"github.com/dotcloud/docker/graphdriver" |
| 13 | 13 |
"github.com/dotcloud/docker/graphdriver/aufs" |
| 14 | 14 |
_ "github.com/dotcloud/docker/graphdriver/btrfs" |
| ... | ... |
@@ -702,17 +702,18 @@ func NewRuntimeFromDirectory(config *DaemonConfig, eng *engine.Engine) (*Runtime |
| 702 | 702 |
sysInitPath = localCopy |
| 703 | 703 |
} |
| 704 | 704 |
|
| 705 |
- sysInfo := sysinfo.New(false) |
|
| 705 |
+ var ( |
|
| 706 |
+ ed execdriver.Driver |
|
| 707 |
+ sysInfo = sysinfo.New(false) |
|
| 708 |
+ ) |
|
| 706 | 709 |
|
| 707 |
- var ed execdriver.Driver |
|
| 708 |
- utils.Debugf("execDriver: provided %s", config.ExecDriver)
|
|
| 709 |
- if config.ExecDriver == "chroot" && false {
|
|
| 710 |
- // chroot is presently a noop driver https://github.com/dotcloud/docker/pull/4189#issuecomment-35330655 |
|
| 711 |
- ed, err = chroot.NewDriver() |
|
| 712 |
- utils.Debugf("execDriver: using chroot")
|
|
| 713 |
- } else {
|
|
| 710 |
+ switch config.ExecDriver {
|
|
| 711 |
+ case "lxc": |
|
| 714 | 712 |
ed, err = lxc.NewDriver(config.Root, sysInfo.AppArmor) |
| 715 |
- utils.Debugf("execDriver: using lxc")
|
|
| 713 |
+ case "native": |
|
| 714 |
+ ed, err = native.NewDriver(config.Root) |
|
| 715 |
+ default: |
|
| 716 |
+ return nil, fmt.Errorf("unknow exec driver %s", config.ExecDriver)
|
|
| 716 | 717 |
} |
| 717 | 718 |
if err != nil {
|
| 718 | 719 |
return nil, err |