func (p *AWSProvider) BuildCreateTar(app string, src io.Reader, manifest, description string, cache bool) (*structs.Build, error) { a, err := p.AppGet(app) if err != nil { return nil, err } b := structs.NewBuild(app) b.Description = description err = p.BuildSave(b) if err != nil { return nil, err } // TODO: save the tarball in s3? args := p.buildArgs(a, b, "-") env, err := p.buildEnv(a, b, manifest, cache) if err != nil { return b, err } err = p.buildRun(a, b, args, env, src) p.EventSend(&structs.Event{ Action: "build:create", Data: map[string]string{ "app": b.App, "id": b.Id, }, }, err) return b, err }
func (p *AWSProvider) BuildCreateRepo(app, url, manifest, description string, cache bool) (*structs.Build, error) { a, err := p.AppGet(app) if err != nil { return nil, err } b := structs.NewBuild(app) b.Description = description err = p.BuildSave(b) if err != nil { return nil, err } args := p.buildArgs(a, b, url) env, err := p.buildEnv(a, b, manifest, cache) if err != nil { return b, err } err = p.buildRun(a, b, args, env, nil) // build create is now complete or failed p.EventSend(&structs.Event{ Action: "build:create", Data: map[string]string{ "app": b.App, "id": b.Id, }, }, err) return b, err }
func (p *AWSProvider) BuildCreate(app, method, url string, opts structs.BuildOptions) (*structs.Build, error) { log := Logger.At("BuildCreate").Namespace("app=%q method=%q url=%q", app, method, url).Start() _, err := p.AppGet(app) if err != nil { log.Error(err) return nil, err } b := structs.NewBuild(app) b.Description = opts.Description b.Started = time.Now() if p.IsTest() { b.Id = "B123" b.Started = time.Unix(1473028693, 0).UTC() b.Ended = time.Unix(1473028892, 0).UTC() } if err := p.BuildSave(b); err != nil { log.Error(err) return nil, err } if err := p.runBuild(b, method, url, opts); err != nil { log.Error(err) return nil, err } p.EventSend(&structs.Event{ Action: "build:create", Data: map[string]string{ "app": b.App, "id": b.Id, }, }, nil) // AWS currently has a limit of 1000 images in ECR // This is a "hopefully temporary" and brute force means // to prevent hitting limits during deployment bs, err := p.BuildList(app, 150) if err != nil { fmt.Printf("Error listing builds for cleanup: %s\n", err.Error()) } else { if len(bs) >= 50 { go func() { for _, b := range bs[50:] { _, err := p.BuildDelete(app, b.Id) if err != nil { fmt.Printf("Error cleaning up build %s: %s\n", b.Id, err.Error()) } time.Sleep(1 * time.Second) } }() } } log.Success() return b, nil }
// BuildImport imports a build artifact func (p *AWSProvider) BuildImport(app string, r io.Reader) (*structs.Build, error) { log := Logger.At("BuildImport").Namespace("app=%s", app).Start() var sourceBuild structs.Build // set up the new build targetBuild := structs.NewBuild(app) targetBuild.Started = time.Now() targetBuild.Status = "complete" if p.IsTest() { targetBuild.Id = "B12345" } repo, err := p.appRepository(app) if err != nil { log.Error(err) return nil, err } if err := p.dockerLogin(); err != nil { log.Error(err) return nil, err } gz, err := gzip.NewReader(r) if err != nil { log.Error(err) return nil, err } tr := tar.NewReader(gz) for { header, err := tr.Next() if err == io.EOF { break } if err != nil { log.Error(err) return nil, err } if header.Typeflag != tar.TypeReg { continue } if header.Name == "build.json" { var buf bytes.Buffer io.Copy(&buf, tr) if err := json.Unmarshal(buf.Bytes(), &sourceBuild); err != nil { log.Error(err) return nil, err } } if strings.HasSuffix(header.Name, ".tar") { log.Step("load").Logf("tar=%q", header.Name) cmd := exec.Command("docker", "load") pr, pw := io.Pipe() tee := io.TeeReader(tr, pw) outb := &bytes.Buffer{} cmd.Stdin = pr cmd.Stdout = outb if err := cmd.Start(); err != nil { log.Error(err) return nil, err } log.Step("manifest").Logf("tar=%q", header.Name) manifest, err := extractImageManifest(tee) if err != nil { log.Error(err) return nil, err } if err := pw.Close(); err != nil { log.Error(err) return nil, err } if err := cmd.Wait(); err != nil { return nil, log.Errorf("%s: %s\n", lastline(outb.Bytes()), err.Error()) } if len(manifest) != 1 || len(manifest[0].RepoTags) != 1 { log.Errorf("invalid image manifest") return nil, fmt.Errorf("invalid image manifest") } image := manifest[0].RepoTags[0] ps := strings.Split(header.Name, ".")[0] target := fmt.Sprintf("%s:%s.%s", repo.URI, ps, targetBuild.Id) log.Step("tag").Logf("from=%q to=%q", image, target) if out, err := exec.Command("docker", "tag", image, target).CombinedOutput(); err != nil { return nil, log.Error(fmt.Errorf("%s: %s\n", lastline(out), err.Error())) } log.Step("push").Logf("to=%q", target) if out, err := exec.Command("docker", "push", target).CombinedOutput(); err != nil { return nil, log.Error(fmt.Errorf("%s: %s\n", lastline(out), err.Error())) } } } env, err := p.EnvironmentGet(app) if err != nil { log.Error(err) return nil, err } release := structs.NewRelease(app) if p.IsTest() { release.Id = "R23456" } targetBuild.Description = sourceBuild.Description targetBuild.Ended = time.Now() targetBuild.Logs = sourceBuild.Logs targetBuild.Manifest = sourceBuild.Manifest targetBuild.Release = release.Id if err := p.BuildSave(targetBuild); err != nil { log.Error(err) return nil, err } release.Env = env.Raw() release.Build = targetBuild.Id release.Manifest = targetBuild.Manifest if err := p.ReleaseSave(release); err != nil { log.Error(err) return nil, err } log.Successf("build=%q release=%q", targetBuild.Id, release.Id) return targetBuild, nil }