Archived
1
0
Fork 0

Initial release

This commit is contained in:
Julien Riou 2019-03-08 18:14:22 +01:00
commit 9818566369
No known key found for this signature in database
GPG key ID: BA3E15176E45E85D
10 changed files with 634 additions and 0 deletions

101
src/backend.go Normal file
View 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")
}