Archived
1
0
Fork 0
This repository has been archived on 2024-12-18. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
patroniglue/src/backend.go

113 lines
2.5 KiB
Go

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)
IsReadWrite() (bool, error)
IsReplica() (bool, error)
IsReadOnly() (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 /primary route on patroni API
func (b HTTPBackend) IsPrimary() (bool, error) {
return b.request("primary")
}
// IsReadWrite will call /read-write route on patroni API
func (b HTTPBackend) IsReadWrite() (bool, error) {
return b.request("read-write")
}
// IsReplica will call /replica route on patroni API
func (b HTTPBackend) IsReplica() (bool, error) {
return b.request("replica")
}
// IsReadOnly will call /read-only route on patroni API
func (b HTTPBackend) IsReadOnly() (bool, error) {
return b.request("read-only")
}