- Fix issue #94

- Fix linter
- Remove useless code/deadcode
This commit is contained in:
Nicolas JUHEL
2021-04-13 13:08:49 +02:00
parent 499b5ee613
commit dbb443eb65
48 changed files with 673 additions and 1418 deletions

View File

@@ -35,7 +35,6 @@ import (
"time"
"github.com/go-playground/validator/v10"
libtls "github.com/nabbar/golib/certificates"
liberr "github.com/nabbar/golib/errors"
)
@@ -129,10 +128,37 @@ func (p PoolServerConfig) MapRun(f MapRunPoolServerConfig) PoolServerConfig {
return r
}
//nolint #maligned
type ServerConfig struct {
getTLSDefault func() libtls.TLSConfig
// Name is the name of the current server
// the configuration allow multipke server, which each one must be identify by a name
// If not defined, will use the listen address
Name string `mapstructure:"name" json:"name" yaml:"name" toml:"name" validate:"required"`
// Listen is the local address (ip, hostname, unix socket, ...) with a port
// The server will bind with this address only and listen for the port defined
Listen string `mapstructure:"listen" json:"listen" yaml:"listen" toml:"listen" validate:"required,hostname_port"`
// Expose is the address use to call this server. This can be allow to use a single fqdn to multiple server"
Expose string `mapstructure:"expose" json:"expose" yaml:"expose" toml:"expose" validate:"required,url"`
// HandlerKeys is an options to associate current server with a specifc handler defined by the key
// This allow to defined multiple server in only one config for different handler to start multiple api
HandlerKeys string `mapstructure:"handler_keys" json:"handler_keys" yaml:"handler_keys" toml:"handler_keys"`
//private
getTLSDefault func() libtls.TLSConfig
//private
getParentContext func() context.Context
// TimeoutCacheInfo defined the validity time of cache for info (name, version, hash)
TimeoutCacheInfo time.Duration `mapstructure:"timeout_cache_info" json:"timeout_cache_info" yaml:"timeout_cache_info" toml:"timeout_cache_info"`
// TimeoutCacheHealth defined the validity time of cache for healthcheck of this server
TimeoutCacheHealth time.Duration `mapstructure:"timeout_cache_health" json:"timeout_cache_health" yaml:"timeout_cache_health" toml:"timeout_cache_health"`
// Enabled allow to disable a server without clean his configuration
Disabled bool `mapstructure:"disabled" json:"disabled" yaml:"disabled" toml:"disabled"`
@@ -140,11 +166,13 @@ type ServerConfig struct {
// y defined if the component for status is mandatory or not
Mandatory bool `mapstructure:"mandatory" json:"mandatory" yaml:"mandatory" toml:"mandatory"`
// TimeoutCacheInfo defined the validity time of cache for info (name, version, hash)
TimeoutCacheInfo time.Duration `mapstructure:"timeout_cache_info" json:"timeout_cache_info" yaml:"timeout_cache_info" toml:"timeout_cache_info"`
// TLSMandatory is a flag to defined that TLS must be valid to start current server.
TLSMandatory bool `mapstructure:"tls_mandatory" json:"tls_mandatory" yaml:"tls_mandatory" toml:"tls_mandatory"`
// TimeoutCacheHealth defined the validity time of cache for healthcheck of this server
TimeoutCacheHealth time.Duration `mapstructure:"timeout_cache_health" json:"timeout_cache_health" yaml:"timeout_cache_health" toml:"timeout_cache_health"`
// TLS is the tls configuration for this server.
// To allow tls on this server, at least the TLS Config option InheritDefault must be at true and the default TLS config must be set.
// If you don't want any tls config, just omit or set an empty struct.
TLS libtls.Config `mapstructure:"tls" json:"tls" yaml:"tls" toml:"tls"`
/*** http options ***/
@@ -220,30 +248,6 @@ type ServerConfig struct {
// be larger than 2^32-1. If the value is zero or larger than the
// maximum, a default value will be used instead.
MaxUploadBufferPerStream int32 `json:"max_upload_buffer_per_stream" json:"max_upload_buffer_per_stream" yaml:"max_upload_buffer_per_stream" toml:"max_upload_buffer_per_stream"`
// Name is the name of the current server
// the configuration allow multipke server, which each one must be identify by a name
// If not defined, will use the listen address
Name string `mapstructure:"name" json:"name" yaml:"name" toml:"name" validate:"required"`
// Listen is the local address (ip, hostname, unix socket, ...) with a port
// The server will bind with this address only and listen for the port defined
Listen string `mapstructure:"listen" json:"listen" yaml:"listen" toml:"listen" validate:"required,hostname_port"`
// Expose is the address use to call this server. This can be allow to use a single fqdn to multiple server"
Expose string `mapstructure:"expose" json:"expose" yaml:"expose" toml:"expose" validate:"required,url"`
// HandlerKeys is an options to associate current server with a specifc handler defined by the key
// This allow to defined multiple server in only one config for different handler to start multiple api
HandlerKeys string `mapstructure:"handler_keys" json:"handler_keys" yaml:"handler_keys" toml:"handler_keys"`
// TLSMandatory is a flag to defined that TLS must be valid to start current server.
TLSMandatory bool `mapstructure:"tls_mandatory" json:"tls_mandatory" yaml:"tls_mandatory" toml:"tls_mandatory"`
// TLS is the tls configuration for this server.
// To allow tls on this server, at least the TLS Config option InheritDefault must be at true and the default TLS config must be set.
// If you don't want any tls config, just omit or set an empty struct.
TLS libtls.Config `mapstructure:"tls" json:"tls" yaml:"tls" toml:"tls"`
}
func (c *ServerConfig) Clone() ServerConfig {
@@ -319,7 +323,7 @@ func (c ServerConfig) GetListen() *url.URL {
if c.Listen != "" {
if add, err = url.Parse(c.Listen); err != nil {
if host, prt, err := net.SplitHostPort(c.Listen); err == nil {
if host, prt, e := net.SplitHostPort(c.Listen); e == nil {
add = &url.URL{
Host: fmt.Sprintf("%s:%s", host, prt),
}

View File

@@ -36,13 +36,10 @@ import (
"strings"
"syscall"
"github.com/nabbar/golib/status"
"github.com/nabbar/golib/logger"
"github.com/nabbar/golib/semaphore"
liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger"
libsem "github.com/nabbar/golib/semaphore"
libsts "github.com/nabbar/golib/status"
)
type FieldType uint8
@@ -82,7 +79,7 @@ type PoolServer interface {
StatusInfo(bindAddress string) (name string, release string, hash string)
StatusHealth(bindAddress string) error
StatusRoute(prefix string, fctMessage status.FctMessage, sts status.RouteStatus)
StatusRoute(prefix string, fctMessage libsts.FctMessage, sts libsts.RouteStatus)
}
func NewPool(srv ...Server) PoolServer {
@@ -353,7 +350,7 @@ func (p pool) ListenMultiHandler(handler map[string]http.Handler) liberr.Error {
var e liberr.Error
e = ErrorPoolListen.Error(nil)
logger.InfoLevel.Log("Calling listen for All Servers")
liblog.InfoLevel.Log("Calling listen for All Servers")
p.MapRun(func(srv Server) {
if len(handler) < 1 {
@@ -371,7 +368,7 @@ func (p pool) ListenMultiHandler(handler map[string]http.Handler) liberr.Error {
}
})
logger.InfoLevel.Log("End of Calling listen for All Servers")
liblog.InfoLevel.Log("End of Calling listen for All Servers")
if !e.HasParent() {
e = nil
@@ -380,64 +377,66 @@ func (p pool) ListenMultiHandler(handler map[string]http.Handler) liberr.Error {
return e
}
func (p pool) Restart() {
func (p pool) runMapCommand(f func(sem libsem.Sem, srv Server)) {
if p.Len() < 1 {
return
}
var (
s semaphore.Sem
s libsem.Sem
x context.Context
c context.CancelFunc
)
x, c = context.WithTimeout(context.Background(), timeoutShutdown)
defer func() {
c()
s.DeferMain()
}()
x, c = context.WithTimeout(context.Background(), timeoutRestart)
s = semaphore.NewSemaphoreWithContext(x, 0)
s = libsem.NewSemaphoreWithContext(x, 0)
p.MapRun(func(srv Server) {
_ = s.NewWorker()
go func() {
defer s.DeferWorker()
srv.Restart()
}()
go func(sem libsem.Sem, srv Server) {
f(sem, srv)
}(s, srv)
})
_ = s.WaitAll()
}
func (p pool) Shutdown() {
if p.Len() < 1 {
return
}
var (
s semaphore.Sem
x context.Context
c context.CancelFunc
)
func (p pool) runMapRestart(sem libsem.Sem, srv Server) {
defer func() {
c()
s.DeferMain()
if sem != nil {
sem.DeferWorker()
}
}()
x, c = context.WithTimeout(context.Background(), timeoutShutdown)
s = semaphore.NewSemaphoreWithContext(x, 0)
if srv != nil {
srv.Restart()
}
}
p.MapRun(func(srv Server) {
_ = s.NewWorker()
go func() {
defer s.DeferWorker()
srv.Shutdown()
}()
})
func (p pool) runMapShutdown(sem libsem.Sem, srv Server) {
defer func() {
if sem != nil {
sem.DeferWorker()
}
}()
_ = s.WaitAll()
if srv != nil {
srv.Shutdown()
}
}
func (p pool) Restart() {
p.runMapCommand(p.runMapRestart)
}
func (p pool) Shutdown() {
p.runMapCommand(p.runMapShutdown)
}
func (p pool) StatusInfo(bindAddress string) (name string, release string, hash string) {
@@ -453,10 +452,11 @@ func (p pool) StatusHealth(bindAddress string) error {
return s.StatusHealth()
}
//nolint #goerr113
return fmt.Errorf("missing server '%s'", bindAddress)
}
func (p pool) StatusRoute(keyPrefix string, fctMessage status.FctMessage, sts status.RouteStatus) {
func (p pool) StatusRoute(keyPrefix string, fctMessage libsts.FctMessage, sts libsts.RouteStatus) {
p.MapRun(func(srv Server) {
bind := srv.GetBindable()
sts.ComponentNew(fmt.Sprintf("%s-%s", keyPrefix, bind), srv.StatusComponent(fctMessage))

View File

@@ -45,6 +45,8 @@ import (
"golang.org/x/net/http2"
)
const _TimeoutWaitingPortFreeing = 500 * time.Microsecond
type srvRun struct {
err *atomic.Value
run *atomic.Value
@@ -109,6 +111,7 @@ func (s *srvRun) setErr(e error) {
if e != nil {
s.err.Store(e)
} else {
//nolint #goerr113
s.err.Store(errors.New(""))
}
}
@@ -141,6 +144,7 @@ func (s *srvRun) Merge(srv Server) bool {
panic("implement me")
}
//nolint #gocognit
func (s *srvRun) Listen(cfg *ServerConfig, handler http.Handler) liberr.Error {
ssl, err := cfg.GetTLS()
if err != nil {
@@ -263,6 +267,7 @@ func (s *srvRun) Listen(cfg *ServerConfig, handler http.Handler) liberr.Error {
s.setRunning(true)
err = s.srv.ListenAndServeTLS("", "")
} else if tlsMandatory {
//nolint #goerr113
err = fmt.Errorf("missing valid server certificates")
} else {
liblog.InfoLevel.Logf("Server '%s' is starting with bindable: %s", name, host)
@@ -333,7 +338,7 @@ func (s *srvRun) PortInUse(listen string) liberr.Error {
}
}()
ctx, cnl = context.WithTimeout(context.TODO(), 2*time.Second)
ctx, cnl = context.WithTimeout(context.TODO(), _TimeoutWaitingPortFreeing)
con, err = dia.DialContext(ctx, "tcp", listen)
if con != nil {

View File

@@ -34,24 +34,22 @@ import (
"sync/atomic"
"time"
"github.com/nabbar/golib/status"
liberr "github.com/nabbar/golib/errors"
libsts "github.com/nabbar/golib/status"
)
const (
timeoutShutdown = 10 * time.Second
timeoutRestart = 30 * time.Second
)
type server struct {
run *atomic.Value
cfg ServerConfig
cfg *atomic.Value
}
type Server interface {
GetConfig() *ServerConfig
SetConfig(cfg *ServerConfig)
SetConfig(cfg *ServerConfig) bool
GetName() string
GetBindable() string
@@ -69,16 +67,50 @@ type Server interface {
StatusInfo() (name string, release string, hash string)
StatusHealth() error
StatusComponent(message status.FctMessage) status.Component
StatusComponent(message libsts.FctMessage) libsts.Component
}
func NewServer(cfg *ServerConfig) Server {
c := new(atomic.Value)
c.Store(cfg.Clone())
return &server{
cfg: cfg.Clone(),
cfg: c,
run: new(atomic.Value),
}
}
func (s *server) GetConfig() *ServerConfig {
if s.cfg == nil {
return nil
} else if i := s.cfg.Load(); i == nil {
return nil
} else if c, ok := i.(ServerConfig); !ok {
return nil
} else {
return &c
}
}
func (s *server) SetConfig(cfg *ServerConfig) bool {
if cfg == nil {
return false
}
if s.cfg == nil {
s.cfg = new(atomic.Value)
}
c := cfg.Clone()
if c.Name == "" {
c.Name = c.GetListen().Host
}
s.cfg.Store(cfg.Clone())
return true
}
func (s *server) getRun() run {
if s.run == nil {
return newRun()
@@ -103,32 +135,20 @@ func (s *server) getErr() error {
}
}
func (s *server) GetConfig() *ServerConfig {
return &s.cfg
}
func (s *server) SetConfig(cfg *ServerConfig) {
s.cfg = cfg.Clone()
}
func (s server) GetName() string {
if s.cfg.Name == "" {
s.cfg.Name = s.GetBindable()
}
return s.cfg.Name
return s.GetConfig().Name
}
func (s *server) GetBindable() string {
return s.cfg.GetListen().Host
return s.GetConfig().GetListen().Host
}
func (s *server) GetExpose() string {
return s.cfg.GetExpose().String()
return s.GetConfig().GetExpose().String()
}
func (s *server) GetHandlerKey() string {
return s.cfg.GetHandlerKey()
return s.GetConfig().GetHandlerKey()
}
func (s *server) IsRunning() bool {
@@ -136,12 +156,12 @@ func (s *server) IsRunning() bool {
}
func (s *server) IsTLS() bool {
return s.cfg.IsTLS()
return s.GetConfig().IsTLS()
}
func (s *server) Listen(handler http.Handler) liberr.Error {
r := s.getRun()
e := r.Listen(&s.cfg, handler)
e := r.Listen(s.GetConfig(), handler)
s.setRun(r)
return e
@@ -163,12 +183,11 @@ func (s *server) Shutdown() {
}
func (s *server) Merge(srv Server) bool {
if x, ok := srv.(*server); ok {
s.cfg = x.cfg
return true
if x, ok := srv.(*server); !ok {
return false
} else {
return s.SetConfig(x.GetConfig())
}
return false
}
func (s *server) StatusInfo() (name string, release string, hash string) {
@@ -180,17 +199,20 @@ func (s *server) StatusInfo() (name string, release string, hash string) {
}
func (s *server) StatusHealth() error {
if !s.cfg.Disabled && s.IsRunning() {
c := s.GetConfig()
if !c.Disabled && s.IsRunning() {
return nil
} else if s.cfg.Disabled {
} else if c.Disabled {
//nolint #goerr113
return fmt.Errorf("server disabled")
} else if e := s.getErr(); e != nil {
return e
} else {
//nolint #goerr113
return fmt.Errorf("server is offline -- missing error")
}
}
func (s *server) StatusComponent(message status.FctMessage) status.Component {
return status.NewComponent(s.cfg.Mandatory, s.StatusInfo, s.StatusHealth, message, s.cfg.TimeoutCacheInfo, s.cfg.TimeoutCacheHealth)
func (s *server) StatusComponent(message libsts.FctMessage) libsts.Component {
return libsts.NewComponent(s.GetConfig().Mandatory, s.StatusInfo, s.StatusHealth, message, s.GetConfig().TimeoutCacheInfo, s.GetConfig().TimeoutCacheHealth)
}