OpenRC generator

This commit is contained in:
Maurice
2025-07-21 21:44:02 +02:00
commit da47934db9
6 changed files with 313 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

142
Cargo.lock generated Normal file
View File

@@ -0,0 +1,142 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "hashbrown"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
[[package]]
name = "indexmap"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "podman-openrc"
version = "0.1.0"
dependencies = [
"serde",
"toml",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "serde"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_spanned"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83"
dependencies = [
"serde",
]
[[package]]
name = "syn"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "toml"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"toml_parser",
"toml_writer",
"winnow",
]
[[package]]
name = "toml_datetime"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3"
dependencies = [
"serde",
]
[[package]]
name = "toml_parser"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30"
dependencies = [
"winnow",
]
[[package]]
name = "toml_writer"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64"
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "winnow"
version = "0.7.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"

8
Cargo.toml Normal file
View File

@@ -0,0 +1,8 @@
[package]
name = "podman-openrc"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
toml = "0.9.2"

31
example.toml Normal file
View File

@@ -0,0 +1,31 @@
user = "maurict"
[service]
name = "nc-test-api"
image = "numberchords-api"
network = "nc-network"
depend = ["nc-test-database"]
[environment]
ASPNETCORE_ENVIRONMENT = "Test"
"NC_Security__OtherIssuerKeys__identity.numberchords.com__AuthPublicKey" = ""
[[secrets]]
key = "connection_string"
target = "Database__ConnectionString"
[[secrets]]
key = "api_secret_key"
[[ports]]
host = 80
container = 8080
protocol = "tcp"
[[ports]]
host = 22
container = 2222
[[volumes]]
volume = "test"
path = "/data/test"

81
src/main.rs Normal file
View File

@@ -0,0 +1,81 @@
use std::fs;
use crate::service::ServiceConfig;
mod service;
pub fn generate_openrc(config: &ServiceConfig) {
let mut script = String::from("#!/sbin/openrc-run\n# !!! AUTO GENERATED - DO NOT EDIT !!!\n\n");
let wrap = |cmd: &str| {
if let Some(user) = config.user.as_ref() {
format!("\tsu -c \"{}\" {} ", cmd, user)
} else {
format!("\t{}", cmd)
}
};
// depend() {
script.push_str("depend() {\n\tneed sysfs cgroups; ");
if config.service.depend.len() > 0 {
script.push_str(&format!("\n\tuse {}; ", config.service.depend.join(" ")));
}
script.push_str("\n}\n\n");
// }
// start_pre()
script.push_str("start_pre() {\n");
script.push_str(&wrap(&format!("podman rm {} --ignore", config.service.name)));
script.push_str("\n}\n\n");
// }
// start()
script.push_str("start() {\n");
let mut arguments = vec![String::from("--restart unless-stopped"), format!("--name {}", config.service.name)];
if let Some(network) = &config.service.network {
arguments.push(format!("--network {}", network));
}
for secret in &config.secrets {
if let Some(target) = &secret.target {
arguments.push(format!("--secret {},target={}", &secret.key, target));
} else {
arguments.push(format!("--secret {}", &secret.key));
}
}
for (key, value) in &config.environment {
arguments.push(format!("--env {}={}", key, value));
}
for volume in &config.volumes {
arguments.push(format!("--volume {}:{}", &volume.volume, &volume.path));
}
arguments.push(config.service.image.clone());
script.push_str(&wrap(&format!("podman run -d {}", arguments.iter()
.enumerate()
.map(|(i, arg)| if i > 0 { format!("\t{}", arg) } else { arg.to_string() })
.collect::<Vec<_>>()
.join(" \\\n"))));
script.push_str("\n}\n\n");
// }
// stop()
script.push_str("stop() {\n");
script.push_str(&wrap(&format!("podman stop {} --ignore", config.service.name)));
script.push_str("\n}\n\n");
// }
println!("\n\n{}", script);
}
fn main() {
let file = fs::read_to_string("example.toml").unwrap();
let service: ServiceConfig = toml::from_str(&file).unwrap();
println!("{:?}", service);
generate_openrc(&service);
}

50
src/service.rs Normal file
View File

@@ -0,0 +1,50 @@
use serde::Deserialize;
use std::collections::HashMap;
#[derive(Debug, Deserialize)]
pub struct ServiceConfig {
pub service: Service,
// Optionally support simple or structured secrets list
#[serde(default)]
pub secrets: Vec<Secret>,
#[serde(default)]
pub environment: HashMap<String, String>,
#[serde(default)]
pub ports: Vec<PortMapping>,
#[serde(default)]
pub volumes: Vec<VolumeMapping>,
pub user: Option<String>
}
#[derive(Debug, Deserialize)]
pub struct Service {
pub name: String,
pub image: String,
pub network: Option<String>,
#[serde(default)]
pub depend: Vec<String>
}
#[derive(Debug, Deserialize)]
pub struct Secret {
pub key: String,
pub target: Option<String>
}
#[derive(Debug, Deserialize)]
pub struct PortMapping {
pub host: u16,
pub container: u16,
pub protocol: Option<String>
}
#[derive(Debug, Deserialize)]
pub struct VolumeMapping {
pub volume: String,
pub path: String
}