initial commit
This commit is contained in:
commit
7715fcf373
37 changed files with 2957 additions and 0 deletions
7
pkg/api/api.go
Normal file
7
pkg/api/api.go
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package api
|
||||
|
||||
type Route struct {
|
||||
Path string
|
||||
Handler http.HandlerFunc
|
||||
Methods []string
|
||||
}
|
||||
34
pkg/api/v1/schema/schema.go
Normal file
34
pkg/api/v1/schema/schema.go
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package schema
|
||||
|
||||
/*
|
||||
healthCheckNodePort
|
||||
|
||||
*/
|
||||
|
||||
type LBConfig struct {
|
||||
LoadBalancers []LoadBalancer
|
||||
}
|
||||
|
||||
type LoadBalancer struct {
|
||||
Name string `json:"name"`
|
||||
IP string `json:"ip"`
|
||||
Options Options `json:"options,omitempty"`
|
||||
Ports []Port `json:"ports,omitempty"`
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
Frontend []string `json:"frontend,omitempty"`
|
||||
Backend []string `json:"backend,omitempty"`
|
||||
DefaultServer string `json:"defaultServer,omitempty`
|
||||
}
|
||||
|
||||
type Port struct {
|
||||
Port int `json:"port,omitempty"`
|
||||
Servers []Server `json:"servers,omitempty"`
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
IP string `json:"ip,omitempty"`
|
||||
Port int `json:"port,omitempty"`
|
||||
}
|
||||
103
pkg/api/v1/server/context.go
Normal file
103
pkg/api/v1/server/context.go
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func newContext(w http.ResponseWriter, r *http.Request, srv *Server) *Context {
|
||||
h := w.Header()
|
||||
h.Set("Content-Type", "application/json")
|
||||
return &Context{
|
||||
Status: http.StatusOK,
|
||||
Request: r,
|
||||
Response: w,
|
||||
s: srv,
|
||||
}
|
||||
}
|
||||
|
||||
// Context is the context object shared between http handlers
|
||||
type Context struct {
|
||||
Body []byte
|
||||
Status int
|
||||
|
||||
Request *http.Request
|
||||
Response http.ResponseWriter
|
||||
s *Server
|
||||
}
|
||||
|
||||
// Method returns the request method
|
||||
func (c *Context) Method() string {
|
||||
return c.Request.Method
|
||||
}
|
||||
|
||||
// GetHeader returns the given http header
|
||||
func (c *Context) GetHeader(name string) string {
|
||||
return c.Request.Header.Get(name)
|
||||
}
|
||||
|
||||
// SetHeader sets the given http header
|
||||
func (c *Context) SetHeader(name, value string) {
|
||||
h := c.Response.Header()
|
||||
h.Set(name, value)
|
||||
}
|
||||
|
||||
// Form returns the given form value
|
||||
func (c *Context) Form(name string) string {
|
||||
return c.Request.FormValue(name)
|
||||
}
|
||||
|
||||
// Var returns the given url variable
|
||||
func (c *Context) Var(name string) (ret string) {
|
||||
ret, _ = mux.Vars(c.Request)[name]
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Context) log() {
|
||||
c.s.log.Info("access",
|
||||
"addr", c.Request.RemoteAddr,
|
||||
"method", c.Request.Method,
|
||||
"url", c.Request.URL,
|
||||
"status", c.Status,
|
||||
)
|
||||
}
|
||||
|
||||
func (c *Context) NotFound() {
|
||||
c.Status = http.StatusNotFound
|
||||
c.Response.WriteHeader(http.StatusNotFound)
|
||||
c.Response.Write([]byte(`{"message":"not found","status":404}`))
|
||||
c.log()
|
||||
}
|
||||
|
||||
// OK is a empty HTTP 200 JSON response
|
||||
func (c *Context) OK() {
|
||||
c.Response.Write([]byte("{}"))
|
||||
c.log()
|
||||
}
|
||||
|
||||
// JSON is a json response
|
||||
func (c *Context) JSON(v interface{}) {
|
||||
err := json.NewEncoder(c.Response).Encode(v)
|
||||
if err != nil {
|
||||
c.Err(ise)
|
||||
return
|
||||
}
|
||||
c.log()
|
||||
}
|
||||
|
||||
// Err is a HTTPErr wrapper for the custom Error type
|
||||
func (c *Context) Err(err Error) {
|
||||
c.HTTPErr(err.Error(), err.Status())
|
||||
}
|
||||
|
||||
// HTTPErr is a http.Error wrapper
|
||||
func (c *Context) HTTPErr(err string, status int) {
|
||||
c.Status = status
|
||||
http.Error(c.Response, err, status)
|
||||
c.log()
|
||||
}
|
||||
|
||||
type ctxHandler func(*Context)
|
||||
24
pkg/api/v1/server/handler.go
Normal file
24
pkg/api/v1/server/handler.go
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type notFoundHandler struct {
|
||||
s *Server
|
||||
}
|
||||
|
||||
func (nf *notFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
newContext(w, r, nf.s).NotFound()
|
||||
}
|
||||
|
||||
func authHandler(h ctxHandler) ctxHandler {
|
||||
return func(ctx *Context) {
|
||||
// TODO
|
||||
h(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func healthzHandler(ctx *Context) {
|
||||
ctx.OK()
|
||||
}
|
||||
21
pkg/api/v1/server/routes.go
Normal file
21
pkg/api/v1/server/routes.go
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"git.giftfish.de/ston1th/haproxy-lb/pkg/api"
|
||||
"git.giftfish.de/ston1th/haproxy-lb/pkg/api/v1/schema"
|
||||
)
|
||||
|
||||
const version = "/" + schema.Version
|
||||
|
||||
var routes = []api.Route{
|
||||
{
|
||||
"/healthz",
|
||||
healthzHandler,
|
||||
[]string{"GET"},
|
||||
},
|
||||
{
|
||||
version + "/alloc",
|
||||
authHandler(allocHandler),
|
||||
[]string{"POST"},
|
||||
},
|
||||
}
|
||||
92
pkg/api/v1/server/server.go
Normal file
92
pkg/api/v1/server/server.go
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
stdtls "crypto/tls"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// Server is the webapp and api server
|
||||
type Server struct {
|
||||
srv *http.Server
|
||||
mux *mux.Router
|
||||
log logr.Logger
|
||||
|
||||
stop chan struct{}
|
||||
stopKeyReset chan struct{}
|
||||
|
||||
cert string
|
||||
key string
|
||||
laddr string
|
||||
|
||||
debug bool
|
||||
}
|
||||
|
||||
// NewHTTPServer returns a new HTTPServer
|
||||
func NewServer(log logr.Logger) *Server {
|
||||
s := &Server{
|
||||
mux: mux.NewRouter(),
|
||||
log: log,
|
||||
|
||||
stop: make(chan struct{}),
|
||||
stopKeyReset: make(chan struct{}),
|
||||
|
||||
cert: filepath.Join(core.C.DataDir, core.C.HTTP.Cert),
|
||||
key: filepath.Join(core.C.DataDir, core.C.HTTP.Key),
|
||||
laddr: net.JoinHostPort(core.C.HTTP.Address, core.C.HTTP.Port),
|
||||
|
||||
debug: core.C.Debug,
|
||||
}
|
||||
s.mux.NotFoundHandler = ¬FoundHandler{s}
|
||||
for _, v := range routes {
|
||||
s.mux.HandleFunc(v.Path, s.contextWrapper(v.Handler)).Methods(v.Methods...)
|
||||
}
|
||||
s.start()
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Server) start() error {
|
||||
l, err := tls.Listen("tcp", h.laddr, cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.srv = &http.Server{
|
||||
Handler: h.mux,
|
||||
TLSConfig: cfg,
|
||||
ReadTimeout: 10 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
}
|
||||
go func() {
|
||||
err := h.srv.Serve(l)
|
||||
if err != nil {
|
||||
s.log.Error(err, "")
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) contextWrapper(h ctxHandler) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
h(newContext(w, r, s))
|
||||
}
|
||||
}
|
||||
|
||||
// Stop stops listening for incoming connections and closes currently open connections
|
||||
func (s *Server) Stop() {
|
||||
s.log.Info("stopping")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
defer cancel()
|
||||
err := h.srv.Shutdown(ctx)
|
||||
if err != nil {
|
||||
s.log.Error(err, "")
|
||||
}
|
||||
s.log.Info("stopped")
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue