Initial release
This commit is contained in:
parent
be71075e18
commit
9818566369
10 changed files with 634 additions and 0 deletions
101
src/backend.go
Normal file
101
src/backend.go
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Backend connects to a backend (https)
|
||||
// and forward requests from frontend
|
||||
type Backend interface {
|
||||
IsPrimary() (bool, error)
|
||||
IsReplica() (bool, error)
|
||||
}
|
||||
|
||||
// NewBackend creates a backend from a driver, a connection string
|
||||
// and an optional interval for caching values
|
||||
func NewBackend(config BackendConfig, cache Cache) Backend {
|
||||
if config.Host == "" {
|
||||
config.Host = "localhost"
|
||||
}
|
||||
if config.Port == 0 {
|
||||
config.Port = 80
|
||||
}
|
||||
if config.Scheme == "" {
|
||||
config.Scheme = "http"
|
||||
}
|
||||
|
||||
b := &HTTPBackend{
|
||||
host: config.Host,
|
||||
port: config.Port,
|
||||
scheme: config.Scheme,
|
||||
cache: cache,
|
||||
}
|
||||
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: config.Insecure},
|
||||
}
|
||||
b.client = &http.Client{Transport: tr}
|
||||
return b
|
||||
}
|
||||
|
||||
// HTTPBackend will request a backend with HTTP(s) protocol
|
||||
type HTTPBackend struct {
|
||||
cache Cache
|
||||
host string
|
||||
port int
|
||||
scheme string
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func (b HTTPBackend) baseURL() string {
|
||||
return fmt.Sprintf("%s://%s:%d", b.scheme, b.host, b.port)
|
||||
}
|
||||
|
||||
// request search into the cache to find the given key
|
||||
// then eventually creates a HTTP/HTTPS request on backend and
|
||||
// cache response for further requests
|
||||
func (b HTTPBackend) request(key string) (bool, error) {
|
||||
state, err := b.cache.Get(key)
|
||||
if err != nil {
|
||||
Warning("could not get key %s from cache: %v", key, err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
if state == nil {
|
||||
url := b.baseURL() + "/" + key
|
||||
|
||||
Debug("GET %s", url)
|
||||
response, err := b.client.Get(url)
|
||||
if err != nil {
|
||||
Warning("could not request remote backend: %v", err)
|
||||
return false, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode == http.StatusOK {
|
||||
state = true
|
||||
} else {
|
||||
state = false
|
||||
}
|
||||
|
||||
err = b.cache.Set(key, state)
|
||||
if err != nil {
|
||||
Warning("could not save %s key to cache: %v", key, err)
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
return state.(bool), nil
|
||||
}
|
||||
|
||||
// IsPrimary will call /master route on patroni API
|
||||
func (b HTTPBackend) IsPrimary() (bool, error) {
|
||||
return b.request("master")
|
||||
}
|
||||
|
||||
// IsReplica will call /replica route on patroni API
|
||||
func (b HTTPBackend) IsReplica() (bool, error) {
|
||||
return b.request("replica")
|
||||
}
|
||||
Reference in a new issue