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