Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(104)

Side by Side Diff: go/src/infra/tools/swarming-transition/cmd/swarmbucketcheck/main.go

Issue 2110453002: add swarmbucketcheck (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: coverage Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package main
6
7 import (
8 "flag"
9 "fmt"
10 "net/http"
11 "os"
12 "strings"
13 "time"
14
15 "github.com/luci/luci-go/common/api/buildbucket/buildbucket/v1"
16 )
17
18 var since = flag.Int64("since", 0, "analyze builds since this timestamp. Default s to 10 days ago.")
19 var bucket = flag.String("bucket", "", `buildbucket bucket name, e.g. "master.tr yserver.infra"`)
20 var builders = flag.String("builder", "", `comma-separated list of builder names without swarming suffix, e.g. "Infra Presubmit"`)
21
22 const swarmingSuffix = " (Swarming)"
23
24 func fetchBuilds(bucket, builder string, startingFrom time.Time) ([]*buildbucket .ApiBuildMessage, error) {
25 client, err := buildbucket.New(http.DefaultClient)
26 if err != nil {
27 return nil, err
28 }
29 client.BasePath = "https://cr-buildbucket.appspot.com/_ah/api/buildbucke t/v1/"
30
31 req := client.Search()
32 req.Bucket(bucket)
33 req.Tag("builder:" + builder)
34 req.Status("COMPLETED")
35 req.MaxBuilds(100)
36
37 var result []*buildbucket.ApiBuildMessage
38 for {
39 res, err := req.Do()
40 if err != nil {
41 return result, err
42 }
43 if res.Error != nil {
44 return result, fmt.Errorf(res.Error.Message)
45 }
46
47 for _, b := range res.Builds {
48 createdAt := time.Unix(b.CreatedTs/1000000, 0)
49 if createdAt.Before(startingFrom) {
50 return result, nil
51 }
52 result = append(result, b)
53 }
54
55 if len(res.Builds) == 0 || res.NextCursor == "" {
56 break
57 }
58 req.StartCursor(res.NextCursor)
59 }
60 return result, nil
61 }
62
63 type buildSet struct {
64 builds []*buildbucket.ApiBuildMessage
65 bestResult string
66 }
67
68 // groupBuilds groups builds by buildset tag.
69 func groupBuilds(builds []*buildbucket.ApiBuildMessage) map[string]*buildSet {
70 results := map[string]*buildSet{}
71 for _, b := range builds {
72 tags := parseTags(b.Tags)
73 buildSetName := tags["buildset"]
74 if buildSetName == "" {
75 fmt.Printf("skipped build %d: no buildset tag\n", b.Id)
76 continue
77 }
78 set := results[buildSetName]
79 if set == nil {
80 set = &buildSet{}
81 results[buildSetName] = set
82 }
83
84 set.builds = append(set.builds, b)
85 if set.bestResult == "" || b.Result == "SUCCESS" {
86 set.bestResult = b.Result
87 }
88 }
89 return results
90 }
91
92 func run() error {
93 flag.Parse()
94 if *bucket == "" {
95 return fmt.Errorf("bucket is not specified")
96 }
97 if *builders == "" {
98 return fmt.Errorf("builders are not specified")
99 }
100 if len(flag.Args()) > 0 {
101 return fmt.Errorf("unexpected arguments: %s", flag.Args())
102 }
103
104 var startingFrom time.Time
105 var duration time.Duration
106 if *since == 0 {
107 duration = 240 * time.Hour
108 startingFrom = time.Now().Add(-duration)
109 } else {
110 startingFrom = time.Unix(*since, 0)
111 duration = time.Since(startingFrom)
112 }
113
114 for i, builder := range strings.Split(*builders, ",") {
115 builder = strings.TrimSpace(builder)
116 if builder == "" {
117 continue
118 }
119
120 if i > 0 {
121 fmt.Println()
122 }
123 fmt.Printf("builder %q\n", builder)
124 fmt.Printf("searching for all builds since timestamp %d till %d. ..\n",
125 startingFrom.Unix(), time.Now().Unix())
126 // We will actually fetch builds after after time.Now too, but i t is fine.
127 swarmingBuilds, err := fetchBuilds(*bucket, builder+swarmingSuff ix, startingFrom)
128 if err != nil {
129 return fmt.Errorf("could not fetch builds: %s", err)
130 }
131 if len(swarmingBuilds) == 0 {
132 fmt.Printf("no swarming builds for builder %q\n", builde r)
133 continue
134 }
135 buildbotBuilds, err := fetchBuilds(*bucket, builder, startingFro m)
136 if err != nil {
137 return fmt.Errorf("could not fetch builds: %s", err)
138 }
139
140 swarmingBuildSets := groupBuilds(swarmingBuilds)
141 buildbotBuildSets := groupBuilds(buildbotBuilds)
142
143 consistentN := 0
144 inconsistentN := 0
145 for setName, swarmingSet := range swarmingBuildSets {
146 buildbotSet := buildbotBuildSets[setName]
147 if buildbotSet == nil {
148 fmt.Printf("no buildbot builds for buildset %s\n ", setName)
149 continue
150 }
151 if buildbotSet.bestResult == swarmingSet.bestResult {
152 consistentN++
153 continue
154 }
155 inconsistentN++
156
157 fmt.Printf("%s is inconsistent\n", setName)
158 for _, b := range swarmingSet.builds {
159 fmt.Printf(" %s %s\n", b.Result, b.Url)
160 }
161 for _, b := range buildbotSet.builds {
162 fmt.Printf(" %s %s\n", b.Result, b.Url)
163 }
164 }
165
166 fmt.Printf("%0.2f%% consistent build sets, %d buildbot builds, % d swarming builds\n",
167 100*float64(consistentN)/float64(consistentN+inconsisten tN), len(buildbotBuilds), len(swarmingBuilds))
168 }
169 return nil
170 }
171
172 func main() {
173 if err := run(); err != nil {
174 fmt.Fprintln(os.Stderr, err)
175 os.Exit(1)
176 }
177 }
178
179 func parseTags(tags []string) map[string]string {
180 result := make(map[string]string, len(tags))
181 for _, t := range tags {
182 parts := strings.SplitN(t, ":", 2)
183 if len(parts) == 2 {
184 result[parts[0]] = parts[1]
185 }
186 }
187 return result
188 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698