OLD | NEW |
| (Empty) |
1 // Copyright 2015 The LUCI Authors. All rights reserved. | |
2 // Use of this source code is governed under the Apache License, Version 2.0 | |
3 // that can be found in the LICENSE file. | |
4 | |
5 package swarming | |
6 | |
7 import ( | |
8 "errors" | |
9 "fmt" | |
10 "net/http" | |
11 "os" | |
12 | |
13 "golang.org/x/net/context" | |
14 "google.golang.org/api/googleapi" | |
15 | |
16 "github.com/luci/luci-go/common/logging" | |
17 "github.com/luci/luci-go/milo/appengine/common" | |
18 "github.com/luci/luci-go/server/router" | |
19 "github.com/luci/luci-go/server/templates" | |
20 ) | |
21 | |
22 var errUnrecognizedHost = errors.New("Unregistered Swarming Host") | |
23 | |
24 // getSwarmingHost parses the swarming hostname out of the context. If | |
25 // none is specified, get the default swarming host out of the global | |
26 // configs. | |
27 func getSwarmingHost(c context.Context, r *http.Request) (string, error) { | |
28 settings := common.GetSettings(c) | |
29 if settings.Swarming == nil { | |
30 err := errors.New("swarming not in settings") | |
31 logging.Errorf(c, err.Error()) | |
32 return "", err | |
33 } | |
34 server := r.FormValue("server") | |
35 // If server isn't specified, return the default host. | |
36 if server == "" || server == settings.Swarming.DefaultHost { | |
37 return settings.Swarming.DefaultHost, nil | |
38 } | |
39 // If it is specified, validate the hostname. | |
40 for _, hostname := range settings.Swarming.AllowedHosts { | |
41 if server == hostname { | |
42 return server, nil | |
43 } | |
44 } | |
45 return "", errUnrecognizedHost | |
46 } | |
47 | |
48 // Build is for deciphering recipe builds from swarming based off of logs. | |
49 type Build struct { | |
50 // bl is the buildLoader to use. A zero value is suitable for production
, but | |
51 // this can be overridden for testing. | |
52 bl buildLoader | |
53 } | |
54 | |
55 // LogHandler writes the build log to the given response writer. | |
56 func LogHandler(c *router.Context) { | |
57 id := c.Params.ByName("id") | |
58 if id == "" { | |
59 common.ErrorPage(c, http.StatusBadRequest, "no id") | |
60 return | |
61 } | |
62 logname := c.Params.ByName("logname") | |
63 if logname == "" { | |
64 common.ErrorPage(c, http.StatusBadRequest, "no log name") | |
65 return | |
66 } | |
67 | |
68 hostname, err := getSwarmingHost(c.Context, c.Request) | |
69 if err != nil { | |
70 common.ErrorPage(c, http.StatusBadRequest, | |
71 fmt.Sprintf("no swarming host: %s", err.Error())) | |
72 return | |
73 } | |
74 sf, err := newProdService(c.Context, hostname) | |
75 if err != nil { | |
76 common.ErrorPage(c, errCode(err), err.Error()) | |
77 return | |
78 } | |
79 | |
80 log, closed, err := swarmingBuildLogImpl(c.Context, sf, id, logname) | |
81 if err != nil { | |
82 common.ErrorPage(c, errCode(err), err.Error()) | |
83 return | |
84 } | |
85 | |
86 templates.MustRender(c.Context, c.Writer, "pages/log.html", templates.Ar
gs{ | |
87 "Log": log, | |
88 "Closed": closed, | |
89 }) | |
90 } | |
91 | |
92 func BuildHandler(c *router.Context) { | |
93 (Build{}).Render(c) | |
94 } | |
95 | |
96 // Render renders both the build page and the log. | |
97 func (b Build) Render(c *router.Context) { | |
98 // Get the swarming ID | |
99 id := c.Params.ByName("id") | |
100 if id == "" { | |
101 common.ErrorPage(c, http.StatusBadRequest, "no id") | |
102 return | |
103 } | |
104 | |
105 hostname, err := getSwarmingHost(c.Context, c.Request) | |
106 if err != nil { | |
107 common.ErrorPage(c, http.StatusBadRequest, | |
108 fmt.Sprintf("no swarming host: %s", err.Error())) | |
109 return | |
110 } | |
111 sf, err := newProdService(c.Context, hostname) | |
112 if err != nil { | |
113 common.ErrorPage(c, errCode(err), err.Error()) | |
114 return | |
115 } | |
116 | |
117 result, err := b.bl.swarmingBuildImpl(c.Context, sf, c.Request.URL.Strin
g(), id) | |
118 if err != nil { | |
119 common.ErrorPage(c, errCode(err), err.Error()) | |
120 return | |
121 } | |
122 | |
123 templates.MustRender(c.Context, c.Writer, "pages/build.html", templates.
Args{ | |
124 "Build": result, | |
125 }) | |
126 } | |
127 | |
128 // errCode resolves recognized errors into proper http response codes. | |
129 func errCode(err error) int { | |
130 if err == errUnrecognizedHost { | |
131 return http.StatusBadRequest | |
132 } | |
133 if isAPINotFound(err) || os.IsNotExist(err) { | |
134 return http.StatusNotFound | |
135 } | |
136 return http.StatusInternalServerError | |
137 } | |
138 | |
139 // isAPINotFound returns true if err is a HTTP 404 API response. | |
140 func isAPINotFound(err error) bool { | |
141 if apiErr, ok := err.(*googleapi.Error); ok && apiErr.Code == http.Statu
sNotFound { | |
142 return true | |
143 } | |
144 return false | |
145 } | |
OLD | NEW |