diff --git a/.gitignore b/.gitignore index 40dd2ff..c69fa41 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ /target .idea +/.env Cargo.lock -hagent_test.sock \ No newline at end of file +hagent_test.sock +release diff --git a/Dockerfile b/Dockerfile index ee3f295..b5128cd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:latest +FROM ubuntu:22.04 USER root @@ -9,6 +9,9 @@ RUN apt update && apt install -y \ pkg-config \ libudev-dev \ procps \ + gcc-riscv64-unknown-elf \ + gcc-riscv64-linux-gnu \ + binutils-riscv64-linux-gnu \ && rm -rf /var/lib/apt/lists/* RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y diff --git a/Jenkinsfile b/Jenkinsfile index c11e198..d3043e2 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,22 +1,22 @@ pipeline { agent any stages { - stage('Tests and compiling binaries1') { + stage('Tests and compiling binaries') { when { - expression { env.CHANGE_BRANCH?.startsWith('feature/') } + expression { env.CHANGE_BRANCH?.startsWith('feature/') || env.CHANGE_BRANCH?.startsWith('rc') } } steps { script { echo "Building and running tests in Docker for feature branch..." try { - def targetDirAmd = "${env.WORKSPACE}/${env.CHANGE_BRANCH}/x86" - def targetDirRisc = "${env.WORKSPACE}/${env.CHANGE_BRANCH}/riscv" + def targetDirAmd = "${env.WORKSPACE}/${env.CHANGE_BRANCH}/amd64" + def targetDirRisc = "${env.WORKSPACE}/${env.CHANGE_BRANCH}/riscv64" - sh "mkdir -p ${targetDir}" + sh "mkdir -p ${targetDirAmd}" + sh "mkdir -p ${targetDirRisc}" sh """ docker build --network=host -t e-monitor . - docker run --name e-monitor --dns 8.8.8.8 --network=host e-monitor:latest """ @@ -29,7 +29,6 @@ pipeline { sh "docker cp e-monitor:/usr/src/kii/target/riscv64gc-unknown-linux-gnu/release/noxis-cli ${targetDirRisc}" sh "docker cp e-monitor:/usr/src/kii/target/riscv64gc-unknown-linux-gnu/release/noxis-rs ${targetDirRisc}" - sh "docker stop e-monitor && docker rm e-monitor" echo "Tests passed successfully and binaries were extracted!" } catch (Exception e) { echo "Tests failed during Docker run." @@ -39,13 +38,111 @@ pipeline { } } + stage('Calculate Install Size') { + when { + expression { env.CHANGE_BRANCH?.startsWith('rc') } + } + steps { + script { + echo "Calculating installation size for rc branch..." + def targetDirAmd = "${env.WORKSPACE}/${env.CHANGE_BRANCH}/amd64" + def targetDirRisc = "${env.WORKSPACE}/${env.CHANGE_BRANCH}/riscv64" + + def installSizeAmd = sh(script: "du -s --block-size=1024 ${targetDirAmd} | awk '{print \$1}'", returnStdout: true).trim() + def installSizeRisc = sh(script: "du -s --block-size=1024 ${targetDirRisc} | awk '{print \$1}'", returnStdout: true).trim() + + env.INSTALL_SIZE_AMD = installSizeAmd + env.INSTALL_SIZE_RISC = installSizeRisc + + echo "Installation size for amd64: ${env.INSTALL_SIZE_AMD} kB" + echo "Installation size for riscv64: ${env.INSTALL_SIZE_RISC} kB" + } + } + } + + stage('Create Deb Packages') { + when { + expression { env.CHANGE_BRANCH?.startsWith('rc') } + } + steps { + script { + echo "Creating deb packages for rc branch..." + + def targetDirAmd = "${env.WORKSPACE}/${env.CHANGE_BRANCH}/amd64" + def targetDirRisc = "${env.WORKSPACE}/${env.CHANGE_BRANCH}/riscv64" + def packageName = "noxis" + def version = sh(script: "git describe --tags --abbrev=0", returnStdout: true).trim() + def createDebPackage = { arch, binDir, targetDir, installSize -> + echo "Creating deb package for ${arch}..." + + sh """ + mkdir -p ${targetDir}/package/DEBIAN + mkdir -p ${targetDir}/package/usr/local/enode/${packageName} + mkdir -p ${targetDir}/package/usr/bin + mkdir -p ${targetDir}/package/etc/enode + mkdir -p ${targetDir}/package/lib/systemd/system + + cp ${binDir}/noxis-cli ${targetDir}/package/usr/local/enode/${packageName}/ + cp ${binDir}/noxis-rs ${targetDir}/package/usr/local/enode/${packageName}/ + cp ${binDir}/settings.json ${targetDir}/package/etc/enode/ + + cat > ${targetDir}/package/DEBIAN/control < +Description: Noxis Agent Linux +Installed-Size: ${installSize} +EOF + + chmod +x ${targetDir}/package/usr/local/enode/${packageName}/noxis-cli + chmod +x ${targetDir}/package/usr/local/enode/${packageName}/noxis-rs + + cat > ${targetDir}/package/DEBIAN/postinst < ${targetDir}/package/lib/systemd/system/${packageName}.service < +# Поддерживаемые архитектуры: amd64, riscv64 + +if [ -z "$1" ]; then + echo "Ошибка: Необходимо указать архитектуру (например, amd64 или riscv64)." + exit 1 +fi + +ARCH="$1" +TARGET_DIR="release/${ARCH}" +CONTAINER_NAME="e-monitor" + +SUPPORTED_ARCHS=("amd64" "riscv64") +if [[ ! " ${SUPPORTED_ARCHS[@]} " =~ " ${ARCH} " ]]; then + echo "Ошибка: Неизвестная архитектура $ARCH. Допустимые значения: ${SUPPORTED_ARCHS[*]}." + exit 1 +fi + +# На случай, если контейнер с таким именем уже существует +docker stop e-monitor && docker rm e-monitor + +echo "Building Docker image..." + +docker build --network=host -t e-monitor . || { + echo "Ошибка: Не удалось построить Docker-образ." + exit 1 +} + +echo "Running Docker container..." + +docker run --name "$CONTAINER_NAME" --dns 8.8.8.8 --network=host e-monitor:latest || { + echo "Ошибка: Не удалось запустить Docker-контейнер." + exit 1 +} + +echo "Creating target directory: $TARGET_DIR" +mkdir -p "$TARGET_DIR" + +case "$ARCH" in + amd64) + echo "Copying binaries for architecture: amd64" + docker cp "$CONTAINER_NAME:/usr/src/kii/target/x86_64-unknown-linux-gnu/release/noxis-cli" "$TARGET_DIR/" || { + echo "Ошибка: Не удалось скопировать noxis-cli для amd64." + docker stop "$CONTAINER_NAME" && docker rm "$CONTAINER_NAME" + exit 1 + } + docker cp "$CONTAINER_NAME:/usr/src/kii/target/x86_64-unknown-linux-gnu/release/noxis-rs" "$TARGET_DIR/" || { + echo "Ошибка: Не удалось скопировать noxis-rs для amd64." + docker stop "$CONTAINER_NAME" && docker rm "$CONTAINER_NAME" + exit 1 + } + ;; + riscv64) + echo "Copying binaries for architecture: riscv64" + docker cp "$CONTAINER_NAME:/usr/src/kii/target/riscv64gc-unknown-linux-gnu/release/noxis-cli" "$TARGET_DIR/" || { + echo "Ошибка: Не удалось скопировать noxis-cli для riscv64." + docker stop "$CONTAINER_NAME" && docker rm "$CONTAINER_NAME" + exit 1 + } + docker cp "$CONTAINER_NAME:/usr/src/kii/target/riscv64gc-unknown-linux-gnu/release/noxis-rs" "$TARGET_DIR/" || { + echo "Ошибка: Не удалось скопировать noxis-rs для riscv64." + docker stop "$CONTAINER_NAME" && docker rm "$CONTAINER_NAME" + exit 1 + } + ;; +esac + +echo "Stopping and removing Docker container..." +docker stop "$CONTAINER_NAME" && docker rm "$CONTAINER_NAME" + +echo "Build and extraction completed successfully for architecture: $ARCH" +exit 0 diff --git a/noxis-cli/Cargo.toml b/noxis-cli/Cargo.toml index 22666eb..4c34412 100644 --- a/noxis-cli/Cargo.toml +++ b/noxis-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "noxis-cli" -version = "0.1.6" +version = "0.2.4" edition = "2021" [dependencies] @@ -8,4 +8,5 @@ anyhow = "1.0.94" clap = { version = "4.5.22", features = ["derive"] } serde = { version = "1.0.215", features = ["derive"] } serde_json = "1.0.133" +thiserror = "2.0.11" tokio = { version = "1.42.0", features = ["full", "net"] } diff --git a/noxis-cli/src/cli_error.rs b/noxis-cli/src/cli_error.rs new file mode 100644 index 0000000..bb3a8bd --- /dev/null +++ b/noxis-cli/src/cli_error.rs @@ -0,0 +1,14 @@ +use thiserror::Error; +use super::cli_net::NOXIS_RS_CREDS; + +#[derive(Debug, Error)] +pub enum NoxisCliError { + #[error("Can't send any data to {:?}. Noxis-rs daemon is disabled or can't be accessed", NOXIS_RS_CREDS)] + NoxisDaemonMissing, + #[error("Noxis CLI can't write any data to the Noxis-rs port. Check daemon and it's web-functionality")] + PortIsNotWritable, + #[error("Can't send Cli-prompt to the Noxis-rs. Check it's state")] + CliPromptCanNotBeSent, + #[error("Can't parse CLI struct and send as byte stream")] + ToStringCliParsingParsing, +} \ No newline at end of file diff --git a/noxis-cli/src/net.rs b/noxis-cli/src/cli_net.rs similarity index 59% rename from noxis-cli/src/net.rs rename to noxis-cli/src/cli_net.rs index 2e8c43a..b0fbfe7 100644 --- a/noxis-cli/src/net.rs +++ b/noxis-cli/src/cli_net.rs @@ -3,26 +3,28 @@ use tokio::io::AsyncWriteExt; use tokio::time::{Duration, sleep}; use anyhow::Result; use super::Cli; +use super::cli_error::NoxisCliError; + +pub const NOXIS_RS_CREDS: &str = "127.0.0.1:7753"; pub async fn create_tcp_stream() -> Result { - let stream = TcpStream::connect("127.0.0.1:7753").await?; - Ok(stream) + Ok(TcpStream::connect(NOXIS_RS_CREDS).await.map_err(|_| NoxisCliError::NoxisDaemonMissing)?) } pub async fn try_send(stream: Result, params: Cli) -> Result<()> { use serde_json::to_string; - let mut stream = stream?; + let mut stream = stream.map_err(|_| NoxisCliError::NoxisDaemonMissing)?; loop { if stream.writable().await.is_err() { sleep(Duration::from_millis(100)).await; continue; } // let msg: Cli = from_str(&format!("{:?}", params))?; - let msg= to_string(¶ms)?; + let msg= to_string(¶ms).map_err(|_| NoxisCliError::ToStringCliParsingParsing)?; // let msg = r"HTTP/1.1 POST\r\nContent-Length: 14\r\nContent-Type: text/plain\r\n\r\nHello, World!@"; - stream.write_all(msg.as_bytes()).await?; + stream.write_all(msg.as_bytes()).await.map_err(|_| NoxisCliError::CliPromptCanNotBeSent)?; // ... break; } diff --git a/noxis-cli/src/lib.rs b/noxis-cli/src/lib.rs index 163fc0a..5515aa9 100644 --- a/noxis-cli/src/lib.rs +++ b/noxis-cli/src/lib.rs @@ -1,3 +1,5 @@ mod cli; +mod cli_net; +mod cli_error; pub use cli::*; \ No newline at end of file diff --git a/noxis-cli/src/main.rs b/noxis-cli/src/main.rs index 0b9e00f..9262502 100644 --- a/noxis-cli/src/main.rs +++ b/noxis-cli/src/main.rs @@ -1,9 +1,10 @@ mod cli; -mod net; +mod cli_net; +mod cli_error; use clap::Parser; use cli::Cli; -use net::{create_tcp_stream, try_send}; +use cli_net::{create_tcp_stream, try_send}; use anyhow::Result; #[tokio::main] diff --git a/noxis-rs/Cargo.toml b/noxis-rs/Cargo.toml index 62c917f..0745074 100644 --- a/noxis-rs/Cargo.toml +++ b/noxis-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "noxis-rs" -version = "0.11.3" +version = "0.11.10" edition = "2021" [dependencies] @@ -17,3 +17,4 @@ serde_json = "1.0.118" sysinfo = "0.32.0" tokio = { version = "1.38.0", features = ["full", "time"] } noxis-cli = { path = "../noxis-cli" } +dotenv = "0.15.0" diff --git a/noxis-rs/settings.json b/noxis-rs/settings.json index 8fb8d10..f830fce 100644 --- a/noxis-rs/settings.json +++ b/noxis-rs/settings.json @@ -31,4 +31,3 @@ } ] } - diff --git a/noxis-rs/src/main.rs b/noxis-rs/src/main.rs index 556521e..29886c8 100644 --- a/noxis-rs/src/main.rs +++ b/noxis-rs/src/main.rs @@ -18,11 +18,6 @@ use options::preboot::PrebootParams; #[tokio::main(flavor = "multi_thread")] async fn main() -> anyhow::Result<()>{ let preboot = Arc::new(PrebootParams::parse().validate()?); - - // if let Err(_) = preboot { - // return; - // } - // let preboot = Arc::new(preboot); let _ = setup_logger(); diff --git a/noxis-rs/src/options/config.rs b/noxis-rs/src/options/config.rs index 0bc5ecc..d9451b9 100644 --- a/noxis-rs/src/options/config.rs +++ b/noxis-rs/src/options/config.rs @@ -7,7 +7,6 @@ use std::os::unix::process::CommandExt; use std::process::Command; use std::sync::Arc; use std::{env, fs}; -// use std::fmt::format; use super::preboot::PrebootParams; use tokio::time::{Duration, sleep}; @@ -336,7 +335,6 @@ pub async fn subscribe_config_stream(actual_prcs: Arc, params: Arc = msg.get_payload(); match get_remote_config { Ok(payload) => { @@ -353,7 +351,10 @@ pub async fn subscribe_config_stream(actual_prcs: Arc, params: Arc continue, + _ => { + warn!("Pulled new config. Current config is more actual ..."); + continue + }, } } else { diff --git a/noxis-rs/src/options/preboot.rs b/noxis-rs/src/options/preboot.rs index 8130e96..8293f8a 100644 --- a/noxis-rs/src/options/preboot.rs +++ b/noxis-rs/src/options/preboot.rs @@ -3,14 +3,96 @@ use anyhow::{Result, Ok, Error}; use clap::Parser; use std::path::PathBuf; +use std::env::var; +use dotenv::dotenv; const SOCKET_PATH: &str = "/var/run/enode/hostagent.sock"; +/// +enum EnvVars { + NoxisNoHagent, + NoxisNoLogs, + NoxisRefreshLogs, + NoxisNoRemoteConfig, + NoxisNoConfigSub, + NoxisSocketPath, + NoxisLogTo, + NoxisRemoteServerUrl, + NoxisConfig, + NoxisMetrics, +} + +/// +impl std::fmt::Display for EnvVars { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + EnvVars::NoxisNoHagent => write!(f, "NOXIS_NO_HAGENT"), + EnvVars::NoxisNoLogs => write!(f, "NOXIS_NO_LOGS"), + EnvVars::NoxisRefreshLogs => write!(f, "NOXIS_REFRESH_LOGS"), + EnvVars::NoxisNoRemoteConfig => write!(f, "NOXIS_NO_REMOTE_CONFIG"), + EnvVars::NoxisNoConfigSub => write!(f, "NOXIS_NO_CONFIG_SUB"), + EnvVars::NoxisSocketPath => write!(f, "NOXIS_SOCKET_PATH"), + EnvVars::NoxisLogTo => write!(f, "NOXIS_LOG_TO"), + EnvVars::NoxisRemoteServerUrl => write!(f, "NOXIS_REMOTE_SERVER_URL"), + EnvVars::NoxisConfig => write!(f, "NOXIS_CONFIG"), + EnvVars::NoxisMetrics => write!(f, "NOXIS_METRICS"), + } + } +} + +/// +impl<'a> EnvVars { + // Default trait func is not satisfying this issue + fn default(self) -> &'a str { + match self { + EnvVars::NoxisNoHagent => "false", + EnvVars::NoxisNoLogs => "false", + EnvVars::NoxisRefreshLogs => "false", + EnvVars::NoxisNoRemoteConfig => "false", + EnvVars::NoxisNoConfigSub => "false", + EnvVars::NoxisSocketPath => "/var/run/enode/hostagent.sock", + EnvVars::NoxisLogTo => "./", + EnvVars::NoxisRemoteServerUrl => "localhost", + EnvVars::NoxisConfig => "./settings.json", + EnvVars::NoxisMetrics => "full", + } + } + fn process_env_var(self, preboot_value: &str) { + // let default = self.default(); + match var(self.to_string()) { + std::result::Result::Ok(val) => { + if val != preboot_value { + std::env::set_var(self.to_string(), self.default()); + } + }, + Err(_) => { + std::env::set_var(self.to_string(), preboot_value); + }, + } + } + pub fn setup(preboot: &PrebootParams) { + // setup default if not exists + // check values and save preboot states in env vars if not equal + + Self::NoxisNoHagent.process_env_var(&preboot.no_hostagent.to_string()); + Self::NoxisNoLogs.process_env_var(&preboot.no_logs.to_string()); + Self::NoxisRefreshLogs.process_env_var(&preboot.refresh_logs.to_string()); + Self::NoxisNoRemoteConfig.process_env_var(&preboot.no_remote_config.to_string()); + Self::NoxisNoConfigSub.process_env_var(&preboot.no_sub.to_string()); + Self::NoxisSocketPath.process_env_var(preboot.socket_path.to_str().unwrap()); + Self::NoxisLogTo.process_env_var(preboot.log_to.to_str().unwrap()); + Self::NoxisRemoteServerUrl.process_env_var(&preboot.remote_server_url); + Self::NoxisConfig.process_env_var(preboot.config.to_str().unwrap()); + Self::NoxisMetrics.process_env_var(&preboot.metrics.to_string()); + + } +} + /// # Enum `MetricsPrebootParams` /// ## for setting up metrics mode as preboot param from command prompt /// /// examples: -/// ``` +/// ``` bash /// noxis-rs ... --metrics full /// noxis-rs ... --metrics system /// noxis-rs ... --metrics processes @@ -187,6 +269,7 @@ pub struct PrebootParams { /// ## to enable validation mechanism impl PrebootParams { pub fn validate(mut self) -> Result { + dotenv().ok(); if !self.socket_path.exists() && !self.no_hostagent { if self.socket_path.to_string_lossy() == SOCKET_PATH { self.no_hostagent = true; @@ -211,10 +294,15 @@ impl PrebootParams { // existing sock file if !self.config.exists() { eprintln!("Error: Invalid character in config file. Config path was set to default"); + let config = PathBuf::from("/etc/settings.json"); + if !config.exists() && self.no_remote_config { + return Err(Error::msg("Noxis cannot run without config. Create local config or enable remote-config mechanism")); + } self.config = PathBuf::from("settings.json"); // return Err(Error::msg("Local Config Not Found or Noxis can't read it. Cannot start")); } // redis server check + EnvVars::setup(&self); Ok(self) } }