Skip to content

multi: introduce status server and sub-server manager #442

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions cmd/litcli/lit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package main

import (
"context"
"fmt"

"github.com/lightninglabs/lightning-terminal/litrpc"
"github.com/urfave/cli"
)

var litCommands = []cli.Command{
{
Name: "stop",
Usage: "shutdown the LiT daemon",
Category: "LiT",
Action: shutdownLit,
},
}

func shutdownLit(ctx *cli.Context) error {
clientConn, cleanup, err := connectClient(ctx)
if err != nil {
return err
}
defer cleanup()
client := litrpc.NewLitServiceClient(clientConn)

ctxb := context.Background()
_, err = client.StopDaemon(ctxb, &litrpc.StopDaemonRequest{})
if err != nil {
return err
}

fmt.Println("Successfully shutdown LiTd")

return nil
}
27 changes: 2 additions & 25 deletions cmd/litcli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/lightninglabs/lndclient"
"github.com/lightninglabs/protobuf-hex-display/jsonpb"
"github.com/lightninglabs/protobuf-hex-display/proto"
"github.com/lightningnetwork/lnd"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/macaroons"
"github.com/urfave/cli"
Expand Down Expand Up @@ -47,16 +46,6 @@ var (
Usage: "path to lit's TLS certificate",
Value: terminal.DefaultTLSCertPath,
}
lndMode = cli.StringFlag{
Name: "lndmode",
Usage: "the mode that lnd is running in: remote or integrated",
Value: terminal.ModeIntegrated,
}
lndTlsCertFlag = cli.StringFlag{
Name: "lndtlscertpath",
Usage: "path to lnd's TLS certificate",
Value: lnd.DefaultConfig().TLSCertPath,
}
macaroonPathFlag = cli.StringFlag{
Name: "macaroonpath",
Usage: "path to lit's macaroon file",
Expand All @@ -78,16 +67,16 @@ func main() {
},
networkFlag,
baseDirFlag,
lndMode,
tlsCertFlag,
lndTlsCertFlag,
macaroonPathFlag,
}
app.Commands = append(app.Commands, sessionCommands...)
app.Commands = append(app.Commands, accountsCommands...)
app.Commands = append(app.Commands, listActionsCommand)
app.Commands = append(app.Commands, privacyMapCommands)
app.Commands = append(app.Commands, autopilotCommands)
app.Commands = append(app.Commands, litCommands...)
app.Commands = append(app.Commands, statusCommands...)

err := app.Run(os.Args)
if err != nil {
Expand Down Expand Up @@ -175,18 +164,6 @@ func extractPathArgs(ctx *cli.Context) (string, string, error) {
)
}

// Get the LND mode. If Lit is in integrated LND mode, then LND's tls
// cert is used directly. Otherwise, Lit's own tls cert is used.
lndmode := strings.ToLower(ctx.GlobalString(lndMode.Name))
if lndmode == terminal.ModeIntegrated {
tlsCertPath := lncfg.CleanAndExpandPath(ctx.GlobalString(
lndTlsCertFlag.Name,
))

return tlsCertPath, macaroonPath, nil
}

// Lit is in remote LND mode. So we need Lit's tls cert.
tlsCertPath := lncfg.CleanAndExpandPath(ctx.GlobalString(
tlsCertFlag.Name,
))
Expand Down
38 changes: 38 additions & 0 deletions cmd/litcli/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package main

import (
"context"

"github.com/lightninglabs/lightning-terminal/litrpc"
"github.com/urfave/cli"
)

var statusCommands = []cli.Command{
{
Name: "status",
Usage: "info about litd status",
Category: "Status",
Action: getStatus,
},
}

func getStatus(ctx *cli.Context) error {
clientConn, cleanup, err := connectClient(ctx)
if err != nil {
return err
}
defer cleanup()
client := litrpc.NewStatusClient(clientConn)

ctxb := context.Background()
resp, err := client.SubServerState(
ctxb, &litrpc.SubServerStatusReq{},
)
if err != nil {
return err
}

printRespJSON(resp)

return nil
}
77 changes: 41 additions & 36 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ type Config struct {
LetsEncryptDir string `long:"letsencryptdir" description:"The directory where the Let's Encrypt library will store its key and certificate."`
LetsEncryptListen string `long:"letsencryptlisten" description:"The IP:port on which LiT will listen for Let's Encrypt challenges. Let's Encrypt will always try to contact on port 80. Often non-root processes are not allowed to bind to ports lower than 1024. This configuration option allows a different port to be used, but must be used in combination with port forwarding from port 80. This configuration can also be used to specify another IP address to listen on, for example an IPv6 address."`

TLSCertPath string `long:"tlscertpath" description:"Path to write the self signed TLS certificate for LiT's RPC and REST proxy service (if Let's Encrypt is not used). This only applies to the HTTP(S)Listen port."`
TLSKeyPath string `long:"tlskeypath" description:"Path to write the self signed TLS private key for LiT's RPC and REST proxy service (if Let's Encrypt is not used). This only applies to the HTTP(S)Listen port."`

LitDir string `long:"lit-dir" description:"The main directory where LiT looks for its configuration file. If LiT is running in 'remote' lnd mode, this is also the directory where the TLS certificates and log files are stored by default."`
ConfigFile string `long:"configfile" description:"Path to LiT's configuration file."`

Expand Down Expand Up @@ -211,9 +214,6 @@ type Config struct {
// RemoteConfig holds the configuration parameters that are needed when running
// LiT in the "remote" lnd mode.
type RemoteConfig struct {
LitTLSCertPath string `long:"lit-tlscertpath" description:"For lnd remote mode only: Path to write the self signed TLS certificate for LiT's RPC and REST proxy service (if Let's Encrypt is not used)."`
LitTLSKeyPath string `long:"lit-tlskeypath" description:"For lnd remote mode only: Path to write the self signed TLS private key for LiT's RPC and REST proxy service (if Let's Encrypt is not used)."`

LitLogDir string `long:"lit-logdir" description:"For lnd remote mode only: Directory to log output."`
LitMaxLogFiles int `long:"lit-maxlogfiles" description:"For lnd remote mode only: Maximum logfiles to keep (0 for no rotation)"`
LitMaxLogFileSize int `long:"lit-maxlogfilesize" description:"For lnd remote mode only: Maximum logfile size in MB"`
Expand Down Expand Up @@ -286,9 +286,9 @@ func (c *Config) lndConnectParams() (string, lndclient.Network, string,
func defaultConfig() *Config {
return &Config{
HTTPSListen: defaultHTTPSListen,
TLSCertPath: DefaultTLSCertPath,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also update doc/config-lnd-integrated.md and perhaps explain the difference (and reasoning) between the lnd 10009 (gRPC only) and the litd 8443 (grpc-web, REST, gRPC proxy, UI) a bit more explicitly?
Also this change should be made very explicit in the release notes (not sure where to put the reminder for us).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah good call here, as it would also be a breaking change (CLI/config wise).

TLSKeyPath: defaultTLSKeyPath,
Remote: &RemoteConfig{
LitTLSCertPath: DefaultTLSCertPath,
LitTLSKeyPath: defaultTLSKeyPath,
LitDebugLevel: defaultLogLevel,
LitLogDir: defaultLogDir,
LitMaxLogFiles: defaultMaxLogFiles,
Expand Down Expand Up @@ -598,6 +598,33 @@ func loadConfigFile(preCfg *Config, interceptor signal.Interceptor) (*Config,
return nil, fmt.Errorf("invalid lnd mode %v", cfg.LndMode)
}

// If the provided lit directory is not the default, we'll modify the
// path to all of the files and directories that will live within it.
if litDir != DefaultLitDir {
if cfg.TLSKeyPath == defaultTLSKeyPath {
cfg.TLSKeyPath = filepath.Join(
litDir, DefaultTLSKeyFilename,
)
}

if cfg.TLSCertPath == DefaultTLSCertPath {
cfg.TLSCertPath = filepath.Join(
litDir, DefaultTLSCertFilename,
)
}
}

cfg.TLSCertPath = lncfg.CleanAndExpandPath(cfg.TLSCertPath)
cfg.TLSKeyPath = lncfg.CleanAndExpandPath(cfg.TLSKeyPath)

// Make sure the parent directories of our certificate files exist.
if err := makeDirectories(filepath.Dir(cfg.TLSCertPath)); err != nil {
return nil, err
}
if err := makeDirectories(filepath.Dir(cfg.TLSKeyPath)); err != nil {
return nil, err
}

// Warn about missing config file only after all other configuration is
// done. This prevents the warning on help messages and invalid options.
// Note this should go directly before the return.
Expand Down Expand Up @@ -637,25 +664,15 @@ func validateRemoteModeConfig(cfg *Config) error {
// path to all of the files and directories that will live within it.
litDir := lnd.CleanAndExpandPath(cfg.LitDir)
if litDir != DefaultLitDir {
r.LitTLSCertPath = filepath.Join(litDir, DefaultTLSCertFilename)
r.LitTLSKeyPath = filepath.Join(litDir, DefaultTLSKeyFilename)
r.LitLogDir = filepath.Join(litDir, defaultLogDirname)
if r.LitLogDir == defaultLogDir {
r.LitLogDir = filepath.Join(
litDir, defaultLogDirname,
)
}
}

r.LitTLSCertPath = lncfg.CleanAndExpandPath(r.LitTLSCertPath)
r.LitTLSKeyPath = lncfg.CleanAndExpandPath(r.LitTLSKeyPath)
r.LitLogDir = lncfg.CleanAndExpandPath(r.LitLogDir)

// Make sure the parent directories of our certificate files exist. We
// don't need to do the same for the log dir as the log rotator will do
// just that.
if err := makeDirectories(filepath.Dir(r.LitTLSCertPath)); err != nil {
return err
}
if err := makeDirectories(filepath.Dir(r.LitTLSKeyPath)); err != nil {
return err
}

// In remote mode, we don't call lnd's ValidateConfig that sets up a
// logging backend for us. We need to manually create and start one. The
// root logger should've already been created as part of the default
Expand Down Expand Up @@ -745,8 +762,7 @@ func readUIPassword(config *Config) error {
func buildTLSConfigForHttp2(config *Config) (*tls.Config, error) {
var tlsConfig *tls.Config

switch {
case config.LetsEncrypt:
if config.LetsEncrypt {
serverName := config.LetsEncryptHost
if serverName == "" {
return nil, errors.New("let's encrypt host name " +
Expand Down Expand Up @@ -782,10 +798,9 @@ func buildTLSConfigForHttp2(config *Config) (*tls.Config, error) {
tlsConfig = &tls.Config{
GetCertificate: manager.GetCertificate,
}

case config.LndMode == ModeRemote:
tlsCertPath := config.Remote.LitTLSCertPath
tlsKeyPath := config.Remote.LitTLSKeyPath
} else {
tlsCertPath := config.TLSCertPath
tlsKeyPath := config.TLSKeyPath

if !lnrpc.FileExists(tlsCertPath) &&
!lnrpc.FileExists(tlsKeyPath) {
Expand All @@ -807,16 +822,6 @@ func buildTLSConfigForHttp2(config *Config) (*tls.Config, error) {
"keys: %v", err)
}
tlsConfig = cert.TLSConfFromCert(tlsCert)

default:
tlsCert, _, err := cert.LoadCert(
config.Lnd.TLSCertPath, config.Lnd.TLSKeyPath,
)
if err != nil {
return nil, fmt.Errorf("failed reading TLS server "+
"keys: %v", err)
}
tlsConfig = cert.TLSConfFromCert(tlsCert)
}

// lnd's cipher suites are too restrictive for HTTP/2, we need to add
Expand Down
11 changes: 11 additions & 0 deletions doc/config-lnd-integrated.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ Example `~/.lit/lit.conf`:
```text
# Application Options
httpslisten=0.0.0.0:8443
tlscertpath=~/.lit/tls.cert
tlskeypath=~/.lit/tls.key
letsencrypt=true
letsencrypthost=loop.merchant.com
lnd-mode=integrated
Expand Down Expand Up @@ -117,6 +119,15 @@ system:
- **On Linux**: `~/.lit/lit.conf`
- **On Windows**: `~/AppData/Roaming/Lit/lit.conf`

## LiT and LND interfaces

Port 10009 is the port that LND uses to expose its gRPC interface. LND's tls
cert and macaroons will be required when making requests to this interface.

Port 8443 is a port that LiT uses to expose a variety of interfaces: gRPC,
REST, grpc-web. When making requests using this interface, LiT's tls cert and
macaroons should be used.

## Upgrade Existing Nodes

If you already have existing `lnd`, `loop`, or `faraday` nodes, you can easily
Expand Down
21 changes: 8 additions & 13 deletions itest/litd_mode_integrated_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ func testModeIntegrated(net *NetworkHarness, t *harnessTest) {

tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
runGRPCAuthTest(
ttt, cfg.LitAddr(), cfg.TLSCertPath,
ttt, cfg.LitAddr(), cfg.LitTLSCertPath,
endpoint.macaroonFn(cfg),
endpoint.requestFn,
endpoint.successPattern,
Expand All @@ -315,7 +315,7 @@ func testModeIntegrated(net *NetworkHarness, t *harnessTest) {

tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
runUIPasswordCheck(
ttt, cfg.LitAddr(), cfg.TLSCertPath,
ttt, cfg.LitAddr(), cfg.LitTLSCertPath,
cfg.UIPassword, endpoint.requestFn,
false, endpoint.successPattern,
)
Expand Down Expand Up @@ -364,7 +364,7 @@ func testModeIntegrated(net *NetworkHarness, t *harnessTest) {

tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
runGRPCAuthTest(
ttt, cfg.LitAddr(), cfg.TLSCertPath,
ttt, cfg.LitAddr(), cfg.LitTLSCertPath,
superMacFile,
endpoint.requestFn,
endpoint.successPattern,
Expand Down Expand Up @@ -403,7 +403,7 @@ func testModeIntegrated(net *NetworkHarness, t *harnessTest) {
defer cancel()

rawLNCConn := setUpLNCConn(
ctxt, t.t, cfg.LitAddr(), cfg.TLSCertPath,
ctxt, t.t, cfg.LitAddr(), cfg.LitTLSCertPath,
cfg.LitMacPath,
litrpc.SessionType_TYPE_MACAROON_READONLY, nil,
)
Expand Down Expand Up @@ -434,11 +434,11 @@ func testModeIntegrated(net *NetworkHarness, t *harnessTest) {

ht := newHarnessTest(tt, net)
runAccountSystemTest(
ht, net.Alice, cfg.RPCAddr(), cfg.TLSCertPath,
ht, net.Alice, cfg.LitAddr(), cfg.LitTLSCertPath,
superMacFile, 1,
)
runAccountSystemTest(
ht, net.Alice, cfg.LitAddr(), cfg.TLSCertPath,
ht, net.Alice, cfg.LitAddr(), cfg.LitTLSCertPath,
superMacFile, 2,
)
})
Expand All @@ -465,7 +465,7 @@ func testModeIntegrated(net *NetworkHarness, t *harnessTest) {
}

rawLNCConn := setUpLNCConn(
ctxt, t.t, cfg.LitAddr(), cfg.TLSCertPath,
ctxt, t.t, cfg.LitAddr(), cfg.LitTLSCertPath,
cfg.LitMacPath,
litrpc.SessionType_TYPE_MACAROON_CUSTOM, customPerms,
)
Expand Down Expand Up @@ -525,14 +525,11 @@ func setUpLNCConn(ctx context.Context, t *testing.T, hostPort, tlsCertPath,
// runCertificateCheck checks that the TLS certificates presented to clients are
// what we expect them to be.
func runCertificateCheck(t *testing.T, node *HarnessNode) {
// In integrated mode we expect the LiT HTTPS port (8443 by default) and
// lnd's RPC port to present the same certificate, namely lnd's TLS
// cert.
litCerts, err := getServerCertificates(node.Cfg.LitAddr())
require.NoError(t, err)
require.Len(t, litCerts, 1)
require.Equal(
t, "lnd autogenerated cert", litCerts[0].Issuer.Organization[0],
t, "litd autogenerated cert", litCerts[0].Issuer.Organization[0],
)

lndCerts, err := getServerCertificates(node.Cfg.RPCAddr())
Expand All @@ -541,8 +538,6 @@ func runCertificateCheck(t *testing.T, node *HarnessNode) {
require.Equal(
t, "lnd autogenerated cert", lndCerts[0].Issuer.Organization[0],
)

require.Equal(t, litCerts[0].Raw, lndCerts[0].Raw)
}

// runGRPCAuthTest tests authentication of the given gRPC interface.
Expand Down
Loading