mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 01:43:16 +01:00
multi: refactor external subserver config
As a preparation for making more and more implementation details configurable, we add a new ImplementationCfg struct that houses all the interfaces that can be defined externally.
This commit is contained in:
parent
140d5a8086
commit
0e279eb15a
@ -31,11 +31,12 @@ func main() {
|
||||
// Help was requested, exit normally.
|
||||
os.Exit(0)
|
||||
}
|
||||
implCfg := loadedConfig.ImplementationConfig()
|
||||
|
||||
// Call the "real" main in a nested manner so the defers will properly
|
||||
// be executed in the case of a graceful shutdown.
|
||||
if err = lnd.Main(
|
||||
loadedConfig, lnd.ListenerCfg{}, shutdownInterceptor,
|
||||
loadedConfig, lnd.ListenerCfg{}, implCfg, shutdownInterceptor,
|
||||
); err != nil {
|
||||
_, _ = fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
|
11
config.go
11
config.go
@ -1536,6 +1536,17 @@ func (c *Config) graphDatabaseDir() string {
|
||||
)
|
||||
}
|
||||
|
||||
// ImplementationConfig returns the configuration of what actual implementations
|
||||
// should be used when creating the main lnd instance.
|
||||
func (c *Config) ImplementationConfig() *ImplementationCfg {
|
||||
defaultImpl := &DefaultWalletImpl{}
|
||||
return &ImplementationCfg{
|
||||
GrpcRegistrar: defaultImpl,
|
||||
RestRegistrar: defaultImpl,
|
||||
ExternalValidator: defaultImpl,
|
||||
}
|
||||
}
|
||||
|
||||
// CleanAndExpandPath expands environment variables and leading ~ in the
|
||||
// passed path, cleans the result, and returns it.
|
||||
// This function is taken from https://github.com/btcsuite/btcd
|
||||
|
115
config_builder.go
Normal file
115
config_builder.go
Normal file
@ -0,0 +1,115 @@
|
||||
package lnd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
proxy "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/lightningnetwork/lnd/macaroons"
|
||||
"google.golang.org/grpc"
|
||||
"gopkg.in/macaroon-bakery.v2/bakery"
|
||||
)
|
||||
|
||||
// GrpcRegistrar is an interface that must be satisfied by an external subserver
|
||||
// that wants to be able to register its own gRPC server onto lnd's main
|
||||
// grpc.Server instance.
|
||||
type GrpcRegistrar interface {
|
||||
// RegisterGrpcSubserver is called for each net.Listener on which lnd
|
||||
// creates a grpc.Server instance. External subservers implementing this
|
||||
// method can then register their own gRPC server structs to the main
|
||||
// server instance.
|
||||
RegisterGrpcSubserver(*grpc.Server) error
|
||||
}
|
||||
|
||||
// RestRegistrar is an interface that must be satisfied by an external subserver
|
||||
// that wants to be able to register its own REST mux onto lnd's main
|
||||
// proxy.ServeMux instance.
|
||||
type RestRegistrar interface {
|
||||
// RegisterRestSubserver is called after lnd creates the main
|
||||
// proxy.ServeMux instance. External subservers implementing this method
|
||||
// can then register their own REST proxy stubs to the main server
|
||||
// instance.
|
||||
RegisterRestSubserver(context.Context, *proxy.ServeMux, string,
|
||||
[]grpc.DialOption) error
|
||||
}
|
||||
|
||||
// ExternalValidator is an interface that must be satisfied by an external
|
||||
// macaroon validator.
|
||||
type ExternalValidator interface {
|
||||
macaroons.MacaroonValidator
|
||||
|
||||
// Permissions returns the permissions that the external validator is
|
||||
// validating. It is a map between the full HTTP URI of each RPC and its
|
||||
// required macaroon permissions. If multiple action/entity tuples are
|
||||
// specified per URI, they are all required. See rpcserver.go for a list
|
||||
// of valid action and entity values.
|
||||
Permissions() map[string][]bakery.Op
|
||||
}
|
||||
|
||||
// ImplementationCfg is a struct that holds all configuration items for
|
||||
// components that can be implemented outside lnd itself.
|
||||
type ImplementationCfg struct {
|
||||
// GrpcRegistrar is a type that can register additional gRPC subservers
|
||||
// before the main gRPC server is started.
|
||||
GrpcRegistrar
|
||||
|
||||
// RestRegistrar is a type that can register additional REST subservers
|
||||
// before the main REST proxy is started.
|
||||
RestRegistrar
|
||||
|
||||
// ExternalValidator is a type that can provide external macaroon
|
||||
// validation.
|
||||
ExternalValidator
|
||||
}
|
||||
|
||||
// DefaultWalletImpl is the default implementation of our normal, btcwallet
|
||||
// backed configuration.
|
||||
type DefaultWalletImpl struct {
|
||||
}
|
||||
|
||||
// RegisterRestSubserver is called after lnd creates the main proxy.ServeMux
|
||||
// instance. External subservers implementing this method can then register
|
||||
// their own REST proxy stubs to the main server instance.
|
||||
//
|
||||
// NOTE: This is part of the GrpcRegistrar interface.
|
||||
func (d *DefaultWalletImpl) RegisterRestSubserver(context.Context,
|
||||
*proxy.ServeMux, string, []grpc.DialOption) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterGrpcSubserver is called for each net.Listener on which lnd creates a
|
||||
// grpc.Server instance. External subservers implementing this method can then
|
||||
// register their own gRPC server structs to the main server instance.
|
||||
//
|
||||
// NOTE: This is part of the GrpcRegistrar interface.
|
||||
func (d *DefaultWalletImpl) RegisterGrpcSubserver(*grpc.Server) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateMacaroon extracts the macaroon from the context's gRPC metadata,
|
||||
// checks its signature, makes sure all specified permissions for the called
|
||||
// method are contained within and finally ensures all caveat conditions are
|
||||
// met. A non-nil error is returned if any of the checks fail.
|
||||
//
|
||||
// NOTE: This is part of the ExternalValidator interface.
|
||||
func (d *DefaultWalletImpl) ValidateMacaroon(ctx context.Context,
|
||||
requiredPermissions []bakery.Op, fullMethod string) error {
|
||||
|
||||
// Because the default implementation does not return any permissions,
|
||||
// we shouldn't be registered as an external validator at all and this
|
||||
// should never be invoked.
|
||||
return fmt.Errorf("default implementation does not support external " +
|
||||
"macaroon validation")
|
||||
}
|
||||
|
||||
// Permissions returns the permissions that the external validator is
|
||||
// validating. It is a map between the full HTTP URI of each RPC and its
|
||||
// required macaroon permissions. If multiple action/entity tuples are specified
|
||||
// per URI, they are all required. See rpcserver.go for a list of valid action
|
||||
// and entity values.
|
||||
//
|
||||
// NOTE: This is part of the ExternalValidator interface.
|
||||
func (d *DefaultWalletImpl) Permissions() map[string][]bakery.Op {
|
||||
return nil
|
||||
}
|
64
lnd.go
64
lnd.go
@ -122,51 +122,6 @@ func AdminAuthOptions(cfg *Config, skipMacaroons bool) ([]grpc.DialOption, error
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
// GrpcRegistrar is an interface that must be satisfied by an external subserver
|
||||
// that wants to be able to register its own gRPC server onto lnd's main
|
||||
// grpc.Server instance.
|
||||
type GrpcRegistrar interface {
|
||||
// RegisterGrpcSubserver is called for each net.Listener on which lnd
|
||||
// creates a grpc.Server instance. External subservers implementing this
|
||||
// method can then register their own gRPC server structs to the main
|
||||
// server instance.
|
||||
RegisterGrpcSubserver(*grpc.Server) error
|
||||
}
|
||||
|
||||
// RestRegistrar is an interface that must be satisfied by an external subserver
|
||||
// that wants to be able to register its own REST mux onto lnd's main
|
||||
// proxy.ServeMux instance.
|
||||
type RestRegistrar interface {
|
||||
// RegisterRestSubserver is called after lnd creates the main
|
||||
// proxy.ServeMux instance. External subservers implementing this method
|
||||
// can then register their own REST proxy stubs to the main server
|
||||
// instance.
|
||||
RegisterRestSubserver(context.Context, *proxy.ServeMux, string,
|
||||
[]grpc.DialOption) error
|
||||
}
|
||||
|
||||
// RPCSubserverConfig is a struct that can be used to register an external
|
||||
// subserver with the custom permissions that map to the gRPC server that is
|
||||
// going to be registered with the GrpcRegistrar.
|
||||
type RPCSubserverConfig struct {
|
||||
// Registrar is a callback that is invoked for each net.Listener on
|
||||
// which lnd creates a grpc.Server instance.
|
||||
Registrar GrpcRegistrar
|
||||
|
||||
// Permissions is the permissions required for the external subserver.
|
||||
// It is a map between the full HTTP URI of each RPC and its required
|
||||
// macaroon permissions. If multiple action/entity tuples are specified
|
||||
// per URI, they are all required. See rpcserver.go for a list of valid
|
||||
// action and entity values.
|
||||
Permissions map[string][]bakery.Op
|
||||
|
||||
// MacaroonValidator is a custom macaroon validator that should be used
|
||||
// instead of the default lnd validator. If specified, the custom
|
||||
// validator is used for all URIs specified in the above Permissions
|
||||
// map.
|
||||
MacaroonValidator macaroons.MacaroonValidator
|
||||
}
|
||||
|
||||
// ListenerWithSignal is a net.Listener that has an additional Ready channel that
|
||||
// will be closed when a server starts listening.
|
||||
type ListenerWithSignal struct {
|
||||
@ -187,14 +142,6 @@ type ListenerCfg struct {
|
||||
// RPCListeners can be set to the listeners to use for the RPC server.
|
||||
// If empty a regular network listener will be created.
|
||||
RPCListeners []*ListenerWithSignal
|
||||
|
||||
// ExternalRPCSubserverCfg is optional and specifies the registration
|
||||
// callback and permissions to register external gRPC subservers.
|
||||
ExternalRPCSubserverCfg *RPCSubserverConfig
|
||||
|
||||
// ExternalRestRegistrar is optional and specifies the registration
|
||||
// callback to register external REST subservers.
|
||||
ExternalRestRegistrar RestRegistrar
|
||||
}
|
||||
|
||||
var errStreamIsolationWithProxySkip = errors.New(
|
||||
@ -205,7 +152,9 @@ var errStreamIsolationWithProxySkip = errors.New(
|
||||
// validated main configuration struct and an optional listener config struct.
|
||||
// This function starts all main system components then blocks until a signal
|
||||
// is received on the shutdownChan at which point everything is shut down again.
|
||||
func Main(cfg *Config, lisCfg ListenerCfg, interceptor signal.Interceptor) error {
|
||||
func Main(cfg *Config, lisCfg ListenerCfg, implCfg *ImplementationCfg,
|
||||
interceptor signal.Interceptor) error {
|
||||
|
||||
defer func() {
|
||||
ltndLog.Info("Shutdown complete\n")
|
||||
err := cfg.LogWriter.Close()
|
||||
@ -387,12 +336,7 @@ func Main(cfg *Config, lisCfg ListenerCfg, interceptor signal.Interceptor) error
|
||||
|
||||
// Initialize, and register our implementation of the gRPC interface
|
||||
// exported by the rpcServer.
|
||||
rpcServer := newRPCServer(
|
||||
cfg, interceptorChain, lisCfg.ExternalRPCSubserverCfg,
|
||||
lisCfg.ExternalRestRegistrar,
|
||||
interceptor,
|
||||
)
|
||||
|
||||
rpcServer := newRPCServer(cfg, interceptorChain, implCfg, interceptor)
|
||||
err = rpcServer.RegisterWithGrpcServer(grpcServer)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -99,6 +99,7 @@ func Start(extraArgs string, rpcReady Callback) {
|
||||
Ready: rpcListening,
|
||||
}},
|
||||
}
|
||||
implCfg := loadedConfig.ImplementationConfig()
|
||||
|
||||
// Call the "real" main in a nested manner so the defers will properly
|
||||
// be executed in the case of a graceful shutdown.
|
||||
@ -107,7 +108,7 @@ func Start(extraArgs string, rpcReady Callback) {
|
||||
defer close(quit)
|
||||
|
||||
if err := lnd.Main(
|
||||
loadedConfig, cfg, shutdownInterceptor,
|
||||
loadedConfig, cfg, implCfg, shutdownInterceptor,
|
||||
); err != nil {
|
||||
if e, ok := err.(*flags.Error); ok &&
|
||||
e.Type == flags.ErrHelp {
|
||||
|
82
rpcserver.go
82
rpcserver.go
@ -611,16 +611,12 @@ type rpcServer struct {
|
||||
// selfNode is our own pubkey.
|
||||
selfNode route.Vertex
|
||||
|
||||
// interceptorChain is the the interceptor added to our gRPC server.
|
||||
// interceptorChain is the interceptor added to our gRPC server.
|
||||
interceptorChain *rpcperms.InterceptorChain
|
||||
|
||||
// extSubserverCfg is optional and specifies the registration
|
||||
// callback and permissions to register external gRPC subservers.
|
||||
extSubserverCfg *RPCSubserverConfig
|
||||
|
||||
// extRestRegistrar is optional and specifies the registration
|
||||
// callback to register external REST subservers.
|
||||
extRestRegistrar RestRegistrar
|
||||
// implCfg is the configuration for some of the interfaces that can be
|
||||
// provided externally.
|
||||
implCfg *ImplementationCfg
|
||||
|
||||
// interceptor is used to be able to request a shutdown
|
||||
interceptor signal.Interceptor
|
||||
@ -634,9 +630,7 @@ var _ lnrpc.LightningServer = (*rpcServer)(nil)
|
||||
// dependencies are added, this will be an non-functioning RPC server only to
|
||||
// be used to register the LightningService with the gRPC server.
|
||||
func newRPCServer(cfg *Config, interceptorChain *rpcperms.InterceptorChain,
|
||||
extSubserverCfg *RPCSubserverConfig,
|
||||
extRestRegistrar RestRegistrar,
|
||||
interceptor signal.Interceptor) *rpcServer {
|
||||
implCfg *ImplementationCfg, interceptor signal.Interceptor) *rpcServer {
|
||||
|
||||
// We go trhough the list of registered sub-servers, and create a gRPC
|
||||
// handler for each. These are used to register with the gRPC server
|
||||
@ -654,8 +648,7 @@ func newRPCServer(cfg *Config, interceptorChain *rpcperms.InterceptorChain,
|
||||
cfg: cfg,
|
||||
subGrpcHandlers: subServerHandlers,
|
||||
interceptorChain: interceptorChain,
|
||||
extSubserverCfg: extSubserverCfg,
|
||||
extRestRegistrar: extRestRegistrar,
|
||||
implCfg: implCfg,
|
||||
quit: make(chan struct{}, 1),
|
||||
interceptor: interceptor,
|
||||
}
|
||||
@ -785,30 +778,22 @@ func (r *rpcServer) addDeps(s *server, macService *macaroons.Service,
|
||||
|
||||
// External subserver possibly need to register their own permissions
|
||||
// and macaroon validator.
|
||||
if r.extSubserverCfg != nil {
|
||||
macValidator := r.extSubserverCfg.MacaroonValidator
|
||||
for method, ops := range r.extSubserverCfg.Permissions {
|
||||
err := r.interceptorChain.AddPermission(method, ops)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for method, ops := range r.implCfg.ExternalValidator.Permissions() {
|
||||
err := r.interceptorChain.AddPermission(method, ops)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Give the external subservers the possibility
|
||||
// to also use their own validator to check any
|
||||
// macaroons attached to calls to this method.
|
||||
// This allows them to have their own root key
|
||||
// ID database and permission entities.
|
||||
if macValidator != nil {
|
||||
err := macService.RegisterExternalValidator(
|
||||
method, macValidator,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could "+
|
||||
"not register "+
|
||||
"external macaroon "+
|
||||
"validator: %v", err)
|
||||
}
|
||||
}
|
||||
// Give the external subservers the possibility to also use
|
||||
// their own validator to check any macaroons attached to calls
|
||||
// to this method. This allows them to have their own root key
|
||||
// ID database and permission entities.
|
||||
err = macService.RegisterExternalValidator(
|
||||
method, r.implCfg.ExternalValidator,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not register external "+
|
||||
"macaroon validator: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -846,13 +831,10 @@ func (r *rpcServer) RegisterWithGrpcServer(grpcServer *grpc.Server) error {
|
||||
// their own, we just let them register their services to the same
|
||||
// server instance so all of them can be exposed on the same
|
||||
// port/listener.
|
||||
if r.extSubserverCfg != nil && r.extSubserverCfg.Registrar != nil {
|
||||
registerer := r.extSubserverCfg.Registrar
|
||||
err := registerer.RegisterGrpcSubserver(grpcServer)
|
||||
if err != nil {
|
||||
rpcsLog.Errorf("error registering external gRPC "+
|
||||
"subserver: %v", err)
|
||||
}
|
||||
err := r.implCfg.RegisterGrpcSubserver(grpcServer)
|
||||
if err != nil {
|
||||
rpcsLog.Errorf("error registering external gRPC "+
|
||||
"subserver: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -908,14 +890,12 @@ func (r *rpcServer) RegisterWithRestProxy(restCtx context.Context,
|
||||
// Before listening on any of the interfaces, we also want to give the
|
||||
// external subservers a chance to register their own REST proxy stub
|
||||
// with our mux instance.
|
||||
if r.extRestRegistrar != nil {
|
||||
err := r.extRestRegistrar.RegisterRestSubserver(
|
||||
restCtx, restMux, restProxyDest, restDialOpts,
|
||||
)
|
||||
if err != nil {
|
||||
rpcsLog.Errorf("error registering "+
|
||||
"external REST subserver: %v", err)
|
||||
}
|
||||
err = r.implCfg.RegisterRestSubserver(
|
||||
restCtx, restMux, restProxyDest, restDialOpts,
|
||||
)
|
||||
if err != nil {
|
||||
rpcsLog.Errorf("error registering external REST subserver: %v",
|
||||
err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user