func TestPushKey(t *testing.T) {
	sha, err := git.NewSha(rawSha)
	if err != nil {
		t.Fatalf("error building git sha (%s)", err)
	}
	sbi := NewSlugBuilderInfo(s3Endpoint, appName, slugName, sha)
	expectedPushKey := "home/" + appName + ":git-" + sha.Short() + "/push"
	if sbi.PushKey() != expectedPushKey {
		t.Errorf("push key %s didn't match expected %s", sbi.PushKey(), expectedPushKey)
	}
}
func TestTarKey(t *testing.T) {
	sha, err := git.NewSha(rawSha)
	if err != nil {
		t.Fatalf("error building git sha (%s)", err)
	}
	sbi := NewSlugBuilderInfo(s3Endpoint, appName, slugName, sha)
	expectedTarKey := "home/" + slugName + "/tar"
	if sbi.TarKey() != expectedTarKey {
		t.Errorf("tar key %s didn't match expected %s", sbi.TarKey(), expectedTarKey)
	}
}
func TestS3Endpoint(t *testing.T) {
	sha, err := git.NewSha(rawSha)
	if err != nil {
		t.Fatalf("error building git sha (%s)", err)
	}
	sbi := NewSlugBuilderInfo(s3Endpoint, appName, slugName, sha)

	expectedPushURL := s3Endpoint + "/git/" + sbi.PushKey()
	if sbi.PushURL() != expectedPushURL {
		t.Errorf("push URL %s didn't match expected %s", sbi.PushURL(), expectedPushURL)
	}
	expectedTarURL := s3Endpoint + "/git/" + sbi.TarKey()
	if sbi.TarURL() != expectedTarURL {
		t.Errorf("tar URL %s didn't match expected %s", sbi.TarURL(), expectedTarURL)
	}
}
示例#4
0
func build(conf *Config, kubeClient *client.Client, rawGitSha string) error {
	repo := conf.Repository
	gitSha, err := git.NewSha(rawGitSha)
	if err != nil {
		return err
	}

	appName := conf.App()

	repoDir := filepath.Join(conf.GitHome, repo)
	buildDir := filepath.Join(repoDir, "build")

	slugName := fmt.Sprintf("%s:git-%s", appName, gitSha.Short())
	if err := os.MkdirAll(buildDir, os.ModeDir); err != nil {
		return fmt.Errorf("making the build directory %s (%s)", buildDir, err)
	}
	tmpDir := buildDir + gitSha.Short()
	err = os.MkdirAll(tmpDir, 0777)
	if err != nil {
		return fmt.Errorf("unable to create tmpdir %s (%s)", buildDir, err)
	}

	slugBuilderInfo := storage.NewSlugBuilderInfo(appName, slugName, gitSha)

	// build a tarball from the new objects
	appTgz := fmt.Sprintf("%s.tar.gz", appName)
	gitArchiveCmd := repoCmd(repoDir, "git", "archive", "--format=tar.gz", fmt.Sprintf("--output=%s", appTgz), gitSha.Short())
	gitArchiveCmd.Stdout = os.Stdout
	gitArchiveCmd.Stderr = os.Stderr
	if err := run(gitArchiveCmd); err != nil {
		return fmt.Errorf("running %s (%s)", strings.Join(gitArchiveCmd.Args, " "), err)
	}

	// untar the archive into the temp dir
	tarCmd := repoCmd(repoDir, "tar", "-xzf", appTgz, "-C", fmt.Sprintf("%s/", tmpDir))
	tarCmd.Stdout = os.Stdout
	tarCmd.Stderr = os.Stderr
	if err := run(tarCmd); err != nil {
		return fmt.Errorf("running %s (%s)", strings.Join(tarCmd.Args, " "), err)
	}

	bType := getBuildTypeForDir(tmpDir)
	usingDockerfile := bType == buildTypeDockerfile

	procType := pkg.ProcessType{}
	if bType == buildTypeProcfile {
		rawProcFile, err := ioutil.ReadFile(fmt.Sprintf("%s/Procfile", tmpDir))
		if err != nil {
			return fmt.Errorf("reading %s/Procfile", tmpDir)
		}
		if err := yaml.Unmarshal(rawProcFile, &procType); err != nil {
			return fmt.Errorf("procfile %s/ProcFile is malformed (%s)", tmpDir, err)
		}
	}

	var pod *api.Pod
	var buildPodName string
	if usingDockerfile {
		buildPodName = dockerBuilderPodName(appName, gitSha.Short())
		pod = dockerBuilderPod(
			conf.Debug,
			false,
			buildPodName,
			conf.PodNamespace,
			slugBuilderInfo.TarURL(),
			slugName,
		)
	} else {
		buildPodName = slugBuilderPodName(appName, gitSha.Short())
		pod = slugbuilderPod(
			conf.Debug,
			false,
			buildPodName,
			conf.PodNamespace,
			slugBuilderInfo.TarURL(),
			slugBuilderInfo.PushURL(),
		)
	}

	log.Info("Starting build... but first, coffee!")
	log.Debug("Starting pod %s", buildPodName)
	json, err := prettyPrintJSON(pod)
	if err == nil {
		log.Debug("Pod spec: %v", json)
	} else {
		log.Debug("Error creating json representaion of pod spec: %v", err)
	}

	podsInterface := kubeClient.Pods(conf.PodNamespace)

	newPod, err := podsInterface.Create(pod)
	if err != nil {
		return fmt.Errorf("creating builder pod (%s)", err)
	}

	if err := waitForPod(kubeClient, newPod.Namespace, newPod.Name, conf.BuilderPodTickDuration(), conf.BuilderPodWaitDuration()); err != nil {
		return fmt.Errorf("watching events for builder pod startup (%s)", err)
	}

	req := kubeClient.Get().Namespace(newPod.Namespace).Name(newPod.Name).Resource("pods").SubResource("log").VersionedParams(
		&api.PodLogOptions{
			Follow: true,
		}, api.Scheme)

	rc, err := req.Stream()
	if err != nil {
		return fmt.Errorf("attempting to stream logs (%s)", err)
	}
	defer rc.Close()

	size, err := io.Copy(os.Stdout, rc)
	if err != nil {
		return fmt.Errorf("fetching builder logs (%s)", err)
	}
	log.Debug("size of streamed logs %v", size)

	// check the state and exit code of the build pod.
	// if the code is not 0 return error
	if err := waitForPodEnd(kubeClient, newPod.Namespace, newPod.Name, conf.BuilderPodTickDuration(), conf.BuilderPodWaitDuration()); err != nil {
		return fmt.Errorf("error getting builder pod status (%s)", err)
	}
	buildPod, err := kubeClient.Pods(newPod.Namespace).Get(newPod.Name)
	if err != nil {
		return fmt.Errorf("error getting builder pod status (%s)", err)
	}

	for _, containerStatus := range buildPod.Status.ContainerStatuses {
		state := containerStatus.State.Terminated
		if state.ExitCode != 0 {
			return fmt.Errorf("Stopping build.")
		}
	}

	// poll the s3 server to ensure the slug exists
	buildPodName = slugBuilderPodName(appName+"run", gitSha.Short())
	pod = slugrunnerPod(
		conf.Debug,
		false,
		buildPodName,
		conf.PodNamespace,
		slugBuilderInfo.SlugURL(),
	)

	newPod, err = podsInterface.Create(pod)
	if err != nil {
		return fmt.Errorf("creating builder pod (%s)", err)
	}

	if err := waitForPod(kubeClient, newPod.Namespace, newPod.Name, conf.BuilderPodTickDuration(), conf.BuilderPodWaitDuration()); err != nil {
		return fmt.Errorf("watching events for builder pod startup (%s)", err)
	}

	log.Info("Build complete.")
	log.Info("Launching app.")
	log.Info("Launching...")

	// 	buildHook := &pkg.BuildHook{
	// 		Sha:         gitSha.Short(),
	// 		ReceiveUser: conf.Username,
	// 		ReceiveRepo: appName,
	// 		Image:       appName,
	// 		Procfile:    procType,
	// 	}
	// 	if !usingDockerfile {
	// 		buildHook.Dockerfile = ""
	// 		// need this to tell the controller what URL to give the slug runner
	// 		buildHook.Image = slugBuilderInfo.PushURL() + "/slug.tgz"
	// 	} else {
	// 		buildHook.Dockerfile = "true"
	// 	}
	// 	buildHookResp, err := publishRelease(conf, builderKey, buildHook)
	// 	if err != nil {
	// 		return fmt.Errorf("publishing release (%s)", err)
	// 	}
	// 	release, ok := buildHookResp.Release["version"]
	// 	if !ok {
	// 		return fmt.Errorf("No release returned from Deis controller")
	// 	}
	//
	// 	log.Info("Done, %s:v%d deployed to Deis\n", appName, release)
	// 	log.Info("Use 'deis open' to view this application in your browser\n")
	// 	log.Info("To learn more, use 'deis help' or visit http://deis.io\n")
	//

	gcCmd := repoCmd(repoDir, "git", "gc")
	if err := run(gcCmd); err != nil {
		return fmt.Errorf("cleaning up the repository with %s (%s)", strings.Join(gcCmd.Args, " "), err)
	}

	return nil
}