| Index: appengine/cmd/milo/collectors/buildbot/collector.go
|
| diff --git a/appengine/cmd/milo/collectors/buildbot/collector.go b/appengine/cmd/milo/collectors/buildbot/collector.go
|
| deleted file mode 100644
|
| index 1378ebeb9902cf4cc5efe6b37c0dd8f7dc3e9b01..0000000000000000000000000000000000000000
|
| --- a/appengine/cmd/milo/collectors/buildbot/collector.go
|
| +++ /dev/null
|
| @@ -1,255 +0,0 @@
|
| -// Copyright 2015 The LUCI Authors. All rights reserved.
|
| -// Use of this source code is governed under the Apache License, Version 2.0
|
| -// that can be found in the LICENSE file.
|
| -
|
| -package buildbot
|
| -
|
| -import (
|
| - "encoding/json"
|
| - "fmt"
|
| - "net/http"
|
| - "strings"
|
| - "time"
|
| -
|
| - "github.com/luci/gae/service/datastore"
|
| - "github.com/luci/luci-go/appengine/cmd/milo/model"
|
| - log "github.com/luci/luci-go/common/logging"
|
| - "github.com/luci/luci-go/common/parallel"
|
| - "golang.org/x/net/context"
|
| -)
|
| -
|
| -// BuildExtractURL is the URL of Chrome Build extract, which caches buildbot
|
| -// json.
|
| -const BuildExtractURL = "https://chrome-build-extract.appspot.com"
|
| -
|
| -const workPoolSizeMultiplier = 2
|
| -
|
| -type changeJSON struct {
|
| - Repository string `json:"repository"`
|
| - Digest string `json:"revision"`
|
| - UnixTime int64 `json:"when"`
|
| -}
|
| -
|
| -type sourceJSON struct {
|
| - Changes []changeJSON `json:"changes"`
|
| -}
|
| -
|
| -type buildJSON struct {
|
| - // Times elements are a float64 unix time that the build was started. It's
|
| - // an array because buildbot :)
|
| - Times []float64 `json:"times"`
|
| - Builder string `json:"builderName"`
|
| - Master string `json:"masterName"`
|
| - Error string `json:"error"`
|
| - Logs [][]string `json:"logs"`
|
| - SourceStamp sourceJSON `json:"sourceStamp"`
|
| - Number int `json:"number"`
|
| - Text []string `json:"text"`
|
| -}
|
| -
|
| -func getRevForChange(c context.Context, change changeJSON) model.RevisionInfo {
|
| - repo := model.GetRepository(c, change.Repository)
|
| -
|
| - generation := -1
|
| - if rev, err := repo.GetRevision(c, change.Digest); err == nil {
|
| - generation = rev.Generation
|
| - }
|
| -
|
| - return model.RevisionInfo{
|
| - Repository: change.Repository,
|
| - Digest: change.Digest,
|
| - Generation: generation,
|
| - }
|
| -}
|
| -
|
| -func (b *buildJSON) toDS(c context.Context) *model.Build {
|
| - perRepo := make(map[string]*changeJSON)
|
| - for _, change := range b.SourceStamp.Changes {
|
| - current := perRepo[change.Repository]
|
| - if current != nil {
|
| - if current.UnixTime < change.UnixTime {
|
| - perRepo[change.Repository] = &change
|
| - }
|
| - } else {
|
| - perRepo[change.Repository] = &change
|
| - }
|
| - }
|
| -
|
| - revisions := make([]model.RevisionInfo, 0, len(perRepo))
|
| - for _, change := range perRepo {
|
| - revisions = append(revisions, getRevForChange(c, *change))
|
| - }
|
| -
|
| - logKey := ""
|
| - if len(b.Logs) > 1 && len(b.Logs[1]) > 1 {
|
| - logKey = b.Logs[1][1]
|
| - } else {
|
| - log.Warningf(c, "build %d on %s master %s had weird logs\n", b.Number, b.Builder, b.Master)
|
| - }
|
| -
|
| - userStatus := "UNKNOWN"
|
| - if len(b.Text) < 2 {
|
| - log.Warningf(c, "build %d on %s master %s had strange text\n", b.Number, b.Builder, b.Master)
|
| - } else {
|
| - if b.Text[0] == "exception" {
|
| - userStatus = "EXCEPTION"
|
| - } else if b.Text[0] == "failed" {
|
| - userStatus = "FAILURE"
|
| - } else if b.Text[1] == "successful" {
|
| - userStatus = "SUCCESS"
|
| - }
|
| - if userStatus == "UNKNOWN" {
|
| - log.Warningf(c, "build %d on %s master %s had unknown text %v\n", b.Number, b.Builder, b.Master, b.Text)
|
| - }
|
| - }
|
| -
|
| - return &model.Build{
|
| - ExecutionTime: model.TimeID{time.Unix(int64(b.Times[0]), 0).UTC()},
|
| - BuildRoot: model.GetBuildRoot(c, b.Master, b.Builder).Key,
|
| - BuildLogKey: logKey,
|
| - Revisions: revisions,
|
| - UserStatus: userStatus,
|
| - }
|
| -}
|
| -
|
| -type builderJSON struct {
|
| - Builds []int `json:"cachedBuilds"`
|
| -}
|
| -
|
| -type masterJSON struct {
|
| - Builders map[string]builderJSON `json:"builders"`
|
| -}
|
| -
|
| -func getBuild(master, builder string, build int, useCBE bool) (*buildJSON, error) {
|
| - resp := (*http.Response)(nil)
|
| - err := (error)(nil)
|
| - if useCBE {
|
| - resp, err = http.Get(strings.Join(
|
| - []string{BuildExtractURL, "p", master, "builders", builder, "builds", fmt.Sprintf("%d", build)},
|
| - "/") + "?json=1")
|
| - } else {
|
| - resp, err = http.Get(strings.Join(
|
| - []string{"https://build.chromium.org", "p", master, "json", "builders", builder, "builds", fmt.Sprintf("%d", build)},
|
| - "/"))
|
| - }
|
| -
|
| - if err != nil {
|
| - return nil, err
|
| - }
|
| - defer resp.Body.Close()
|
| -
|
| - dec := json.NewDecoder(resp.Body)
|
| - doneBuild := &buildJSON{}
|
| - err = dec.Decode(doneBuild)
|
| - if err != nil {
|
| - return nil, err
|
| - }
|
| -
|
| - if doneBuild.Error != "" {
|
| - return nil, fmt.Errorf("error while getting Build for master %s builder %s build number %d: %s", master, builder, build, doneBuild.Error)
|
| - }
|
| - return doneBuild, nil
|
| -}
|
| -
|
| -// PopulateMaster puts the data for a master into the datastore.
|
| -//
|
| -// It hits CBE to grab the json, and then creates corresponding entities and
|
| -// puts them into the datastore. It assumes that a datastore impl exists in the
|
| -// supplied context.
|
| -func PopulateMaster(c context.Context, master string, dryRun, buildbotFallback bool) error {
|
| - masterJSON := &masterJSON{}
|
| - resp, err := http.Get(strings.Join([]string{BuildExtractURL, "get_master", master}, "/"))
|
| - if err != nil {
|
| - return err
|
| - }
|
| -
|
| - defer resp.Body.Close()
|
| - dec := json.NewDecoder(resp.Body)
|
| - err = dec.Decode(masterJSON)
|
| - if err != nil {
|
| - return err
|
| - }
|
| -
|
| - buildsToPut := make(map[string][]*model.Build)
|
| - log.Infof(c, "Getting builds for master %s\n", master)
|
| -
|
| - errors := parallel.WorkPool(workPoolSizeMultiplier*len(masterJSON.Builders), func(ch chan<- func() error) {
|
| - for builderName, builder := range masterJSON.Builders {
|
| - if len(builder.Builds) > 0 {
|
| - buildsToPut[builderName] = make([]*model.Build, len(builder.Builds))
|
| -
|
| - for ind, builderNum := range builder.Builds {
|
| - ind := ind
|
| - builderNum := builderNum
|
| - builderName := builderName
|
| -
|
| - ch <- func() error {
|
| - res, err := getBuild(master, builderName, builderNum, true)
|
| - if err != nil {
|
| - if !buildbotFallback {
|
| - log.Warningf(c, "got %s, giving up", err)
|
| - return err
|
| - }
|
| -
|
| - log.Warningf(c, "got %s, retrying without CBE", err)
|
| - res, err = getBuild(master, builderName, builderNum, false)
|
| -
|
| - if err != nil {
|
| - log.Warningf(c, "got %s, giving up", err)
|
| - return err
|
| - }
|
| - }
|
| -
|
| - conv := res.toDS(c)
|
| - buildsToPut[builderName][ind] = conv
|
| - return nil
|
| - }
|
| - }
|
| - log.Infof(c, "Queued builds for builder %s.", builderName)
|
| - }
|
| - }
|
| - })
|
| -
|
| - // We ignore these warnings because, for some reason, CBE sometimes returns
|
| - // 404s for some builds. So we ignore those, and just move on. They're
|
| - // printed to the user above, so if something is really wrong all those
|
| - // errors will show up.
|
| - log.Warningf(c, "Done fetching builds. errors: %s.\n", errors)
|
| -
|
| - for name, builds := range buildsToPut {
|
| - num := 0
|
| - for _, b := range builds {
|
| - if b != nil {
|
| - num++
|
| - }
|
| - }
|
| -
|
| - if num == 0 {
|
| - buildsToPut[name] = nil
|
| - continue
|
| - }
|
| -
|
| - newBuilds := make([]*model.Build, num)
|
| - ind := 0
|
| - for _, b := range builds {
|
| - if b != nil {
|
| - newBuilds[ind] = b
|
| - ind++
|
| - }
|
| - }
|
| - buildsToPut[name] = newBuilds
|
| - }
|
| -
|
| - ds := datastore.Get(c)
|
| - for builderName, toPut := range buildsToPut {
|
| - log.Infof(c, "%d to put for builder %s\n", len(toPut), builderName)
|
| - if toPut != nil {
|
| - if dryRun {
|
| - log.Infof(c, "dry run, not putting any modifications")
|
| - } else {
|
| - ds.Put(toPut)
|
| - }
|
| - }
|
| - }
|
| - return nil
|
| -}
|
|
|