From 5ca633c54b62a98766bab7f69fcd6583e9c3d74b Mon Sep 17 00:00:00 2001 From: karencfv Date: Thu, 29 Aug 2024 20:31:20 +1200 Subject: [PATCH] skeleton --- clickhouse-admin/api/src/lib.rs | 37 +++++++++++++- clickhouse-admin/src/clickward.rs | 40 ++++++++++++++- clickhouse-admin/src/http_entrypoints.rs | 13 ++++- openapi/clickhouse-admin.json | 62 +++++++++++++++++++++++- 4 files changed, 145 insertions(+), 7 deletions(-) diff --git a/clickhouse-admin/api/src/lib.rs b/clickhouse-admin/api/src/lib.rs index 9a011d4387..f1a3e742de 100644 --- a/clickhouse-admin/api/src/lib.rs +++ b/clickhouse-admin/api/src/lib.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use dropshot::{HttpError, HttpResponseOk, RequestContext}; +use dropshot::{HttpError, HttpResponseCreated, HttpResponseOk, RequestContext, TypedBody}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::net::SocketAddrV6; @@ -11,7 +11,7 @@ use std::net::SocketAddrV6; pub trait ClickhouseAdminApi { type Context; - /// Retrieve the address the ClickHouse server or keeper node is listening on + /// Retrieve the address the ClickHouse server or keeper node is listening on. #[endpoint { method = GET, path = "/node/address", @@ -19,6 +19,18 @@ pub trait ClickhouseAdminApi { async fn clickhouse_address( rqctx: RequestContext, ) -> Result, HttpError>; + + /// Generate a ClickHouse configuration file for a server node on a specified + /// directory. + #[endpoint { + method = POST, + // TODO: I'm not sure about this endpoint, could be better? + path = "/server-node/generate-config", + }] + async fn generate_server_config( + rqctx: RequestContext, + body: TypedBody, + ) -> Result, HttpError>; } #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema)] @@ -26,3 +38,24 @@ pub trait ClickhouseAdminApi { pub struct ClickhouseAddress { pub clickhouse_address: SocketAddrV6, } + +// TODO: Perhaps change this response type for something better +// like an object with all the settings or something like that +/// Success response for server node configuration file generation +#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct ServerConfigGenerateResponse { + pub success: bool, +} + +impl ServerConfigGenerateResponse { + pub fn success() -> Self { + Self { success: true } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct ServerSettings { + pub node_id: u64, +} \ No newline at end of file diff --git a/clickhouse-admin/src/clickward.rs b/clickhouse-admin/src/clickward.rs index 114201e44b..7b8217e802 100644 --- a/clickhouse-admin/src/clickward.rs +++ b/clickhouse-admin/src/clickward.rs @@ -2,11 +2,15 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use clickhouse_admin_api::ClickhouseAddress; +use camino::Utf8PathBuf; +use clickhouse_admin_api::{ClickhouseAddress, ServerConfigGenerateResponse, ServerSettings}; +use clickhouse_admin_types::{ClickhouseServerConfig, ServerId}; +use clickhouse_admin_types::config::{KeeperNodeConfig, ServerNodeConfig}; use dropshot::HttpError; use slog_error_chain::{InlineErrorChain, SlogInlineError}; use std::io; -use std::net::SocketAddrV6; +use std::net::{SocketAddrV6, Ipv6Addr}; +use std::str::FromStr; #[derive(Debug, thiserror::Error, SlogInlineError)] pub enum ClickwardError { @@ -35,6 +39,7 @@ impl From for HttpError { #[derive(Debug)] pub struct Clickward { + // TODO: Remove address? clickhouse_address: SocketAddrV6, } @@ -43,9 +48,40 @@ impl Clickward { Self { clickhouse_address } } + // TODO: Remove this endpoint? pub fn clickhouse_address( &self, ) -> Result { Ok(ClickhouseAddress { clickhouse_address: self.clickhouse_address }) } + + pub fn generate_server_config( + &self, + settings: ServerSettings, + ) -> Result { + // TODO: This should be part of the request body + let keepers = vec![ + KeeperNodeConfig::new("ff::01".to_string()), + KeeperNodeConfig::new("127.0.0.1".to_string()), + KeeperNodeConfig::new("we.dont.want.brackets.com".to_string()), + ]; + + let servers = vec![ + ServerNodeConfig::new("ff::08".to_string()), + ServerNodeConfig::new("ff::09".to_string()), + ]; + + let config = ClickhouseServerConfig::new( + Utf8PathBuf::from_str("./").unwrap(), + ServerId(settings.node_id), + Utf8PathBuf::from_str("./").unwrap(), + Ipv6Addr::from_str("ff::08").unwrap(), + keepers, + servers, + ); + + config.generate_xml_file().unwrap(); + + Ok(ServerConfigGenerateResponse::success()) + } } diff --git a/clickhouse-admin/src/http_entrypoints.rs b/clickhouse-admin/src/http_entrypoints.rs index 05988a73b0..009ad9dbfc 100644 --- a/clickhouse-admin/src/http_entrypoints.rs +++ b/clickhouse-admin/src/http_entrypoints.rs @@ -5,8 +5,7 @@ use crate::context::ServerContext; use clickhouse_admin_api::*; use dropshot::HttpError; -use dropshot::HttpResponseOk; -use dropshot::RequestContext; +use dropshot::{HttpResponseOk, HttpResponseCreated, RequestContext, TypedBody}; use std::sync::Arc; type ClickhouseApiDescription = dropshot::ApiDescription>; @@ -28,4 +27,14 @@ impl ClickhouseAdminApi for ClickhouseAdminImpl { let output = ctx.clickward().clickhouse_address()?; Ok(HttpResponseOk(output)) } + + async fn generate_server_config( + rqctx: RequestContext, + body: TypedBody, + ) -> Result, HttpError> { + let ctx = rqctx.context(); + let server_settings = body.into_inner(); + let output = ctx.clickward().generate_server_config(server_settings)?; + Ok(HttpResponseCreated(output)) + } } diff --git a/openapi/clickhouse-admin.json b/openapi/clickhouse-admin.json index 6bb5367712..bcc98da6cb 100644 --- a/openapi/clickhouse-admin.json +++ b/openapi/clickhouse-admin.json @@ -12,7 +12,7 @@ "paths": { "/node/address": { "get": { - "summary": "Retrieve the address the ClickHouse server or keeper node is listening on", + "summary": "Retrieve the address the ClickHouse server or keeper node is listening on.", "operationId": "clickhouse_address", "responses": { "200": { @@ -33,6 +33,41 @@ } } } + }, + "/server-node/generate-config": { + "post": { + "summary": "Generate a ClickHouse configuration file for a server node on a specified", + "description": "directory.", + "operationId": "generate_server_config", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServerSettings" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "successful creation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServerConfigGenerateResponse" + } + } + } + }, + "4XX": { + "$ref": "#/components/responses/Error" + }, + "5XX": { + "$ref": "#/components/responses/Error" + } + } + } } }, "components": { @@ -66,6 +101,31 @@ "message", "request_id" ] + }, + "ServerConfigGenerateResponse": { + "description": "Success response for server node configuration file generation", + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ] + }, + "ServerSettings": { + "type": "object", + "properties": { + "node_id": { + "type": "integer", + "format": "uint64", + "minimum": 0 + } + }, + "required": [ + "node_id" + ] } }, "responses": {