Пример #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
// ClientOrDie creates a new Docker client. If one couldn't be created, logs and error and exits with status code 1
func ClientOrDie() *docker.Client {
	cl, err := docker.NewClientFromEnv()
	if err != nil {
		log.Err("creating new docker client (%s)", err)
		os.Exit(1)
	}
	return cl
}
Пример #3
0
// PathsOrDie gets the current GOPATH, current working directory and package name and returns them all in the Paths struct. If any one of those values can't be obtained, this func logs the error and exits the process
func PathsOrDie() Paths {
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		log.Err("GOPATH environment variable not found")
		os.Exit(1)
	}

	cwd, err := os.Getwd()
	if err != nil {
		log.Err("getting current working dir (%s)", err)
		os.Exit(1)
	}

	pkgPath, err := packagePath(gopath, cwd)
	if err != nil {
		log.Err("Error detecting package name [%s]", err)
		os.Exit(1)
	}

	return Paths{GoPath: gopath, PackageName: pkgPath, CWD: cwd}
}
Пример #4
0
// DockerPush is the cli action for 'godo docker-push'
func DockerPush(c *cli.Context) {
	dockerClient := dockutil.ClientOrDie()
	cfg := config.ReadOrDie(c.String(FlagConfigFile))
	if cfg.Docker.ImageName == "" {
		log.Err("Docker image name was empty")
		os.Exit(1)
	}

	pio := docker.PushImageOptions{
		Name:         cfg.Docker.ImageName,
		Tag:          cfg.Docker.GetTag(),
		OutputStream: os.Stdout,
	}

	authFileLoc := cfg.Docker.Push.GetAuthFileLocation()
	authFile, err := os.Open(authFileLoc)
	if err != nil {
		log.Err("Reading Docker auth file %s [%s]", authFileLoc, err)
		os.Exit(1)
	}
	defer func() {
		if err := authFile.Close(); err != nil {
			log.Err("Closing Docker auth file %s [%s]", authFileLoc, err)
		}
	}()

	auths, err := docker.NewAuthConfigurations(authFile)
	if err != nil {
		log.Err("Parsing auth file %s [%s]", authFileLoc, err)
		os.Exit(1)
	}

	registry := "https://index.docker.io/v1/"
	spl := strings.Split(pio.Name, "/")
	if len(spl) == 3 {
		registry = spl[0]
	}

	auth, ok := auths.Configs[registry]
	if !ok {
		log.Err("Registry %s in your image %s is not in auth file %s ", registry, pio.Name, authFileLoc)
		os.Exit(1)
	}

	if err := dockerClient.PushImage(pio, auth); err != nil {
		log.Err("Pushing Docker image %s [%s]", pio.Name, err)
		os.Exit(1)
	}
	log.Info("Successfully pushed Docker image %s:%s", pio.Name, pio.Tag)
}
Пример #5
0
// DockerBuild is the CLI action for 'godo docker-build'
func DockerBuild(c *cli.Context) {
	dockerClient := dockutil.ClientOrDie()

	cfg := config.ReadOrDie(c.String(FlagConfigFile))
	if cfg.Docker.ImageName == "" {
		log.Err("Docker image name was empty")
		os.Exit(1)
	}

	dockerfileLocation := cfg.Docker.Build.GetDockerfileLocation()
	dockerfileBytes, err := ioutil.ReadFile(dockerfileLocation)
	if err != nil {
		log.Err("Reading Dockerfile %s [%s]", dockerfileLocation, err)
		os.Exit(1)
	}

	t := time.Now()
	buf := bytes.NewBuffer(nil)
	tr := tar.NewWriter(buf)
	tr.WriteHeader(&tar.Header{
		Name:       "Dockerfile",
		Size:       int64(len(dockerfileBytes)),
		ModTime:    t,
		AccessTime: t,
		ChangeTime: t,
	})
	tr.Write(dockerfileBytes)

	buildCtx, err := filepath.Abs(cfg.Docker.Build.Context.GetDirectory())
	if err != nil {
		log.Err("Invalid Docker build context %s [%s]", cfg.Docker.Build.Context.GetDirectory(), err)
		os.Exit(1)
	}

	skipSet := cfg.Docker.Build.Context.GetSkips()
	err = tarDir(buildCtx, tr, func(path string, fi os.FileInfo) bool {
		if _, ok := skipSet[path]; ok {
			return true
		}
		if strings.Contains(path, ".git") {
			return true
		}
		if fi.Name() == "Dockerfile" {
			return true
		}
		return false
	})
	if err != nil {
		log.Err("Archiving the build context directory %s [%s]", buildCtx, err)
		os.Exit(1)
	}

	if err := tr.Close(); err != nil {
		log.Err("Closing the build context archive preparing to send it to the Docker daemon [%s]", err)
		os.Exit(1)
	}

	opts := docker.BuildImageOptions{
		Name:           fmt.Sprintf("%s:%s", cfg.Docker.ImageName, cfg.Docker.GetTag()),
		InputStream:    buf,
		Dockerfile:     "Dockerfile",
		OutputStream:   os.Stdout,
		RmTmpContainer: true,
		Pull:           true,
	}
	if err := dockerClient.BuildImage(opts); err != nil {
		log.Err("Building image %s [%s]", cfg.Docker.ImageName, err)
		os.Exit(1)
	}
	log.Info("Successfully built Docker image %s", opts.Name)
}
Пример #6
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
		}
	}
}