diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f7896d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..cd3dcc0 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,452 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +dependencies = [ + "memchr", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi 0.3.3", + "rustix", + "windows-sys", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "libc" +version = "0.2.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" + +[[package]] +name = "linux-raw-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" + +[[package]] +name = "proc-macro2" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "rustix" +version = "0.38.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_yaml" +version = "0.9.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "syn" +version = "2.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "systemyml" +version = "0.1.0" +dependencies = [ + "clap", + "env_logger", + "log", + "serde", + "serde_yaml", +] + +[[package]] +name = "termcolor" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..99820fb --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "systemyml" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_yaml = "0.9" +log = "0.4" +env_logger = "0.10" +clap = "2.34.0" + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..5508302 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +#  Systemyml + +> Something something generate systemd services from Yaml files. Works for the most part. + +I think I can finally say I know how to write Rust code. diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..69b83f4 --- /dev/null +++ b/default.nix @@ -0,0 +1,8 @@ +{rustPlatform}: +rustPlatform.buildRustPackage { + pname = "systemyml"; + version = "0.0.1"; + + src = ./.; + cargoLock.lockFile = ./Cargo.lock; +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..00a5794 --- /dev/null +++ b/flake.lock @@ -0,0 +1,26 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1695879232, + "narHash": "sha256-lD3dtNh0a69DSHY0irGCiGjv3LCrfmdPWmcm/WCE7fs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e7a162f48ae79bbfb5aa5a1165bd989bec55cc6d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..442c31a --- /dev/null +++ b/flake.nix @@ -0,0 +1,26 @@ +{ + description = "Generate Systemd services from Yaml templates"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + }; + + outputs = { + self, + nixpkgs, + }: let + systems = ["x86_64-linux" "aarch64-linux"]; + forEachSystem = nixpkgs.lib.genAttrs systems; + + pkgsForEach = nixpkgs.legacyPackages; + in rec { + packages = forEachSystem (system: { + default = pkgsForEach.${system}.callPackage ./default.nix {}; + }); + + devShells = forEachSystem (system: { + default = pkgsForEach.${system}.callPackage ./shell.nix {}; + }); + + hydraJobs = packages; + }; +} diff --git a/services/test.yml b/services/test.yml new file mode 100644 index 0000000..dfe574e --- /dev/null +++ b/services/test.yml @@ -0,0 +1,16 @@ +my_service: + name: my_service + install: + WantedBy: multi-user.target + unit: + Description: Example service + After: network.target + Wants: network-online.target + Documentation: https://example.com/my-service-doc + service: + Type: simple + ExecStart: /usr/bin/my_service_executable arg1 arg2 + Restart: always + User: my_user + Group: my_group + WorkingDirectory: /path/to/working/directory diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..6b184ad --- /dev/null +++ b/shell.nix @@ -0,0 +1,18 @@ +{ + callPackage, + rust-analyzer, + rustfmt, + clippy, +}: let + mainPkg = callPackage ./default.nix {}; +in + mainPkg.overrideAttrs (oa: { + nativeBuildInputs = + [ + # Additional rust tooling + rust-analyzer + rustfmt + clippy + ] + ++ (oa.nativeBuildInputs or []); + }) diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..1f73358 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,202 @@ +#[macro_use] +extern crate log; +extern crate clap; +extern crate env_logger; +extern crate serde; + +use clap::{App, Arg}; +use serde::{Deserialize, Serialize}; +use serde_yaml; +use std::collections::HashMap; +use std::error::Error; +use std::fs::{self, File}; +use std::io::Write; +use std::path::{Path, PathBuf}; +mod service_struct; + +#[derive(Debug, Deserialize, Serialize)] +struct ServiceConfig { + pub name: String, + pub install: Option>, + pub unit: Option>, + pub service: Option>, + pub environment: Option>, +} + +fn main() -> Result<(), Box> { + let matches = App::new("systemyml") + .version("0.0.1") + .author("NotAShelf") + .about("Creates systemd service units from YAML configuration files.") + .arg( + Arg::with_name("config") + .short("c") + .long("config") + .value_name("PATH") + .help("Specify the directory or YAML file containing service configuration.") + .default_value("services") // Default value for the config directory. + .takes_value(true), + ) + .arg( + Arg::with_name("target") + .short("t") + .long("target") + .value_name("DIRECTORY") + .help("Specify the target directory for systemd service units.") + .default_value("/etc/systemd/system") // Default value for the target directory. + .takes_value(true), + ) + .arg( + Arg::with_name("verbose") + .short("v") + .long("verbose") + .help("Enable verbose logging."), + ) + .arg( + Arg::with_name("stdout") + .long("stdout") + .help("Print the generated service config to stdout."), + ) + .arg( + Arg::with_name("dryrun") + .long("dryrun") + .help("Describe what would happen without making changes."), + ) + .arg( + Arg::with_name("safe") + .long("safe") + .help("Copy service units to the target directory without starting services."), + ) + .get_matches(); + + if matches.is_present("verbose") { + env_logger::Builder::new() + .filter_level(log::LevelFilter::Debug) + .init(); + } else { + env_logger::Builder::new() + .filter_level(log::LevelFilter::Info) + .init(); + } + + info!("Starting the program."); + + let config_path = Path::new(matches.value_of("config").unwrap()); + let target_dir = PathBuf::from(matches.value_of("target").unwrap()); + + if config_path.is_dir() { + for entry in fs::read_dir(&config_path)? { + if let Ok(entry) = entry { + let file_path = entry.path(); + if file_path.is_file() && file_path.extension().map_or(false, |e| e == "yaml") { + if let Err(err) = process_service_config( + &file_path, + &target_dir, + matches.is_present("stdout"), + matches.is_present("dryrun"), + matches.is_present("safe"), + ) { + error!("Failed to process service configuration: {}", err); + } + } + } + } + } else if config_path.is_file() { + if let Err(err) = process_service_config( + config_path, + &target_dir, + matches.is_present("stdout"), + matches.is_present("dryrun"), + matches.is_present("safe"), + ) { + error!("Failed to process service configuration: {}", err); + } + } else { + error!("Invalid configuration path: {:?}", config_path); + } + + info!("Program completed successfully."); + + Ok(()) +} + +/// Process the service configuration from a YAML file and create systemd service units. +/// +/// # Arguments +/// +/// * `file_path` - The path to the YAML configuration file. +/// * `target_dir` - The target directory where systemd service units will be installed. +/// * `print_to_stdout` - Whether to print the generated service config to stdout. +/// * `dryrun` - Whether to describe what would happen without making changes. +/// * `safe` - Whether to copy service units to the target directory without starting services. +/// +/// # Returns +/// +/// A Result indicating success or an error. +fn process_service_config( + file_path: &std::path::Path, + target_dir: &std::path::Path, + _print_to_stdout: bool, + dryrun: bool, + safe: bool, +) -> Result<(), Box> { + if !target_dir.exists() { + fs::create_dir_all(target_dir)?; + } + + let yaml_content = fs::read_to_string(file_path)?; + let service_config: HashMap = serde_yaml::from_str(&yaml_content)?; + + for (name, config) in &service_config { + let serialized_config = serde_yaml::to_string(&config)?; + + let unit_filename = format!("{}.service", name); + let unit_path = target_dir.join(&unit_filename); + + info!("unit_filename: {:?}", unit_filename); + info!("unit_path: {:?}", unit_path); + + if dryrun { + println!( + "Generated service config for '{}':\n\n{}", + name, serialized_config + ); + println!("Dry run: Would create systemd unit: {:?}", unit_path); + + if safe { + println!("Dry run: Would enable service: {}", name); + println!("Dry run: Would start service: {}", name); + } + } else { + let mut unit_file = File::create(&unit_path)?; + unit_file.write_all(serialized_config.as_bytes())?; + + if safe { + info!("Copied systemd unit to target directory: {:?}", unit_path); + } else { + if let Err(err) = enable_and_start_service(&unit_filename) { + error!("Failed to enable and start service '{}': {}", name, err); + } else { + info!("Enabled and started service: {}", name); + } + } + } + } + + Ok(()) +} + +/// Enable and start a systemd service by its name. +/// +/// # Arguments +/// +/// * `service_name` - The name of the systemd service to enable and start. +/// +/// # Returns +/// +/// A Result indicating success or an error. +fn enable_and_start_service(service_name: &str) -> Result<(), Box> { + // TODO: make this do something + println!("Enabled and started service: {}", service_name); + Ok(()) +} diff --git a/src/service_struct/mod.rs b/src/service_struct/mod.rs new file mode 100644 index 0000000..1e877d9 --- /dev/null +++ b/src/service_struct/mod.rs @@ -0,0 +1,57 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(Debug, Deserialize, Serialize)] +pub struct ServiceConfig { + pub my_service: MyService, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct MyService { + pub name: String, + pub install: Option>, + pub unit: Option>, + pub service: Option, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct ServiceProperties { + pub Type: String, + pub ExecStart: String, + pub Restart: String, + pub User: String, + pub Group: String, + pub WorkingDirectory: String, + pub Nice: i32, + pub UMask: String, + pub RestartSec: String, + pub TimeoutStartSec: String, + pub TimeoutStopSec: String, + pub SuccessExitStatus: String, + pub LimitNOFILE: i32, + pub LimitCORE: String, + pub LimitAS: String, + pub LimitCPU: String, + pub LimitFSIZE: String, + pub LimitNPROC: i32, + pub LimitSTACK: String, + pub LimitRTPRIO: i32, + pub CPUSet: String, + pub Delegate: String, + pub ProtectHome: String, + pub ProtectSystem: String, + pub PrivateTmp: String, + pub PrivateDevices: String, + pub ProtectKernelModules: String, + pub ProtectKernelTunables: String, + pub ProtectControlGroups: String, + pub MemoryDenyGroup: String, + pub IOWeight: i32, + pub IOWeightDevice: Vec, + pub BlockIOWeight: i32, + pub BlockIOWeightDevice: Vec, + pub TasksMax: i32, + pub Slice: String, + pub NUMANode: i32, + pub NUMAAffinity: Vec, +} diff --git a/test/my_service.service b/test/my_service.service new file mode 100644 index 0000000..d4c17cc --- /dev/null +++ b/test/my_service.service @@ -0,0 +1,16 @@ +name: my_service +install: + WantedBy: multi-user.target +unit: + Documentation: https://example.com/my-service-doc + After: network.target + Description: Example service + Wants: network-online.target +service: + WorkingDirectory: /path/to/working/directory + ExecStart: /usr/bin/my_service_executable arg1 arg2 + Restart: always + User: my_user + Type: simple + Group: my_group +environment: null diff --git a/test/service1.service b/test/service1.service new file mode 100644 index 0000000..0c91970 --- /dev/null +++ b/test/service1.service @@ -0,0 +1,7 @@ +[Unit] +Description=Example service 1 + +[Service] +ExecStart=/usr/bin/service1_executable arg1 arg2 +Environment=VAR1=value1 +Environment=VAR2=value2