func (b *Builder) commit(id string, autoCmd *runconfig.Command, comment string) error { if b.disableCommit { return nil } if b.image == "" && !b.noBaseImage { return fmt.Errorf("Please provide a source image with `from` prior to commit") } b.Config.Image = b.image if id == "" { cmd := b.Config.Cmd if runtime.GOOS != "windows" { b.Config.Cmd = runconfig.NewCommand("/bin/sh", "-c", "#(nop) "+comment) } else { b.Config.Cmd = runconfig.NewCommand("cmd", "/S /C", "REM (nop) "+comment) } defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd) hit, err := b.probeCache() if err != nil { return err } if hit { return nil } container, err := b.create() if err != nil { return err } id = container.ID } container, err := b.Daemon.Get(id) if err != nil { return err } // Note: Actually copy the struct autoConfig := *b.Config autoConfig.Cmd = autoCmd // Commit the container image, err := b.Daemon.Commit(container, "", "", "", b.maintainer, true, &autoConfig) if err != nil { return err } b.image = image.ID return nil }
// CMD foo // // Set the default command to run in the container (which may be empty). // Argument handling is the same as RUN. // func cmd(b *Builder, args []string, attributes map[string]bool, original string) error { if err := b.BuilderFlags.Parse(); err != nil { return err } cmdSlice := handleJsonArgs(args, attributes) if !attributes["json"] { if runtime.GOOS != "windows" { cmdSlice = append([]string{"/bin/sh", "-c"}, cmdSlice...) } else { cmdSlice = append([]string{"cmd", "/S /C"}, cmdSlice...) } } b.Config.Cmd = runconfig.NewCommand(cmdSlice...) if err := b.commit("", b.Config.Cmd, fmt.Sprintf("CMD %q", cmdSlice)); err != nil { return err } if len(args) != 0 { b.cmdSet = true } return nil }
func (b *Builder) create() (*daemon.Container, error) { if b.image == "" && !b.noBaseImage { return nil, fmt.Errorf("Please provide a source image with `from` prior to run") } b.Config.Image = b.image config := *b.Config // Create the Pod podId := fmt.Sprintf("buildpod-%s", utils.RandStr(10, "alpha")) podString, err := MakeBasicPod(podId, b.image, b.Config.Cmd.Slice()) if err != nil { return nil, err } err = b.Hyperdaemon.CreatePod(podId, podString, false) if err != nil { return nil, err } // Get the container var ( containerId = "" c *daemon.Container ) ps, ok := b.Hyperdaemon.PodList.GetStatus(podId) if !ok { return nil, fmt.Errorf("Cannot find pod %s", podId) } for _, i := range ps.Containers { containerId = i.Id } c, err = b.Daemon.Get(containerId) if err != nil { glog.Error(err.Error()) return nil, err } b.TmpContainers[c.ID] = struct{}{} b.TmpPods[podId] = struct{}{} fmt.Fprintf(b.OutStream, " ---> Running in %s\n", stringid.TruncateID(c.ID)) if config.Cmd.Len() > 0 { // override the entry point that may have been picked up from the base image s := config.Cmd.Slice() c.Path = s[0] c.Args = s[1:] } else { config.Cmd = runconfig.NewCommand() } return c, nil }
func (cli Docker) SendCmdCreate(name, image string, cmds []string, userConfig interface{}) ([]byte, int, error) { config := runconfig.Config{ Image: image, Cmd: runconfig.NewCommand(cmds...), } if userConfig != nil { config = userConfig.(runconfig.Config) } hostConfig := &runconfig.HostConfig{} containerId, _, err := cli.daemon.ContainerCreate(name, &config, hostConfig) if err != nil { return nil, 500, err } return []byte(containerId), 200, nil }
func (b *Builder) runContextCommand(args []string, allowRemote bool, allowDecompression bool, cmdName string) error { if b.context == nil { return fmt.Errorf("No context given. Impossible to use %s", cmdName) } if len(args) < 2 { return fmt.Errorf("Invalid %s format - at least two arguments required", cmdName) } dest := args[len(args)-1] // last one is always the dest copyInfos := []*copyInfo{} b.Config.Image = b.image defer func() { for _, ci := range copyInfos { if ci.tmpDir != "" { os.RemoveAll(ci.tmpDir) } } }() // Loop through each src file and calculate the info we need to // do the copy (e.g. hash value if cached). Don't actually do // the copy until we've looked at all src files for _, orig := range args[0 : len(args)-1] { if err := calcCopyInfo( b, cmdName, ©Infos, orig, dest, allowRemote, allowDecompression, true, ); err != nil { glog.Error(err.Error()) return err } } if len(copyInfos) == 0 { return fmt.Errorf("No source files were specified") } if len(copyInfos) > 1 && !strings.HasSuffix(dest, "/") { return fmt.Errorf("When using %s with more than one source file, the destination must be a directory and end with a /", cmdName) } // For backwards compat, if there's just one CI then use it as the // cache look-up string, otherwise hash 'em all into one var srcHash string var origPaths string if len(copyInfos) == 1 { srcHash = copyInfos[0].hash origPaths = copyInfos[0].origPath } else { var hashs []string var origs []string for _, ci := range copyInfos { hashs = append(hashs, ci.hash) origs = append(origs, ci.origPath) } hasher := sha256.New() hasher.Write([]byte(strings.Join(hashs, ","))) srcHash = "multi:" + hex.EncodeToString(hasher.Sum(nil)) origPaths = strings.Join(origs, " ") } cmd := b.Config.Cmd if runtime.GOOS != "windows" { b.Config.Cmd = runconfig.NewCommand("/bin/sh", "-c", fmt.Sprintf("#(nop) %s %s in %s", cmdName, srcHash, dest)) } else { b.Config.Cmd = runconfig.NewCommand("cmd", "/S /C", fmt.Sprintf("REM (nop) %s %s in %s", cmdName, srcHash, dest)) } defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd) hit, err := b.probeCache() if err != nil { return err } if hit { return nil } b.Config.Image = b.image // config := *b.Config // Create the Pod podId := fmt.Sprintf("buildpod-%s", utils.RandStr(10, "alpha")) tempSrcDir := fmt.Sprintf("/var/run/hyper/temp/%s/", podId) if err := os.MkdirAll(tempSrcDir, 0755); err != nil { glog.Errorf(err.Error()) return err } if _, err := os.Stat(tempSrcDir); err != nil { glog.Errorf(err.Error()) return err } shellDir := fmt.Sprintf("/var/run/hyper/shell/%s/", podId) if err := os.MkdirAll(shellDir, 0755); err != nil { glog.Errorf(err.Error()) return err } copyshell, err1 := os.Create(shellDir + "/exec-copy.sh") if err1 != nil { glog.Errorf(err1.Error()) return err1 } fmt.Fprintf(copyshell, "#!/bin/sh\n") podString, err := MakeCopyPod(podId, b.image, b.Config.WorkingDir, tempSrcDir, dest, shellDir) if err != nil { return err } err = b.Hyperdaemon.CreatePod(podId, podString, false) if err != nil { return err } // Get the container var ( containerId = "" container *daemon.Container ) ps, ok := b.Hyperdaemon.PodList.GetStatus(podId) if !ok { return fmt.Errorf("Cannot find pod %s", podId) } for _, i := range ps.Containers { containerId = i.Id } container, err = b.Daemon.Get(containerId) if err != nil { glog.Error(err.Error()) return err } b.TmpContainers[container.ID] = struct{}{} b.TmpPods[podId] = struct{}{} for _, ci := range copyInfos { glog.V(1).Infof("container %s, origPath %s, destPath %s", container.ID, ci.origPath, ci.destPath) // Copy the source files to tempSrcDir if err := b.addContext(container, ci.origPath, tempSrcDir, ci.decompress); err != nil { glog.Error(err.Error()) return err } if strings.HasSuffix(dest, "/") == true { fmt.Fprintf(copyshell, fmt.Sprintf("cp /tmp/src/%s %s\n", ci.origPath, ci.destPath)) } else { fmt.Fprintf(copyshell, fmt.Sprintf("cp /tmp/src/%s %s\n", ci.origPath, dest)) break } } fmt.Fprintf(copyshell, "umount /tmp/src/\n") fmt.Fprintf(copyshell, "umount /tmp/shell/\n") fmt.Fprintf(copyshell, "rm -rf /tmp/shell/\n") fmt.Fprintf(copyshell, "rm -rf /tmp/src/\n") copyshell.Close() // start or replace pod vm, ok := b.Hyperdaemon.VmList[b.Name] if !ok { glog.Warningf("can not find VM(%s)", b.Name) bo := &hypervisor.BootConfig{ CPU: 1, Memory: 512, Kernel: b.Hyperdaemon.Kernel, Initrd: b.Hyperdaemon.Initrd, Bios: b.Hyperdaemon.Bios, Cbfs: b.Hyperdaemon.Cbfs, Vbox: b.Hyperdaemon.VboxImage, } vm = b.Hyperdaemon.NewVm(b.Name, 1, 512, false, types.VM_KEEP_AFTER_FINISH) err = vm.Launch(bo) if err != nil { return err } b.Hyperdaemon.AddVm(vm) } if vm.Status == types.S_VM_IDLE { code, cause, err := b.Hyperdaemon.StartPod(podId, "", b.Name, nil, false, false, types.VM_KEEP_AFTER_FINISH, []*hypervisor.TtyIO{}) if err != nil { glog.Errorf("Code is %d, Cause is %s, %s", code, cause, err.Error()) b.Hyperdaemon.KillVm(b.Name) return err } vm = b.Hyperdaemon.VmList[b.Name] // wait for cmd finish Status, err := vm.GetResponseChan() if err != nil { glog.Error(err.Error()) return err } defer vm.ReleaseResponseChan(Status) var vmResponse *types.VmResponse for { vmResponse = <-Status if vmResponse.VmId == b.Name { if vmResponse.Code == types.E_POD_FINISHED { glog.Infof("Got E_POD_FINISHED code response") break } } } pod, ok := b.Hyperdaemon.PodList.Get(podId) if !ok { return fmt.Errorf("Cannot find pod %s", podId) } pod.SetVM(b.Name, vm) // release pod from VM glog.Warningf("start stop pod") code, cause, err = b.Hyperdaemon.StopPod(podId, "no") if err != nil { glog.Errorf("Code is %d, Cause is %s, %s", code, cause, err.Error()) b.Hyperdaemon.KillVm(b.Name) return err } glog.Warningf("stop pod finish") } else { glog.Errorf("Vm is not IDLE") return fmt.Errorf("Vm is not IDLE") } glog.Warningf("begin commit") if err := b.commit(container.ID, cmd, fmt.Sprintf("%s %s in %s", cmdName, origPaths, dest)); err != nil { return err } return nil }