From c17a6c10c157a429bf3777486de3121d58e87ed1 Mon Sep 17 00:00:00 2001 From: Marco Neumann Date: Wed, 8 Dec 2021 11:42:10 +0100 Subject: [PATCH 1/5] feat: add `GetRouter` gRPC method --- .../influxdata/iox/router/v1/service.proto | 11 +++++++++++ .../server_type/router/rpc/router.rs | 19 ++++++++++++++++++- .../tests/end_to_end_cases/router_api.rs | 9 +++++++++ influxdb_iox_client/src/client/router.rs | 17 +++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/generated_types/protos/influxdata/iox/router/v1/service.proto b/generated_types/protos/influxdata/iox/router/v1/service.proto index c6eefed97b..8ac87820d8 100644 --- a/generated_types/protos/influxdata/iox/router/v1/service.proto +++ b/generated_types/protos/influxdata/iox/router/v1/service.proto @@ -5,6 +5,9 @@ option go_package = "github.com/influxdata/iox/router/v1"; import "influxdata/iox/router/v1/router.proto"; service RouterService { + // Get router. + rpc GetRouter(GetRouterRequest) returns (GetRouterResponse); + // List configured routers. rpc ListRouters(ListRoutersRequest) returns (ListRoutersResponse); @@ -15,6 +18,14 @@ service RouterService { rpc DeleteRouter(DeleteRouterRequest) returns (DeleteRouterResponse); } +message GetRouterRequest { + string router_name = 1; +} + +message GetRouterResponse { + Router router = 1; +} + message ListRoutersRequest {} message ListRoutersResponse { diff --git a/influxdb_iox/src/influxdb_ioxd/server_type/router/rpc/router.rs b/influxdb_iox/src/influxdb_ioxd/server_type/router/rpc/router.rs index d82d19bad5..d5aa5d138c 100644 --- a/influxdb_iox/src/influxdb_ioxd/server_type/router/rpc/router.rs +++ b/influxdb_iox/src/influxdb_ioxd/server_type/router/rpc/router.rs @@ -1,6 +1,9 @@ use std::sync::Arc; -use generated_types::{google::FromOptionalField, influxdata::iox::router::v1::*}; +use generated_types::{ + google::{FromOptionalField, NotFound, ResourceType}, + influxdata::iox::router::v1::*, +}; use router::server::RouterServer; use tonic::{Request, Response, Status}; @@ -10,6 +13,20 @@ struct RouterService { #[tonic::async_trait] impl router_service_server::RouterService for RouterService { + async fn get_router( + &self, + request: Request, + ) -> Result, Status> { + let GetRouterRequest { router_name } = request.into_inner(); + let router = self + .server + .router(&router_name) + .ok_or_else(|| NotFound::new(ResourceType::Router, router_name))?; + Ok(Response::new(GetRouterResponse { + router: Some(router.config().clone().into()), + })) + } + async fn list_routers( &self, _: Request, diff --git a/influxdb_iox/tests/end_to_end_cases/router_api.rs b/influxdb_iox/tests/end_to_end_cases/router_api.rs index f00a2d9a28..e1d7baf8fd 100644 --- a/influxdb_iox/tests/end_to_end_cases/router_api.rs +++ b/influxdb_iox/tests/end_to_end_cases/router_api.rs @@ -45,6 +45,7 @@ async fn test_router_crud() { // no routers assert_eq!(client.list_routers().await.unwrap().len(), 0); + assert_error!(client.get_router(&cfg_foo_1.name).await, Error::NotFound(_)); client.delete_router(&router_name_b).await.unwrap(); // add routers @@ -54,6 +55,8 @@ async fn test_router_crud() { assert_eq!(routers.len(), 2); assert_eq!(&routers[0], &cfg_bar); assert_eq!(&routers[1], &cfg_foo_1); + assert_eq!(client.get_router(&cfg_bar.name).await.unwrap(), cfg_bar); + assert_eq!(client.get_router(&cfg_foo_1.name).await.unwrap(), cfg_foo_1); // update router client.update_router(cfg_foo_2.clone()).await.unwrap(); @@ -61,12 +64,18 @@ async fn test_router_crud() { assert_eq!(routers.len(), 2); assert_eq!(&routers[0], &cfg_bar); assert_eq!(&routers[1], &cfg_foo_2); + assert_eq!(client.get_router(&cfg_bar.name).await.unwrap(), cfg_bar); + assert_eq!(client.get_router(&cfg_foo_2.name).await.unwrap(), cfg_foo_2); // delete routers client.delete_router(&router_name_b).await.unwrap(); let routers = client.list_routers().await.unwrap(); assert_eq!(routers.len(), 1); assert_eq!(&routers[0], &cfg_bar); + assert_eq!(client.get_router(&cfg_bar.name).await.unwrap(), cfg_bar); + assert_error!(client.get_router(&cfg_foo_2.name).await, Error::NotFound(_)); + + // deleting router a second time is a no-op client.delete_router(&router_name_b).await.unwrap(); } diff --git a/influxdb_iox_client/src/client/router.rs b/influxdb_iox_client/src/client/router.rs index 9585ce0cd7..fbb2a73f5d 100644 --- a/influxdb_iox_client/src/client/router.rs +++ b/influxdb_iox_client/src/client/router.rs @@ -1,3 +1,5 @@ +use ::generated_types::google::OptionalField; + use self::generated_types::{router_service_client::RouterServiceClient, *}; use crate::connection::Connection; @@ -49,6 +51,21 @@ impl Client { } } + /// Get router + pub async fn get_router( + &mut self, + router_name: &str, + ) -> Result { + let response = self + .inner + .get_router(GetRouterRequest { + router_name: router_name.to_string(), + }) + .await?; + + Ok(response.into_inner().router.unwrap_field("router")?) + } + /// List routers. pub async fn list_routers(&mut self) -> Result, Error> { let response = self.inner.list_routers(ListRoutersRequest {}).await?; From b7d6865f870dc7b778ce9c8d2e73482c10441143 Mon Sep 17 00:00:00 2001 From: Marco Neumann Date: Wed, 8 Dec 2021 11:52:23 +0100 Subject: [PATCH 2/5] feat: add router CLI Closes #3331. --- influxdb_iox/src/commands/router.rs | 101 ++++++++++++++++++ influxdb_iox/src/main.rs | 10 ++ influxdb_iox/tests/end_to_end_cases/mod.rs | 1 + .../tests/end_to_end_cases/router_cli.rs | 91 ++++++++++++++++ 4 files changed, 203 insertions(+) create mode 100644 influxdb_iox/src/commands/router.rs create mode 100644 influxdb_iox/tests/end_to_end_cases/router_cli.rs diff --git a/influxdb_iox/src/commands/router.rs b/influxdb_iox/src/commands/router.rs new file mode 100644 index 0000000000..044af1f9db --- /dev/null +++ b/influxdb_iox/src/commands/router.rs @@ -0,0 +1,101 @@ +//! This module implements the `database` CLI command + +use influxdb_iox_client::{ + connection::Connection, + router::{self, generated_types::Router as RouterConfig}, +}; +use structopt::StructOpt; +use thiserror::Error; + +#[allow(clippy::enum_variant_names)] +#[derive(Debug, Error)] +pub enum Error { + #[error("Error formatting: {0}")] + FormattingError(#[from] influxdb_iox_client::format::Error), + + #[error("Error querying: {0}")] + Query(#[from] influxdb_iox_client::flight::Error), + + #[error("JSON Serialization error: {0}")] + Serde(#[from] serde_json::Error), + + #[error("Client error: {0}")] + ClientError(#[from] influxdb_iox_client::error::Error), +} + +pub type Result = std::result::Result; + +/// Manage IOx databases +#[derive(Debug, StructOpt)] +pub struct Config { + #[structopt(subcommand)] + command: Command, +} + +/// Create a new router +#[derive(Debug, StructOpt)] +struct Update { + /// The name of the router + name: String, +} + +/// Return configuration of specific router +#[derive(Debug, StructOpt)] +struct Get { + /// The name of the router + name: String, +} + +/// Delete specific router +#[derive(Debug, StructOpt)] +struct Delete { + /// The name of the router + name: String, +} + +/// All possible subcommands for database +#[derive(Debug, StructOpt)] +enum Command { + Update(Update), + List, + Get(Get), + Delete(Delete), +} + +pub async fn command(connection: Connection, config: Config) -> Result<()> { + match config.command { + Command::Update(command) => { + let mut client = router::Client::new(connection); + let config = RouterConfig { + name: command.name.clone(), + ..Default::default() + }; + + client.update_router(config).await?; + + println!("Updated router {}", command.name); + } + Command::List => { + let mut client = router::Client::new(connection); + let routers = client.list_routers().await?; + for router in routers { + println!("{}", router.name); + } + } + Command::Get(get) => { + let Get { name } = get; + let mut client = router::Client::new(connection); + let router = client.get_router(&name).await?; + println!("{}", serde_json::to_string_pretty(&router)?); + } + Command::Delete(delete) => { + let Delete { name } = delete; + let mut client = router::Client::new(connection); + client.delete_router(&name).await?; + + println!("Deleted router {}", name); + } + } + + Ok(()) +} diff --git a/influxdb_iox/src/main.rs b/influxdb_iox/src/main.rs index 8067682952..7212801dd1 100644 --- a/influxdb_iox/src/main.rs +++ b/influxdb_iox/src/main.rs @@ -22,6 +22,7 @@ mod commands { pub mod database; pub mod debug; pub mod operations; + pub mod router; pub mod run; pub mod server; pub mod server_remote; @@ -147,6 +148,7 @@ enum Command { Database(commands::database::Config), // Clippy recommended boxing this variant because it's much larger than the others Run(Box), + Router(commands::router::Config), Server(commands::server::Config), Operation(commands::operations::Config), Sql(commands::sql::Config), @@ -216,6 +218,14 @@ fn main() -> Result<(), std::io::Error> { std::process::exit(ReturnCode::Failure as _) } } + Command::Router(config) => { + let _tracing_guard = handle_init_logs(init_simple_logs(log_verbose_count)); + let connection = connection().await; + if let Err(e) = commands::router::command(connection, config).await { + eprintln!("{}", e); + std::process::exit(ReturnCode::Failure as _) + } + } Command::Run(config) => { let _tracing_guard = handle_init_logs(init_logs_and_tracing(log_verbose_count, &config)); diff --git a/influxdb_iox/tests/end_to_end_cases/mod.rs b/influxdb_iox/tests/end_to_end_cases/mod.rs index bd009b0613..df22d58e96 100644 --- a/influxdb_iox/tests/end_to_end_cases/mod.rs +++ b/influxdb_iox/tests/end_to_end_cases/mod.rs @@ -19,6 +19,7 @@ mod read_cli; mod remote_api; mod remote_cli; mod router_api; +mod router_cli; mod run_cli; pub mod scenario; mod sql_cli; diff --git a/influxdb_iox/tests/end_to_end_cases/router_cli.rs b/influxdb_iox/tests/end_to_end_cases/router_cli.rs new file mode 100644 index 0000000000..d42ce299f4 --- /dev/null +++ b/influxdb_iox/tests/end_to_end_cases/router_cli.rs @@ -0,0 +1,91 @@ +use crate::{ + common::server_fixture::{ServerFixture, ServerType}, + end_to_end_cases::scenario::rand_name, +}; +use assert_cmd::Command; +use predicates::prelude::*; + +#[tokio::test] +async fn test_router_crud() { + let server_fixture = ServerFixture::create_shared(ServerType::Router).await; + let addr = server_fixture.grpc_base(); + let router_name = rand_name(); + + Command::cargo_bin("influxdb_iox") + .unwrap() + .arg("router") + .arg("get") + .arg(&router_name) + .arg("--host") + .arg(addr) + .assert() + .failure() + .stderr(predicate::str::contains(format!( + "Resource router/{} not found", + router_name, + ))); + + Command::cargo_bin("influxdb_iox") + .unwrap() + .arg("router") + .arg("update") + .arg(&router_name) + .arg("--host") + .arg(addr) + .assert() + .success() + .stdout(predicate::str::contains(format!( + "Updated router {}", + router_name + ))); + + Command::cargo_bin("influxdb_iox") + .unwrap() + .arg("router") + .arg("list") + .arg("--host") + .arg(addr) + .assert() + .success() + .stdout(predicate::str::contains(&router_name)); + + Command::cargo_bin("influxdb_iox") + .unwrap() + .arg("router") + .arg("get") + .arg(&router_name) + .arg("--host") + .arg(addr) + .assert() + .success() + .stdout( + predicate::str::contains(&router_name).and(predicate::str::contains(format!( + r#""name": "{}"#, + &router_name + ))), // validate the defaults have been set reasonably + ); + + Command::cargo_bin("influxdb_iox") + .unwrap() + .arg("router") + .arg("delete") + .arg(&router_name) + .arg("--host") + .arg(addr) + .assert() + .success() + .stdout(predicate::str::contains(format!( + "Deleted router {}", + router_name + ))); + + Command::cargo_bin("influxdb_iox") + .unwrap() + .arg("router") + .arg("list") + .arg("--host") + .arg(addr) + .assert() + .success() + .stdout(predicate::str::contains(&router_name).not()); +} From af71e2422eb8ab01643d59a21374afe2b47b478c Mon Sep 17 00:00:00 2001 From: Marco Neumann Date: Wed, 8 Dec 2021 12:39:25 +0000 Subject: [PATCH 3/5] fix: typos Co-authored-by: Andrew Lamb --- influxdb_iox/src/commands/router.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/influxdb_iox/src/commands/router.rs b/influxdb_iox/src/commands/router.rs index 044af1f9db..f553c5297f 100644 --- a/influxdb_iox/src/commands/router.rs +++ b/influxdb_iox/src/commands/router.rs @@ -1,4 +1,4 @@ -//! This module implements the `database` CLI command +//! This module implements the `router` CLI command use influxdb_iox_client::{ connection::Connection, @@ -53,7 +53,7 @@ struct Delete { name: String, } -/// All possible subcommands for database +/// All possible subcommands for router #[derive(Debug, StructOpt)] enum Command { Update(Update), From e42c6974cf1f1710b2fb1fe146d6211f05acd2c7 Mon Sep 17 00:00:00 2001 From: Marco Neumann Date: Wed, 8 Dec 2021 13:45:16 +0100 Subject: [PATCH 4/5] fix: remove unused code --- influxdb_iox/src/commands/router.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/influxdb_iox/src/commands/router.rs b/influxdb_iox/src/commands/router.rs index f553c5297f..dfce698d41 100644 --- a/influxdb_iox/src/commands/router.rs +++ b/influxdb_iox/src/commands/router.rs @@ -10,12 +10,6 @@ use thiserror::Error; #[allow(clippy::enum_variant_names)] #[derive(Debug, Error)] pub enum Error { - #[error("Error formatting: {0}")] - FormattingError(#[from] influxdb_iox_client::format::Error), - - #[error("Error querying: {0}")] - Query(#[from] influxdb_iox_client::flight::Error), - #[error("JSON Serialization error: {0}")] Serde(#[from] serde_json::Error), From 3e97e49c35691c9a46a27868610307c16da6d982 Mon Sep 17 00:00:00 2001 From: Marco Neumann Date: Wed, 8 Dec 2021 13:45:48 +0100 Subject: [PATCH 5/5] refactor: "update router" -> "create or update router" --- influxdb_iox/src/commands/router.rs | 14 +++++++++----- influxdb_iox/tests/end_to_end_cases/router_cli.rs | 4 ++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/influxdb_iox/src/commands/router.rs b/influxdb_iox/src/commands/router.rs index dfce698d41..996a27342f 100644 --- a/influxdb_iox/src/commands/router.rs +++ b/influxdb_iox/src/commands/router.rs @@ -26,9 +26,9 @@ pub struct Config { command: Command, } -/// Create a new router +/// Create a new router or update an existing one. #[derive(Debug, StructOpt)] -struct Update { +struct CreateOrUpdate { /// The name of the router name: String, } @@ -50,15 +50,19 @@ struct Delete { /// All possible subcommands for router #[derive(Debug, StructOpt)] enum Command { - Update(Update), + CreateOrUpdate(CreateOrUpdate), + + /// List routers List, + Get(Get), + Delete(Delete), } pub async fn command(connection: Connection, config: Config) -> Result<()> { match config.command { - Command::Update(command) => { + Command::CreateOrUpdate(command) => { let mut client = router::Client::new(connection); let config = RouterConfig { name: command.name.clone(), @@ -67,7 +71,7 @@ pub async fn command(connection: Connection, config: Config) -> Result<()> { client.update_router(config).await?; - println!("Updated router {}", command.name); + println!("Created/Updated router {}", command.name); } Command::List => { let mut client = router::Client::new(connection); diff --git a/influxdb_iox/tests/end_to_end_cases/router_cli.rs b/influxdb_iox/tests/end_to_end_cases/router_cli.rs index d42ce299f4..5695879c43 100644 --- a/influxdb_iox/tests/end_to_end_cases/router_cli.rs +++ b/influxdb_iox/tests/end_to_end_cases/router_cli.rs @@ -28,14 +28,14 @@ async fn test_router_crud() { Command::cargo_bin("influxdb_iox") .unwrap() .arg("router") - .arg("update") + .arg("create-or-update") .arg(&router_name) .arg("--host") .arg(addr) .assert() .success() .stdout(predicate::str::contains(format!( - "Updated router {}", + "Created/Updated router {}", router_name )));