mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-15 11:59:16 +01:00
grpc-plugin: Make the grpc port to listen on configurable
Changelog-Added: cln-grpc-plugin: The plugin can be configured to listen on a specific port using the `grpc-port` option
This commit is contained in:
parent
647ed6a8c8
commit
dd66c85fcb
3 changed files with 47 additions and 20 deletions
|
@ -1,4 +1,4 @@
|
|||
use anyhow::{Context, Result};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use cln_grpc::pb::node_server::NodeServer;
|
||||
use cln_plugin::{options, Builder};
|
||||
use log::{debug, warn};
|
||||
|
@ -10,7 +10,6 @@ mod tls;
|
|||
#[derive(Clone, Debug)]
|
||||
struct PluginState {
|
||||
rpc_path: PathBuf,
|
||||
bind_address: SocketAddr,
|
||||
identity: tls::Identity,
|
||||
ca_cert: Vec<u8>,
|
||||
}
|
||||
|
@ -19,14 +18,12 @@ struct PluginState {
|
|||
async fn main() -> Result<()> {
|
||||
debug!("Starting grpc plugin");
|
||||
let path = Path::new("lightning-rpc");
|
||||
let addr: SocketAddr = "0.0.0.0:50051".parse().unwrap();
|
||||
|
||||
let directory = std::env::current_dir()?;
|
||||
let (identity, ca_cert) = tls::init(&directory)?;
|
||||
|
||||
let state = PluginState {
|
||||
rpc_path: path.into(),
|
||||
bind_address: addr,
|
||||
identity,
|
||||
ca_cert,
|
||||
};
|
||||
|
@ -34,14 +31,21 @@ async fn main() -> Result<()> {
|
|||
let plugin = Builder::new(state.clone(), tokio::io::stdin(), tokio::io::stdout())
|
||||
.option(options::ConfigOption::new(
|
||||
"grpc-port",
|
||||
options::Value::Integer(29735),
|
||||
options::Value::Integer(50051),
|
||||
"Which port should the grpc plugin listen for incoming connections?",
|
||||
))
|
||||
.start()
|
||||
.await?;
|
||||
|
||||
let bind_port = match plugin.option("grpc-port") {
|
||||
Some(options::Value::Integer(i)) => i,
|
||||
None => return Err(anyhow!("Missing 'grpc-port' option")),
|
||||
Some(o) => return Err(anyhow!("grpc-port is not a valid integer: {:?}", o)),
|
||||
};
|
||||
let bind_addr: SocketAddr = format!("0.0.0.0:{}", bind_port).parse().unwrap();
|
||||
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = run_interface(state).await {
|
||||
if let Err(e) = run_interface(bind_addr, state).await {
|
||||
warn!("Error running the grpc interface: {}", e);
|
||||
}
|
||||
});
|
||||
|
@ -49,12 +53,7 @@ async fn main() -> Result<()> {
|
|||
plugin.join().await
|
||||
}
|
||||
|
||||
async fn run_interface(state: PluginState) -> Result<()> {
|
||||
debug!(
|
||||
"Connecting to {:?} and serving grpc on {:?}",
|
||||
&state.rpc_path, &state.bind_address
|
||||
);
|
||||
|
||||
async fn run_interface(bind_addr: SocketAddr, state: PluginState) -> Result<()> {
|
||||
let identity = state.identity.to_tonic_identity();
|
||||
let ca_cert = tonic::transport::Certificate::from_pem(state.ca_cert);
|
||||
|
||||
|
@ -62,7 +61,7 @@ async fn run_interface(state: PluginState) -> Result<()> {
|
|||
.identity(identity)
|
||||
.client_ca_root(ca_cert);
|
||||
|
||||
tonic::transport::Server::builder()
|
||||
let server = tonic::transport::Server::builder()
|
||||
.tls_config(tls)
|
||||
.context("configuring tls")?
|
||||
.add_service(NodeServer::new(
|
||||
|
@ -70,9 +69,14 @@ async fn run_interface(state: PluginState) -> Result<()> {
|
|||
.await
|
||||
.context("creating NodeServer instance")?,
|
||||
))
|
||||
.serve(state.bind_address)
|
||||
.await
|
||||
.context("serving requests")?;
|
||||
.serve(bind_addr);
|
||||
|
||||
debug!(
|
||||
"Connecting to {:?} and serving grpc on {:?}",
|
||||
&state.rpc_path, &bind_addr
|
||||
);
|
||||
|
||||
server.await.context("serving requests")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -331,6 +331,19 @@ where
|
|||
sender: tokio::sync::mpsc::Sender<serde_json::Value>,
|
||||
}
|
||||
|
||||
impl<S> Plugin<S>
|
||||
where
|
||||
S: Clone + Send,
|
||||
{
|
||||
pub fn option(&self, name: &str) -> Option<options::Value> {
|
||||
self.options
|
||||
.iter()
|
||||
.filter(|o| o.name() == name)
|
||||
.next()
|
||||
.map(|co| co.value.clone().unwrap_or(co.default().clone()))
|
||||
}
|
||||
}
|
||||
|
||||
/// The [PluginDriver] is used to run the IO loop, reading messages
|
||||
/// from the Lightning daemon, dispatching calls and notifications to
|
||||
/// the plugin, and returning responses to the the daemon. We also use
|
||||
|
|
|
@ -2,6 +2,7 @@ from fixtures import * # noqa: F401,F403
|
|||
from node_pb2_grpc import NodeStub
|
||||
from pathlib import Path
|
||||
from pyln.testing.utils import env, TEST_NETWORK
|
||||
from ephemeral_port_reserve import reserve
|
||||
import grpc
|
||||
import node_pb2 as nodepb
|
||||
import pytest
|
||||
|
@ -67,8 +68,9 @@ def test_plugin_start(node_factory):
|
|||
|
||||
def test_grpc_connect(node_factory):
|
||||
"""Attempts to connect to the grpc interface and call getinfo"""
|
||||
grpc_port = reserve()
|
||||
bin_path = Path.cwd() / "target" / "debug" / "grpc-plugin"
|
||||
l1 = node_factory.get_node(options={"plugin": str(bin_path)})
|
||||
l1 = node_factory.get_node(options={"plugin": str(bin_path), "grpc-port": str(grpc_port)})
|
||||
|
||||
p = Path(l1.daemon.lightning_dir) / TEST_NETWORK
|
||||
cert_path = p / "client.pem"
|
||||
|
@ -80,8 +82,9 @@ def test_grpc_connect(node_factory):
|
|||
certificate_chain=cert_path.open('rb').read()
|
||||
)
|
||||
|
||||
l1.daemon.wait_for_log(r'serving grpc on 0.0.0.0:')
|
||||
channel = grpc.secure_channel(
|
||||
"localhost:50051",
|
||||
f"localhost:{grpc_port}",
|
||||
creds,
|
||||
options=(('grpc.ssl_target_name_override', 'cln'),)
|
||||
)
|
||||
|
@ -101,9 +104,11 @@ def test_grpc_generate_certificate(node_factory):
|
|||
- If we have certs, we they should just get loaded
|
||||
- If we delete one cert or its key it should get regenerated.
|
||||
"""
|
||||
grpc_port = reserve()
|
||||
bin_path = Path.cwd() / "target" / "debug" / "grpc-plugin"
|
||||
l1 = node_factory.get_node(options={
|
||||
"plugin": str(bin_path),
|
||||
"grpc-port": str(grpc_port),
|
||||
}, start=False)
|
||||
|
||||
p = Path(l1.daemon.lightning_dir) / TEST_NETWORK
|
||||
|
@ -140,8 +145,13 @@ def test_grpc_wrong_auth(node_factory):
|
|||
We create two instances, each generates its own certs and keys,
|
||||
and then we try to cross the wires.
|
||||
"""
|
||||
grpc_port = reserve()
|
||||
bin_path = Path.cwd() / "target" / "debug" / "grpc-plugin"
|
||||
l1, l2 = node_factory.get_nodes(2, opts={"plugin": str(bin_path), "start": False})
|
||||
l1, l2 = node_factory.get_nodes(2, opts={
|
||||
"plugin": str(bin_path),
|
||||
"start": False,
|
||||
"grpc-port": str(grpc_port),
|
||||
})
|
||||
l1.start()
|
||||
l1.daemon.wait_for_log(r'serving grpc on 0.0.0.0:')
|
||||
|
||||
|
@ -159,7 +169,7 @@ def test_grpc_wrong_auth(node_factory):
|
|||
)
|
||||
|
||||
channel = grpc.secure_channel(
|
||||
"localhost:50051",
|
||||
f"localhost:{grpc_port}",
|
||||
creds,
|
||||
options=(('grpc.ssl_target_name_override', 'cln'),)
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue