some api changes

This commit is contained in:
ston1th 2021-10-19 21:24:14 +02:00
commit 70fd3f71e5
11 changed files with 118 additions and 76 deletions

View file

@ -23,6 +23,7 @@ type Client struct {
endpoint string
username string
password string
auth bool
httpClient *http.Client
debugWriter io.Writer
insecure bool
@ -62,6 +63,7 @@ func WithCredentials(username, password string) ClientOption {
return func(client *Client) {
client.username = username
client.password = password
client.auth = true
}
}
@ -77,6 +79,7 @@ var (
type Config struct {
Endpoint string `json:"endpoint"`
NoAuth bool `json:"no_auth"`
User string `json:"user"`
Password string `json:"password"`
Insecure bool `json:"insecure"`
@ -87,6 +90,13 @@ func ClientOptionsFromConfig(cfg Config) (options []ClientOption, err error) {
err = ErrMissingEndpoint
return
}
options = []ClientOption{
WithEndpoint(cfg.Endpoint),
WithInsecureClient(cfg.Insecure),
}
if cfg.NoAuth {
return
}
if cfg.User == "" {
err = ErrMissingUser
return
@ -95,11 +105,7 @@ func ClientOptionsFromConfig(cfg Config) (options []ClientOption, err error) {
err = ErrMissingPassword
return
}
options = []ClientOption{
WithEndpoint(cfg.Endpoint),
WithCredentials(cfg.User, cfg.Password),
WithInsecureClient(cfg.Insecure),
}
options = append(options, WithCredentials(cfg.User, cfg.Password))
return
}
@ -109,6 +115,17 @@ func ClientOptionsFromEnv() (options []ClientOption, err error) {
err = ErrMissingEndpointEnv
return
}
insecure, _ := strconv.ParseBool(os.Getenv("HAPROXY_LB_INSECURE"))
options = []ClientOption{
WithEndpoint(endpoint),
WithInsecureClient(insecure),
}
noAuth, _ := strconv.ParseBool(os.Getenv("HAPROXY_LB_NO_AUTH"))
if noAuth {
return
}
user := os.Getenv("HAPROXY_LB_USER")
if user == "" {
err = ErrMissingUserEnv
@ -121,13 +138,7 @@ func ClientOptionsFromEnv() (options []ClientOption, err error) {
return
}
insecure, _ := strconv.ParseBool(os.Getenv("HAPROXY_LB_INSECURE"))
options = []ClientOption{
WithEndpoint(endpoint),
WithCredentials(user, pass),
WithInsecureClient(insecure),
}
options = append(options, WithCredentials(user, pass))
return
}
@ -163,7 +174,9 @@ func (c *Client) NewRequest(ctx context.Context, method, path string, body io.Re
if err != nil {
return nil, err
}
req.SetBasicAuth(c.username, c.password)
if c.auth {
req.SetBasicAuth(c.username, c.password)
}
req = req.WithContext(ctx)
return req, nil
}

View file

@ -2,13 +2,16 @@ package client
import (
"encoding/json"
"errors"
"net/http"
)
type Error struct {
Message string `json:"message"`
Status int `json:"status"`
Err string `json:"error"`
Status int `json:"status"`
}
func (e Error) Error() string {
return e.Err
}
func decodeResp(resp *http.Response, v interface{}) error {
@ -22,16 +25,13 @@ func decodeResp(resp *http.Response, v interface{}) error {
}
return json.NewDecoder(resp.Body).Decode(&v)
}
if resp.StatusCode == 404 {
return ErrNotFound
}
var e Error
err := json.NewDecoder(resp.Body).Decode(&e)
if err != nil {
return err
}
if resp.StatusCode >= 400 && resp.StatusCode <= 599 {
return errors.New(e.Message)
return e
}
return nil
}

View file

@ -43,7 +43,7 @@ type notFoundHandler struct {
}
func (nf *notFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
types.NewContext(w, r, nf.s.Data, nf.s.log).NotFound()
types.NewContext(w, r, nf.s.Data, nf.s.log).Err(types.ErrInvalidAPIRoute)
}
// NewHTTPServer returns a new HTTPServer

View file

@ -86,7 +86,7 @@ func (c *Context) log() {
c.Log.Info("access",
"addr", c.Request.RemoteAddr,
"method", c.Request.Method,
"url", c.Request.URL.Path,
"path", c.Request.URL.Path,
"status", c.Status,
)
}

View file

@ -19,7 +19,7 @@ type Err struct {
// Error returns the error string
func (a Err) Error() string {
return `{"message":"` + a.err + `","status":` + strconv.Itoa(a.status) + `}`
return `{"error":"` + a.err + `","status":` + strconv.Itoa(a.status) + `}`
}
// Status returns the HTTP status code
@ -35,13 +35,17 @@ func newError(err string, status int) Error {
}
var (
ErrBadreq = newError("bad request", http.StatusBadRequest)
ErrInvalid = newError("invalid data", http.StatusBadRequest)
ErrUnauthorized = newError("unauthorized", http.StatusUnauthorized)
ErrForbidden = newError("forbidden", http.StatusForbidden)
ErrNotFound = newError("not found", http.StatusNotFound)
ErrMNA = newError("method not allowed", http.StatusMethodNotAllowed)
ErrExists = newError("resource already exists", http.StatusConflict)
ErrISE = newError("internal server error", http.StatusInternalServerError)
ErrFollower = newError("follower write forbidden", http.StatusForbidden)
ErrInvalidAPIRoute = newError("invalid api route", http.StatusNotFound)
ErrBadreq = newError("bad request", http.StatusBadRequest)
ErrInvalid = newError("invalid data", http.StatusBadRequest)
ErrUnauthorized = newError("unauthorized", http.StatusUnauthorized)
ErrForbidden = newError("forbidden", http.StatusForbidden)
ErrNotFound = newError("not found", http.StatusNotFound)
ErrLBNotFound = newError("loadbalancer not found", http.StatusNotFound)
ErrMNA = newError("method not allowed", http.StatusMethodNotAllowed)
ErrExists = newError("resource already exists", http.StatusConflict)
ErrISE = newError("internal server error", http.StatusInternalServerError)
ErrFollower = newError("follower write forbidden", http.StatusForbidden)
ErrClusterNotFound = newError("cluster not found", http.StatusNotFound)
ErrLBsNotFound = newError("loadbalancers not found", http.StatusNotFound)
)

View file

@ -13,7 +13,7 @@ import (
var (
ErrClientIsNil = errors.New("client is nil")
base = "/" + schema.Version
base = schema.LBPath
)
type Client struct {
@ -32,7 +32,7 @@ func (c *Client) GetLoadBalancers(ctx context.Context) (lbs map[string]schema.Lo
}
func (c *Client) GetLoadBalancersWithCluster(ctx context.Context, cluster string) (lbs map[string]schema.LoadBalancer, err error) {
path := base + "/lb"
path := base
if cluster != "" {
path += "/" + cluster
}
@ -46,7 +46,7 @@ func (c *Client) GetLoadBalancersWithCluster(ctx context.Context, cluster string
}
func (c *Client) GetLoadBalancer(ctx context.Context, cluster, name string) (lb schema.LoadBalancer, err error) {
path := fmt.Sprintf("%s/lb/%s/%s", base, cluster, name)
path := fmt.Sprintf("%s/%s/%s", base, cluster, name)
req, err := c.c.NewRequest(ctx, "GET", path, nil)
if err != nil {
return
@ -57,7 +57,7 @@ func (c *Client) GetLoadBalancer(ctx context.Context, cluster, name string) (lb
func (c *Client) CreateLoadBalancer(ctx context.Context, cluster, name string, lb schema.LoadBalancer) (err error) {
buf := new(bytes.Buffer)
path := fmt.Sprintf("%s/lb/%s/%s", base, cluster, name)
path := fmt.Sprintf("%s/%s/%s", base, cluster, name)
err = lb.ValidateClient()
if err != nil {
return
@ -75,7 +75,7 @@ func (c *Client) CreateLoadBalancer(ctx context.Context, cluster, name string, l
}
func (c *Client) DeleteLoadBalancer(ctx context.Context, cluster, name string) (err error) {
path := fmt.Sprintf("%s/lb/%s/%s", base, cluster, name)
path := fmt.Sprintf("%s/%s/%s", base, cluster, name)
req, err := c.c.NewRequest(ctx, "DELETE", path, nil)
if err != nil {
return
@ -88,7 +88,7 @@ func (c *Client) DeleteLoadBalancersWithCluster(ctx context.Context, cluster str
if cluster == "" {
return errors.New("cluster value can not be empty")
}
path := base + "/lb/" + cluster
path := base + "/" + cluster
req, err := c.c.NewRequest(ctx, "DELETE", path, nil)
if err != nil {
return

View file

@ -12,7 +12,11 @@ healthCheckNodePort
*/
const Version = "v1"
const (
Version = "v1"
LBName = "lb"
LBPath = "/" + Version + "/" + LBName
)
type ProxyProtocol string

View file

@ -62,7 +62,7 @@ func lbHandler(ctx *types.Context) {
if err != nil {
ctx.Log.Error(err, "error reading loadbalancer", "cluster", cl, "name", n)
if err == cluster.ErrKeyNotFound {
ctx.Err(types.ErrNotFound)
ctx.Err(types.ErrLBNotFound)
return
}
ctx.Err(types.ErrISE)
@ -139,7 +139,7 @@ func lbHandler(ctx *types.Context) {
return
}
if !ctx.Data.DB.LBExists(name) {
ctx.Err(types.ErrNotFound)
ctx.Err(types.ErrLBNotFound)
return
}
cidr, err := ctx.Data.DB.GetCIDR(name)
@ -175,6 +175,10 @@ func lbList(lbs map[string][]byte) (m map[string]json.RawMessage) {
func lbClusterHandler(ctx *types.Context) {
cl := ctx.Var("cluster")
m, err := ctx.Data.DB.GetLBs(cl)
if err == cluster.ErrPrefixNotFound {
ctx.Err(types.ErrClusterNotFound)
return
}
if err != nil {
ctx.Log.Error(err, "error reading loadbalancers", "cluster", cl)
ctx.Err(types.ErrISE)
@ -214,6 +218,10 @@ func lbClusterHandler(ctx *types.Context) {
}
func lbListHandler(ctx *types.Context) {
m, err := ctx.Data.DB.GetLBs("")
if err == cluster.ErrPrefixNotFound {
ctx.Err(types.ErrLBsNotFound)
return
}
if err != nil {
ctx.Log.Error(err, "error reading loadbalancer clusters")
ctx.Err(types.ErrISE)

View file

@ -2,29 +2,33 @@ package server
import (
"git.giftfish.de/ston1th/haproxy-lb/pkg/api/types"
schemav1 "git.giftfish.de/ston1th/haproxy-lb/pkg/api/v1/schema"
"git.giftfish.de/ston1th/haproxy-lb/pkg/api/v1/schema"
)
const v1 = "/" + schemav1.Version
const (
healthz = "/healthz"
lbcluster = schema.LBPath + "/{cluster:[a-zA-Z0-9-]+$}"
lbclustername = schema.LBPath + "/{cluster:[a-zA-Z0-9-]+}/{name:[a-zA-Z0-9-_]+$}"
)
var Routes = []types.Route{
{
"/healthz",
healthz,
healthzHandler,
[]string{"GET"},
},
{
v1 + "/lb",
schema.LBPath,
authHandler(lbListHandler),
[]string{"GET"},
},
{
v1 + "/lb/{cluster:[a-zA-Z0-9-]+$}",
lbcluster,
authHandler(lbClusterHandler),
[]string{"GET", "DELETE"},
},
{
v1 + "/lb/{cluster:[a-zA-Z0-9-]+}/{name:[a-zA-Z0-9-_]+$}",
lbclustername,
authHandler(lbHandler),
[]string{"GET", "POST", "DELETE"},
},

View file

@ -86,10 +86,6 @@ func (db *DB) GetLBs(cl string) (lbs map[string][]byte, err error) {
cl = cl + "/"
}
m, err := db.kv.GetPrefix(lbPrefix + cl)
if err == cluster.ErrPrefixNotFound {
err = nil
return
}
if err != nil {
return
}