Merge pull request #388 from technosophos/fix/manager-routes

fix(manager): update routes and error handling
pull/394/head
Matt Butcher 9 years ago
commit 98d550181b

@ -43,27 +43,6 @@ import (
"github.com/kubernetes/helm/pkg/util" "github.com/kubernetes/helm/pkg/util"
) )
var deployments = []Route{
{"CreateDeployment", "/deployments", "POST", createDeploymentHandlerFunc, "JSON"},
{"DeleteDeplyment", "/deployments/{deployment}", "DELETE", deleteDeploymentHandlerFunc, ""},
{"PutDeployment", "/deployments/{deployment}", "PUT", putDeploymentHandlerFunc, "JSON"},
{"ListManifests", "/deployments/{deployment}/manifests", "GET", listManifestsHandlerFunc, ""},
{"GetManifest", "/deployments/{deployment}/manifests/{manifest}", "GET", getManifestHandlerFunc, ""},
{"Expand", "/expand", "POST", expandHandlerFunc, ""},
{"ListTypes", "/types", "GET", listTypesHandlerFunc, ""},
{"ListTypeInstances", "/types/{type}/instances", "GET", listTypeInstancesHandlerFunc, ""},
{"GetRegistryForType", "/types/{type}/registry", "GET", getRegistryForTypeHandlerFunc, ""},
{"GetMetadataForType", "/types/{type}/metadata", "GET", getMetadataForTypeHandlerFunc, ""},
{"ListRegistries", "/registries", "GET", listRegistriesHandlerFunc, ""},
{"GetRegistry", "/registries/{registry}", "GET", getRegistryHandlerFunc, ""},
{"CreateRegistry", "/registries/{registry}", "POST", createRegistryHandlerFunc, "JSON"},
{"ListRegistryTypes", "/registries/{registry}/types", "GET", listRegistryTypesHandlerFunc, ""},
{"GetDownloadURLs", "/registries/{registry}/types/{type}", "GET", getDownloadURLsHandlerFunc, ""},
{"GetFile", "/registries/{registry}/download", "GET", getFileHandlerFunc, ""},
{"CreateCredential", "/credentials/{credential}", "POST", createCredentialHandlerFunc, "JSON"},
{"GetCredential", "/credentials/{credential}", "GET", getCredentialHandlerFunc, ""},
}
// Deprecated. Use Context.Manager instead. // Deprecated. Use Context.Manager instead.
var backend manager.Manager var backend manager.Manager
@ -79,21 +58,27 @@ type Route struct {
} }
func registerDeploymentRoutes(c *router.Context, h *router.Handler) { func registerDeploymentRoutes(c *router.Context, h *router.Handler) {
re := regexp.MustCompile("{[a-z]+}")
h.Add("GET /healthz", healthz) h.Add("GET /healthz", healthz)
h.Add("GET /deployments", listDeploymentsHandlerFunc) h.Add("GET /deployments", listDeploymentsHandlerFunc)
h.Add("GET /deployments/*", getDeploymentHandlerFunc) h.Add("GET /deployments/*", getDeploymentHandlerFunc)
h.Add("POST /deployments", createDeploymentHandlerFunc)
// TODO: Replace these routes with updated ones. h.Add("DELETE /deployments/*", deleteDeploymentHandlerFunc)
for _, d := range deployments { h.Add("PUT /deployments/*", putDeploymentHandlerFunc)
path := fmt.Sprintf("%s %s", d.Methods, re.ReplaceAllString(d.Path, "*")) h.Add("GET /deployments/*/manifests", listManifestsHandlerFunc)
fmt.Printf("\t%s\n", path) h.Add("GET /deployments/*/manifests/*", getManifestHandlerFunc)
h.Add(path, func(w http.ResponseWriter, r *http.Request, c *router.Context) error { h.Add("POST /expand", expandHandlerFunc)
d.HandlerFunc(w, r) h.Add("GET /types", listTypesHandlerFunc)
return nil h.Add("GET /types/*/instances", listTypeInstancesHandlerFunc)
}) h.Add("GET /types/*/registry", getRegistryForTypeHandlerFunc)
} h.Add("GET /types/*/metadata", getMetadataForTypeHandlerFunc)
h.Add("GET /registries", listRegistriesHandlerFunc)
h.Add("GET /registries/*", getRegistryHandlerFunc)
h.Add("POST /registries/*", createRegistryHandlerFunc)
h.Add("GET /registries/*/types", listRegistryTypesHandlerFunc)
h.Add("GET /registries/*/types/*", getDownloadURLsHandlerFunc)
h.Add("GET /registries/*/download", getFileHandlerFunc)
h.Add("POST /credentials/*", createCredentialHandlerFunc)
h.Add("GET /credentials/*", getCredentialHandlerFunc)
} }
func healthz(w http.ResponseWriter, r *http.Request, c *router.Context) error { func healthz(w http.ResponseWriter, r *http.Request, c *router.Context) error {
@ -207,7 +192,7 @@ func listDeploymentsHandlerFunc(w http.ResponseWriter, r *http.Request, c *route
func getDeploymentHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error { func getDeploymentHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get deployment" handler := "manager: get deployment"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
name, err := getPathVariable(w, r, "deployment", handler) name, err := pos(w, r, 2)
if err != nil { if err != nil {
return nil return nil
} }
@ -222,7 +207,7 @@ func getDeploymentHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.
return nil return nil
} }
func createDeploymentHandlerFunc(w http.ResponseWriter, r *http.Request) { func createDeploymentHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: create deployment" handler := "manager: create deployment"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
defer r.Body.Close() defer r.Body.Close()
@ -230,52 +215,53 @@ func createDeploymentHandlerFunc(w http.ResponseWriter, r *http.Request) {
if t != nil { if t != nil {
d, err := backend.CreateDeployment(t) d, err := backend.CreateDeployment(t)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
util.LogHandlerExitWithJSON(handler, w, d, http.StatusCreated) util.LogHandlerExitWithJSON(handler, w, d, http.StatusCreated)
return
} }
return nil
} }
func deleteDeploymentHandlerFunc(w http.ResponseWriter, r *http.Request) { func deleteDeploymentHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: delete deployment" handler := "manager: delete deployment"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
defer r.Body.Close() defer r.Body.Close()
name, err := pos(w, r, 2) //getPathVariable(w, r, "deployment", handler) name, err := pos(w, r, 2)
if err != nil { if err != nil {
return return err
} }
d, err := backend.DeleteDeployment(name, true) d, err := c.Manager.DeleteDeployment(name, true)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) return err
return
} }
util.LogHandlerExitWithJSON(handler, w, d, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, d, http.StatusOK)
return nil
} }
func putDeploymentHandlerFunc(w http.ResponseWriter, r *http.Request) { func putDeploymentHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: update deployment" handler := "manager: update deployment"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
defer r.Body.Close() defer r.Body.Close()
name, err := pos(w, r, 2) //getPathVariable(w, r, "deployment", handler) name, err := pos(w, r, 2)
if err != nil { if err != nil {
return return err
} }
t := getTemplate(w, r, handler) t := getTemplate(w, r, handler)
if t != nil { if t != nil {
d, err := backend.PutDeployment(name, t) d, err := backend.PutDeployment(name, t)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
util.LogHandlerExitWithJSON(handler, w, d, http.StatusCreated) util.LogHandlerExitWithJSON(handler, w, d, http.StatusCreated)
} }
return nil
} }
// pos gets a path item by position. // pos gets a path item by position.
@ -288,7 +274,6 @@ func putDeploymentHandlerFunc(w http.ResponseWriter, r *http.Request) {
func pos(w http.ResponseWriter, r *http.Request, i int) (string, error) { func pos(w http.ResponseWriter, r *http.Request, i int) (string, error) {
parts := strings.Split(r.URL.Path, "/") parts := strings.Split(r.URL.Path, "/")
if len(parts) < i-1 { if len(parts) < i-1 {
httputil.BadRequest(w, r)
return "", fmt.Errorf("No index for %d", i) return "", fmt.Errorf("No index for %d", i)
} }
return parts[i], nil return parts[i], nil
@ -331,18 +316,17 @@ func getTemplate(w http.ResponseWriter, r *http.Request, handler string) *common
return t return t
} }
func listManifestsHandlerFunc(w http.ResponseWriter, r *http.Request) { func listManifestsHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: list manifests" handler := "manager: list manifests"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
deploymentName, err := pos(w, r, 2) deploymentName, err := pos(w, r, 2)
if err != nil { if err != nil {
return return err
} }
m, err := backend.ListManifests(deploymentName) m, err := backend.ListManifests(deploymentName)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusInternalServerError, err, w) return err
return
} }
var manifestNames []string var manifestNames []string
@ -351,31 +335,33 @@ func listManifestsHandlerFunc(w http.ResponseWriter, r *http.Request) {
} }
util.LogHandlerExitWithJSON(handler, w, manifestNames, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, manifestNames, http.StatusOK)
return nil
} }
func getManifestHandlerFunc(w http.ResponseWriter, r *http.Request) { func getManifestHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get manifest" handler := "manager: get manifest"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
deploymentName, err := pos(w, r, 2) deploymentName, err := pos(w, r, 2)
if err != nil { if err != nil {
return return err
} }
manifestName, err := pos(w, r, 4) manifestName, err := pos(w, r, 4)
if err != nil { if err != nil {
return return err
} }
m, err := backend.GetManifest(deploymentName, manifestName) m, err := backend.GetManifest(deploymentName, manifestName)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
util.LogHandlerExitWithJSON(handler, w, m, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, m, http.StatusOK)
return nil
} }
func expandHandlerFunc(w http.ResponseWriter, r *http.Request) { func expandHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: expand config" handler := "manager: expand config"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
defer r.Body.Close() defer r.Body.Close()
@ -383,108 +369,114 @@ func expandHandlerFunc(w http.ResponseWriter, r *http.Request) {
if t != nil { if t != nil {
c, err := backend.Expand(t) c, err := backend.Expand(t)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
util.LogHandlerExitWithJSON(handler, w, c, http.StatusCreated) util.LogHandlerExitWithJSON(handler, w, c, http.StatusCreated)
return
} }
return nil
} }
// Putting Type handlers here for now because deployments.go // Putting Type handlers here for now because deployments.go
// currently owns its own Manager backend and doesn't like to share. // currently owns its own Manager backend and doesn't like to share.
func listTypesHandlerFunc(w http.ResponseWriter, r *http.Request) { func listTypesHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: list types" handler := "manager: list types"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
types, err := backend.ListTypes() types, err := backend.ListTypes()
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
util.LogHandlerExitWithJSON(handler, w, types, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, types, http.StatusOK)
return nil
} }
func listTypeInstancesHandlerFunc(w http.ResponseWriter, r *http.Request) { func listTypeInstancesHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: list instances" handler := "manager: list instances"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
typeName, err := pos(w, r, 2) typeName, err := pos(w, r, 2)
if err != nil { if err != nil {
return return err
} }
instances, err := backend.ListInstances(typeName) instances, err := backend.ListInstances(typeName)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
util.LogHandlerExitWithJSON(handler, w, instances, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, instances, http.StatusOK)
return nil
} }
func getRegistryForTypeHandlerFunc(w http.ResponseWriter, r *http.Request) { func getRegistryForTypeHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get type registry" handler := "manager: get type registry"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
typeName, err := pos(w, r, 2) typeName, err := pos(w, r, 2)
if err != nil { if err != nil {
return return err
} }
registry, err := backend.GetRegistryForType(typeName) registry, err := backend.GetRegistryForType(typeName)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
util.LogHandlerExitWithJSON(handler, w, registry, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, registry, http.StatusOK)
return nil
} }
func getMetadataForTypeHandlerFunc(w http.ResponseWriter, r *http.Request) { func getMetadataForTypeHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get type metadata" handler := "manager: get type metadata"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
typeName, err := pos(w, r, 2) typeName, err := pos(w, r, 2)
if err != nil { if err != nil {
return return err
} }
metadata, err := backend.GetMetadataForType(typeName) metadata, err := backend.GetMetadataForType(typeName)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
util.LogHandlerExitWithJSON(handler, w, metadata, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, metadata, http.StatusOK)
return nil
} }
// Putting Registry handlers here for now because deployments.go // Putting Registry handlers here for now because deployments.go
// currently owns its own Manager backend and doesn't like to share. // currently owns its own Manager backend and doesn't like to share.
func listRegistriesHandlerFunc(w http.ResponseWriter, r *http.Request) { func listRegistriesHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: list registries" handler := "manager: list registries"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
registries, err := backend.ListRegistries() registries, err := backend.ListRegistries()
if err != nil { if err != nil {
return return err
} }
util.LogHandlerExitWithJSON(handler, w, registries, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, registries, http.StatusOK)
return nil
} }
func getRegistryHandlerFunc(w http.ResponseWriter, r *http.Request) { func getRegistryHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get registry" handler := "manager: get registry"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
registryName, err := pos(w, r, 2) registryName, err := pos(w, r, 2)
if err != nil { if err != nil {
return return err
} }
cr, err := backend.GetRegistry(registryName) cr, err := backend.GetRegistry(registryName)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
util.LogHandlerExitWithJSON(handler, w, cr, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, cr, http.StatusOK)
return nil
} }
func getRegistry(w http.ResponseWriter, r *http.Request, handler string) *common.Registry { func getRegistry(w http.ResponseWriter, r *http.Request, handler string) *common.Registry {
@ -504,44 +496,45 @@ func getRegistry(w http.ResponseWriter, r *http.Request, handler string) *common
return t return t
} }
func createRegistryHandlerFunc(w http.ResponseWriter, r *http.Request) { func createRegistryHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: create registry" handler := "manager: create registry"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
defer r.Body.Close() defer r.Body.Close()
registryName, err := pos(w, r, 2) registryName, err := pos(w, r, 2)
if err != nil { if err != nil {
return return err
} }
reg := getRegistry(w, r, handler) reg := getRegistry(w, r, handler)
if reg.Name != registryName { if reg.Name != registryName {
e := fmt.Errorf("Registry name does not match %s != %s", reg.Name, registryName) e := fmt.Errorf("Registry name does not match %s != %s", reg.Name, registryName)
util.LogAndReturnError(handler, http.StatusBadRequest, e, w) httputil.BadRequest(w, r, e)
return return nil
} }
if reg != nil { if reg != nil {
err = backend.CreateRegistry(reg) err = backend.CreateRegistry(reg)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
} }
util.LogHandlerExitWithJSON(handler, w, reg, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, reg, http.StatusOK)
return nil
} }
func listRegistryTypesHandlerFunc(w http.ResponseWriter, r *http.Request) { func listRegistryTypesHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: list registry types" handler := "manager: list registry types"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
registryName, err := pos(w, r, 2) registryName, err := pos(w, r, 2)
if err != nil { if err != nil {
return return err
} }
values, err := url.ParseQuery(r.URL.RawQuery) values, err := url.ParseQuery(r.URL.RawQuery)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
var regex *regexp.Regexp var regex *regexp.Regexp
@ -549,72 +542,73 @@ func listRegistryTypesHandlerFunc(w http.ResponseWriter, r *http.Request) {
if regexString != "" { if regexString != "" {
regex, err = regexp.Compile(regexString) regex, err = regexp.Compile(regexString)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
} }
registryTypes, err := backend.ListRegistryTypes(registryName, regex) registryTypes, err := backend.ListRegistryTypes(registryName, regex)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusInternalServerError, err, w) return err
return
} }
util.LogHandlerExitWithJSON(handler, w, registryTypes, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, registryTypes, http.StatusOK)
return nil
} }
func getDownloadURLsHandlerFunc(w http.ResponseWriter, r *http.Request) { func getDownloadURLsHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get download URLs" handler := "manager: get download URLs"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
registryName, err := pos(w, r, 2) registryName, err := pos(w, r, 2)
if err != nil { if err != nil {
return return err
} }
typeName, err := pos(w, r, 4) typeName, err := pos(w, r, 4)
if err != nil { if err != nil {
return return err
} }
tt, err := registry.ParseType(typeName) tt, err := registry.ParseType(typeName)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusInternalServerError, err, w) return err
return
} }
c, err := backend.GetDownloadURLs(registryName, tt) cr, err := backend.GetDownloadURLs(registryName, tt)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
urls := []string{} urls := []string{}
for _, u := range c { for _, u := range cr {
urls = append(urls, u.String()) urls = append(urls, u.String())
} }
util.LogHandlerExitWithJSON(handler, w, urls, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, urls, http.StatusOK)
return nil
} }
func getFileHandlerFunc(w http.ResponseWriter, r *http.Request) { func getFileHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get file" handler := "manager: get file"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
registryName, err := pos(w, r, 2) registryName, err := pos(w, r, 2)
if err != nil { if err != nil {
return return err
} }
file := r.FormValue("file") file := r.FormValue("file")
if file == "" { if file == "" {
return return err
} }
b, err := backend.GetFile(registryName, file) b, err := backend.GetFile(registryName, file)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
util.LogHandlerExitWithJSON(handler, w, b, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, b, http.StatusOK)
return nil
} }
func getCredential(w http.ResponseWriter, r *http.Request, handler string) *common.RegistryCredential { func getCredential(w http.ResponseWriter, r *http.Request, handler string) *common.RegistryCredential {
@ -634,42 +628,44 @@ func getCredential(w http.ResponseWriter, r *http.Request, handler string) *comm
return t return t
} }
func createCredentialHandlerFunc(w http.ResponseWriter, r *http.Request) { func createCredentialHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: create credential" handler := "manager: create credential"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
defer r.Body.Close() defer r.Body.Close()
credentialName, err := pos(w, r, 2) credentialName, err := pos(w, r, 2)
if err != nil { if err != nil {
return return err
} }
c := getCredential(w, r, handler) cr := getCredential(w, r, handler)
if c != nil { if cr != nil {
err = backend.CreateCredential(credentialName, c) err = backend.CreateCredential(credentialName, cr)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
} }
util.LogHandlerExitWithJSON(handler, w, c, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, c, http.StatusOK)
return nil
} }
func getCredentialHandlerFunc(w http.ResponseWriter, r *http.Request) { func getCredentialHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get credential" handler := "manager: get credential"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
credentialName, err := pos(w, r, 2) credentialName, err := pos(w, r, 2)
if err != nil { if err != nil {
return return err
} }
c, err := backend.GetCredential(credentialName) cr, err := backend.GetCredential(credentialName)
if err != nil { if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w) httputil.BadRequest(w, r, err)
return return nil
} }
util.LogHandlerExitWithJSON(handler, w, c, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, cr, http.StatusOK)
return nil
} }
func getJSONFromRequest(w http.ResponseWriter, r *http.Request, handler string) ([]byte, error) { func getJSONFromRequest(w http.ResponseWriter, r *http.Request, handler string) ([]byte, error) {

@ -31,6 +31,7 @@ package router
import ( import (
"log" "log"
"net/http" "net/http"
"reflect"
"github.com/Masterminds/httputil" "github.com/Masterminds/httputil"
helmhttp "github.com/kubernetes/helm/pkg/httputil" helmhttp "github.com/kubernetes/helm/pkg/httputil"
@ -68,6 +69,7 @@ func NewHandler(c *Context) *Handler {
// //
// The route name is "VERB /ENPOINT/PATH", e.g. "GET /foo". // The route name is "VERB /ENPOINT/PATH", e.g. "GET /foo".
func (h *Handler) Add(route string, fn HandlerFunc) { func (h *Handler) Add(route string, fn HandlerFunc) {
log.Printf("Map %q to %s", route, reflect.ValueOf(fn).Type().Name())
h.routes[route] = fn h.routes[route] = fn
h.paths = append(h.paths, route) h.paths = append(h.paths, route)
h.resolver = httputil.NewResolver(h.paths) h.resolver = httputil.NewResolver(h.paths)
@ -84,6 +86,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fn, ok := h.routes[route] fn, ok := h.routes[route]
if !ok { if !ok {
// This is a 500 because the route was registered, but not here.
helmhttp.Fatal(w, r, "route %s missing", route) helmhttp.Fatal(w, r, "route %s missing", route)
} }

@ -28,6 +28,9 @@ import (
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
) )
// DefaultEncoder is an *AcceptEncoder with the default application/json encoding.
var DefaultEncoder = &AcceptEncoder{DefaultEncoding: "application/json"}
// Encoder takes input and translate it to an expected encoded output. // Encoder takes input and translate it to an expected encoded output.
// //
// Implementations of encoders may use details of the HTTP request and response // Implementations of encoders may use details of the HTTP request and response
@ -40,7 +43,9 @@ type Encoder interface {
// //
// When an encoder fails, it logs any necessary data and then responds to // When an encoder fails, it logs any necessary data and then responds to
// the client. // the client.
Encode(http.ResponseWriter, *http.Request, interface{}) //
// The integer must be a valid http.Status* status code.
Encode(http.ResponseWriter, *http.Request, interface{}, int)
} }
// AcceptEncoder uses the accept headers on a request to determine the response type. // AcceptEncoder uses the accept headers on a request to determine the response type.
@ -56,7 +61,7 @@ type AcceptEncoder struct {
} }
// Encode encodeds the given interface to the first available type in the Accept header. // Encode encodeds the given interface to the first available type in the Accept header.
func (e *AcceptEncoder) Encode(w http.ResponseWriter, r *http.Request, out interface{}) { func (e *AcceptEncoder) Encode(w http.ResponseWriter, r *http.Request, out interface{}, statusCode int) {
a := r.Header.Get("accept") a := r.Header.Get("accept")
fn := encoders[e.DefaultEncoding] fn := encoders[e.DefaultEncoding]
mt := e.DefaultEncoding mt := e.DefaultEncoding
@ -70,6 +75,7 @@ func (e *AcceptEncoder) Encode(w http.ResponseWriter, r *http.Request, out inter
return return
} }
w.Header().Add("content-type", mt) w.Header().Add("content-type", mt)
w.WriteHeader(statusCode)
w.Write(data) w.Write(data)
} }

@ -77,7 +77,7 @@ func TestAcceptEncoder(t *testing.T) {
DefaultEncoding: "application/json", DefaultEncoding: "application/json",
} }
fn := func(w http.ResponseWriter, r *http.Request) { fn := func(w http.ResponseWriter, r *http.Request) {
enc.Encode(w, r, []string{"hello", "world"}) enc.Encode(w, r, []string{"hello", "world"}, http.StatusOK)
} }
s := httptest.NewServer(http.HandlerFunc(fn)) s := httptest.NewServer(http.HandlerFunc(fn))
defer s.Close() defer s.Close()

@ -30,27 +30,46 @@ const (
// LogFatal is for logging 500 errors. Form: Internal Server Error r.Method r.URL message // LogFatal is for logging 500 errors. Form: Internal Server Error r.Method r.URL message
LogFatal = "Internal Server Error: %s %s %s" LogFatal = "Internal Server Error: %s %s %s"
// LogBadRequest logs 400 errors. // LogBadRequest logs 400 errors.
LogBadRequest = "Bad Request: %s %s" LogBadRequest = "Bad Request: %s %s %s"
) )
// Error represents an HTTP error that can be converted to structured types.
//
// For example, and error can be serialized to JSON or YAML. Likewise, the
// string marshal can convert it to a string.
type Error struct {
Msg string `json:"message, omitempty"`
Status string `json:"status"`
}
// Error implements the error interface.
func (e *Error) Error() string {
return fmt.Sprintf("%s: %s", e.Status, e.Msg)
}
// NotFound writes a 404 error to the client and logs an error. // NotFound writes a 404 error to the client and logs an error.
func NotFound(w http.ResponseWriter, r *http.Request) { func NotFound(w http.ResponseWriter, r *http.Request) {
log.Printf(LogNotFound, r.Method, r.URL) msg := fmt.Sprintf(LogNotFound, r.Method, r.URL)
w.WriteHeader(http.StatusNotFound) log.Println(msg)
fmt.Fprintln(w, "File Not Found") writeErr(w, r, msg, http.StatusNotFound)
}
// BadRequest writes an HTTP 400.
func BadRequest(w http.ResponseWriter, r *http.Request, err error) {
log.Printf(LogBadRequest, r.Method, r.URL, err)
writeErr(w, r, err.Error(), http.StatusBadRequest)
} }
func BadRequest(w http.ResponseWriter, r *http.Request) { // writeErr formats and writes the error using the default encoder.
log.Printf(LogNotFound, r.Method, r.URL) func writeErr(w http.ResponseWriter, r *http.Request, msg string, status int) {
w.WriteHeader(http.StatusBadRequest) DefaultEncoder.Encode(w, r, &Error{Status: http.StatusText(status), Msg: msg}, status)
fmt.Fprintln(w, "Bad Request")
} }
// Fatal writes a 500 response to the client and logs the message. // Fatal writes a 500 response to the client and logs the message.
// //
// Additional arguments are past into the the formatter as params to msg. // Additional arguments are past into the the formatter as params to msg.
func Fatal(w http.ResponseWriter, r *http.Request, msg string, v ...interface{}) { func Fatal(w http.ResponseWriter, r *http.Request, msg string, v ...interface{}) {
log.Printf(LogFatal, r.Method, r.URL, fmt.Sprintf(msg, v...)) m := fmt.Sprintf(msg, v...)
w.WriteHeader(http.StatusInternalServerError) log.Printf(LogFatal, r.Method, r.URL, m)
fmt.Fprintln(w, "Internal Server Error") writeErr(w, r, m, http.StatusInternalServerError)
} }

Loading…
Cancel
Save