func (srv *Server) Containers(all, size bool, n int, since, before string) []APIContainers { var foundBefore bool var displayed int out := []APIContainers{} for _, container := range srv.runtime.List() { if !container.State.Running && !all && n == -1 && since == "" && before == "" { continue } if before != "" { if container.ID == before || utils.TruncateID(container.ID) == before { foundBefore = true continue } if !foundBefore { continue } } if displayed == n { break } if container.ID == since || utils.TruncateID(container.ID) == since { break } displayed++ c := createAPIContainer(container, size, srv.runtime) out = append(out, c) } return out }
func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgID, endpoint string, token []string, sf *utils.StreamFormatter) error { history, err := r.GetRemoteHistory(imgID, endpoint, token) if err != nil { return err } // FIXME: Try to stream the images? // FIXME: Launch the getRemoteImage() in goroutines for _, id := range history { if !srv.runtime.graph.Exists(id) { out.Write(sf.FormatProgress(utils.TruncateID(id), "Pulling", "metadata")) imgJSON, imgSize, err := r.GetRemoteImageJSON(id, endpoint, token) if err != nil { // FIXME: Keep going in case of error? return err } img, err := NewImgJSON(imgJSON) if err != nil { return fmt.Errorf("Failed to parse json: %s", err) } // Get the layer out.Write(sf.FormatProgress(utils.TruncateID(id), "Pulling", "fs layer")) layer, err := r.GetRemoteImageLayer(img.ID, endpoint, token) if err != nil { return err } defer layer.Close() if err := srv.runtime.graph.Register(imgJSON, utils.ProgressReader(layer, imgSize, out, sf.FormatProgress(utils.TruncateID(id), "Downloading", "%8v/%v (%v)"), sf, false), img); err != nil { return err } } } return nil }
func (b *buildFile) Build(context io.Reader) (string, error) { // FIXME: @creack "name" is a terrible variable name name, err := ioutil.TempDir("", "docker-build") if err != nil { return "", err } if err := Untar(context, name); err != nil { return "", err } defer os.RemoveAll(name) b.context = name filename := path.Join(name, "Dockerfile") if _, err := os.Stat(filename); os.IsNotExist(err) { return "", fmt.Errorf("Can't build a directory with no Dockerfile") } fileBytes, err := ioutil.ReadFile(filename) if err != nil { return "", err } dockerfile := string(fileBytes) dockerfile = lineContinuation.ReplaceAllString(dockerfile, "") stepN := 0 for _, line := range strings.Split(dockerfile, "\n") { line = strings.Trim(strings.Replace(line, "\t", " ", -1), " \t\r\n") // Skip comments and empty line if len(line) == 0 || line[0] == '#' { continue } tmp := strings.SplitN(line, " ", 2) if len(tmp) != 2 { return "", fmt.Errorf("Invalid Dockerfile format") } instruction := strings.ToLower(strings.Trim(tmp[0], " ")) arguments := strings.Trim(tmp[1], " ") method, exists := reflect.TypeOf(b).MethodByName("Cmd" + strings.ToUpper(instruction[:1]) + strings.ToLower(instruction[1:])) if !exists { fmt.Fprintf(b.out, "# Skipping unknown instruction %s\n", strings.ToUpper(instruction)) continue } stepN += 1 fmt.Fprintf(b.out, "Step %d : %s %s\n", stepN, strings.ToUpper(instruction), arguments) ret := method.Func.Call([]reflect.Value{reflect.ValueOf(b), reflect.ValueOf(arguments)})[0].Interface() if ret != nil { return "", ret.(error) } fmt.Fprintf(b.out, " ---> %v\n", utils.TruncateID(b.image)) } if b.image != "" { fmt.Fprintf(b.out, "Successfully built %s\n", utils.TruncateID(b.image)) if b.rm { b.clearTmp(b.tmpContainers) } return b.image, nil } return "", fmt.Errorf("An error occurred during the build\n") }
func (b *buildFile) Build(dockerfile, context io.Reader) (string, error) { if context != nil { name, err := ioutil.TempDir("/tmp", "docker-build") if err != nil { return "", err } if err := Untar(context, name); err != nil { return "", err } defer os.RemoveAll(name) b.context = name } file := bufio.NewReader(dockerfile) stepN := 0 for { line, err := file.ReadString('\n') if err != nil { if err == io.EOF && line == "" { break } else if err != io.EOF { return "", err } } line = strings.Replace(strings.TrimSpace(line), " ", " ", 1) // Skip comments and empty line if len(line) == 0 || line[0] == '#' { continue } tmp := strings.SplitN(line, " ", 2) if len(tmp) != 2 { return "", fmt.Errorf("Invalid Dockerfile format") } instruction := strings.ToLower(strings.Trim(tmp[0], " ")) arguments := strings.Trim(tmp[1], " ") stepN += 1 // FIXME: only count known instructions as build steps fmt.Fprintf(b.out, "Step %d : %s %s\n", stepN, strings.ToUpper(instruction), arguments) method, exists := reflect.TypeOf(b).MethodByName("Cmd" + strings.ToUpper(instruction[:1]) + strings.ToLower(instruction[1:])) if !exists { fmt.Fprintf(b.out, "# Skipping unknown instruction %s\n", strings.ToUpper(instruction)) continue } ret := method.Func.Call([]reflect.Value{reflect.ValueOf(b), reflect.ValueOf(arguments)})[0].Interface() if ret != nil { return "", ret.(error) } fmt.Fprintf(b.out, " ---> %v\n", utils.TruncateID(b.image)) } if b.image != "" { fmt.Fprintf(b.out, "Successfully built %s\n", utils.TruncateID(b.image)) return b.image, nil } return "", fmt.Errorf("An error occured during the build\n") }
func (b *buildFile) clearTmp(containers map[string]struct{}) { for c := range containers { tmp := b.runtime.Get(c) if err := b.runtime.Destroy(tmp); err != nil { fmt.Fprintf(b.outStream, "Error removing intermediate container %s: %s\n", utils.TruncateID(c), err.Error()) } else { fmt.Fprintf(b.outStream, "Removing intermediate container %s\n", utils.TruncateID(c)) } } }
func (b *buildFile) run() (string, error) { if b.image == "" { return "", fmt.Errorf("Please provide a source image with `from` prior to run") } b.config.Image = b.image // Create the container and start it c, _, err := b.runtime.Create(b.config, "") if err != nil { return "", err } b.tmpContainers[c.ID] = struct{}{} if b.sf.Used() { b.out.Write(b.sf.FormatStatus("", " ---> Running in %s", utils.TruncateID(c.ID))) } else { fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(c.ID)) } // override the entry point that may have been picked up from the base image c.Path = b.config.Cmd[0] c.Args = b.config.Cmd[1:] var errCh chan error if b.verbose { errCh = utils.Go(func() error { return <-c.Attach(nil, nil, b.out, b.out) }) } //start the container if err := c.Start(); err != nil { return "", err } if errCh != nil { if err := <-errCh; err != nil { return "", err } } // Wait for it to finish if ret := c.Wait(); ret != 0 { err := &utils.JSONError{ Message: fmt.Sprintf("The command %v returned a non-zero code: %d", b.config.Cmd, ret), Code: ret, } return "", err } return c.ID, nil }
func (b *buildFile) run() (string, error) { if b.image == "" { return "", fmt.Errorf("Please provide a source image with `from` prior to run") } b.config.Image = b.image // Create the container and start it c, err := b.builder.Create(b.config) if err != nil { return "", err } b.tmpContainers[c.ID] = struct{}{} fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(c.ID)) //start the container hostConfig := &HostConfig{} if err := c.Start(hostConfig); err != nil { return "", err } // Wait for it to finish if ret := c.Wait(); ret != 0 { return "", fmt.Errorf("The command %v returned a non-zero code: %d", b.config.Cmd, ret) } return c.ID, nil }
// TestAttachDetachTruncatedID checks that attach in tty mode can be detached func TestAttachDetachTruncatedID(t *testing.T) { stdin, stdinPipe := io.Pipe() stdout, stdoutPipe := io.Pipe() cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr) defer cleanup(globalRuntime) go stdout.Read(make([]byte, 1024)) setTimeout(t, "Starting container timed out", 2*time.Second, func() { if err := cli.CmdRun("-i", "-t", "-d", unitTestImageID, "cat"); err != nil { t.Fatal(err) } }) container := globalRuntime.List()[0] stdin, stdinPipe = io.Pipe() stdout, stdoutPipe = io.Pipe() cli = NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr) ch := make(chan struct{}) go func() { defer close(ch) if err := cli.CmdAttach(utils.TruncateID(container.ID)); err != nil { if err != io.ErrClosedPipe { t.Fatal(err) } } }() setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() { if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil { if err != io.ErrClosedPipe { t.Fatal(err) } } }) setTimeout(t, "Escape sequence timeout", 5*time.Second, func() { stdinPipe.Write([]byte{16, 17}) if err := stdinPipe.Close(); err != nil { t.Fatal(err) } }) closeWrap(stdin, stdinPipe, stdout, stdoutPipe) // wait for CmdRun to return setTimeout(t, "Waiting for CmdAttach timed out", 15*time.Second, func() { <-ch }) time.Sleep(500 * time.Millisecond) if !container.State.Running { t.Fatal("The detached container should be still running") } setTimeout(t, "Waiting for container to die timedout", 5*time.Second, func() { container.Kill() }) }
func (daemon *Daemon) reserveName(id, name string) (string, error) { if !validContainerNamePattern.MatchString(name) { return "", fmt.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars) } if name[0] != '/' { name = "/" + name } if _, err := daemon.containerGraph.Set(name, id); err != nil { if !graphdb.IsNonUniqueNameError(err) { return "", err } conflictingContainer, err := daemon.GetByName(name) if err != nil { if strings.Contains(err.Error(), "Could not find entity") { return "", err } // Remove name and continue starting the container if err := daemon.containerGraph.Delete(name); err != nil { return "", err } } else { nameAsKnownByUser := strings.TrimPrefix(name, "/") return "", fmt.Errorf( "Conflict, The name %s is already assigned to %s. You have to delete (or rename) that container to be able to assign %s to a container again.", nameAsKnownByUser, utils.TruncateID(conflictingContainer.ID), nameAsKnownByUser) } } return name, nil }
func (b *buildFile) clearTmp(containers map[string]struct{}) { for c := range containers { tmp := b.runtime.Get(c) b.runtime.Destroy(tmp) fmt.Fprintf(b.out, "Removing intermediate container %s\n", utils.TruncateID(c)) } }
func (b *buildFile) CmdAdd(args string) error { if b.context == "" { return fmt.Errorf("No context given. Impossible to use ADD") } tmp := strings.SplitN(args, " ", 2) if len(tmp) != 2 { return fmt.Errorf("Invalid ADD format") } orig := strings.Trim(tmp[0], " ") dest := strings.Trim(tmp[1], " ") cmd := b.config.Cmd // Create the container and start it b.config.Cmd = []string{"/bin/sh", "-c", fmt.Sprintf("#(nop) ADD %s in %s", orig, dest)} b.config.Image = b.image container, err := b.builder.Create(b.config) if err != nil { return err } b.tmpContainers[container.ID] = struct{}{} fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(container.ID)) if err := container.EnsureMounted(); err != nil { return err } defer container.Unmount() origPath := path.Join(b.context, orig) destPath := path.Join(container.RootfsPath(), dest) fi, err := os.Stat(origPath) if err != nil { return err } if fi.IsDir() { if err := os.MkdirAll(destPath, 0700); err != nil { return err } if err := CopyWithTar(origPath, destPath); err != nil { return err } // First try to unpack the source as an archive } else if err := UntarPath(origPath, destPath); err != nil { utils.Debugf("Couldn't untar %s to %s: %s", origPath, destPath, err) // If that fails, just copy it as a regular file if err := os.MkdirAll(path.Dir(destPath), 0700); err != nil { return err } if err := CopyWithTar(origPath, destPath); err != nil { return err } } if err := b.commit(container.ID, cmd, fmt.Sprintf("ADD %s in %s", orig, dest)); err != nil { return err } b.config.Cmd = cmd return nil }
// Test that an image can be deleted by its shorthand prefix func TestDeletePrefix(t *testing.T) { graph := tempGraph(t) defer os.RemoveAll(graph.Root) img := createTestImage(graph, t) if err := graph.Delete(utils.TruncateID(img.ID)); err != nil { t.Fatal(err) } assertNImages(graph, t, 0) }
func (runtime *Runtime) generateIdAndName(name string) (string, string, error) { var ( err error id = utils.GenerateRandomID() ) if name == "" { name, err = generateRandomName(runtime) if err != nil { name = utils.TruncateID(id) } } else { if !validContainerNamePattern.MatchString(name) { return "", "", fmt.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars) } } if name[0] != '/' { name = "/" + name } // Set the enitity in the graph using the default name specified if _, err := runtime.containerGraph.Set(name, id); err != nil { if !graphdb.IsNonUniqueNameError(err) { return "", "", err } conflictingContainer, err := runtime.GetByName(name) if err != nil { if strings.Contains(err.Error(), "Could not find entity") { return "", "", err } // Remove name and continue starting the container if err := runtime.containerGraph.Delete(name); err != nil { return "", "", err } } else { nameAsKnownByUser := strings.TrimPrefix(name, "/") return "", "", fmt.Errorf( "Conflict, The name %s is already assigned to %s. You have to delete (or rename) that container to be able to assign %s to a container again.", nameAsKnownByUser, utils.TruncateID(conflictingContainer.ID), nameAsKnownByUser) } } return id, name, 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 (srv *Server) deleteImageAndChildren(id string, imgs *[]APIRmi) error { // If the image is referenced by a repo, do not delete if len(srv.runtime.repositories.ByID()[id]) != 0 { return ErrImageReferenced } // If the image is not referenced but has children, go recursive referenced := false byParents, err := srv.runtime.graph.ByParent() if err != nil { return err } for _, img := range byParents[id] { if err := srv.deleteImageAndChildren(img.ID, imgs); err != nil { if err != ErrImageReferenced { return err } referenced = true } } if referenced { return ErrImageReferenced } // If the image is not referenced and has no children, remove it byParents, err = srv.runtime.graph.ByParent() if err != nil { return err } if len(byParents[id]) == 0 { if err := srv.runtime.repositories.DeleteAll(id); err != nil { return err } err := srv.runtime.graph.Delete(id) if err != nil { return err } *imgs = append(*imgs, APIRmi{Deleted: utils.TruncateID(id)}) srv.LogEvent("delete", utils.TruncateID(id), "") return nil } return nil }
func (b *buildFile) Build(context io.Reader) (string, error) { tmpdirPath, err := ioutil.TempDir("", "docker-build") if err != nil { return "", err } decompressedStream, err := archive.DecompressStream(context) if err != nil { return "", err } b.context = &utils.TarSum{Reader: decompressedStream, DisableCompression: true} if err := archive.Untar(b.context, tmpdirPath, nil); err != nil { return "", err } defer os.RemoveAll(tmpdirPath) b.contextPath = tmpdirPath filename := path.Join(tmpdirPath, "Dockerfile") if _, err := os.Stat(filename); os.IsNotExist(err) { return "", fmt.Errorf("Can't build a directory with no Dockerfile") } fileBytes, err := ioutil.ReadFile(filename) if err != nil { return "", err } if len(fileBytes) == 0 { return "", ErrDockerfileEmpty } var ( dockerfile = lineContinuation.ReplaceAllString(stripComments(fileBytes), "") stepN = 0 ) for _, line := range strings.Split(dockerfile, "\n") { line = strings.Trim(strings.Replace(line, "\t", " ", -1), " \t\r\n") if len(line) == 0 { continue } if err := b.BuildStep(fmt.Sprintf("%d", stepN), line); err != nil { if b.forceRm { b.clearTmp(b.tmpContainers) } return "", err } else if b.rm { b.clearTmp(b.tmpContainers) } stepN += 1 } if b.image != "" { fmt.Fprintf(b.outStream, "Successfully built %s\n", utils.TruncateID(b.image)) return b.image, nil } return "", fmt.Errorf("No image was generated. This may be because the Dockerfile does not, like, do anything.\n") }
func TestEnv(t *testing.T) { os.Setenv("TRUE", "false") os.Setenv("TRICKY", "tri\ncky\n") runtime := mkRuntime(t) defer nuke(runtime) config, _, _, err := ParseRun([]string{"-e=FALSE=true", "-e=TRUE", "-e=TRICKY", GetTestImage(runtime).ID, "env"}, nil) if err != nil { t.Fatal(err) } container, _, err := runtime.Create(config, "") if err != nil { t.Fatal(err) } defer runtime.Destroy(container) stdout, err := container.StdoutPipe() if err != nil { t.Fatal(err) } defer stdout.Close() if err := container.Start(); err != nil { t.Fatal(err) } container.Wait() output, err := ioutil.ReadAll(stdout) if err != nil { t.Fatal(err) } actualEnv := strings.Split(string(output), "\n") if actualEnv[len(actualEnv)-1] == "" { actualEnv = actualEnv[:len(actualEnv)-1] } sort.Strings(actualEnv) goodEnv := []string{ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HOME=/", "container=lxc", "HOSTNAME=" + utils.TruncateID(container.ID), "FALSE=true", "TRUE=false", "TRICKY=tri", "cky", "", } sort.Strings(goodEnv) if len(goodEnv) != len(actualEnv) { t.Fatalf("Wrong environment: should be %d variables, not: '%s'\n", len(goodEnv), strings.Join(actualEnv, ", ")) } for i := range goodEnv { if actualEnv[i] != goodEnv[i] { t.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i]) } } }
// During cleanup aufs needs to unmount all mountpoints func (a *Driver) Cleanup() error { ids, err := loadIds(path.Join(a.rootPath(), "layers")) if err != nil { return err } for _, id := range ids { if err := a.unmount(id); err != nil { utils.Errorf("Unmounting %s: %s", utils.TruncateID(id), err) } } return nil }
func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgID, endpoint string, token []string, sf *utils.StreamFormatter) error { history, err := r.GetRemoteHistory(imgID, endpoint, token) if err != nil { return err } out.Write(sf.FormatProgress(utils.TruncateID(imgID), "Pulling", "dependend layers")) // FIXME: Try to stream the images? // FIXME: Launch the getRemoteImage() in goroutines for _, id := range history { // ensure no two downloads of the same layer happen at the same time if err := srv.poolAdd("pull", "layer:"+id); err != nil { utils.Debugf("Image (id: %s) pull is already running, skipping: %v", id, err) return nil } defer srv.poolRemove("pull", "layer:"+id) if !srv.runtime.graph.Exists(id) { out.Write(sf.FormatProgress(utils.TruncateID(id), "Pulling", "metadata")) imgJSON, imgSize, err := r.GetRemoteImageJSON(id, endpoint, token) if err != nil { out.Write(sf.FormatProgress(utils.TruncateID(id), "Error", "pulling dependend layers")) // FIXME: Keep going in case of error? return err } img, err := NewImgJSON(imgJSON) if err != nil { out.Write(sf.FormatProgress(utils.TruncateID(id), "Error", "pulling dependend layers")) return fmt.Errorf("Failed to parse json: %s", err) } // Get the layer out.Write(sf.FormatProgress(utils.TruncateID(id), "Pulling", "fs layer")) layer, err := r.GetRemoteImageLayer(img.ID, endpoint, token) if err != nil { out.Write(sf.FormatProgress(utils.TruncateID(id), "Error", "pulling dependend layers")) return err } defer layer.Close() if err := srv.runtime.graph.Register(imgJSON, utils.ProgressReader(layer, imgSize, out, sf.FormatProgress(utils.TruncateID(id), "Downloading", "%8v/%v (%v)"), sf, false), img); err != nil { out.Write(sf.FormatProgress(utils.TruncateID(id), "Error", "downloading dependend layers")) return err } } out.Write(sf.FormatProgress(utils.TruncateID(id), "Download", "complete")) } return nil }
func (store *TagStore) GetRepoRefs() map[string][]string { store.Lock() reporefs := make(map[string][]string) for name, repository := range store.Repositories { for tag, id := range repository { shortID := utils.TruncateID(id) reporefs[shortID] = append(reporefs[shortID], fmt.Sprintf("%s:%s", name, tag)) } } store.Unlock() return reporefs }
// 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) hit, err := b.probeCache() if err != nil { return err } if hit { return nil } container, warnings, err := b.daemon.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.Mount(); err != nil { return err } defer container.Unmount() } container := b.daemon.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.daemon.Commit(container, "", "", "", b.maintainer, &autoConfig) if err != nil { return err } b.tmpImages[image.ID] = struct{}{} b.image = image.ID return nil }
func TestImagesViz(t *testing.T) { stdout, stdoutPipe := io.Pipe() cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr) defer cleanup(globalRuntime) srv := &Server{runtime: globalRuntime} image := buildTestImages(t, srv) c := make(chan struct{}) go func() { defer close(c) if err := cli.CmdImages("-viz"); err != nil { t.Fatal(err) } stdoutPipe.Close() }() setTimeout(t, "Reading command output time out", 2*time.Second, func() { cmdOutputBytes, err := ioutil.ReadAll(bufio.NewReader(stdout)) if err != nil { t.Fatal(err) } cmdOutput := string(cmdOutputBytes) regexpStrings := []string{ "digraph docker {", fmt.Sprintf("base -> \"%s\" \\[style=invis]", unitTestImageIDShort), fmt.Sprintf("label=\"%s\\\\n%s:latest\"", unitTestImageIDShort, unitTestImageName), fmt.Sprintf("label=\"%s\\\\n%s:%s\"", utils.TruncateID(image.ID), "test", "latest"), "base \\[style=invisible]", } compiledRegexps := []*regexp.Regexp{} for _, regexpString := range regexpStrings { regexp, err := regexp.Compile(regexpString) if err != nil { fmt.Println("Error in regex string: ", err) return } compiledRegexps = append(compiledRegexps, regexp) } for _, regexp := range compiledRegexps { if !regexp.MatchString(cmdOutput) { t.Fatalf("images -viz content '%s' did not match regexp '%s'", cmdOutput, regexp) } } }) }
func (srv *Server) ImagesViz(out io.Writer) error { images, _ := srv.runtime.graph.All() if images == nil { return nil } out.Write([]byte("digraph docker {\n")) var ( parentImage *Image err error ) for _, image := range images { parentImage, err = image.GetParent() if err != nil { return fmt.Errorf("Error while getting parent image: %v", err) } if parentImage != nil { out.Write([]byte(" \"" + parentImage.ShortID() + "\" -> \"" + image.ShortID() + "\"\n")) } else { out.Write([]byte(" base -> \"" + image.ShortID() + "\" [style=invis]\n")) } } reporefs := make(map[string][]string) for name, repository := range srv.runtime.repositories.Repositories { for tag, id := range repository { reporefs[utils.TruncateID(id)] = append(reporefs[utils.TruncateID(id)], fmt.Sprintf("%s:%s", name, tag)) } } for id, repos := range reporefs { out.Write([]byte(" \"" + id + "\" [label=\"" + id + "\\n" + strings.Join(repos, "\\n") + "\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n")) } out.Write([]byte(" base [style=invisible]\n}\n")) return nil }
func TestImagesTree(t *testing.T) { t.Skip("Image tree is deprecated") stdout, stdoutPipe := io.Pipe() cli := client.NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr, nil) defer cleanup(globalEngine, t) image := buildTestImages(t, globalEngine) c := make(chan struct{}) go func() { defer close(c) if err := cli.CmdImages("--tree"); err != nil { t.Fatal(err) } stdoutPipe.Close() }() setTimeout(t, "Reading command output time out", 2*time.Second, func() { cmdOutputBytes, err := ioutil.ReadAll(bufio.NewReader(stdout)) if err != nil { t.Fatal(err) } cmdOutput := string(cmdOutputBytes) regexpStrings := []string{ fmt.Sprintf("└─%s Virtual Size: \\d+.\\d+ MB Tags: %s:latest", unitTestImageIDShort, unitTestImageName), "(?m) └─[0-9a-f]+.*", "(?m) └─[0-9a-f]+.*", "(?m) └─[0-9a-f]+.*", fmt.Sprintf("(?m)^ └─%s Virtual Size: \\d+.\\d+ MB Tags: test:latest", utils.TruncateID(image.ID)), } compiledRegexps := []*regexp.Regexp{} for _, regexpString := range regexpStrings { regexp, err := regexp.Compile(regexpString) if err != nil { fmt.Println("Error in regex string: ", err) return } compiledRegexps = append(compiledRegexps, regexp) } for _, regexp := range compiledRegexps { if !regexp.MatchString(cmdOutput) { t.Fatalf("images --tree content '%s' did not match regexp '%s'", cmdOutput, regexp) } } }) }
func (container *Container) kill(sig int) error { container.Lock() defer container.Unlock() if !container.State.IsRunning() { return nil } if output, err := exec.Command("lxc-kill", "-n", container.ID, strconv.Itoa(sig)).CombinedOutput(); err != nil { log.Printf("error killing container %s (%s, %s)", utils.TruncateID(container.ID), output, err) return err } return nil }
func GenerateID() string { for { id := make([]byte, 32) if _, err := io.ReadFull(rand.Reader, id); err != nil { panic(err) // This shouldn't happen } value := hex.EncodeToString(id) // if we try to parse the truncated for as an int and we don't have // an error then the value is all numberic and causes issues when // used as a hostname. ref #3869 if _, err := strconv.Atoi(utils.TruncateID(value)); err == nil { continue } return value } }
// TempLayerArchive creates a temporary archive of the given image's filesystem layer. // The archive is stored on disk and will be automatically deleted as soon as has been read. // If output is not nil, a human-readable progress bar will be written to it. // FIXME: does this belong in Graph? How about MktempFile, let the caller use it for archives? func (graph *Graph) TempLayerArchive(id string, compression archive.Compression, sf *utils.StreamFormatter, output io.Writer) (*archive.TempArchive, error) { image, err := graph.Get(id) if err != nil { return nil, err } tmp, err := graph.Mktemp("") if err != nil { return nil, err } a, err := image.TarLayer() if err != nil { return nil, err } progress := utils.ProgressReader(a, 0, output, sf, false, utils.TruncateID(id), "Buffering to disk") defer progress.Close() return archive.NewTempArchive(progress, tmp) }
func (runtime *Runtime) ensureName(container *Container) error { if container.Name == "" { name, err := generateRandomName(runtime) if err != nil { name = utils.TruncateID(container.ID) } container.Name = name if err := container.ToDisk(); err != nil { utils.Debugf("Error saving container name %s", err) } if !runtime.containerGraph.Exists(name) { if _, err := runtime.containerGraph.Set(name, container.ID); err != nil { utils.Debugf("Setting default id - %s", err) } } } return nil }
func (b *buildFile) create() (*runtime.Container, error) { if b.image == "" { return nil, fmt.Errorf("Please provide a source image with `from` prior to run") } b.config.Image = b.image // Create the container and start it c, _, err := b.runtime.Create(b.config, "") if err != nil { return nil, err } b.tmpContainers[c.ID] = struct{}{} fmt.Fprintf(b.outStream, " ---> Running in %s\n", utils.TruncateID(c.ID)) // override the entry point that may have been picked up from the base image c.Path = b.config.Cmd[0] c.Args = b.config.Cmd[1:] return c, nil }
func (b *buildFile) run() (string, error) { if b.image == "" { return "", fmt.Errorf("Please provide a source image with `from` prior to run") } b.config.Image = b.image // Create the container and start it c, err := b.runtime.Create(b.config) if err != nil { return "", err } b.tmpContainers[c.ID] = struct{}{} fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(c.ID)) // override the entry point that may have been picked up from the base image c.Path = b.config.Cmd[0] c.Args = b.config.Cmd[1:] //start the container hostConfig := &HostConfig{} if err := c.Start(hostConfig); err != nil { return "", err } if b.verbose { err = <-c.Attach(nil, nil, b.out, b.out) if err != nil { return "", err } } // Wait for it to finish if ret := c.Wait(); ret != 0 { return "", fmt.Errorf("The command %v returned a non-zero code: %d", b.config.Cmd, ret) } return c.ID, nil }