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) } }
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 }