Beispiel #1
0
// NewDeployOptions constructor
func NewDeployOptions(c util.Settings, e *util.Environment) (*PipelineOptions, error) {
	pipelineOpts, err := NewPipelineOptions(c, e)
	if err != nil {
		return nil, err
	}
	// default to last build output if none defined
	target, _ := c.String("target")
	if target == "" {
		found, err := util.Exists("./.wercker/latest/output")
		if err == nil && found {
			util.RootLogger().Println("No target specified, using recent build output.")
			pipelineOpts.ProjectPath, _ = filepath.Abs("./.wercker/latest/output")
		}
	}

	// if the deploy target path does not have a wercker.yml, use the current one
	werckerYml, _ := c.String("wercker-yml")
	if werckerYml == "" {
		found, _ := util.Exists(filepath.Join(pipelineOpts.ProjectPath, "wercker.yml"))
		if !found {
			pipelineOpts.WerckerYml = "./wercker.yml"
		}
	}

	if pipelineOpts.RunID == "" {
		pipelineOpts.RunID = uuid.NewRandom().String()
	}
	return pipelineOpts, nil
}
Beispiel #2
0
// Execute actually sends the commands for the step.
func (s *ExternalStep) Execute(sessionCtx context.Context, sess *Session) (int, error) {
	err := s.SetupGuest(sessionCtx, sess)
	if err != nil {
		return 1, err
	}
	_, _, err = sess.SendChecked(sessionCtx, s.env.Export()...)
	if err != nil {
		return 1, err
	}

	// if s.options.GlobalOptions.Verbose {
	// 	sess.SendChecked(sessionCtx, "set -xv")
	// }

	if yes, _ := util.Exists(s.HostPath("init.sh")); yes {
		exit, _, err := sess.SendChecked(sessionCtx, fmt.Sprintf(`source "%s"`, s.GuestPath("init.sh")))
		if exit != 0 {
			return exit, errors.New("Ack!")
		}
		if err != nil {
			return 1, err
		}
	}

	if yes, _ := util.Exists(s.HostPath("run.sh")); yes {
		exit, _, err := sess.SendChecked(sessionCtx, fmt.Sprintf(`source "%s" < /dev/null`, s.GuestPath("run.sh")))
		return exit, err
	}

	return 0, nil
}
Beispiel #3
0
// guessAuthToken will attempt to read from the token store location if
// no auth token was provided
func guessAuthToken(c util.Settings, e *util.Environment, authTokenStore string) string {
	token, _ := c.GlobalString("auth-token")
	if token != "" {
		return token
	}
	if foundToken, _ := util.Exists(authTokenStore); !foundToken {
		return ""
	}

	tokenBytes, err := ioutil.ReadFile(authTokenStore)
	if err != nil {
		util.RootLogger().WithField("Logger", "Options").Errorln(err)
		return ""
	}
	return strings.TrimSpace(string(tokenBytes))
}
Beispiel #4
0
// LocalSymlink makes sure we have an easy to use local symlink
func (s *ExternalStep) LocalSymlink() {
	name := strings.Replace(s.DisplayName(), " ", "-", -1)
	checkName := fmt.Sprintf("step-%s", name)
	checkPath := s.options.HostPath(checkName)

	counter := 1
	newPath := checkPath
	for {
		already, _ := util.Exists(newPath)
		if !already {
			os.Symlink(s.HostPath(), newPath)
			break
		}

		newPath = fmt.Sprintf("%s-%d", checkPath, counter)
		counter++
	}
}
Beispiel #5
0
func findYaml(searchDirs []string) (string, error) {
	possibleYaml := []string{"ewok.yml", "wercker.yml", ".wercker.yml"}

	for _, v := range searchDirs {
		for _, y := range possibleYaml {
			possibleYaml := path.Join(v, y)
			ymlExists, err := util.Exists(possibleYaml)
			if err != nil {
				return "", err
			}
			if !ymlExists {
				continue
			}
			return possibleYaml, nil
		}
	}
	return "", fmt.Errorf("No wercker.yml found")
}
Beispiel #6
0
func cmdPull(c *cli.Context, options *core.PullOptions, dockerOptions *dockerlocal.DockerOptions) error {
	soft := NewSoftExit(options.GlobalOptions)
	logger := util.RootLogger().WithField("Logger", "Main")

	if options.Debug {
		DumpOptions(options)
	}

	client := api.NewAPIClient(&api.APIOptions{
		BaseURL:   options.GlobalOptions.BaseURL,
		AuthToken: options.GlobalOptions.AuthToken,
	})

	var buildID string

	if core.IsBuildID(options.Repository) {
		buildID = options.Repository
	} else {
		username, applicationName, err := core.ParseApplicationID(options.Repository)
		if err != nil {
			return soft.Exit(err)
		}

		logger.Println("Fetching build information for application", options.Repository)

		opts := &api.GetBuildsOptions{
			Limit:  1,
			Branch: options.Branch,
			Result: options.Result,
			Status: "finished",
			Stack:  5,
		}

		builds, err := client.GetBuilds(username, applicationName, opts)
		if err != nil {
			return soft.Exit(err)
		}

		if len(builds) != 1 {
			return soft.Exit(errors.New("No finished builds found for this application"))
		}

		buildID = builds[0].ID
	}

	if buildID == "" {
		return soft.Exit(errors.New("Unable to parse argument as application or build-id"))
	}

	logger.Println("Downloading Docker repository for build", buildID)

	if !options.Force {
		outputExists, err := util.Exists(options.Output)
		if err != nil {
			logger.WithField("Error", err).Error("Unable to create output file")
			return soft.Exit(err)
		}

		if outputExists {
			return soft.Exit(errors.New("The file repository.tar already exists. Delete it, or run again with -f"))
		}
	}

	file, err := os.Create(options.Output)
	if err != nil {
		logger.WithField("Error", err).Error("Unable to create output file")
		return soft.Exit(err)
	}

	repository, err := client.GetDockerRepository(buildID)
	if err != nil {
		os.Remove(file.Name())
		return soft.Exit(err)
	}
	defer repository.Content.Close()

	// Diagram of the various readers/writers
	//   repository <-- tee <-- s <-- [io.Copy] --> file
	//               |
	//               +--> hash       *Legend: --> == write, <-- == read

	counter := util.NewCounterReader(repository.Content)

	stopEmit := emitProgress(counter, repository.Size, util.NewRawLogger())

	hash := sha256.New()
	tee := io.TeeReader(counter, hash)
	s := snappystream.NewReader(tee, true)

	_, err = io.Copy(file, s)
	if err != nil {
		logger.WithField("Error", err).Error("Unable to copy data from URL to file")
		os.Remove(file.Name())
		return soft.Exit(err)
	}

	stopEmit <- true

	logger.Println("Download complete")

	calculatedHash := hex.EncodeToString(hash.Sum(nil))
	if calculatedHash != repository.Sha256 {
		return soft.Exit(fmt.Errorf("Calculated hash did not match provided hash (calculated: %s ; expected: %s)", calculatedHash, repository.Sha256))
	}

	if options.Load {
		_, err = file.Seek(0, 0)
		if err != nil {
			logger.WithField("Error", err).Error("Unable to reset seeker")
			return soft.Exit(err)
		}

		dockerClient, err := dockerlocal.NewDockerClient(dockerOptions)
		if err != nil {
			logger.WithField("Error", err).Error("Unable to create Docker client")
			return soft.Exit(err)
		}

		logger.Println("Importing into Docker")

		importImageOptions := docker.LoadImageOptions{InputStream: file}
		err = dockerClient.LoadImage(importImageOptions)
		if err != nil {
			logger.WithField("Error", err).Error("Unable to load image")
			return soft.Exit(err)
		}

		logger.Println("Finished importing into Docker")
	}

	return nil
}
Beispiel #7
0
// Fetch grabs the Step content (or calls FetchScript for script steps).
func (s *ExternalStep) Fetch() (string, error) {
	// NOTE(termie): polymorphism based on kind, we could probably do something
	//               with interfaces here, but this is okay for now
	if s.IsScript() {
		return s.FetchScript()
	}

	stepPath := filepath.Join(s.options.StepPath(), s.CachedName())
	stepExists, err := util.Exists(stepPath)
	if err != nil {
		return "", err
	}

	if !stepExists {
		// If we don't have a url already
		if s.url == "" {
			// Grab the info about the step from the api

			// TODO(termie): probably don't need these in global options?
			apiOptions := api.APIOptions{
				BaseURL:   s.options.GlobalOptions.BaseURL,
				AuthToken: s.options.GlobalOptions.AuthToken,
			}
			client := api.NewAPIClient(&apiOptions)
			stepInfo, err := client.GetStepVersion(s.Owner(), s.Name(), s.Version())
			if err != nil {
				if apiErr, ok := err.(*api.APIError); ok && apiErr.StatusCode == 404 {
					return "", fmt.Errorf("The step \"%s\" was not found", s.ID())
				}
				return "", err
			}

			s.url = stepInfo.TarballURL
		}

		// If we have a file uri let's just copytree it.
		if strings.HasPrefix(s.url, "file:///") {
			if s.options.EnableDevSteps {
				localPath := s.url[len("file://"):]
				err = shutil.CopyTree(localPath, stepPath, nil)
				if err != nil {
					return "", err
				}
			} else {
				return "", fmt.Errorf("Dev mode is not enabled so refusing to copy local file urls: %s", s.url)
			}
		} else {
			// Grab the tarball and util.Untargzip it
			resp, err := util.FetchTarball(s.url)
			if err != nil {
				return "", err
			}

			// Assuming we have a gzip'd tarball at this point
			err = util.Untargzip(stepPath, resp.Body)
			if err != nil {
				return "", err
			}
		}
	}

	hostStepPath := s.HostPath()

	err = shutil.CopyTree(stepPath, hostStepPath, nil)
	if err != nil {
		return "", nil
	}

	// Now that we have the code, load any step config we might find
	desc, err := ReadStepDesc(s.HostPath("wercker-step.yml"))
	if err != nil && !os.IsNotExist(err) {
		// TODO(termie): Log an error instead of printing
		s.logger.Println("ERROR: Reading wercker-step.yml:", err)
	}
	if err == nil {
		s.stepDesc = desc
	}
	return hostStepPath, nil
}
Beispiel #8
0
// EnsureCode makes sure the code is in the ProjectDir.
// NOTE(termie): When launched by kiddie-pool the ProjectPath will be
// set to the location where grappler checked out the code and the copy
// will be a little superfluous, but in the case where this is being
// run in Single Player Mode this copy is necessary to avoid screwing
// with the local dir.
func (p *Runner) EnsureCode() (string, error) {
	projectDir := p.ProjectDir()
	if p.options.DirectMount {
		return projectDir, nil
	}

	// If the target is a tarball feetch and build that
	if p.options.ProjectURL != "" {
		resp, err := util.FetchTarball(p.options.ProjectURL)
		if err != nil {
			return projectDir, err
		}
		err = util.Untargzip(projectDir, resp.Body)
		if err != nil {
			return projectDir, err
		}
	} else {
		// We were pointed at a path with ProjectPath, copy it to projectDir

		ignoreFiles := []string{
			p.options.BuildPath(),
			p.options.ProjectDownloadPath(),
			p.options.StepPath(),
			p.options.ContainerPath(),
			p.options.CachePath(),
		}

		var gitIgnoreRules *ignore.GitIgnore
		var err error

		if p.options.EnableGitIgnore {
			gitIgnorePath := filepath.Join(p.options.ProjectPath, ".gitignore")
			if hasGitIgnore, _ := util.Exists(gitIgnorePath); hasGitIgnore {
				gitIgnoreRules, err = ignore.CompileIgnoreFile(gitIgnorePath)
				if err != nil {
					return projectDir, err
				}
			}
		}
		// Make sure we don't accidentally recurse or copy extra files
		ignoreFunc := func(src string, files []os.FileInfo) []string {
			ignores := []string{}
			for _, file := range files {
				abspath, err := filepath.Abs(filepath.Join(src, file.Name()))
				if err != nil {
					// Something went sufficiently wrong
					panic(err)
				}
				if util.ContainsString(ignoreFiles, abspath) {
					ignores = append(ignores, file.Name())
				} else if gitIgnoreRules != nil && gitIgnoreRules.MatchesPath(file.Name()) {
					ignores = append(ignores, file.Name())
				}
			}
			return ignores
		}
		copyOpts := &shutil.CopyTreeOptions{Ignore: ignoreFunc, CopyFunction: shutil.Copy}
		os.Rename(projectDir, fmt.Sprintf("%s-%s", projectDir, uuid.NewRandom().String()))
		err = shutil.CopyTree(p.options.ProjectPath, projectDir, copyOpts)
		if err != nil {
			return projectDir, err
		}
	}
	return projectDir, nil
}