Пример #1
0
// Build is the CLI handler for 'godo build'
func Build(c *cli.Context) {
	cfg := config.ReadOrDie(c.String(FlagConfigFile))
	paths := PathsOrDie()

	dockerClient := docker.ClientOrDie()
	imgStr := fmt.Sprintf("%s:%s", cfg.Build.ImageName, cfg.Build.ImageTag)
	img, err := docker.ParseImageFromName(imgStr)
	if err != nil {
		log.Err("error parsing docker image %s (%s)", imgStr, err)
		os.Exit(1)
	}

	rmContainerCh := make(chan func())
	stdOutCh := make(chan docker.Log)
	stdErrCh := make(chan docker.Log)
	exitCodeCh := make(chan int)
	errCh := make(chan error)

	projName := filepath.Base(paths.CWD)
	binaryName := cfg.Build.GetOutputBinary(projName)
	go docker.Run(
		dockerClient,
		img,
		"build",
		paths.CWD,
		docker.ContainerGopath(cfg.Build.Gopath, paths.PackageName),
		fmt.Sprintf("go build -o %s .", binaryName),
		cfg.Build.Env,
		rmContainerCh,
		stdOutCh,
		stdErrCh,
		exitCodeCh,
		errCh,
	)

	for {
		select {
		case rmContainerFn := <-rmContainerCh:
			defer rmContainerFn()
		case l := <-stdOutCh:
			log.Info("%s", l)
		case l := <-stdErrCh:
			log.Warn("%s", l)
		case err := <-errCh:
			log.Err("%s", err)
			return
		case i := <-exitCodeCh:
			log.Info("exited with code %d", i)
			return
		}
	}

}
Пример #2
0
// Run runs cmd in the given image using the docker client cl. It mounts cwd into containerMount in the running container and sends on the following channels:
//
// - rmContainerCh: a function closure that the receiver should call, after they receive on errCh or exitCodeCh, to remove the container. this is commonly done with a 'defer'
// - stdOut: all logs from STDOUT in the container. this may never receive
// - stdErr: all logs from STDERR in the container. this may never receive
// - exitCodeCh: the exit code of the container
// - errCh: any error in setting up or running the container. if errCh receives, exitCodeCh may not receive
func Run(
	cl *docker.Client,
	image *Image,
	taskName,
	cwd,
	containerMount,
	cmd string,
	env []string,
	rmContainerCh chan<- func(),
	stdOut chan<- Log,
	stdErr chan<- Log,
	exitCodeCh chan<- int,
	errCh chan<- error,
) {

	mounts := []docker.Mount{
		{Name: "pwd", Source: cwd, Destination: containerMount, Mode: "rxw"},
	}
	cmdSpl := strings.Split(cmd, " ")

	containerName := NewContainerName(taskName, cwd)
	createContainerOpts, hostConfig := CreateAndStartContainerOpts(image.String(), containerName, cmdSpl, env, mounts, containerMount)
	if err := EnsureImage(cl, image.String(), func() (io.Writer, error) {
		return os.Stdout, nil
	}); err != nil {
		errCh <- err
		return
	}

	container, err := cl.CreateContainer(createContainerOpts)
	if err != nil {
		errCh <- err
	}

	rmContainerCh <- func() {
		if err := cl.RemoveContainer(docker.RemoveContainerOptions{ID: container.ID, Force: true}); err != nil {
			log.Warn("Error removing container %s (%s)", container.ID, err)
		}
	}

	log.Debug(CmdStr(createContainerOpts, hostConfig))

	attachOpts := AttachToContainerOpts(container.ID, NewChanWriter(stdOut), NewChanWriter(stdErr))
	// attach before the container starts, so we get all the logs etc...
	go AttachAndWait(cl, container.ID, attachOpts, exitCodeCh, errCh)

	if startErr := cl.StartContainer(container.ID, &hostConfig); startErr != nil {
		errCh <- err
		return
	}
}
Пример #3
0
// Custom is the CLI action for 'godo custom ...' commands
func Custom(c *cli.Context) {
	cfg := config.ReadOrDie(c.String(FlagConfigFile))
	if c.Bool(ListCustomFlag) {
		for _, customTarget := range cfg.Custom {
			log.Info("'%s' - %s", customTarget.Name, customTarget.Description)
		}
		return
	}
	if len(c.Args()) < 1 || c.Args()[0] == "" {
		log.Err("you must call this command as 'godo custom <target>'")
		os.Exit(1)
	}
	customName := c.Args()[0]
	customMap := make(map[string]config.CustomTarget)
	for _, customTarget := range cfg.Custom {
		customMap[customTarget.Name] = customTarget
	}
	target, ok := customMap[customName]
	if !ok {
		log.Err("no custom target '%s' found", customName)
		os.Exit(1)
	}

	dockerImage, err := docker.ParseImageFromName(fmt.Sprintf("%s:%s", target.ImageName, target.ImageTag))
	if err != nil {
		log.Err("invalid image name %s:%s (%s)", target.ImageName, target.ImageTag)
		os.Exit(1)
	}

	dockerCl := docker.ClientOrDie()
	paths := PathsOrDie()
	log.Info("executing %s in a %s:%s container", customName, target.ImageName, target.ImageTag)

	rmContainerCh := make(chan func())
	stdOutCh := make(chan docker.Log)
	stdErrCh := make(chan docker.Log)
	exitCodeCh := make(chan int)
	errCh := make(chan error)
	go docker.Run(
		dockerCl,
		dockerImage,
		customName,
		paths.CWD,
		target.MountTarget,
		target.Command,
		target.Envs,
		rmContainerCh,
		stdOutCh,
		stdErrCh,
		exitCodeCh,
		errCh,
	)

	for {
		select {
		case fn := <-rmContainerCh:
			defer fn()
		case l := <-stdOutCh:
			log.Info("%s", l)
		case l := <-stdErrCh:
			log.Warn("%s", l)
		case i := <-exitCodeCh:
			log.Info("exited with code %d", i)
			return
		case err := <-errCh:
			log.Err("%s", err)
			return
		}
	}
}