2019-03-08 18:14:22 +01:00
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 )
2019-08-16 19:11:27 +02:00
IsReadWrite ( ) ( bool , error )
2019-03-08 18:14:22 +01:00
IsReplica ( ) ( bool , error )
2019-08-16 19:11:27 +02:00
IsReadOnly ( ) ( bool , error )
2019-03-08 18:14:22 +01:00
}
// 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
}
2019-08-16 19:11:27 +02:00
// IsPrimary will call /primary route on patroni API
2019-03-08 18:14:22 +01:00
func ( b HTTPBackend ) IsPrimary ( ) ( bool , error ) {
2019-08-16 19:11:27 +02:00
return b . request ( "primary" )
}
// IsReadWrite will call /read-write route on patroni API
func ( b HTTPBackend ) IsReadWrite ( ) ( bool , error ) {
return b . request ( "read-write" )
2019-03-08 18:14:22 +01:00
}
// IsReplica will call /replica route on patroni API
func ( b HTTPBackend ) IsReplica ( ) ( bool , error ) {
return b . request ( "replica" )
}
2019-08-16 19:11:27 +02:00
// IsReadOnly will call /read-only route on patroni API
func ( b HTTPBackend ) IsReadOnly ( ) ( bool , error ) {
return b . request ( "read-only" )
}