From eb74d4db31655b31fe944bf2dcedae60fc7d6884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Thu, 10 Oct 2024 09:59:11 +0100 Subject: [PATCH] feat(rust): add a simple API to register and run scripts --- rust/agama-lib/src/install_settings.rs | 4 +- rust/agama-lib/src/lib.rs | 1 + rust/agama-lib/src/scripts.rs | 32 +++++ rust/agama-lib/src/scripts/client.rs | 43 +++++++ rust/agama-lib/src/scripts/error.rs | 32 +++++ rust/agama-lib/src/scripts/model.rs | 162 +++++++++++++++++++++++++ rust/agama-lib/src/scripts/settings.rs | 40 ++++++ rust/agama-lib/src/scripts/store.rs | 51 ++++++++ rust/agama-lib/src/store.rs | 9 +- rust/agama-server/src/lib.rs | 1 + rust/agama-server/src/scripts.rs | 21 ++++ rust/agama-server/src/scripts/web.rs | 111 +++++++++++++++++ rust/agama-server/src/web.rs | 2 + 13 files changed, 507 insertions(+), 2 deletions(-) create mode 100644 rust/agama-lib/src/scripts.rs create mode 100644 rust/agama-lib/src/scripts/client.rs create mode 100644 rust/agama-lib/src/scripts/error.rs create mode 100644 rust/agama-lib/src/scripts/model.rs create mode 100644 rust/agama-lib/src/scripts/settings.rs create mode 100644 rust/agama-lib/src/scripts/store.rs create mode 100644 rust/agama-server/src/scripts.rs create mode 100644 rust/agama-server/src/scripts/web.rs diff --git a/rust/agama-lib/src/install_settings.rs b/rust/agama-lib/src/install_settings.rs index c5fbd2b8f..fad3c78d1 100644 --- a/rust/agama-lib/src/install_settings.rs +++ b/rust/agama-lib/src/install_settings.rs @@ -23,7 +23,7 @@ //! This module implements the mechanisms to load and store the installation settings. use crate::{ localization::LocalizationSettings, network::NetworkSettings, product::ProductSettings, - software::SoftwareSettings, users::UserSettings, + scripts::ScriptsSettings, software::SoftwareSettings, users::UserSettings, }; use serde::{Deserialize, Serialize}; use serde_json::value::RawValue; @@ -55,6 +55,8 @@ pub struct InstallSettings { pub network: Option, #[serde(default)] pub localization: Option, + #[serde(default)] + pub scripts: Option, } impl InstallSettings { diff --git a/rust/agama-lib/src/lib.rs b/rust/agama-lib/src/lib.rs index 6c86b035a..659b6505f 100644 --- a/rust/agama-lib/src/lib.rs +++ b/rust/agama-lib/src/lib.rs @@ -63,6 +63,7 @@ pub mod proxies; mod store; pub use store::Store; pub mod questions; +pub mod scripts; pub mod transfer; use crate::error::ServiceError; use reqwest::{header, Client}; diff --git a/rust/agama-lib/src/scripts.rs b/rust/agama-lib/src/scripts.rs new file mode 100644 index 000000000..2636b6f61 --- /dev/null +++ b/rust/agama-lib/src/scripts.rs @@ -0,0 +1,32 @@ +// Copyright (c) [2024] SUSE LLC +// +// All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, contact SUSE LLC. +// +// To contact SUSE LLC about this file by physical or electronic mail, you may +// find current contact information at www.suse.com. + +//! Implements support for handling the user-defined scripts. + +mod client; +mod error; +mod model; +mod settings; +mod store; + +pub use error::ScriptError; +pub use model::*; +pub use settings::*; +pub use store::ScriptsStore; diff --git a/rust/agama-lib/src/scripts/client.rs b/rust/agama-lib/src/scripts/client.rs new file mode 100644 index 000000000..bd750b0b6 --- /dev/null +++ b/rust/agama-lib/src/scripts/client.rs @@ -0,0 +1,43 @@ +// Copyright (c) [2024] SUSE LLC +// +// All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, contact SUSE LLC. +// +// To contact SUSE LLC about this file by physical or electronic mail, you may +// find current contact information at www.suse.com. + +use crate::{base_http_client::BaseHTTPClient, error::ServiceError}; + +use super::settings::ScriptSettings; + +pub struct ScriptsClient { + client: BaseHTTPClient, +} + +impl ScriptsClient { + pub fn new() -> Result { + Ok(Self { + client: BaseHTTPClient::new()?, + }) + } + + pub async fn add_script(&self, script: &ScriptSettings) -> Result<(), ServiceError> { + self.client.post_void("/scripts", script).await + } + + pub async fn run_scripts(&self) -> Result<(), ServiceError> { + self.client.post_void("/scripts/run", &()).await + } +} diff --git a/rust/agama-lib/src/scripts/error.rs b/rust/agama-lib/src/scripts/error.rs new file mode 100644 index 000000000..d6dbc3b3b --- /dev/null +++ b/rust/agama-lib/src/scripts/error.rs @@ -0,0 +1,32 @@ +// Copyright (c) [2024] SUSE LLC +// +// All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, contact SUSE LLC. +// +// To contact SUSE LLC about this file by physical or electronic mail, you may +// find current contact information at www.suse.com. + +use std::io; +use thiserror::Error; + +use crate::transfer::TransferError; + +#[derive(Error, Debug)] +pub enum ScriptError { + #[error("Could not fetch the profile: '{0}'")] + Unreachable(#[from] TransferError), + #[error("I/O error: '{0}'")] + InputOutputError(#[from] io::Error), +} diff --git a/rust/agama-lib/src/scripts/model.rs b/rust/agama-lib/src/scripts/model.rs new file mode 100644 index 000000000..401542b33 --- /dev/null +++ b/rust/agama-lib/src/scripts/model.rs @@ -0,0 +1,162 @@ +// Copyright (c) [2024] SUSE LLC +// +// All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, contact SUSE LLC. +// +// To contact SUSE LLC about this file by physical or electronic mail, you may +// find current contact information at www.suse.com. + +use std::{ + fs, + io::Write, + os::unix::fs::OpenOptionsExt, + path::{Path, PathBuf}, + process, +}; + +use crate::transfer::Transfer; + +use super::ScriptError; + +/// Represents a script to run as part of the installation process. +pub struct Script { + /// Location of the script in the local disk. + pub path: PathBuf, +} + +impl Script { + /// Runs the script and returns the output. + /// + /// TODO: write stdout and stderr to the file system. + pub async fn run(&self) -> Result { + Ok(process::Command::new(&self.path).output()?) + } +} + +/// Manages a set of installation scripts. +/// +/// It offers an API to add and execute installation scripts. +pub struct ScriptsRepository { + workdir: PathBuf, + scripts: Vec