mirror of https://github.com/helm/helm
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
5.4 KiB
204 lines
5.4 KiB
9 years ago
|
/*
|
||
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||
|
|
||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
you may not use this file except in compliance with the License.
|
||
|
You may obtain a copy of the License at
|
||
|
|
||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
Unless required by applicable law or agreed to in writing, software
|
||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
See the License for the specific language governing permissions and
|
||
|
limitations under the License.
|
||
|
*/
|
||
|
|
||
|
/* Package router is an HTTP router.
|
||
|
|
||
|
This router provides appropriate dependency injection/encapsulation for the
|
||
|
HTTP routing layer. This removes the requirement to set global variables for
|
||
|
resources like database handles.
|
||
|
|
||
|
This library does not replace the default HTTP mux because there is no need.
|
||
|
Instead, it implements an HTTP handler.
|
||
|
|
||
|
It then defines a handler function that is given a context as well as a
|
||
|
request and response.
|
||
|
*/
|
||
|
package router
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"net/http"
|
||
|
"os"
|
||
|
|
||
|
"github.com/Masterminds/httputil"
|
||
|
"github.com/kubernetes/deployment-manager/cmd/manager/manager"
|
||
|
"github.com/kubernetes/deployment-manager/pkg/common"
|
||
|
)
|
||
|
|
||
|
const LogAccess = "Access: %s %s"
|
||
|
|
||
|
// Config holds the global configuration parameters passed into the router.
|
||
|
//
|
||
|
// Config is used concurrently. Once a config is created, it should be treated
|
||
|
// as immutable.
|
||
|
type Config struct {
|
||
|
// Address is the host and port (:8080)
|
||
|
Address string
|
||
|
// MaxTemplateLength is the maximum length of a template.
|
||
|
MaxTemplateLength int64
|
||
|
// ExpanderName is the DNS name of the expansion service.
|
||
|
ExpanderName string
|
||
|
// ExpanderURL is the expander service's URL.
|
||
|
ExpanderURL string
|
||
|
// DeployerName is the deployer's DNS name
|
||
|
DeployerName string
|
||
|
// DeployerURL is the deployer's URL
|
||
|
DeployerURL string
|
||
|
// CredentialFile is the file to the credentials.
|
||
|
CredentialFile string
|
||
|
// CredentialSecrets tells the service to use a secrets file instead.
|
||
|
CredentialSecrets bool
|
||
|
// MongoName is the DNS name of the mongo server.
|
||
|
MongoName string
|
||
|
// MongoPort is the port for the MongoDB protocol on the mongo server.
|
||
|
// It is a string for historical reasons.
|
||
|
MongoPort string
|
||
|
// MongoAddress is the name and port.
|
||
|
MongoAddress string
|
||
|
}
|
||
|
|
||
|
// Context contains dependencies that are passed to each handler function.
|
||
|
//
|
||
|
// Context carries typed information, often scoped to interfaces, so that the
|
||
|
// caller's contract with the service is known at compile time.
|
||
|
//
|
||
|
// Members of the context must be concurrency safe.
|
||
|
type Context struct {
|
||
|
Config *Config
|
||
|
// Manager is a deployment-manager/manager/manager.Manager
|
||
|
Manager manager.Manager
|
||
|
Encoder Encoder
|
||
|
CredentialProvider common.CredentialProvider
|
||
|
}
|
||
|
|
||
|
func (c *Context) Log(msg string, v ...interface{}) {
|
||
|
// FIXME: This should be configurable via the context.
|
||
|
fmt.Fprintf(os.Stdout, msg+"\n", v...)
|
||
|
}
|
||
|
|
||
|
func (c *Context) Err(msg string, v ...interface{}) {
|
||
|
// FIXME: This should be configurable via the context.
|
||
|
fmt.Fprintf(os.Stderr, msg+"\n", v...)
|
||
|
}
|
||
|
|
||
|
// NotFound writes a 404 error to the client and logs an error.
|
||
|
func NotFound(w http.ResponseWriter, r *http.Request) {
|
||
|
// TODO: Log this.
|
||
|
w.WriteHeader(http.StatusNotFound)
|
||
|
fmt.Fprintln(w, "File Not Found")
|
||
|
}
|
||
|
|
||
|
// Fatal writes a 500 response to the client and logs the message.
|
||
|
//
|
||
|
// Additional arguments are past into the the formatter as params to msg.
|
||
|
func Fatal(w http.ResponseWriter, r *http.Request, msg string, v ...interface{}) {
|
||
|
// TODO: Log this.
|
||
|
w.WriteHeader(http.StatusInternalServerError)
|
||
|
fmt.Fprintln(w, "Internal Server Error")
|
||
|
}
|
||
|
|
||
|
// HandlerFunc responds to an individual HTTP request.
|
||
|
//
|
||
|
// Returned errors will be captured, logged, and returned as HTTP 500 errors.
|
||
|
type HandlerFunc func(w http.ResponseWriter, r *http.Request, c *Context) error
|
||
|
|
||
|
// Handler implements an http.Handler.
|
||
|
//
|
||
|
// This is the top level route handler.
|
||
|
type Handler struct {
|
||
|
c *Context
|
||
|
resolver *httputil.Resolver
|
||
|
routes Routes
|
||
|
}
|
||
|
|
||
|
// Create a new Handler.
|
||
|
//
|
||
|
// Routes cannot be modified after construction. The order that the route
|
||
|
// names are returned by Routes.Paths() determines the lookup order.
|
||
|
func NewHandler(c *Context, r Routes) *Handler {
|
||
|
paths := make([]string, r.Len())
|
||
|
i := 0
|
||
|
for _, k := range r.Paths() {
|
||
|
paths[i] = k
|
||
|
i++
|
||
|
}
|
||
|
|
||
|
return &Handler{
|
||
|
c: c,
|
||
|
resolver: httputil.NewResolver(paths),
|
||
|
routes: r,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ServeHTTP serves an HTTP request.
|
||
|
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||
|
h.c.Log(LogAccess, r.Method, r.URL)
|
||
|
route, err := h.resolver.Resolve(r)
|
||
|
if err != nil {
|
||
|
NotFound(w, r)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
fn, ok := h.routes.Get(route)
|
||
|
if !ok {
|
||
|
Fatal(w, r, "route %s missing", route)
|
||
|
}
|
||
|
|
||
|
if err := fn(w, r, h.c); err != nil {
|
||
|
Fatal(w, r, err.Error())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Routes defines a container for route-to-function mapping.
|
||
|
type Routes interface {
|
||
|
Add(string, HandlerFunc)
|
||
|
Get(string) (HandlerFunc, bool)
|
||
|
Len() int
|
||
|
Paths() []string
|
||
|
}
|
||
|
|
||
|
// NewRoutes creates a default implementation of a Routes.
|
||
|
//
|
||
|
// The ordering of routes is nonderministic.
|
||
|
func NewRoutes() Routes {
|
||
|
return routeMap{}
|
||
|
}
|
||
|
|
||
|
type routeMap map[string]HandlerFunc
|
||
|
|
||
|
func (r routeMap) Add(name string, fn HandlerFunc) {
|
||
|
r[name] = fn
|
||
|
}
|
||
|
|
||
|
func (r routeMap) Get(name string) (HandlerFunc, bool) {
|
||
|
f, ok := r[name]
|
||
|
return f, ok
|
||
|
}
|
||
|
|
||
|
func (r routeMap) Len() int {
|
||
|
return len(r)
|
||
|
}
|
||
|
|
||
|
func (r routeMap) Paths() []string {
|
||
|
b := make([]string, len(r))
|
||
|
i := 0
|
||
|
for k := range r {
|
||
|
b[i] = k
|
||
|
i++
|
||
|
}
|
||
|
return b
|
||
|
}
|