mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-08-31 17:51:33 +02:00
Merge pull request #5536 from Kixunil/systemd-notify
Implemented systemd notify
This commit is contained in:
@@ -25,6 +25,12 @@ for more information.
|
|||||||
* [Stub code for interacting with `lnrpc` from a WASM context through JSON
|
* [Stub code for interacting with `lnrpc` from a WASM context through JSON
|
||||||
messages was added](https://github.com/lightningnetwork/lnd/pull/5601).
|
messages was added](https://github.com/lightningnetwork/lnd/pull/5601).
|
||||||
|
|
||||||
|
* LND now [reports to systemd](https://github.com/lightningnetwork/lnd/pull/5536)
|
||||||
|
that RPC is ready (port bound, certificate generated, macaroons created,
|
||||||
|
in case of `wallet-unlock-password-file` wallet unlocked). This can be used to
|
||||||
|
avoid misleading error messages from dependent services if they use `After`
|
||||||
|
systemd option.
|
||||||
|
|
||||||
## Wallet
|
## Wallet
|
||||||
|
|
||||||
* It is now possible to fund a psbt [without specifying any
|
* It is now possible to fund a psbt [without specifying any
|
||||||
|
1
go.mod
1
go.mod
@@ -14,6 +14,7 @@ require (
|
|||||||
github.com/btcsuite/btcwallet/wallet/txrules v1.0.0
|
github.com/btcsuite/btcwallet/wallet/txrules v1.0.0
|
||||||
github.com/btcsuite/btcwallet/walletdb v1.3.6-0.20210803004036-eebed51155ec
|
github.com/btcsuite/btcwallet/walletdb v1.3.6-0.20210803004036-eebed51155ec
|
||||||
github.com/btcsuite/btcwallet/wtxmgr v1.3.1-0.20210803004036-eebed51155ec
|
github.com/btcsuite/btcwallet/wtxmgr v1.3.1-0.20210803004036-eebed51155ec
|
||||||
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||||
github.com/go-errors/errors v1.0.1
|
github.com/go-errors/errors v1.0.1
|
||||||
|
8
lnd.go
8
lnd.go
@@ -537,6 +537,10 @@ func Main(cfg *Config, lisCfg ListenerCfg, interceptor signal.Interceptor) error
|
|||||||
// to the default behavior of waiting for the wallet creation/unlocking
|
// to the default behavior of waiting for the wallet creation/unlocking
|
||||||
// over RPC.
|
// over RPC.
|
||||||
default:
|
default:
|
||||||
|
if err := interceptor.Notifier.NotifyReady(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
params, err := waitForWalletPassword(
|
params, err := waitForWalletPassword(
|
||||||
cfg, pwService, []btcwallet.LoaderOption{dbs.walletDB},
|
cfg, pwService, []btcwallet.LoaderOption{dbs.walletDB},
|
||||||
interceptor.ShutdownChannel(),
|
interceptor.ShutdownChannel(),
|
||||||
@@ -893,6 +897,10 @@ func Main(cfg *Config, lisCfg ListenerCfg, interceptor signal.Interceptor) error
|
|||||||
// We transition the RPC state to Active, as the RPC server is up.
|
// We transition the RPC state to Active, as the RPC server is up.
|
||||||
interceptorChain.SetRPCActive()
|
interceptorChain.SetRPCActive()
|
||||||
|
|
||||||
|
if err := interceptor.Notifier.NotifyReady(true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// If we're not in regtest or simnet mode, We'll wait until we're fully
|
// If we're not in regtest or simnet mode, We'll wait until we're fully
|
||||||
// synced to continue the start up of the remainder of the daemon. This
|
// synced to continue the start up of the remainder of the daemon. This
|
||||||
// ensures that we don't accept any possibly invalid state transitions, or
|
// ensures that we don't accept any possibly invalid state transitions, or
|
||||||
|
@@ -7,10 +7,13 @@ package signal
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/coreos/go-systemd/daemon"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -19,8 +22,78 @@ var (
|
|||||||
started int32
|
started int32
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// systemdNotifyReady notifies systemd about LND being ready, logs the result of
|
||||||
|
// the operation or possible error. Besides logging, systemd being unavailable
|
||||||
|
// is ignored.
|
||||||
|
func systemdNotifyReady() error {
|
||||||
|
notified, err := daemon.SdNotify(false, daemon.SdNotifyReady)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("failed to notify systemd %v (if you aren't "+
|
||||||
|
"running systemd clear the environment variable "+
|
||||||
|
"NOTIFY_SOCKET)", err)
|
||||||
|
log.Error(err)
|
||||||
|
|
||||||
|
// The SdNotify doc says it's common to ignore the
|
||||||
|
// error. We don't want to ignore it because if someone
|
||||||
|
// set up systemd to wait for initialization other
|
||||||
|
// processes would get stuck.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if notified {
|
||||||
|
log.Info("Systemd was notified about our readiness")
|
||||||
|
} else {
|
||||||
|
log.Info("We're not running within systemd")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// systemdNotifyStop notifies systemd that LND is stopping and logs error if
|
||||||
|
// the notification failed. It also logs if the notification was actually sent.
|
||||||
|
// Systemd being unavailable is intentionally ignored.
|
||||||
|
func systemdNotifyStop() {
|
||||||
|
notified, err := daemon.SdNotify(false, daemon.SdNotifyStopping)
|
||||||
|
|
||||||
|
// Just log - we're stopping anyway.
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to notify systemd: %v", err)
|
||||||
|
}
|
||||||
|
if notified {
|
||||||
|
log.Infof("Systemd was notified about stopping")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notifier handles notifications about status of LND.
|
||||||
|
type Notifier struct {
|
||||||
|
// notifiedReady remembers whether Ready was sent to avoid sending it
|
||||||
|
// multiple times.
|
||||||
|
notifiedReady bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotifyReady notifies other applications that RPC is ready.
|
||||||
|
func (notifier *Notifier) NotifyReady(walletUnlocked bool) error {
|
||||||
|
if !notifier.notifiedReady {
|
||||||
|
err := systemdNotifyReady()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
notifier.notifiedReady = true
|
||||||
|
}
|
||||||
|
if walletUnlocked {
|
||||||
|
_, _ = daemon.SdNotify(false, "STATUS=Wallet unlocked")
|
||||||
|
} else {
|
||||||
|
_, _ = daemon.SdNotify(false, "STATUS=Wallet locked")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// notifyStop notifies other applications that LND is stopping.
|
||||||
|
func (notifier *Notifier) notifyStop() {
|
||||||
|
systemdNotifyStop()
|
||||||
|
}
|
||||||
|
|
||||||
// Interceptor contains channels and methods regarding application shutdown
|
// Interceptor contains channels and methods regarding application shutdown
|
||||||
// and interrupt signals
|
// and interrupt signals.
|
||||||
type Interceptor struct {
|
type Interceptor struct {
|
||||||
// interruptChannel is used to receive SIGINT (Ctrl+C) signals.
|
// interruptChannel is used to receive SIGINT (Ctrl+C) signals.
|
||||||
interruptChannel chan os.Signal
|
interruptChannel chan os.Signal
|
||||||
@@ -33,11 +106,16 @@ type Interceptor struct {
|
|||||||
shutdownRequestChannel chan struct{}
|
shutdownRequestChannel chan struct{}
|
||||||
|
|
||||||
// quit is closed when instructing the main interrupt handler to exit.
|
// quit is closed when instructing the main interrupt handler to exit.
|
||||||
|
// Note that to avoid losing notifications, only shutdown func may
|
||||||
|
// close this channel.
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
|
|
||||||
|
// Notifier handles sending shutdown notifications.
|
||||||
|
Notifier Notifier
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intercept starts the interception of interrupt signals and returns an `Interceptor` instance.
|
// Intercept starts the interception of interrupt signals and returns an `Interceptor` instance.
|
||||||
// Note that any previous active interceptor must be stopped before a new one can be created
|
// Note that any previous active interceptor must be stopped before a new one can be created.
|
||||||
func Intercept() (Interceptor, error) {
|
func Intercept() (Interceptor, error) {
|
||||||
if !atomic.CompareAndSwapInt32(&started, 0, 1) {
|
if !atomic.CompareAndSwapInt32(&started, 0, 1) {
|
||||||
return Interceptor{}, errors.New("intercept already started")
|
return Interceptor{}, errors.New("intercept already started")
|
||||||
@@ -85,6 +163,7 @@ func (c *Interceptor) mainInterruptHandler() {
|
|||||||
}
|
}
|
||||||
isShutdown = true
|
isShutdown = true
|
||||||
log.Infof("Shutting down...")
|
log.Infof("Shutting down...")
|
||||||
|
c.Notifier.notifyStop()
|
||||||
|
|
||||||
// Signal the main interrupt handler to exit, and stop accept
|
// Signal the main interrupt handler to exit, and stop accept
|
||||||
// post-facto requests.
|
// post-facto requests.
|
||||||
|
Reference in New Issue
Block a user