summaryrefslogtreecommitdiffstats
path: root/tedge
diff options
context:
space:
mode:
authorMatthias Beyer <matthias.beyer@ifm.com>2022-03-15 14:31:44 +0100
committerMatthias Beyer <matthias.beyer@ifm.com>2022-03-17 10:24:55 +0100
commit09eaab7b8a1c4cb5faee50f893c2061d994347c3 (patch)
tree3c5e1493822b9864198f3ecd165655e50ee45344 /tedge
parent07c50a1495fddf57bbae41003671a694d59a0427 (diff)
Add tedge-cli binary
Signed-off-by: Matthias Beyer <matthias.beyer@ifm.com>
Diffstat (limited to 'tedge')
-rw-r--r--tedge/Cargo.toml44
-rw-r--r--tedge/example-config.toml53
-rw-r--r--tedge/src/cli.rs27
-rw-r--r--tedge/src/logging.rs25
-rw-r--r--tedge/src/main.rs156
5 files changed, 305 insertions, 0 deletions
diff --git a/tedge/Cargo.toml b/tedge/Cargo.toml
new file mode 100644
index 00000000..b6d80a75
--- /dev/null
+++ b/tedge/Cargo.toml
@@ -0,0 +1,44 @@
+[package]
+name = "tedge-cli"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+clap = { version = "3", features = ["derive", "cargo", "suggestions"] }
+anyhow = "1"
+toml = "0.5.8"
+tokio = { version = "1", features = ["fs", "macros", "rt-multi-thread", "signal"] }
+cfg-if = "1"
+tracing = "0.1"
+tracing-subscriber = { version = "0.3", features = ["env-filter"], optional = true }
+console-subscriber = { version = "0.1", optional = true }
+
+tedge_api = { path = "../crates/core/tedge_api" }
+tedge_core = { path = "../crates/core/tedge_core" }
+
+env_logger = { version = "0.9", optional = true }
+
+plugin_avg = { path = "../plugins/plugin_avg", optional = true }
+plugin_log = { path = "../plugins/plugin_log", optional = true }
+plugin_sysstat = { path = "../plugins/plugin_sysstat", optional = true }
+plugin_inotify = { path = "../plugins/plugin_inotify", optional = true }
+
+
+[features]
+default = [
+ "core_logging",
+ "builtin_plugin_avg",
+ "builtin_plugin_log",
+ "builtin_plugin_sysstat",
+ "builtin_plugin_inotify",
+]
+
+core_debugging = ["console-subscriber"]
+core_logging = ["tracing-subscriber"]
+builtin_plugin_avg = ["plugin_avg"]
+builtin_plugin_log = ["plugin_log"]
+builtin_plugin_sysstat = ["plugin_sysstat"]
+builtin_plugin_inotify = ["plugin_inotify"]
+
diff --git a/tedge/example-config.toml b/tedge/example-config.toml
new file mode 100644
index 00000000..8a60fb05
--- /dev/null
+++ b/tedge/example-config.toml
@@ -0,0 +1,53 @@
+communication_buffer_size = 10
+
+[plugins]
+
+
+[plugins.logging]
+kind = "log"
+
+[plugins.logging.configuration]
+name = "logging"
+level = "trace"
+acknowledge = false
+setup_logger = false
+
+
+[plugins.syscpu]
+kind = "sysinfo"
+
+[plugins.syscpu.configuration.cpu]
+send_to = ["logging"]
+interval_ms = 1000
+
+
+[plugins.syscpu.configuration.cpu.report_global_processor_info]
+enable = true
+frequency = true
+cpu_usage = true
+name = true
+vendor_id = true
+brand = true
+
+[plugins.syscpu.configuration.cpu.report_processor_info]
+enable = false
+frequency = false
+cpu_usage = false
+name = false
+vendor_id = false
+brand = false
+
+[plugins.syscpu.configuration.cpu.report_physical_core_count]
+enable = true
+
+
+[plugins.watchcargotoml]
+kind = "inotify"
+
+[plugins.watchcargotoml.configuration]
+target = "logging"
+fail_on_err = false
+
+[plugins.watchcargotoml.configuration.pathes]
+"Cargo.toml" = [ "ALL_EVENTS" ]
+
diff --git a/tedge/src/cli.rs b/tedge/src/cli.rs
new file mode 100644
index 00000000..27c99526
--- /dev/null
+++ b/tedge/src/cli.rs
@@ -0,0 +1,27 @@
+use std::path::PathBuf;
+
+#[derive(Debug, clap::Parser)]
+#[clap(
+ name = clap::crate_name!(),
+ version = clap::crate_version!(),
+ about = clap::crate_description!()
+)]
+pub(crate) struct Cli {
+ #[clap(short, long)]
+ pub(crate) verbose: bool,
+
+ #[clap(short, long)]
+ pub(crate) debug: bool,
+
+ #[clap(subcommand)]
+ pub(crate) command: CliCommand,
+}
+
+#[derive(Debug, clap::Subcommand)]
+pub(crate) enum CliCommand {
+ #[clap(name = "run")]
+ Run { config: PathBuf },
+
+ #[clap(name = "validate-config")]
+ ValidateConfig { config: PathBuf },
+}
diff --git a/tedge/src/logging.rs b/tedge/src/logging.rs
new file mode 100644
index 00000000..26e3e1a4
--- /dev/null
+++ b/tedge/src/logging.rs
@@ -0,0 +1,25 @@
+#[allow(unused)]
+pub(crate) fn setup_logging(verbose: bool, debugging: bool) -> anyhow::Result<()> {
+ #[cfg(all(feature = "core_logging", not(feature = "core_debugging")))]
+ {
+ use tracing_subscriber::filter::EnvFilter;
+ use tracing_subscriber::filter::LevelFilter;
+
+ let filter = if verbose && !debugging {
+ EnvFilter::from_default_env().add_directive(LevelFilter::INFO.into())
+ } else if debugging {
+ EnvFilter::from_default_env().add_directive(LevelFilter::DEBUG.into())
+ } else {
+ EnvFilter::from_default_env()
+ };
+
+ let subscriber = tracing_subscriber::fmt::Subscriber::builder()
+ .with_env_filter(filter)
+ .finish();
+
+ tracing::subscriber::set_global_default(subscriber)
+ .map_err(|e| anyhow::anyhow!("Failed to set global subscriber: {:?}", e))?;
+ }
+
+ Ok(())
+}
diff --git a/tedge/src/main.rs b/tedge/src/main.rs
new file mode 100644
index 00000000..7922f220
--- /dev/null
+++ b/tedge/src/main.rs
@@ -0,0 +1,156 @@
+use std::collections::HashSet;
+
+use clap::Parser;
+
+use tedge_api::PluginBuilder;
+use tedge_core::configuration::TedgeConfiguration;
+use tedge_core::TedgeApplication;
+use tedge_core::TedgeApplicationCancelSender;
+use tracing::debug;
+use tracing::error;
+use tracing::info;
+use tracing::trace;
+
+mod cli;
+mod logging;
+
+#[tokio::main]
+#[tracing::instrument]
+async fn main() -> anyhow::Result<()> {
+ #[cfg(feature = "core_debugging")]
+ {
+ console_subscriber::init();
+ }
+ let args = crate::cli::Cli::parse();
+ crate::logging::setup_logging(args.verbose, args.debug)?;
+ info!("Tedge booting...");
+ debug!("Tedge CLI: {:?}", args);
+ let config = match args.command {
+ cli::CliCommand::Run { ref config } => config,
+ cli::CliCommand::ValidateConfig { ref config } => config,
+ };
+
+ let configuration = tokio::fs::read_to_string(config).await?;
+
+ let config: TedgeConfiguration = toml::de::from_str(&configuration)?;
+ info!("Configuration loaded.");
+
+ let application = TedgeApplication::builder();
+ let mut plugin_kinds = HashSet::new();
+ info!("Building application");
+
+ macro_rules! register_plugin {
+ ($app:ident, $cfg:tt, $pluginbuilder:expr) => {{
+ cfg_if::cfg_if! {
+ if #[cfg(feature = $cfg)] {
+ info!("Registering plugin builder for plugins of type {}", $pluginbuilder.kind_name());
+ if !plugin_kinds.insert($pluginbuilder.kind_name()) {
+ anyhow::bail!("Plugin kind '{}' was already registered, cannot register!", $pluginbuilder.kind_name())
+ }
+ $app.with_plugin_builder(Box::new($pluginbuilder))?
+ } else {
+ trace!("Not supporting plugins of type {}", std::stringify!($pluginbuilder));
+ $app
+ }
+ }
+ }}
+ }
+
+ let application = register_plugin!(
+ application,
+ "builtin_plugin_avg",
+ plugin_avg::AvgPluginBuilder
+ );
+ let application = register_plugin!(
+ application,
+ "builtin_plugin_log",
+ plugin_log::LogPluginBuilder
+ );
+ let application = register_plugin!(
+ application,
+ "builtin_plugin_sysstat",
+ plugin_sysstat::SysStatPluginBuilder
+ );
+ let application = register_plugin!(
+ application,
+ "builtin_plugin_inotify",
+ plugin_inotify::InotifyPluginBuilder
+ );
+
+ let (cancel_sender, application) = application.with_config(config)?;
+ info!("Application built");
+
+ match args.command {
+ cli::CliCommand::Run { .. } => {
+ debug!("Going to validate the configuration and run the application");
+
+ validate_config(&application).await?;
+ info!("Configuration validated");
+
+ run(cancel_sender, application).await
+ }
+ cli::CliCommand::ValidateConfig { .. } => {
+ debug!("Only going to validate the configuration");
+ validate_config(&application).await?;
+ info!("Configuration validated");
+ Ok(())
+ }
+ }
+}
+
+async fn run(
+ cancel_sender: TedgeApplicationCancelSender,
+ application: TedgeApplication,
+) -> anyhow::Result<()> {
+ info!("Booting app now.");
+ let mut run_fut = Box::pin(application.run());
+
+ let kill_app = |fut| -> anyhow::Result<()> {
+ error!("Killing application");
+ drop(fut);
+ anyhow::bail!("Application killed")
+ };
+
+ let res = tokio::select! {
+ res = &mut run_fut => {
+ res.map_err(anyhow::Error::from)
+ },
+
+ _int = tokio::signal::ctrl_c() => {
+ if !cancel_sender.is_cancelled() {
+ info!("Shutting down...");
+ cancel_sender.cancel_app();
+ tokio::select! {
+ res = &mut run_fut => res.map_err(anyhow::Error::from),
+ _ = tokio::signal::ctrl_c() => kill_app(run_fut),
+ }
+ } else {
+ kill_app(run_fut)
+ }
+ },
+ };
+
+ info!("Bye");
+ res
+}
+
+async fn validate_config(application: &TedgeApplication) -> anyhow::Result<()> {
+ let mut any_err = false;
+ for (plugin_name, res) in application.verify_configurations().await {
+ match res {
+ Err(e) => {
+ error!("Error in Plugin '{}' configuration: {:?}", plugin_name, e);
+ any_err = true;
+ }
+ Ok(_) => {
+ info!("Plugin '{}' configured correctly", plugin_name);
+ }
+ }
+ }
+
+ if any_err {
+ Err(anyhow::anyhow!("Plugin configuration error"))
+ } else {
+ Ok(())
+ }
+}