forked from TrueCloudLab/frostfs-http-gw
[#200] Reload resolvers on SIGHUP
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
939f5f0c65
commit
1e05d8a935
3 changed files with 116 additions and 55 deletions
32
app.go
32
app.go
|
@ -158,6 +158,21 @@ func newApp(ctx context.Context, opt ...Option) App {
|
||||||
a.log.Fatal("failed to dial pool", zap.Error(err))
|
a.log.Fatal("failed to dial pool", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.initResolver()
|
||||||
|
a.initMetrics()
|
||||||
|
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) initResolver() {
|
||||||
|
var err error
|
||||||
|
a.resolver, err = resolver.NewContainerResolver(a.getResolverConfig())
|
||||||
|
if err != nil {
|
||||||
|
a.log.Fatal("failed to create resolver", zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) getResolverConfig() ([]string, *resolver.Config) {
|
||||||
resolveCfg := &resolver.Config{
|
resolveCfg := &resolver.Config{
|
||||||
NeoFS: resolver.NewNeoFSResolver(a.pool),
|
NeoFS: resolver.NewNeoFSResolver(a.pool),
|
||||||
RPCAddress: a.cfg.GetString(cfgRPCEndpoint),
|
RPCAddress: a.cfg.GetString(cfgRPCEndpoint),
|
||||||
|
@ -169,18 +184,11 @@ func newApp(ctx context.Context, opt ...Option) App {
|
||||||
a.log.Warn(fmt.Sprintf("resolver '%s' won't be used since '%s' isn't provided", resolver.NNSResolver, cfgRPCEndpoint))
|
a.log.Warn(fmt.Sprintf("resolver '%s' won't be used since '%s' isn't provided", resolver.NNSResolver, cfgRPCEndpoint))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(order) != 0 {
|
if len(order) == 0 {
|
||||||
a.resolver, err = resolver.NewResolver(order, resolveCfg)
|
a.log.Info("container resolver will be disabled because of resolvers 'resolver_order' is empty")
|
||||||
if err != nil {
|
|
||||||
a.log.Fatal("failed to create resolver", zap.Error(err))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
a.log.Info("container resolver is disabled")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a.initMetrics()
|
return order, resolveCfg
|
||||||
|
|
||||||
return a
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *app) initMetrics() {
|
func (a *app) initMetrics() {
|
||||||
|
@ -365,6 +373,10 @@ func (a *app) configReload() {
|
||||||
a.logLevel.SetLevel(lvl)
|
a.logLevel.SetLevel(lvl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := a.resolver.UpdateResolvers(a.getResolverConfig()); err != nil {
|
||||||
|
a.log.Warn("failed to update resolvers", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
a.stopServices()
|
a.stopServices()
|
||||||
a.startServices()
|
a.startServices()
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,9 @@ package resolver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/ns"
|
"github.com/nspcc-dev/neofs-sdk-go/ns"
|
||||||
|
@ -13,6 +15,9 @@ const (
|
||||||
DNSResolver = "dns"
|
DNSResolver = "dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrNoResolvers returns when trying to resolve container without any resolver.
|
||||||
|
var ErrNoResolvers = errors.New("no resolvers")
|
||||||
|
|
||||||
// NeoFS represents virtual connection to the NeoFS network.
|
// NeoFS represents virtual connection to the NeoFS network.
|
||||||
type NeoFS interface {
|
type NeoFS interface {
|
||||||
// SystemDNS reads system DNS network parameters of the NeoFS.
|
// SystemDNS reads system DNS network parameters of the NeoFS.
|
||||||
|
@ -28,66 +33,116 @@ type Config struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerResolver struct {
|
type ContainerResolver struct {
|
||||||
Name string
|
mu sync.RWMutex
|
||||||
resolve func(context.Context, string) (*cid.ID, error)
|
resolvers []*Resolver
|
||||||
|
|
||||||
next *ContainerResolver
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ContainerResolver) SetResolveFunc(fn func(context.Context, string) (*cid.ID, error)) {
|
type Resolver struct {
|
||||||
|
Name string
|
||||||
|
resolve func(context.Context, string) (*cid.ID, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) SetResolveFunc(fn func(context.Context, string) (*cid.ID, error)) {
|
||||||
r.resolve = fn
|
r.resolve = fn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ContainerResolver) Resolve(ctx context.Context, name string) (*cid.ID, error) {
|
func (r *Resolver) Resolve(ctx context.Context, name string) (*cid.ID, error) {
|
||||||
cnrID, err := r.resolve(ctx, name)
|
return r.resolve(ctx, name)
|
||||||
if err != nil {
|
|
||||||
if r.next != nil {
|
|
||||||
cnrID, inErr := r.next.Resolve(ctx, name)
|
|
||||||
if inErr != nil {
|
|
||||||
return nil, fmt.Errorf("%s; %w", err.Error(), inErr)
|
|
||||||
}
|
|
||||||
return cnrID, nil
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return cnrID, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewResolver(order []string, cfg *Config) (*ContainerResolver, error) {
|
func NewContainerResolver(resolverNames []string, cfg *Config) (*ContainerResolver, error) {
|
||||||
if len(order) == 0 {
|
resolvers, err := createResolvers(resolverNames, cfg)
|
||||||
return nil, fmt.Errorf("resolving order must not be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
bucketResolver, err := newResolver(order[len(order)-1], cfg, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := len(order) - 2; i >= 0; i-- {
|
return &ContainerResolver{
|
||||||
resolverName := order[i]
|
resolvers: resolvers,
|
||||||
next := bucketResolver
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
bucketResolver, err = newResolver(resolverName, cfg, next)
|
func createResolvers(resolverNames []string, cfg *Config) ([]*Resolver, error) {
|
||||||
|
resolvers := make([]*Resolver, len(resolverNames))
|
||||||
|
for i, name := range resolverNames {
|
||||||
|
cnrResolver, err := newResolver(name, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
resolvers[i] = cnrResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
return bucketResolver, nil
|
return resolvers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newResolver(name string, cfg *Config, next *ContainerResolver) (*ContainerResolver, error) {
|
func (r *ContainerResolver) Resolve(ctx context.Context, cnrName string) (*cid.ID, error) {
|
||||||
|
r.mu.RLock()
|
||||||
|
defer r.mu.RUnlock()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for _, resolver := range r.resolvers {
|
||||||
|
cnrID, resolverErr := resolver.Resolve(ctx, cnrName)
|
||||||
|
if resolverErr != nil {
|
||||||
|
resolverErr = fmt.Errorf("%s: %w", resolver.Name, resolverErr)
|
||||||
|
if err == nil {
|
||||||
|
err = resolverErr
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("%s: %w", err.Error(), resolverErr)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return cnrID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, ErrNoResolvers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ContainerResolver) UpdateResolvers(resolverNames []string, cfg *Config) error {
|
||||||
|
r.mu.Lock()
|
||||||
|
defer r.mu.Unlock()
|
||||||
|
|
||||||
|
if r.equals(resolverNames) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvers, err := createResolvers(resolverNames, cfg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
r.resolvers = resolvers
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ContainerResolver) equals(resolverNames []string) bool {
|
||||||
|
if len(r.resolvers) != len(resolverNames) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(resolverNames); i++ {
|
||||||
|
if r.resolvers[i].Name != resolverNames[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func newResolver(name string, cfg *Config) (*Resolver, error) {
|
||||||
switch name {
|
switch name {
|
||||||
case DNSResolver:
|
case DNSResolver:
|
||||||
return NewDNSResolver(cfg.NeoFS, next)
|
return NewDNSResolver(cfg.NeoFS)
|
||||||
case NNSResolver:
|
case NNSResolver:
|
||||||
return NewNNSResolver(cfg.RPCAddress, next)
|
return NewNNSResolver(cfg.RPCAddress)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown resolver: %s", name)
|
return nil, fmt.Errorf("unknown resolver: %s", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDNSResolver(neoFS NeoFS, next *ContainerResolver) (*ContainerResolver, error) {
|
func NewDNSResolver(neoFS NeoFS) (*Resolver, error) {
|
||||||
if neoFS == nil {
|
if neoFS == nil {
|
||||||
return nil, fmt.Errorf("pool must not be nil for DNS resolver")
|
return nil, fmt.Errorf("pool must not be nil for DNS resolver")
|
||||||
}
|
}
|
||||||
|
@ -108,15 +163,13 @@ func NewDNSResolver(neoFS NeoFS, next *ContainerResolver) (*ContainerResolver, e
|
||||||
return &cnrID, nil
|
return &cnrID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ContainerResolver{
|
return &Resolver{
|
||||||
Name: DNSResolver,
|
Name: DNSResolver,
|
||||||
|
|
||||||
resolve: resolveFunc,
|
resolve: resolveFunc,
|
||||||
next: next,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNNSResolver(rpcAddress string, next *ContainerResolver) (*ContainerResolver, error) {
|
func NewNNSResolver(rpcAddress string) (*Resolver, error) {
|
||||||
var nns ns.NNS
|
var nns ns.NNS
|
||||||
|
|
||||||
if err := nns.Dial(rpcAddress); err != nil {
|
if err := nns.Dial(rpcAddress); err != nil {
|
||||||
|
@ -131,10 +184,8 @@ func NewNNSResolver(rpcAddress string, next *ContainerResolver) (*ContainerResol
|
||||||
return &cnrID, nil
|
return &cnrID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ContainerResolver{
|
return &Resolver{
|
||||||
Name: NNSResolver,
|
Name: NNSResolver,
|
||||||
|
|
||||||
resolve: resolveFunc,
|
resolve: resolveFunc,
|
||||||
next: next,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,7 @@ func GetContainerID(ctx context.Context, containerID string, resolver *resolver.
|
||||||
cnrID := new(cid.ID)
|
cnrID := new(cid.ID)
|
||||||
err := cnrID.DecodeString(containerID)
|
err := cnrID.DecodeString(containerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if resolver != nil {
|
cnrID, err = resolver.Resolve(ctx, containerID)
|
||||||
cnrID, err = resolver.Resolve(ctx, containerID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return cnrID, err
|
return cnrID, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue