func init() { out, err := exec.Command(dockerBinary, "images").CombinedOutput() if err != nil { panic(err) } lines := strings.Split(string(out), "\n")[1:] for _, l := range lines { if l == "" { continue } fields := strings.Fields(l) imgTag := fields[0] + ":" + fields[1] // just for case if we have dangling images in tested daemon if imgTag != "<none>:<none>" { protectedImages[imgTag] = struct{}{} } } // Obtain the daemon platform so that it can be used by tests to make // intelligent decisions about how to configure themselves, and validate // that the target platform is valid. res, _, err := sockRequestRaw("GET", "/version", nil, "application/json") if err != nil || res == nil || (res != nil && res.StatusCode != http.StatusOK) { panic(fmt.Errorf("Init failed to get version: %v. Res=%v", err.Error(), res)) } svrHeader, _ := httputils.ParseServerHeader(res.Header.Get("Server")) daemonPlatform = svrHeader.OS if daemonPlatform != "linux" && daemonPlatform != "windows" { panic("Cannot run tests against platform: " + daemonPlatform) } }
// ImageBuild sends request to the daemon to build images. // The Body in the response implement an io.ReadCloser and it's up to the caller to // close it. func (cli *Client) ImageBuild(options types.ImageBuildOptions) (types.ImageBuildResponse, error) { query, err := imageBuildOptionsToQuery(options) if err != nil { return types.ImageBuildResponse{}, err } headers := http.Header(make(map[string][]string)) buf, err := json.Marshal(options.AuthConfigs) if err != nil { return types.ImageBuildResponse{}, err } headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf)) headers.Set("Content-Type", "application/tar") serverResp, err := cli.postRaw("/build", query, options.Context, headers) if err != nil { return types.ImageBuildResponse{}, err } var osType string if h, err := httputils.ParseServerHeader(serverResp.header.Get("Server")); err == nil { osType = h.OS } return types.ImageBuildResponse{ Body: serverResp.body, OSType: osType, }, nil }
func init() { out, err := exec.Command(dockerBinary, "images").CombinedOutput() if err != nil { panic(err) } lines := strings.Split(string(out), "\n")[1:] for _, l := range lines { if l == "" { continue } fields := strings.Fields(l) imgTag := fields[0] + ":" + fields[1] // just for case if we have dangling images in tested daemon if imgTag != "<none>:<none>" { protectedImages[imgTag] = struct{}{} } } // Obtain the daemon platform so that it can be used by tests to make // intelligent decisions about how to configure themselves, and validate // that the target platform is valid. res, _, err := sockRequestRaw("GET", "/version", nil, "application/json") if err != nil || res == nil || (res != nil && res.StatusCode != http.StatusOK) { panic(fmt.Errorf("Init failed to get version: %v. Res=%v", err.Error(), res)) } svrHeader, _ := httputils.ParseServerHeader(res.Header.Get("Server")) daemonPlatform = svrHeader.OS if daemonPlatform != "linux" && daemonPlatform != "windows" { panic("Cannot run tests against platform: " + daemonPlatform) } // On Windows, extract out the version as we need to make selective // decisions during integration testing as and when features are implemented. if daemonPlatform == "windows" { if body, err := ioutil.ReadAll(res.Body); err == nil { var server types.Version if err := json.Unmarshal(body, &server); err == nil { // eg in "10.0 10550 (10550.1000.amd64fre.branch.date-time)" we want 10550 windowsDaemonKV, _ = strconv.Atoi(strings.Split(server.KernelVersion, " ")[1]) } } } // Now we know the daemon platform, can set paths used by tests. _, body, err := sockRequest("GET", "/info", nil) if err != nil { panic(err) } var info types.Info err = json.Unmarshal(body, &info) dockerBasePath = info.DockerRootDir volumesConfigPath = filepath.Join(dockerBasePath, "volumes") containerStoragePath = filepath.Join(dockerBasePath, "containers") }
func init() { cmd := exec.Command(dockerBinary, "images", "-f", "dangling=false", "--format", "{{.Repository}}:{{.Tag}}") cmd.Env = appendBaseEnv(true) out, err := cmd.CombinedOutput() if err != nil { panic(fmt.Errorf("err=%v\nout=%s\n", err, out)) } images := strings.Split(strings.TrimSpace(string(out)), "\n") for _, img := range images { protectedImages[img] = struct{}{} } res, body, err := sockRequestRaw("GET", "/info", nil, "application/json") if err != nil { panic(fmt.Errorf("Init failed to get /info: %v", err)) } defer body.Close() if res.StatusCode != http.StatusOK { panic(fmt.Errorf("Init failed to get /info. Res=%v", res)) } svrHeader, _ := httputils.ParseServerHeader(res.Header.Get("Server")) daemonPlatform = svrHeader.OS if daemonPlatform != "linux" && daemonPlatform != "windows" { panic("Cannot run tests against platform: " + daemonPlatform) } // Now we know the daemon platform, can set paths used by tests. var info types.Info err = json.NewDecoder(body).Decode(&info) if err != nil { panic(fmt.Errorf("Init failed to unmarshal docker info: %v", err)) } daemonStorageDriver = info.Driver dockerBasePath = info.DockerRootDir volumesConfigPath = filepath.Join(dockerBasePath, "volumes") containerStoragePath = filepath.Join(dockerBasePath, "containers") // Make sure in context of daemon, not the local platform. Note we can't // use filepath.FromSlash or ToSlash here as they are a no-op on Unix. if daemonPlatform == "windows" { volumesConfigPath = strings.Replace(volumesConfigPath, `/`, `\`, -1) containerStoragePath = strings.Replace(containerStoragePath, `/`, `\`, -1) // On Windows, extract out the version as we need to make selective // decisions during integration testing as and when features are implemented. // eg in "10.0 10550 (10550.1000.amd64fre.branch.date-time)" we want 10550 windowsDaemonKV, _ = strconv.Atoi(strings.Split(info.KernelVersion, " ")[1]) } else { volumesConfigPath = strings.Replace(volumesConfigPath, `\`, `/`, -1) containerStoragePath = strings.Replace(containerStoragePath, `\`, `/`, -1) } isolation = info.Isolation }
// CmdBuild builds a new image from the source code at a given path. // // If '-' is provided instead of a path or URL, Docker will build an image from either a Dockerfile or tar archive read from STDIN. // // Usage: docker build [OPTIONS] PATH | URL | - func (cli *DockerCli) CmdBuild(args ...string) error { cmd := Cli.Subcmd("build", []string{"PATH | URL | -"}, Cli.DockerCommands["build"].Description, true) flTags := opts.NewListOpts(validateTag) cmd.Var(&flTags, []string{"t", "-tag"}, "Name and optionally a tag in the 'name:tag' format") suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers") noCache := cmd.Bool([]string{"#no-cache", "-no-cache"}, false, "Do not use cache when building the image") rm := cmd.Bool([]string{"#rm", "-rm"}, true, "Remove intermediate containers after a successful build") forceRm := cmd.Bool([]string{"-force-rm"}, false, "Always remove intermediate containers") pull := cmd.Bool([]string{"-pull"}, false, "Always attempt to pull a newer version of the image") dockerfileName := cmd.String([]string{"f", "-file"}, "", "Name of the Dockerfile (Default is 'PATH/Dockerfile')") flMemoryString := cmd.String([]string{"m", "-memory"}, "", "Memory limit") flMemorySwap := cmd.String([]string{"-memory-swap"}, "", "Total memory (memory + swap), '-1' to disable swap") flCPUShares := cmd.Int64([]string{"#c", "-cpu-shares"}, 0, "CPU shares (relative weight)") flCPUPeriod := cmd.Int64([]string{"-cpu-period"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) period") flCPUQuota := cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota") flCPUSetCpus := cmd.String([]string{"-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)") flCPUSetMems := cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)") flCgroupParent := cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container") flBuildArg := opts.NewListOpts(opts.ValidateEnv) cmd.Var(&flBuildArg, []string{"-build-arg"}, "Set build-time variables") ulimits := make(map[string]*ulimit.Ulimit) flUlimits := opts.NewUlimitOpt(&ulimits) cmd.Var(flUlimits, []string{"-ulimit"}, "Ulimit options") cmd.Require(flag.Exact, 1) // For trusted pull on "FROM <image>" instruction. addTrustedFlags(cmd, true) cmd.ParseFlags(args, true) var ( context io.ReadCloser isRemote bool err error ) _, err = exec.LookPath("git") hasGit := err == nil specifiedContext := cmd.Arg(0) var ( contextDir string tempDir string relDockerfile string ) switch { case specifiedContext == "-": tempDir, relDockerfile, err = getContextFromReader(cli.in, *dockerfileName) case urlutil.IsGitURL(specifiedContext) && hasGit: tempDir, relDockerfile, err = getContextFromGitURL(specifiedContext, *dockerfileName) case urlutil.IsURL(specifiedContext): tempDir, relDockerfile, err = getContextFromURL(cli.out, specifiedContext, *dockerfileName) default: contextDir, relDockerfile, err = getContextFromLocalDir(specifiedContext, *dockerfileName) } if err != nil { return fmt.Errorf("unable to prepare context: %s", err) } if tempDir != "" { defer os.RemoveAll(tempDir) contextDir = tempDir } // Resolve the FROM lines in the Dockerfile to trusted digest references // using Notary. On a successful build, we must tag the resolved digests // to the original name specified in the Dockerfile. newDockerfile, resolvedTags, err := rewriteDockerfileFrom(filepath.Join(contextDir, relDockerfile), cli.trustedReference) if err != nil { return fmt.Errorf("unable to process Dockerfile: %v", err) } defer newDockerfile.Close() // And canonicalize dockerfile name to a platform-independent one relDockerfile, err = archive.CanonicalTarNameForPath(relDockerfile) if err != nil { return fmt.Errorf("cannot canonicalize dockerfile path %s: %v", relDockerfile, err) } f, err := os.Open(filepath.Join(contextDir, ".dockerignore")) if err != nil && !os.IsNotExist(err) { return err } var excludes []string if err == nil { excludes, err = utils.ReadDockerIgnore(f) if err != nil { return err } } if err := utils.ValidateContextDirectory(contextDir, excludes); err != nil { return fmt.Errorf("Error checking context: '%s'.", err) } // If .dockerignore mentions .dockerignore or the Dockerfile // then make sure we send both files over to the daemon // because Dockerfile is, obviously, needed no matter what, and // .dockerignore is needed to know if either one needs to be // removed. The deamon will remove them for us, if needed, after it // parses the Dockerfile. Ignore errors here, as they will have been // caught by ValidateContextDirectory above. var includes = []string{"."} keepThem1, _ := fileutils.Matches(".dockerignore", excludes) keepThem2, _ := fileutils.Matches(relDockerfile, excludes) if keepThem1 || keepThem2 { includes = append(includes, ".dockerignore", relDockerfile) } context, err = archive.TarWithOptions(contextDir, &archive.TarOptions{ Compression: archive.Uncompressed, ExcludePatterns: excludes, IncludeFiles: includes, }) if err != nil { return err } // Wrap the tar archive to replace the Dockerfile entry with the rewritten // Dockerfile which uses trusted pulls. context = replaceDockerfileTarWrapper(context, newDockerfile, relDockerfile) // Setup an upload progress bar // FIXME: ProgressReader shouldn't be this annoying to use sf := streamformatter.NewStreamFormatter() var body io.Reader = progressreader.New(progressreader.Config{ In: context, Out: cli.out, Formatter: sf, NewLines: true, ID: "", Action: "Sending build context to Docker daemon", }) var memory int64 if *flMemoryString != "" { parsedMemory, err := units.RAMInBytes(*flMemoryString) if err != nil { return err } memory = parsedMemory } var memorySwap int64 if *flMemorySwap != "" { if *flMemorySwap == "-1" { memorySwap = -1 } else { parsedMemorySwap, err := units.RAMInBytes(*flMemorySwap) if err != nil { return err } memorySwap = parsedMemorySwap } } // Send the build context v := url.Values{ "t": flTags.GetAll(), } if *suppressOutput { v.Set("q", "1") } if isRemote { v.Set("remote", cmd.Arg(0)) } if *noCache { v.Set("nocache", "1") } if *rm { v.Set("rm", "1") } else { v.Set("rm", "0") } if *forceRm { v.Set("forcerm", "1") } if *pull { v.Set("pull", "1") } v.Set("cpusetcpus", *flCPUSetCpus) v.Set("cpusetmems", *flCPUSetMems) v.Set("cpushares", strconv.FormatInt(*flCPUShares, 10)) v.Set("cpuquota", strconv.FormatInt(*flCPUQuota, 10)) v.Set("cpuperiod", strconv.FormatInt(*flCPUPeriod, 10)) v.Set("memory", strconv.FormatInt(memory, 10)) v.Set("memswap", strconv.FormatInt(memorySwap, 10)) v.Set("cgroupparent", *flCgroupParent) v.Set("dockerfile", relDockerfile) ulimitsVar := flUlimits.GetList() ulimitsJSON, err := json.Marshal(ulimitsVar) if err != nil { return err } v.Set("ulimits", string(ulimitsJSON)) // collect all the build-time environment variables for the container buildArgs := runconfig.ConvertKVStringsToMap(flBuildArg.GetAll()) buildArgsJSON, err := json.Marshal(buildArgs) if err != nil { return err } v.Set("buildargs", string(buildArgsJSON)) headers := http.Header(make(map[string][]string)) buf, err := json.Marshal(cli.configFile.AuthConfigs) if err != nil { return err } headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf)) headers.Set("Content-Type", "application/tar") sopts := &streamOpts{ rawTerminal: true, in: body, out: cli.out, headers: headers, } serverResp, err := cli.stream("POST", fmt.Sprintf("/build?%s", v.Encode()), sopts) // Windows: show error message about modified file permissions. if runtime.GOOS == "windows" { h, err := httputils.ParseServerHeader(serverResp.header.Get("Server")) if err == nil { if h.OS != "windows" { fmt.Fprintln(cli.err, `SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.`) } } } if jerr, ok := err.(*jsonmessage.JSONError); ok { // If no error code is set, default to 1 if jerr.Code == 0 { jerr.Code = 1 } return Cli.StatusError{Status: jerr.Message, StatusCode: jerr.Code} } if err != nil { return err } // Since the build was successful, now we must tag any of the resolved // images from the above Dockerfile rewrite. for _, resolved := range resolvedTags { if err := cli.tagTrusted(resolved.repoInfo, resolved.digestRef, resolved.tagRef); err != nil { return err } } return nil }
// CmdInfo displays system-wide information. // // Usage: docker info func (cli *DockerCli) CmdInfo(args ...string) error { cmd := cli.Subcmd("info", nil, "Display system-wide information", true) cmd.Require(flag.Exact, 0) cmd.ParseFlags(args, true) serverResp, err := cli.call("GET", "/info", nil, nil) if err != nil { return err } defer serverResp.body.Close() info := &types.Info{} if err := json.NewDecoder(serverResp.body).Decode(info); err != nil { return fmt.Errorf("Error reading remote info: %v", err) } fmt.Fprintf(cli.out, "Containers: %d\n", info.Containers) fmt.Fprintf(cli.out, "Images: %d\n", info.Images) ioutils.FprintfIfNotEmpty(cli.out, "Storage Driver: %s\n", info.Driver) if info.DriverStatus != nil { for _, pair := range info.DriverStatus { fmt.Fprintf(cli.out, " %s: %s\n", pair[0], pair[1]) } } ioutils.FprintfIfNotEmpty(cli.out, "Execution Driver: %s\n", info.ExecutionDriver) ioutils.FprintfIfNotEmpty(cli.out, "Logging Driver: %s\n", info.LoggingDriver) ioutils.FprintfIfNotEmpty(cli.out, "Kernel Version: %s\n", info.KernelVersion) ioutils.FprintfIfNotEmpty(cli.out, "Operating System: %s\n", info.OperatingSystem) fmt.Fprintf(cli.out, "CPUs: %d\n", info.NCPU) fmt.Fprintf(cli.out, "Total Memory: %s\n", units.BytesSize(float64(info.MemTotal))) ioutils.FprintfIfNotEmpty(cli.out, "Name: %s\n", info.Name) ioutils.FprintfIfNotEmpty(cli.out, "ID: %s\n", info.ID) if info.Debug { fmt.Fprintf(cli.out, "Debug mode (server): %v\n", info.Debug) fmt.Fprintf(cli.out, "File Descriptors: %d\n", info.NFd) fmt.Fprintf(cli.out, "Goroutines: %d\n", info.NGoroutines) fmt.Fprintf(cli.out, "System Time: %s\n", info.SystemTime) fmt.Fprintf(cli.out, "EventsListeners: %d\n", info.NEventsListener) fmt.Fprintf(cli.out, "Init SHA1: %s\n", info.InitSha1) fmt.Fprintf(cli.out, "Init Path: %s\n", info.InitPath) fmt.Fprintf(cli.out, "Docker Root Dir: %s\n", info.DockerRootDir) } ioutils.FprintfIfNotEmpty(cli.out, "Http Proxy: %s\n", info.HttpProxy) ioutils.FprintfIfNotEmpty(cli.out, "Https Proxy: %s\n", info.HttpsProxy) ioutils.FprintfIfNotEmpty(cli.out, "No Proxy: %s\n", info.NoProxy) if info.IndexServerAddress != "" { u := cli.configFile.AuthConfigs[info.IndexServerAddress].Username if len(u) > 0 { fmt.Fprintf(cli.out, "Username: %v\n", u) fmt.Fprintf(cli.out, "Registry: %v\n", info.IndexServerAddress) } } // Only output these warnings if the server supports these features if h, err := httputils.ParseServerHeader(serverResp.header.Get("Server")); err == nil { if h.OS != "windows" { if !info.MemoryLimit { fmt.Fprintf(cli.err, "WARNING: No memory limit support\n") } if !info.SwapLimit { fmt.Fprintf(cli.err, "WARNING: No swap limit support\n") } if !info.IPv4Forwarding { fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled.\n") } if !info.BridgeNfIptables { fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-iptables is disabled\n") } if !info.BridgeNfIp6tables { fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-ip6tables is disabled\n") } } } if info.Labels != nil { fmt.Fprintln(cli.out, "Labels:") for _, attribute := range info.Labels { fmt.Fprintf(cli.out, " %s\n", attribute) } } if info.ExperimentalBuild { fmt.Fprintf(cli.out, "Experimental: true\n") } return nil }
// CmdBuild builds a new image from the source code at a given path. // // If '-' is provided instead of a path or URL, Docker will build an image from either a Dockerfile or tar archive read from STDIN. // // Usage: docker build [OPTIONS] PATH | URL | - func (cli *DockerCli) CmdBuild(args ...string) error { cmd := Cli.Subcmd("build", []string{"PATH | URL | -"}, "Build a new image from the source code at PATH", true) tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) for the image") suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers") noCache := cmd.Bool([]string{"#no-cache", "-no-cache"}, false, "Do not use cache when building the image") rm := cmd.Bool([]string{"#rm", "-rm"}, true, "Remove intermediate containers after a successful build") forceRm := cmd.Bool([]string{"-force-rm"}, false, "Always remove intermediate containers") pull := cmd.Bool([]string{"-pull"}, false, "Always attempt to pull a newer version of the image") dockerfileName := cmd.String([]string{"f", "-file"}, "", "Name of the Dockerfile (Default is 'PATH/Dockerfile')") flMemoryString := cmd.String([]string{"m", "-memory"}, "", "Memory limit") flMemorySwap := cmd.String([]string{"-memory-swap"}, "", "Total memory (memory + swap), '-1' to disable swap") flCPUShares := cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)") flCpuPeriod := cmd.Int64([]string{"-cpu-period"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) period") flCpuQuota := cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota") flCPUSetCpus := cmd.String([]string{"-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)") flCPUSetMems := cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)") flCgroupParent := cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container") ulimits := make(map[string]*ulimit.Ulimit) flUlimits := opts.NewUlimitOpt(&ulimits) cmd.Var(flUlimits, []string{"-ulimit"}, "Ulimit options") cmd.Require(flag.Exact, 1) cmd.ParseFlags(args, true) var ( context archive.Archive isRemote bool err error ) _, err = exec.LookPath("git") hasGit := err == nil if cmd.Arg(0) == "-" { // As a special case, 'docker build -' will build from either an empty context with the // contents of stdin as a Dockerfile, or a tar-ed context from stdin. buf := bufio.NewReader(cli.in) magic, err := buf.Peek(tarHeaderSize) if err != nil && err != io.EOF { return fmt.Errorf("failed to peek context header from STDIN: %v", err) } if !archive.IsArchive(magic) { dockerfile, err := ioutil.ReadAll(buf) if err != nil { return fmt.Errorf("failed to read Dockerfile from STDIN: %v", err) } // -f option has no meaning when we're reading it from stdin, // so just use our default Dockerfile name *dockerfileName = api.DefaultDockerfileName context, err = archive.Generate(*dockerfileName, string(dockerfile)) } else { context = ioutil.NopCloser(buf) } } else if urlutil.IsURL(cmd.Arg(0)) && (!urlutil.IsGitURL(cmd.Arg(0)) || !hasGit) { isRemote = true } else { root := cmd.Arg(0) if urlutil.IsGitURL(root) { root, err = utils.GitClone(root) if err != nil { return err } defer os.RemoveAll(root) } if _, err := os.Stat(root); err != nil { return err } absRoot, err := filepath.Abs(root) if err != nil { return err } filename := *dockerfileName // path to Dockerfile if *dockerfileName == "" { // No -f/--file was specified so use the default *dockerfileName = api.DefaultDockerfileName filename = filepath.Join(absRoot, *dockerfileName) // Just to be nice ;-) look for 'dockerfile' too but only // use it if we found it, otherwise ignore this check if _, err = os.Lstat(filename); os.IsNotExist(err) { tmpFN := path.Join(absRoot, strings.ToLower(*dockerfileName)) if _, err = os.Lstat(tmpFN); err == nil { *dockerfileName = strings.ToLower(*dockerfileName) filename = tmpFN } } } origDockerfile := *dockerfileName // used for error msg if filename, err = filepath.Abs(filename); err != nil { return err } // Verify that 'filename' is within the build context filename, err = symlink.FollowSymlinkInScope(filename, absRoot) if err != nil { return fmt.Errorf("The Dockerfile (%s) must be within the build context (%s)", origDockerfile, root) } // Now reset the dockerfileName to be relative to the build context *dockerfileName, err = filepath.Rel(absRoot, filename) if err != nil { return err } // And canonicalize dockerfile name to a platform-independent one *dockerfileName, err = archive.CanonicalTarNameForPath(*dockerfileName) if err != nil { return fmt.Errorf("Cannot canonicalize dockerfile path %s: %v", *dockerfileName, err) } if _, err = os.Lstat(filename); os.IsNotExist(err) { return fmt.Errorf("Cannot locate Dockerfile: %s", origDockerfile) } var includes = []string{"."} excludes, err := utils.ReadDockerIgnore(path.Join(root, ".dockerignore")) if err != nil { return err } // If .dockerignore mentions .dockerignore or the Dockerfile // then make sure we send both files over to the daemon // because Dockerfile is, obviously, needed no matter what, and // .dockerignore is needed to know if either one needs to be // removed. The deamon will remove them for us, if needed, after it // parses the Dockerfile. keepThem1, _ := fileutils.Matches(".dockerignore", excludes) keepThem2, _ := fileutils.Matches(*dockerfileName, excludes) if keepThem1 || keepThem2 { includes = append(includes, ".dockerignore", *dockerfileName) } if err := utils.ValidateContextDirectory(root, excludes); err != nil { return fmt.Errorf("Error checking context: '%s'.", err) } options := &archive.TarOptions{ Compression: archive.Uncompressed, ExcludePatterns: excludes, IncludeFiles: includes, } context, err = archive.TarWithOptions(root, options) if err != nil { return err } } var body io.Reader // Setup an upload progress bar // FIXME: ProgressReader shouldn't be this annoying to use if context != nil { sf := streamformatter.NewStreamFormatter() body = progressreader.New(progressreader.Config{ In: context, Out: cli.out, Formatter: sf, NewLines: true, ID: "", Action: "Sending build context to Docker daemon", }) } var memory int64 if *flMemoryString != "" { parsedMemory, err := units.RAMInBytes(*flMemoryString) if err != nil { return err } memory = parsedMemory } var memorySwap int64 if *flMemorySwap != "" { if *flMemorySwap == "-1" { memorySwap = -1 } else { parsedMemorySwap, err := units.RAMInBytes(*flMemorySwap) if err != nil { return err } memorySwap = parsedMemorySwap } } // Send the build context v := &url.Values{} //Check if the given image name can be resolved if *tag != "" { repository, tag := parsers.ParseRepositoryTag(*tag) if err := registry.ValidateRepositoryName(repository); err != nil { return err } if len(tag) > 0 { if err := tags.ValidateTagName(tag); err != nil { return err } } } v.Set("t", *tag) if *suppressOutput { v.Set("q", "1") } if isRemote { v.Set("remote", cmd.Arg(0)) } if *noCache { v.Set("nocache", "1") } if *rm { v.Set("rm", "1") } else { v.Set("rm", "0") } if *forceRm { v.Set("forcerm", "1") } if *pull { v.Set("pull", "1") } v.Set("cpusetcpus", *flCPUSetCpus) v.Set("cpusetmems", *flCPUSetMems) v.Set("cpushares", strconv.FormatInt(*flCPUShares, 10)) v.Set("cpuquota", strconv.FormatInt(*flCpuQuota, 10)) v.Set("cpuperiod", strconv.FormatInt(*flCpuPeriod, 10)) v.Set("memory", strconv.FormatInt(memory, 10)) v.Set("memswap", strconv.FormatInt(memorySwap, 10)) v.Set("cgroupparent", *flCgroupParent) v.Set("dockerfile", *dockerfileName) ulimitsVar := flUlimits.GetList() ulimitsJson, err := json.Marshal(ulimitsVar) if err != nil { return err } v.Set("ulimits", string(ulimitsJson)) headers := http.Header(make(map[string][]string)) buf, err := json.Marshal(cli.configFile.AuthConfigs) if err != nil { return err } headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf)) if context != nil { headers.Set("Content-Type", "application/tar") } sopts := &streamOpts{ rawTerminal: true, in: body, out: cli.out, headers: headers, } serverResp, err := cli.stream("POST", fmt.Sprintf("/build?%s", v.Encode()), sopts) // Windows: show error message about modified file permissions. if runtime.GOOS == "windows" { h, err := httputils.ParseServerHeader(serverResp.header.Get("Server")) if err == nil { if h.OS != "windows" { fmt.Fprintln(cli.err, `SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.`) } } } if jerr, ok := err.(*jsonmessage.JSONError); ok { // If no error code is set, default to 1 if jerr.Code == 0 { jerr.Code = 1 } return Cli.StatusError{Status: jerr.Message, StatusCode: jerr.Code} } return err }
// CmdInfo displays system-wide information. // // Usage: docker info func (cli *DockerCli) CmdInfo(args ...string) error { cmd := Cli.Subcmd("info", nil, Cli.DockerCommands["info"].Description, true) cmd.Require(flag.Exact, 0) cmd.ParseFlags(args, true) serverResp, err := cli.call("GET", "/info", nil, nil) if err != nil { return err } defer serverResp.body.Close() info := &types.Info{} if err := json.NewDecoder(serverResp.body).Decode(info); err != nil { return fmt.Errorf("Error reading remote info: %v", err) } fmt.Fprintf(cli.out, "Containers: %d\n", info.Containers) fmt.Fprintf(cli.out, "Images: %d\n", info.Images) ioutils.FprintfIfNotEmpty(cli.out, "Server Version: %s\n", info.ServerVersion) ioutils.FprintfIfNotEmpty(cli.out, "Storage Driver: %s\n", info.Driver) if info.DriverStatus != nil { for _, pair := range info.DriverStatus { fmt.Fprintf(cli.out, " %s: %s\n", pair[0], pair[1]) } } ioutils.FprintfIfNotEmpty(cli.out, "Execution Driver: %s\n", info.ExecutionDriver) ioutils.FprintfIfNotEmpty(cli.out, "Logging Driver: %s\n", info.LoggingDriver) fmt.Fprintf(cli.out, "Plugins: \n") fmt.Fprintf(cli.out, " Volume:") for _, driver := range info.Plugins.Volume { fmt.Fprintf(cli.out, " %s", driver) } fmt.Fprintf(cli.out, "\n") fmt.Fprintf(cli.out, " Network:") for _, driver := range info.Plugins.Network { fmt.Fprintf(cli.out, " %s", driver) } fmt.Fprintf(cli.out, "\n") ioutils.FprintfIfNotEmpty(cli.out, "Kernel Version: %s\n", info.KernelVersion) ioutils.FprintfIfNotEmpty(cli.out, "Operating System: %s\n", info.OperatingSystem) ioutils.FprintfIfNotEmpty(cli.out, "OSType: %s\n", info.OSType) ioutils.FprintfIfNotEmpty(cli.out, "Architecture: %s\n", info.Architecture) fmt.Fprintf(cli.out, "CPUs: %d\n", info.NCPU) fmt.Fprintf(cli.out, "Total Memory: %s\n", units.BytesSize(float64(info.MemTotal))) ioutils.FprintfIfNotEmpty(cli.out, "Name: %s\n", info.Name) ioutils.FprintfIfNotEmpty(cli.out, "ID: %s\n", info.ID) if info.Debug { fmt.Fprintf(cli.out, "Debug mode (server): %v\n", info.Debug) fmt.Fprintf(cli.out, " File Descriptors: %d\n", info.NFd) fmt.Fprintf(cli.out, " Goroutines: %d\n", info.NGoroutines) fmt.Fprintf(cli.out, " System Time: %s\n", info.SystemTime) fmt.Fprintf(cli.out, " EventsListeners: %d\n", info.NEventsListener) fmt.Fprintf(cli.out, " Init SHA1: %s\n", info.InitSha1) fmt.Fprintf(cli.out, " Init Path: %s\n", info.InitPath) fmt.Fprintf(cli.out, " Docker Root Dir: %s\n", info.DockerRootDir) } ioutils.FprintfIfNotEmpty(cli.out, "Http Proxy: %s\n", info.HTTPProxy) ioutils.FprintfIfNotEmpty(cli.out, "Https Proxy: %s\n", info.HTTPSProxy) ioutils.FprintfIfNotEmpty(cli.out, "No Proxy: %s\n", info.NoProxy) if info.IndexServerAddress != "" { u := cli.configFile.AuthConfigs[info.IndexServerAddress].Username if len(u) > 0 { fmt.Fprintf(cli.out, "Username: %v\n", u) fmt.Fprintf(cli.out, "Registry: %v\n", info.IndexServerAddress) } } // Only output these warnings if the server does not support these features if h, err := httputils.ParseServerHeader(serverResp.header.Get("Server")); err == nil { if h.OS != "windows" { if !info.MemoryLimit { fmt.Fprintf(cli.err, "WARNING: No memory limit support\n") } if !info.SwapLimit { fmt.Fprintf(cli.err, "WARNING: No swap limit support\n") } if !info.OomKillDisable { fmt.Fprintf(cli.err, "WARNING: No oom kill disable support\n") } if !info.CPUCfsQuota { fmt.Fprintf(cli.err, "WARNING: No cpu cfs quota support\n") } if !info.CPUCfsPeriod { fmt.Fprintf(cli.err, "WARNING: No cpu cfs period support\n") } if !info.CPUShares { fmt.Fprintf(cli.err, "WARNING: No cpu shares support\n") } if !info.CPUSet { fmt.Fprintf(cli.err, "WARNING: No cpuset support\n") } if !info.IPv4Forwarding { fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled\n") } if !info.BridgeNfIptables { fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-iptables is disabled\n") } if !info.BridgeNfIP6tables { fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-ip6tables is disabled\n") } } } if info.Labels != nil { fmt.Fprintln(cli.out, "Labels:") for _, attribute := range info.Labels { fmt.Fprintf(cli.out, " %s\n", attribute) } } ioutils.FprintfIfTrue(cli.out, "Experimental: %v\n", info.ExperimentalBuild) if info.ClusterStore != "" { fmt.Fprintf(cli.out, "Cluster store: %s\n", info.ClusterStore) } if info.ClusterAdvertise != "" { fmt.Fprintf(cli.out, "Cluster advertise: %s\n", info.ClusterAdvertise) } return nil }