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