Skip to content

Commit

Permalink
Update giganto_config to respond full configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
BLYKIM committed Sep 4, 2024
1 parent 8743129 commit c779eb8
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 198 deletions.
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,14 @@ Versioning](https://semver.org/spec/v2.0.0.html).
integers beyond `i32`.
- Changed the `from_key_value` macro to additionally receive `str_num_field`
for `StringNumber` conversion.
- Changed to support command line interface.
- Changed command line interface.
- Removed `cert`, `key`, `root` fields from config file.
- Changed `set_giganto_config` to receive toml-string with full configuration.
- Added cli options `-c`, `--cert`, `--key` and `--ca-certs`.
- The `--ca-certs` option now supports receiving one or multiple CA
certificate paths. You can provide a single certificate path or specify
multiple paths separated by spaces.
- Changed `setGigantoConfig` to receive toml-string with full configuration.
- Updated `gigantoConfig` to respond full configuration.

## [0.20.0] - 2024-05-17

Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ directories = "5.0"
futures-util = "0.3"
giganto-client = { git = "https://github.com/aicers/giganto-client.git", rev = "cc83f71" }
graphql_client = "0.14"
humantime = "2.1"
humantime-serde = "1"
libc = "0.2"
num_enum = "0.7"
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ processing and real-time analytics.
You can run giganto by invoking the following command:

```sh
giganto --cert <CERT_PATH> --key <KEY_PATH> --ca <CA_PATH> <CENTRAL_SERVER>
giganto --cert <CERT_PATH> --key <KEY_PATH> --ca-certs <CA_CERT_PATH1> <CA_CERT_PATH2>
```

If you want to run giganto with local configuration file,

```sh
giganto -c <CONFIG_PATH> --cert <CERT_PATH> --key <KEY_PATH> --ca <CA_PATH> <CENTRAL_SERVER>
giganto -c <CONFIG_PATH> --cert <CERT_PATH> --key <KEY_PATH> --ca-certs \
<CA_CERT_PATH1> <CA_CERT_PATH2> ...
```

In the config file, you can specify the following options:
Expand Down Expand Up @@ -77,7 +78,7 @@ certificate/key from the tests folder.)

```sh
cargo run -- -c tests/node1/config.toml --cert tests/node1/cert.pem \
--key tests/node1/key.pem --root tests/root.pem hostname@address
--key tests/node1/key.pem --ca-certs tests/ca_cert.pem
```

## License
Expand Down
182 changes: 84 additions & 98 deletions src/graphql/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,18 @@ use std::{
use anyhow::{anyhow, Context as ct};
use async_graphql::{Context, InputObject, Object, Result, SimpleObject};
use toml_edit::{value, DocumentMut, InlineTable};
use tracing::info;

use super::{PowerOffNotify, RebootNotify, ReloadNotify, TerminateNotify};
use crate::peer::PeerIdentity;
use crate::settings::GigantoConfig;
#[cfg(debug_assertions)]
use crate::storage::Database;
use crate::AckTransmissionCount;

const GRAPHQL_REBOOT_DELAY: u64 = 100;
const CONFIG_INGEST_SRV_ADDR: &str = "ingest_srv_addr";
pub const CONFIG_PUBLISH_SRV_ADDR: &str = "publish_srv_addr";
pub const CONFIG_GRAPHQL_SRV_ADDR: &str = "graphql_srv_addr";
const CONFIG_RETENTION: &str = "retention";
const CONFIG_MAX_OPEN_FILES: &str = "max_open_files";
const CONFIG_MAX_MB_OF_LEVEL_BASE: &str = "max_mb_of_level_base";
const CONFIG_ADDR_TO_PEERS: &str = "addr_to_peers";
const CONFIG_PEER_LIST: &str = "peers";
const CONFIG_ACK_TRANSMISSION: &str = "ack_transmission";
pub const TEMP_TOML_POST_FIX: &str = ".temp.toml";

Expand Down Expand Up @@ -52,33 +49,74 @@ struct Properties {
stats: String,
}

#[derive(InputObject, SimpleObject, Debug)]
#[graphql(input_name = "InputPeerList")]
pub struct PeerList {
pub addr: String,
pub hostname: String,
}
#[Object]

Check warning on line 52 in src/graphql/status.rs

View check run for this annotation

Codecov / codecov/patch

src/graphql/status.rs#L52

Added line #L52 was not covered by tests
impl GigantoConfig {
async fn ingest_srv_addr(&self) -> String {
self.ingest_srv_addr.to_string()
}

impl TomlPeers for PeerList {
fn get_hostname(&self) -> String {
self.hostname.clone()
async fn publish_srv_addr(&self) -> String {
self.publish_srv_addr.to_string()
}

async fn graphql_srv_addr(&self) -> String {
self.graphql_srv_addr.to_string()
}

async fn retention(&self) -> String {
humantime::format_duration(self.retention).to_string()
}

async fn data_dir(&self) -> String {
self.data_dir.to_string_lossy().to_string()
}

async fn log_dir(&self) -> String {
self.log_dir.to_string_lossy().to_string()
}

async fn export_dir(&self) -> String {
self.export_dir.to_string_lossy().to_string()
}
fn get_addr(&self) -> String {
self.addr.clone()

async fn max_open_files(&self) -> i32 {
self.max_open_files
}

async fn max_mb_of_level_base(&self) -> u64 {
self.max_mb_of_level_base
}

async fn num_of_thread(&self) -> i32 {
self.num_of_thread
}

async fn max_sub_compactions(&self) -> u32 {
self.max_sub_compactions
}

async fn addr_to_peers(&self) -> Option<String> {
self.addr_to_peers.map(|addr| addr.to_string())

Check warning on line 99 in src/graphql/status.rs

View check run for this annotation

Codecov / codecov/patch

src/graphql/status.rs#L99

Added line #L99 was not covered by tests
}

async fn peers(&self) -> Option<Vec<PeerIdentity>> {
self.peers.clone().map(|peers| peers.into_iter().collect())

Check warning on line 103 in src/graphql/status.rs

View check run for this annotation

Codecov / codecov/patch

src/graphql/status.rs#L103

Added line #L103 was not covered by tests
}

async fn ack_transmission(&self) -> u16 {
self.ack_transmission
}
}

#[derive(SimpleObject, Debug)]
struct GigantoConfig {
ingest_srv_addr: String,
publish_srv_addr: String,
graphql_srv_addr: String,
retention: String,
max_open_files: i32,
max_mb_of_level_base: u64,
addr_to_peers: String,
peer_list: Vec<PeerList>,
ack_transmission_cnt: u16,
#[Object]

Check warning on line 111 in src/graphql/status.rs

View check run for this annotation

Codecov / codecov/patch

src/graphql/status.rs#L111

Added line #L111 was not covered by tests
impl PeerIdentity {
async fn addr(&self) -> String {
self.addr.to_string()
}

async fn hostname(&self) -> String {
self.hostname.clone()
}
}

#[derive(Default)]
Expand Down Expand Up @@ -125,55 +163,11 @@ impl GigantoStatusQuery {
#[allow(clippy::unused_async)]
async fn giganto_config<'ctx>(&self, ctx: &Context<'ctx>) -> Result<GigantoConfig> {
let cfg_path = ctx.data::<String>()?;
let doc = read_toml_file(cfg_path)?;
let ingest_srv_addr = parse_toml_element_to_string(CONFIG_INGEST_SRV_ADDR, &doc)?;
let publish_srv_addr = parse_toml_element_to_string(CONFIG_PUBLISH_SRV_ADDR, &doc)?;
let graphql_srv_addr = parse_toml_element_to_string(CONFIG_GRAPHQL_SRV_ADDR, &doc)?;
let retention = parse_toml_element_to_string(CONFIG_RETENTION, &doc)?;
let max_open_files = parse_toml_element_to_integer(CONFIG_MAX_OPEN_FILES, &doc)?;
let max_mb_of_level_base =
parse_toml_element_to_integer(CONFIG_MAX_MB_OF_LEVEL_BASE, &doc)?;
let ack_transmission_cnt = parse_toml_element_to_integer(CONFIG_ACK_TRANSMISSION, &doc)?;
let mut peer_list = Vec::new();
let addr_to_peers = if doc.get(CONFIG_ADDR_TO_PEERS).is_some() {
let peers_value = doc
.get(CONFIG_PEER_LIST)
.context("peers not found")?
.as_array()
.context("invalid peers format")?;
for peer in peers_value {
if let Some(peer_data) = peer.as_inline_table() {
let (Some(addr_val), Some(hostname_val)) =
(peer_data.get("addr"), peer_data.get("hostname"))
else {
return Err(anyhow!("Invalid `addr`, `hostname` Value format").into());
};
let (Some(addr), Some(hostname)) = (addr_val.as_str(), hostname_val.as_str())
else {
return Err(anyhow!("Invalid `addr`, `hostname` String format").into());
};
peer_list.push(PeerList {
addr: addr.to_string(),
hostname: hostname.to_string(),
});
}
}
parse_toml_element_to_string(CONFIG_ADDR_TO_PEERS, &doc)?
} else {
String::new()
};
let toml = fs::read_to_string(cfg_path).context("toml not found")?;

Check warning on line 166 in src/graphql/status.rs

View check run for this annotation

Codecov / codecov/patch

src/graphql/status.rs#L166

Added line #L166 was not covered by tests

Ok(GigantoConfig {
ingest_srv_addr,
publish_srv_addr,
graphql_srv_addr,
retention,
max_open_files,
max_mb_of_level_base,
addr_to_peers,
peer_list,
ack_transmission_cnt,
})
let config: GigantoConfig = toml::from_str(&toml)?;

Check warning on line 168 in src/graphql/status.rs

View check run for this annotation

Codecov / codecov/patch

src/graphql/status.rs#L168

Added line #L168 was not covered by tests

Ok(config)

Check warning on line 170 in src/graphql/status.rs

View check run for this annotation

Codecov / codecov/patch

src/graphql/status.rs#L170

Added line #L170 was not covered by tests
}

#[allow(clippy::unused_async)]
Expand All @@ -185,15 +179,22 @@ impl GigantoStatusQuery {
#[Object]
impl GigantoConfigMutation {
#[allow(clippy::unused_async)]
async fn set_giganto_config<'ctx>(
&self,
ctx: &Context<'ctx>,
config: String,
) -> Result<String> {
async fn set_giganto_config<'ctx>(&self, ctx: &Context<'ctx>, draft: String) -> Result<String> {
let config_draft: GigantoConfig = toml::from_str(&draft)?;

Check warning on line 183 in src/graphql/status.rs

View check run for this annotation

Codecov / codecov/patch

src/graphql/status.rs#L182-L183

Added lines #L182 - L183 were not covered by tests

let cfg_path = ctx.data::<String>()?;

let config_toml = fs::read_to_string(cfg_path).context("toml not found")?;
let config: GigantoConfig = toml::from_str(&config_toml)?;

Check warning on line 188 in src/graphql/status.rs

View check run for this annotation

Codecov / codecov/patch

src/graphql/status.rs#L187-L188

Added lines #L187 - L188 were not covered by tests

if config == config_draft {
info!("No changes. config: {config:?}, draft: {config_draft:?}");
return Err("No changes".to_string().into());
}

Check warning on line 193 in src/graphql/status.rs

View check run for this annotation

Codecov / codecov/patch

src/graphql/status.rs#L190-L193

Added lines #L190 - L193 were not covered by tests

let new_path = copy_toml_file(cfg_path)?;

fs::write(new_path, config)?;
fs::write(new_path, draft)?;

Check warning on line 197 in src/graphql/status.rs

View check run for this annotation

Codecov / codecov/patch

src/graphql/status.rs#L197

Added line #L197 was not covered by tests

let reload_notify = ctx.data::<ReloadNotify>()?;
let config_reload = reload_notify.0.clone();
Expand All @@ -203,6 +204,7 @@ impl GigantoConfigMutation {
tokio::time::sleep(Duration::from_millis(GRAPHQL_REBOOT_DELAY)).await;
config_reload.notify_one();
});
info!("Draft applied. config: {config:?}, draft: {config_draft:?}");

Check warning on line 207 in src/graphql/status.rs

View check run for this annotation

Codecov / codecov/patch

src/graphql/status.rs#L207

Added line #L207 was not covered by tests

Ok("Done".to_string())
}
Expand Down Expand Up @@ -281,22 +283,6 @@ pub fn parse_toml_element_to_string(key: &str, doc: &DocumentMut) -> Result<Stri
Ok(value.to_string())
}

fn parse_toml_element_to_integer<T>(key: &str, doc: &DocumentMut) -> Result<T>
where
T: std::convert::TryFrom<i64>,
{
let Some(item) = doc.get(key) else {
return Err(anyhow!("{} not found.", key).into());
};
let Some(value) = item.as_integer() else {
return Err(anyhow!("parse failed: {}'s item format is not available.", key).into());
};
let Ok(value) = T::try_from(value) else {
return Err(anyhow!("parse failed: {}'s value format is not available.", key).into());
};
Ok(value)
}

fn insert_toml_element<T>(key: &str, doc: &mut DocumentMut, input: Option<T>)
where
T: std::convert::Into<toml_edit::Value>,
Expand Down
10 changes: 5 additions & 5 deletions src/ingest/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ fn get_token() -> &'static Mutex<u32> {

const CERT_PATH: &str = "tests/certs/node1/cert.pem";
const KEY_PATH: &str = "tests/certs/node1/key.pem";
const ROOT_PATH: &str = "tests/certs/root.pem";
const CA_CERT_PATH: &str = "tests/certs/ca_cert.pem";
const HOST: &str = "node1";
const TEST_PORT: u16 = 60190;
const PROTOCOL_VERSION: &str = "0.21.0-alpha.2";
Expand Down Expand Up @@ -80,8 +80,8 @@ fn server() -> Server {
let cert = to_cert_chain(&cert_pem).unwrap();
let key_pem = fs::read(KEY_PATH).unwrap();
let key = to_private_key(&key_pem).unwrap();
let root_pem = fs::read(ROOT_PATH).unwrap();
let root = to_root_cert(&root_pem).unwrap();
let ca_cert_path = vec![CA_CERT_PATH.to_string()];
let root = to_root_cert(&ca_cert_path).unwrap();

let certs = Arc::new(Certs {
certs: cert,
Expand Down Expand Up @@ -130,8 +130,8 @@ fn init_client() -> Endpoint {
.collect::<Result<_, _>>()
.expect("invalid PEM-encoded certificate")
};
let root = fs::read(ROOT_PATH).expect("Failed to read file");
let server_root = to_root_cert(&root).unwrap();
let ca_cert_path = vec![CA_CERT_PATH.to_string()];
let server_root = to_root_cert(&ca_cert_path).unwrap();

let client_crypto = rustls::ClientConfig::builder()
.with_root_certificates(server_root)
Expand Down
Loading

0 comments on commit c779eb8

Please sign in to comment.