func (container *Container) startPty() error { ptyMaster, ptySlave, err := pty.Open() if err != nil { return err } container.ptyMaster = ptyMaster container.cmd.Stdout = ptySlave container.cmd.Stderr = ptySlave // Copy the PTYs to our broadcasters go func() { defer container.stdout.CloseWriters() utils.Debugf("[startPty] Begin of stdout pipe") io.Copy(container.stdout, ptyMaster) utils.Debugf("[startPty] End of stdout pipe") }() // stdin if container.Config.OpenStdin { container.cmd.Stdin = ptySlave container.cmd.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true} go func() { defer container.stdin.Close() utils.Debugf("[startPty] Begin of stdin pipe") io.Copy(ptyMaster, container.stdin) utils.Debugf("[startPty] End of stdin pipe") }() } if err := container.cmd.Start(); err != nil { return err } ptySlave.Close() return nil }
func makeHttpHandler(srv *Server, logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // log the request utils.Debugf("Calling %s %s", localMethod, localRoute) if logging { log.Println(r.Method, r.RequestURI) } if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") { userAgent := strings.Split(r.Header.Get("User-Agent"), "/") if len(userAgent) == 2 && userAgent[1] != VERSION { utils.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], VERSION) } } version, err := strconv.ParseFloat(mux.Vars(r)["version"], 64) if err != nil { version = APIVERSION } if srv.runtime.config.EnableCors { writeCorsHeaders(w, r) } if version == 0 || version > APIVERSION { w.WriteHeader(http.StatusNotFound) return } if err := handlerFunc(srv, version, w, r, mux.Vars(r)); err != nil { utils.Errorf("Error: %s", err) httpError(w, err) } } }
func (srv *Server) recursiveLoad(address, tmpImageDir string) error { if _, err := srv.ImageInspect(address); err != nil { utils.Debugf("Loading %s", address) imageJson, err := ioutil.ReadFile(path.Join(tmpImageDir, "repo", address, "json")) if err != nil { return err utils.Debugf("Error reading json", err) } layer, err := os.Open(path.Join(tmpImageDir, "repo", address, "layer.tar")) if err != nil { utils.Debugf("Error reading embedded tar", err) return err } img, err := NewImgJSON(imageJson) if err != nil { utils.Debugf("Error unmarshalling json", err) return err } if img.Parent != "" { if !srv.runtime.graph.Exists(img.Parent) { if err := srv.recursiveLoad(img.Parent, tmpImageDir); err != nil { return err } } } if err := srv.runtime.graph.Register(imageJson, layer, img); err != nil { return err } } utils.Debugf("Completed processing %s", address) return nil }
func (runtime *Runtime) restore() error { wheel := "-\\|/" if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" { fmt.Printf("Loading containers: ") } dir, err := ioutil.ReadDir(runtime.repository) if err != nil { return err } for i, v := range dir { id := v.Name() container, err := runtime.Load(id) if i%21 == 0 && os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" { fmt.Printf("\b%c", wheel[i%4]) } if err != nil { utils.Debugf("Failed to load container %v: %v", id, err) continue } utils.Debugf("Loaded container %v", container.ID) } if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" { fmt.Printf("\bdone.\n") } return nil }
func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, enableCors bool, dockerVersion version.Version) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // log the request utils.Debugf("Calling %s %s", localMethod, localRoute) if logging { log.Println(r.Method, r.RequestURI) } if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") { userAgent := strings.Split(r.Header.Get("User-Agent"), "/") if len(userAgent) == 2 && !dockerVersion.Equal(version.Version(userAgent[1])) { utils.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion) } } version := version.Version(mux.Vars(r)["version"]) if version == "" { version = api.APIVERSION } if enableCors { writeCorsHeaders(w, r) } if version.GreaterThan(api.APIVERSION) { http.Error(w, fmt.Errorf("client and server don't have same version (client : %s, server: %s)", version, api.APIVERSION).Error(), http.StatusNotFound) return } if err := handlerFunc(eng, version, w, r, mux.Vars(r)); err != nil { utils.Errorf("Error: %s", err) httpError(w, err) } } }
// waitRemove blocks until either: // a) the device registered at <device_set_prefix>-<hash> is removed, // or b) the 1 second timeout expires. func (devices *DeviceSet) waitRemove(hash string) error { utils.Debugf("[deviceset %s] waitRemove(%s)", devices.devicePrefix, hash) defer utils.Debugf("[deviceset %s] waitRemove(%) END", devices.devicePrefix, hash) devname, err := devices.byHash(hash) if err != nil { return err } i := 0 for ; i < 1000; i += 1 { devinfo, err := getInfo(devname) if err != nil { // If there is an error we assume the device doesn't exist. // The error might actually be something else, but we can't differentiate. return nil } if i%100 == 0 { utils.Debugf("Waiting for removal of %s: exists=%d", devname, devinfo.Exists) } if devinfo.Exists == 0 { break } time.Sleep(1 * time.Millisecond) } if i == 1000 { return fmt.Errorf("Timeout while waiting for device %s to be removed", devname) } return nil }
func (devices *DeviceSet) deactivateDevice(hash string) error { utils.Debugf("[devmapper] deactivateDevice(%s)", hash) defer utils.Debugf("[devmapper] deactivateDevice END") var devname string // FIXME: shouldn't we just register the pool into devices? devname, err := devices.byHash(hash) if err != nil { return err } devinfo, err := getInfo(devname) if err != nil { utils.Debugf("\n--->Err: %s\n", err) return err } if devinfo.Exists != 0 { if err := removeDevice(devname); err != nil { utils.Debugf("\n--->Err: %s\n", err) return err } if err := devices.waitRemove(hash); err != nil { return err } } return nil }
func (devices *DeviceSet) AddDevice(hash, baseHash string) error { devices.Lock() defer devices.Unlock() if devices.Devices[hash] != nil { return fmt.Errorf("hash %s already exists", hash) } baseInfo := devices.Devices[baseHash] if baseInfo == nil { return fmt.Errorf("Error adding device for '%s': can't find device for parent '%s'", hash, baseHash) } deviceId := devices.allocateDeviceId() if err := devices.createSnapDevice(devices.getPoolDevName(), deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil { utils.Debugf("Error creating snap device: %s\n", err) return err } if _, err := devices.registerDevice(deviceId, hash, baseInfo.Size); err != nil { deleteDevice(devices.getPoolDevName(), deviceId) utils.Debugf("Error registering device: %s\n", err) return err } return nil }
func (devices *DeviceSet) AddDevice(hash, baseHash string) error { baseInfo, err := devices.lookupDevice(baseHash) if err != nil { return err } baseInfo.lock.Lock() defer baseInfo.lock.Unlock() devices.Lock() defer devices.Unlock() if info, _ := devices.lookupDevice(hash); info != nil { return fmt.Errorf("device %s already exists", hash) } deviceId := devices.nextDeviceId if err := createSnapDevice(devices.getPoolDevName(), &deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil { utils.Debugf("Error creating snap device: %s\n", err) return err } // Ids are 24bit, so wrap around devices.nextDeviceId = (deviceId + 1) & 0xffffff if _, err := devices.registerDevice(deviceId, hash, baseInfo.Size); err != nil { deleteDevice(devices.getPoolDevName(), deviceId) utils.Debugf("Error registering device: %s\n", err) return err } return nil }
func (devices *DeviceSet) UnmountDevice(hash, path string, deactivate bool) error { utils.Debugf("[devmapper] UnmountDevice(hash=%s path=%s)", hash, path) defer utils.Debugf("[devmapper] UnmountDevice END") devices.Lock() defer devices.Unlock() utils.Debugf("[devmapper] Unmount(%s)", path) if err := sysUnmount(path, 0); err != nil { utils.Debugf("\n--->Err: %s\n", err) return err } utils.Debugf("[devmapper] Unmount done") // Wait for the unmount to be effective, // by watching the value of Info.OpenCount for the device if err := devices.waitClose(hash); err != nil { return err } if count := devices.activeMounts[path]; count > 1 { devices.activeMounts[path] = count - 1 } else { delete(devices.activeMounts, path) } if deactivate { devices.deactivateDevice(hash) } return nil }
// Untar reads a stream of bytes from `archive`, parses it as a tar archive, // and unpacks it into the directory at `path`. // The archive may be compressed with one of the following algorithms: // identity (uncompressed), gzip, bzip2, xz. // FIXME: specify behavior when target path exists vs. doesn't exist. func Untar(archive io.Reader, path string) error { if archive == nil { return fmt.Errorf("Empty archive") } buf := make([]byte, 10) totalN := 0 for totalN < 10 { n, err := archive.Read(buf[totalN:]) if err != nil { if err == io.EOF { return fmt.Errorf("Tarball too short") } return err } totalN += n utils.Debugf("[tar autodetect] n: %d", n) } compression := DetectCompression(buf) utils.Debugf("Archive compression detected: %s", compression.Extension()) cmd := exec.Command("tar", "--numeric-owner", "-f", "-", "-C", path, "-x"+compression.Flag()) cmd.Stdin = io.MultiReader(bytes.NewReader(buf), archive) // Hardcode locale environment for predictable outcome regardless of host configuration. // (see https://github.com/dotcloud/docker/issues/355) cmd.Env = []string{"LANG=en_US.utf-8", "LC_ALL=en_US.utf-8"} output, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("%s: %s", err, output) } return nil }
func DetectCompression(source []byte) Compression { for _, c := range source[:10] { utils.Debugf("%x", c) } sourceLen := len(source) for compression, m := range map[Compression][]byte{ Bzip2: {0x42, 0x5A, 0x68}, Gzip: {0x1F, 0x8B, 0x08}, Xz: {0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00}, } { fail := false if len(m) > sourceLen { utils.Debugf("Len too short") continue } i := 0 for _, b := range m { if b != source[i] { fail = true break } i++ } if !fail { return compression } } return Uncompressed }
func (proxy *UDPProxy) replyLoop(proxyConn *net.UDPConn, clientAddr *net.UDPAddr, clientKey *connTrackKey) { defer func() { proxy.connTrackLock.Lock() delete(proxy.connTrackTable, *clientKey) proxy.connTrackLock.Unlock() utils.Debugf("Done proxying between udp/%v and udp/%v", clientAddr.String(), proxy.backendAddr.String()) proxyConn.Close() }() readBuf := make([]byte, UDPBufSize) for { proxyConn.SetReadDeadline(time.Now().Add(UDPConnTrackTimeout)) again: read, err := proxyConn.Read(readBuf) if err != nil { if err, ok := err.(*net.OpError); ok && err.Err == syscall.ECONNREFUSED { // This will happen if the last write failed // (e.g: nothing is actually listening on the // proxied port on the container), ignore it // and continue until UDPConnTrackTimeout // expires: goto again } return } for i := 0; i != read; { written, err := proxy.listener.WriteToUDP(readBuf[i:read], clientAddr) if err != nil { return } i += written utils.Debugf("Forwarded %v/%v bytes to udp/%v", i, read, clientAddr.String()) } } }
func (b *buildFile) CmdRun(args string) error { if b.image == "" { return fmt.Errorf("Please provide a source image with `from` prior to run") } config, _, err := ParseRun([]string{b.image, "/bin/sh", "-c", args}, nil) if err != nil { return err } cmd := b.config.Cmd b.config.Cmd = nil MergeConfig(b.config, config) utils.Debugf("Command to be executed: %v", b.config.Cmd) if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil { return err } else if cache != nil { utils.Debugf("[BUILDER] Use cached version") b.image = cache.Id return nil } else { utils.Debugf("[BUILDER] Cache miss") } cid, err := b.run() if err != nil { return err } if err := b.commit(cid, cmd, "run"); err != nil { return err } b.config.Cmd = cmd return nil }
func spawnGlobalDaemon() { if globalRuntime != nil { utils.Debugf("Global runtime already exists. Skipping.") return } t := log.New(os.Stderr, "", 0) eng := NewTestEngine(t) globalEngine = eng globalRuntime = mkRuntimeFromEngine(eng, t) // Spawn a Daemon go func() { utils.Debugf("Spawning global daemon for integration tests") listenURL := &url.URL{ Scheme: testDaemonProto, Host: testDaemonAddr, } job := eng.Job("serveapi", listenURL.String()) job.SetenvBool("Logging", os.Getenv("DEBUG") != "") if err := job.Run(); err != nil { log.Fatalf("Unable to spawn the test daemon: %s", err) } }() // Give some time to ListenAndServer to actually start // FIXME: use inmem transports instead of tcp time.Sleep(time.Second) }
// FIXME: comment please! func (runtime *Runtime) UpdateCapabilities(quiet bool) { if cgroupMemoryMountpoint, err := utils.FindCgroupMountpoint("memory"); err != nil { if !quiet { log.Printf("WARNING: %s\n", err) } } else { _, err1 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.limit_in_bytes")) _, err2 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.soft_limit_in_bytes")) runtime.capabilities.MemoryLimit = err1 == nil && err2 == nil if !runtime.capabilities.MemoryLimit && !quiet { log.Printf("WARNING: Your kernel does not support cgroup memory limit.") } _, err = ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.memsw.limit_in_bytes")) runtime.capabilities.SwapLimit = err == nil if !runtime.capabilities.SwapLimit && !quiet { log.Printf("WARNING: Your kernel does not support cgroup swap limit.") } } content, err3 := ioutil.ReadFile("/proc/sys/net/ipv4/ip_forward") runtime.capabilities.IPv4ForwardingDisabled = err3 != nil || len(content) == 0 || content[0] != '1' if runtime.capabilities.IPv4ForwardingDisabled && !quiet { log.Printf("WARNING: IPv4 forwarding is disabled.") } // Check if AppArmor seems to be enabled on this system. if _, err := os.Stat("/sys/kernel/security/apparmor"); os.IsNotExist(err) { utils.Debugf("/sys/kernel/security/apparmor not found; assuming AppArmor is not enabled.") runtime.capabilities.AppArmor = false } else { utils.Debugf("/sys/kernel/security/apparmor found; assuming AppArmor is enabled.") runtime.capabilities.AppArmor = true } }
func (devices *DeviceSet) deactivateDevice(hash string) error { utils.Debugf("[devmapper] deactivateDevice(%s)", hash) defer utils.Debugf("[devmapper] deactivateDevice END") // Wait for the unmount to be effective, // by watching the value of Info.OpenCount for the device if err := devices.waitClose(hash); err != nil { utils.Errorf("Warning: error waiting for device %s to close: %s\n", hash, err) } info := devices.Devices[hash] if info == nil { return fmt.Errorf("Unknown device %s", hash) } devinfo, err := getInfo(info.Name()) if err != nil { utils.Debugf("\n--->Err: %s\n", err) return err } if devinfo.Exists != 0 { if err := devices.removeDeviceAndWait(info.Name()); err != nil { utils.Debugf("\n--->Err: %s\n", err) return err } } return nil }
func newTestRuntime(prefix string) (runtime *Runtime, err error) { if prefix == "" { prefix = "docker-test-" } utils.Debugf("prefix = %s", prefix) utils.Debugf("newTestRuntime start") root, err := ioutil.TempDir("", prefix) defer func() { utils.Debugf("newTestRuntime: %s", root) }() if err != nil { return nil, err } if err := os.Remove(root); err != nil { return nil, err } if err := utils.CopyDirectory(unitTestStoreBase, root); err != nil { return nil, err } config := &DaemonConfig{ GraphPath: root, AutoRestart: false, } runtime, err = NewRuntimeFromDirectory(config) if err != nil { return nil, err } runtime.UpdateCapabilities(true) return runtime, nil }
func (container *Container) setupPty() error { ptyMaster, ptySlave, err := pty.Open() if err != nil { return err } container.ptyMaster = ptyMaster container.command.Stdout = ptySlave container.command.Stderr = ptySlave // Copy the PTYs to our broadcasters go func() { defer container.stdout.CloseWriters() utils.Debugf("startPty: begin of stdout pipe") io.Copy(container.stdout, ptyMaster) utils.Debugf("startPty: end of stdout pipe") }() // stdin if container.Config.OpenStdin { container.command.Stdin = ptySlave container.command.SysProcAttr.Setctty = true go func() { defer container.stdin.Close() utils.Debugf("startPty: begin of stdin pipe") io.Copy(ptyMaster, container.stdin) utils.Debugf("startPty: end of stdin pipe") }() } return nil }
func (devices *DeviceSet) UnmountDevice(hash string, mode UnmountMode) error { utils.Debugf("[devmapper] UnmountDevice(hash=%s, mode=%d)", hash, mode) defer utils.Debugf("[devmapper] UnmountDevice END") devices.Lock() defer devices.Unlock() info := devices.Devices[hash] if info == nil { return fmt.Errorf("UnmountDevice: no such device %s\n", hash) } info.lock.Lock() defer info.lock.Unlock() if mode == UnmountFloat { if info.floating { return fmt.Errorf("UnmountDevice: can't float floating reference %s\n", hash) } // Leave this reference floating info.floating = true return nil } if mode == UnmountSink { if !info.floating { // Someone already sunk this return nil } // Otherwise, treat this as a regular unmount } if info.mountCount == 0 { return fmt.Errorf("UnmountDevice: device not-mounted id %s\n", hash) } info.mountCount-- if info.mountCount > 0 { return nil } utils.Debugf("[devmapper] Unmount(%s)", info.mountPath) if err := sysUnmount(info.mountPath, 0); err != nil { utils.Debugf("\n--->Err: %s\n", err) return err } utils.Debugf("[devmapper] Unmount done") // Wait for the unmount to be effective, // by watching the value of Info.OpenCount for the device if err := devices.waitClose(hash); err != nil { return err } devices.deactivateDevice(hash) info.mountPath = "" return nil }
func (runtime *Runtime) restore() error { wheel := "-\\|/" if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" { fmt.Printf("Loading containers: ") } dir, err := ioutil.ReadDir(runtime.repository) if err != nil { return err } containers := make(map[string]*Container) for i, v := range dir { id := v.Name() container, err := runtime.load(id) if i%21 == 0 && os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" { fmt.Printf("\b%c", wheel[i%4]) } if err != nil { utils.Errorf("Failed to load container %v: %v", id, err) continue } utils.Debugf("Loaded container %v", container.ID) containers[container.ID] = container } register := func(container *Container) { if err := runtime.Register(container); err != nil { utils.Debugf("Failed to register container %s: %s", container.ID, err) } } if entities := runtime.containerGraph.List("/", -1); entities != nil { for _, p := range entities.Paths() { e := entities[p] if container, ok := containers[e.ID()]; ok { register(container) delete(containers, e.ID()) } } } // Any containers that are left over do not exist in the graph for _, container := range containers { // Try to set the default name for a container if it exists prior to links name := generateRandomName(runtime) container.Name = name if _, err := runtime.containerGraph.Set(name, container.ID); err != nil { utils.Debugf("Setting default id - %s", err) } register(container) } if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" { fmt.Printf("\bdone.\n") } return nil }
func pingRegistryEndpoint(endpoint string) (RegistryInfo, error) { if endpoint == IndexServerAddress() { // Skip the check, we now this one is valid // (and we never want to fallback to http in case of error) return RegistryInfo{Standalone: false}, nil } httpDial := func(proto string, addr string) (net.Conn, error) { // Set the connect timeout to 5 seconds conn, err := net.DialTimeout(proto, addr, time.Duration(5)*time.Second) if err != nil { return nil, err } // Set the recv timeout to 10 seconds conn.SetDeadline(time.Now().Add(time.Duration(10) * time.Second)) return conn, nil } httpTransport := &http.Transport{ Dial: httpDial, Proxy: http.ProxyFromEnvironment, } client := &http.Client{Transport: httpTransport} resp, err := client.Get(endpoint + "_ping") if err != nil { return RegistryInfo{Standalone: false}, err } defer resp.Body.Close() jsonString, err := ioutil.ReadAll(resp.Body) if err != nil { return RegistryInfo{Standalone: false}, fmt.Errorf("Error while reading the http response: %s", err) } // If the header is absent, we assume true for compatibility with earlier // versions of the registry. default to true info := RegistryInfo{ Standalone: true, } if err := json.Unmarshal(jsonString, &info); err != nil { utils.Debugf("Error unmarshalling the _ping RegistryInfo: %s", err) // don't stop here. Just assume sane defaults } if hdr := resp.Header.Get("X-Docker-Registry-Version"); hdr != "" { utils.Debugf("Registry version header: '%s'", hdr) info.Version = hdr } utils.Debugf("RegistryInfo.Version: %q", info.Version) standalone := resp.Header.Get("X-Docker-Registry-Standalone") utils.Debugf("Registry standalone header: '%s'", standalone) // Accepted values are "true" (case-insensitive) and "1". if strings.EqualFold(standalone, "true") || standalone == "1" { info.Standalone = true } else if len(standalone) > 0 { // there is a header set, and it is not "true" or "1", so assume fails info.Standalone = false } utils.Debugf("RegistryInfo.Standalone: %q", info.Standalone) return info, nil }
// CreateBridgeIface creates a network bridge interface on the host system with the name `ifaceName`, // and attempts to configure it with an address which doesn't conflict with any other interface on the host. // If it can't find an address which doesn't conflict, it will return an error. func CreateBridgeIface(ifaceName string) error { addrs := []string{ // Here we don't follow the convention of using the 1st IP of the range for the gateway. // This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges. // In theory this shouldn't matter - in practice there's bound to be a few scripts relying // on the internal addressing or other stupid things like that. // The shouldn't, but hey, let's not break them unless we really have to. "172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23 "10.0.42.1/16", // Don't even try using the entire /8, that's too intrusive "10.1.42.1/16", "10.42.42.1/16", "172.16.42.1/24", "172.16.43.1/24", "172.16.44.1/24", "10.0.42.1/24", "10.0.43.1/24", "192.168.42.1/24", "192.168.43.1/24", "192.168.44.1/24", } var ifaceAddr string for _, addr := range addrs { _, dockerNetwork, err := net.ParseCIDR(addr) if err != nil { return err } routes, err := ip("route") if err != nil { return err } if err := checkRouteOverlaps(routes, dockerNetwork); err == nil { ifaceAddr = addr break } else { utils.Debugf("%s: %s", addr, err) } } if ifaceAddr == "" { return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", ifaceName, ifaceName) } utils.Debugf("Creating bridge %s with network %s", ifaceName, ifaceAddr) if output, err := ip("link", "add", ifaceName, "type", "bridge"); err != nil { return fmt.Errorf("Error creating bridge: %s (output: %s)", err, output) } if output, err := ip("addr", "add", ifaceAddr, "dev", ifaceName); err != nil { return fmt.Errorf("Unable to add private network: %s (%s)", err, output) } if output, err := ip("link", "set", ifaceName, "up"); err != nil { return fmt.Errorf("Unable to start network bridge: %s (%s)", err, output) } if err := iptables("-t", "nat", "-A", "POSTROUTING", "-s", ifaceAddr, "!", "-d", ifaceAddr, "-j", "MASQUERADE"); err != nil { return fmt.Errorf("Unable to enable network bridge NAT: %s", err) } return nil }
func (b *builderClient) clearTmp(containers, images map[string]struct{}) { for i := range images { if _, _, err := b.cli.call("DELETE", "/images/"+i, nil); err != nil { utils.Debugf("%s", err) } utils.Debugf("Removing image %s", i) } }
func (devices *DeviceSet) UnmountDevice(hash string, mode UnmountMode) error { utils.Debugf("[devmapper] UnmountDevice(hash=%s, mode=%d)", hash, mode) defer utils.Debugf("[devmapper] UnmountDevice END") info, err := devices.lookupDevice(hash) if err != nil { return err } info.lock.Lock() defer info.lock.Unlock() devices.Lock() defer devices.Unlock() if mode == UnmountFloat { if info.floating { return fmt.Errorf("UnmountDevice: can't float floating reference %s\n", hash) } // Leave this reference floating info.floating = true return nil } if mode == UnmountSink { if !info.floating { // Someone already sunk this return nil } // Otherwise, treat this as a regular unmount } if info.mountCount == 0 { return fmt.Errorf("UnmountDevice: device not-mounted id %s\n", hash) } info.mountCount-- if info.mountCount > 0 { return nil } utils.Debugf("[devmapper] Unmount(%s)", info.mountPath) if err := sysUnmount(info.mountPath, 0); err != nil { utils.Debugf("\n--->Err: %s\n", err) return err } utils.Debugf("[devmapper] Unmount done") if err := devices.deactivateDevice(info); err != nil { return err } info.mountPath = "" return nil }
func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in *os.File, out io.Writer) error { req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), nil) if err != nil { return err } req.Header.Set("User-Agent", "Docker-Client/"+VERSION) req.Header.Set("Content-Type", "plain/text") dial, err := net.Dial(cli.proto, cli.addr) if err != nil { return err } clientconn := httputil.NewClientConn(dial, nil) defer clientconn.Close() // Server hijacks the connection, error 'connection closed' expected clientconn.Do(req) rwc, br := clientconn.Hijack() defer rwc.Close() receiveStdout := utils.Go(func() error { _, err := io.Copy(out, br) return err }) if in != nil && setRawTerminal && term.IsTerminal(in.Fd()) && os.Getenv("NORAW") == "" { oldState, err := term.SetRawTerminal() if err != nil { return err } defer term.RestoreTerminal(oldState) } sendStdin := utils.Go(func() error { io.Copy(rwc, in) if err := rwc.(*net.TCPConn).CloseWrite(); err != nil { utils.Debugf("Couldn't send EOF: %s\n", err) } // Discard errors due to pipe interruption return nil }) if err := <-receiveStdout; err != nil { utils.Debugf("Error receiveStdout: %s", err) return err } if !term.IsTerminal(in.Fd()) { if err := <-sendStdin; err != nil { utils.Debugf("Error sendStdin: %s", err) return err } } return nil }
// Commit the container <id> with the autorun command <autoCmd> func (b *buildFile) commit(id string, autoCmd []string, comment string) error { if b.image == "" { return fmt.Errorf("Please provide a source image with `from` prior to commit") } b.config.Image = b.image if id == "" { cmd := b.config.Cmd b.config.Cmd = []string{"/bin/sh", "-c", "#(nop) " + comment} defer func(cmd []string) { b.config.Cmd = cmd }(cmd) if b.utilizeCache { if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil { return err } else if cache != nil { fmt.Fprintf(b.outStream, " ---> Using cache\n") utils.Debugf("[BUILDER] Use cached version") b.image = cache.ID return nil } else { utils.Debugf("[BUILDER] Cache miss") } } container, warnings, err := b.runtime.Create(b.config, "") if err != nil { return err } for _, warning := range warnings { fmt.Fprintf(b.outStream, " ---> [Warning] %s\n", warning) } b.tmpContainers[container.ID] = struct{}{} fmt.Fprintf(b.outStream, " ---> Running in %s\n", utils.TruncateID(container.ID)) id = container.ID if err := container.EnsureMounted(); err != nil { return err } defer container.Unmount() } container := b.runtime.Get(id) if container == nil { return fmt.Errorf("An error occured while creating the container") } // Note: Actually copy the struct autoConfig := *b.config autoConfig.Cmd = autoCmd // Commit the container image, err := b.runtime.Commit(container, "", "", "", b.maintainer, &autoConfig) if err != nil { return err } b.tmpImages[image.ID] = struct{}{} b.image = image.ID return nil }
func (devices *DeviceSet) setupBaseImage() error { oldInfo, _ := devices.lookupDevice("") if oldInfo != nil && oldInfo.Initialized { return nil } if oldInfo != nil && !oldInfo.Initialized { utils.Debugf("Removing uninitialized base image") if err := devices.deleteDevice(oldInfo); err != nil { utils.Debugf("\n--->Err: %s\n", err) return err } } utils.Debugf("Initializing base device-manager snapshot") id := devices.nextDeviceId // Create initial device if err := createDevice(devices.getPoolDevName(), &id); err != nil { utils.Debugf("\n--->Err: %s\n", err) return err } // Ids are 24bit, so wrap around devices.nextDeviceId = (id + 1) & 0xffffff utils.Debugf("Registering base device (id %v) with FS size %v", id, DefaultBaseFsSize) info, err := devices.registerDevice(id, "", DefaultBaseFsSize) if err != nil { _ = deleteDevice(devices.getPoolDevName(), id) utils.Debugf("\n--->Err: %s\n", err) return err } utils.Debugf("Creating filesystem on base device-manager snapshot") if err = devices.activateDeviceIfNeeded(info); err != nil { utils.Debugf("\n--->Err: %s\n", err) return err } if err := devices.createFilesystem(info); err != nil { utils.Debugf("\n--->Err: %s\n", err) return err } info.Initialized = true if err = devices.saveMetadata(info); err != nil { info.Initialized = false utils.Debugf("\n--->Err: %s\n", err) return err } return nil }
func (b *buildFile) clearTmp(containers, images map[string]struct{}) { for c := range containers { tmp := b.runtime.Get(c) b.runtime.Destroy(tmp) utils.Debugf("Removing container %s", c) } for i := range images { b.runtime.graph.Delete(i) utils.Debugf("Removing image %s", i) } }
func (container *Container) monitor() { // Wait for the program to exit // If the command does not exist, try to wait via lxc // (This probably happens only for ghost containers, i.e. containers that were running when Docker started) if container.cmd == nil { utils.Debugf("monitor: waiting for container %s using waitLxc", container.ID) if err := container.waitLxc(); err != nil { utils.Errorf("monitor: while waiting for container %s, waitLxc had a problem: %s", container.ID, err) } } else { utils.Debugf("monitor: waiting for container %s using cmd.Wait", container.ID) if err := container.cmd.Wait(); err != nil { // Since non-zero exit status and signal terminations will cause err to be non-nil, // we have to actually discard it. Still, log it anyway, just in case. utils.Debugf("monitor: cmd.Wait reported exit status %s for container %s", err, container.ID) } } utils.Debugf("monitor: container %s finished", container.ID) exitCode := -1 if container.cmd != nil { exitCode = container.cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() } if container.runtime != nil && container.runtime.srv != nil { container.runtime.srv.LogEvent("die", container.ID, container.runtime.repositories.ImageName(container.Image)) } // Cleanup container.cleanup() // Re-create a brand new stdin pipe once the container exited if container.Config.OpenStdin { container.stdin, container.stdinPipe = io.Pipe() } // Report status back container.State.SetStopped(exitCode) // Release the lock close(container.waitLock) if err := container.ToDisk(); err != nil { // FIXME: there is a race condition here which causes this to fail during the unit tests. // If another goroutine was waiting for Wait() to return before removing the container's root // from the filesystem... At this point it may already have done so. // This is because State.setStopped() has already been called, and has caused Wait() // to return. // FIXME: why are we serializing running state to disk in the first place? //log.Printf("%s: Failed to dump configuration to the disk: %s", container.ID, err) } }