From 42747c67ff5bd645c6a3e8d19a17e1f779f76950 Mon Sep 17 00:00:00 2001 From: Paul Nettleton Date: Wed, 5 Apr 2023 13:45:36 -0500 Subject: [PATCH 1/6] Move tmpfs to `QuadletOptions` per docs update --- src/cli/container.rs | 18 +----------------- src/cli/container/quadlet.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/cli/container.rs b/src/cli/container.rs index 62007e9..c581f29 100644 --- a/src/cli/container.rs +++ b/src/cli/container.rs @@ -28,12 +28,6 @@ pub struct Container { #[arg(long, value_name = "OPTION")] security_opt: Vec, - /// Create a tmpfs mount - /// - /// Can be specified multiple times - #[arg(long, value_name = "FS")] - tmpfs: Vec, - /// The image to run in the container /// /// Converts to "Image=IMAGE" @@ -66,17 +60,7 @@ impl Display for Container { let userns = map_arg_output(&self.userns, "--userns"); let security_opt = map_arg_output(&self.security_opt, "--security-opt"); - let tmpfs = self.tmpfs.iter().map(|fs| { - ( - "--tmpfs", - if fs == "/tmp" { - Output::QuadletOptions(String::from("VolatileTmp=true")) - } else { - Output::PodmanArg(fs.clone()) - }, - ) - }); - let outputs = userns.chain(security_opt).chain(tmpfs); + let outputs = userns.chain(security_opt); for (arg, output) in outputs { output.write_or_add_arg(arg, f, &mut podman_args)?; } diff --git a/src/cli/container/quadlet.rs b/src/cli/container/quadlet.rs index 346a51e..c3685e6 100644 --- a/src/cli/container/quadlet.rs +++ b/src/cli/container/quadlet.rs @@ -239,10 +239,20 @@ pub struct QuadletOptions { /// Give the container access to a secret /// + /// Converts to "Secret=SECRET[,OPT=OPT,...]" + /// /// Can be specified multiple times #[arg(long, value_name = "SECRET[,OPT=OPT,...]")] secret: Vec, + /// Create a tmpfs mount + /// + /// Converts to "Tmpfs=FS" or, if FS == /tmp, "VolatileTmp=true" + /// + /// Can be specified multiple times + #[arg(long, value_name = "FS")] + tmpfs: Vec, + /// Set the timezone in the container /// /// Converts to "Timezone=TIMEZONE" @@ -424,6 +434,14 @@ impl Display for QuadletOptions { writeln!(f, "Secret={secret}")?; } + for tmpfs in &self.tmpfs { + if tmpfs == "/tmp" { + writeln!(f, "VolatileTmp=true")?; + } else { + writeln!(f, "Tmpfs={tmpfs}")?; + } + } + if let Some(tz) = &self.tz { writeln!(f, "Timezone={tz}")?; } From 71204d8f0b8541d7ec9668767a6465f8da75b1b4 Mon Sep 17 00:00:00 2001 From: Paul Nettleton Date: Sun, 9 Apr 2023 02:35:15 -0500 Subject: [PATCH 2/6] Add "UserNS=" quadlet option for `podman run` Replaces "RemapGid=", "RemapUid=", "RemapUidSize=", and "RemapUsers=" options Also moved `uidmap` and `gidmap` options from `QuadletOptions` to `PodmanArgs` --- src/cli/container.rs | 20 ++------------------ src/cli/container/podman.rs | 18 ++++++++++++++++++ src/cli/container/quadlet.rs | 34 ++++++++++------------------------ 3 files changed, 30 insertions(+), 42 deletions(-) diff --git a/src/cli/container.rs b/src/cli/container.rs index c581f29..245465c 100644 --- a/src/cli/container.rs +++ b/src/cli/container.rs @@ -18,10 +18,6 @@ pub struct Container { #[command(flatten)] podman_args: podman::PodmanArgs, - /// Set the user namespace mode for the container - #[arg(long, value_name = "MODE")] - userns: Option, - /// Security options /// /// Can be specified multiple times @@ -40,15 +36,6 @@ pub struct Container { command: Vec, } -fn map_arg_output<'a, T, U>(iter: T, arg: &'a str) -> impl Iterator -where - T: IntoIterator, - Output: From<&'a U>, - U: 'a, -{ - iter.into_iter().map(move |item| (arg, Output::from(item))) -} - impl Display for Container { fn fmt(&self, f: &mut Formatter) -> fmt::Result { writeln!(f, "[Container]")?; @@ -58,11 +45,8 @@ impl Display for Container { let mut podman_args = self.podman_args.to_string(); - let userns = map_arg_output(&self.userns, "--userns"); - let security_opt = map_arg_output(&self.security_opt, "--security-opt"); - let outputs = userns.chain(security_opt); - for (arg, output) in outputs { - output.write_or_add_arg(arg, f, &mut podman_args)?; + for output in self.security_opt.iter().map(Output::from) { + output.write_or_add_arg("--security-opt", f, &mut podman_args)?; } if !podman_args.is_empty() { diff --git a/src/cli/container/podman.rs b/src/cli/container/podman.rs index 76f88ae..c0b8f91 100644 --- a/src/cli/container/podman.rs +++ b/src/cli/container/podman.rs @@ -170,6 +170,12 @@ pub struct PodmanArgs { #[arg(long, value_name = "ENV")] env_merge: Vec, + /// Run the container in a new user namespace using the supplied GID mapping + /// + /// Can be specified multiple times + #[arg(long, value_name = "CONTAINER_GID:HOST_GID:AMOUNT")] + gidmap: Vec, + /// Assign additional groups to the primary user running within the container process /// /// Can be specified multiple times @@ -402,6 +408,12 @@ pub struct PodmanArgs { #[arg(short, long)] tty: bool, + /// Run the container in a new user namespace using the supplied UID mapping + /// + /// Can be specified multiple times + #[arg(long, value_name = "CONTAINER_UID:FROM_UID:AMOUNT")] + uidmap: Vec, + /// Ulimit options #[arg(long, value_name = "OPTION")] ulimit: Option, @@ -461,6 +473,7 @@ impl PodmanArgs { + self.dns_search.iter().len() + self.entrypoint.iter().len() + self.env_merge.len() + + self.gidmap.len() + self.group_add.len() + self.group_entry.iter().len() + self.hostname.iter().len() @@ -504,6 +517,7 @@ impl PodmanArgs { + self.systemd.iter().len() + self.timeout.iter().len() + self.tls_verify.iter().len() + + self.uidmap.len() + self.ulimit.iter().len() + self.umask.iter().len() + self.variant.iter().len() @@ -617,6 +631,8 @@ impl Display for PodmanArgs { extend_args(&mut args, "--env-merge", &self.env_merge); + extend_args(&mut args, "--gidmap", &self.gidmap); + extend_args(&mut args, "--group-add", &self.group_add); extend_args(&mut args, "--group-entry", &self.group_entry); @@ -762,6 +778,8 @@ impl Display for PodmanArgs { args.push("--tty"); } + extend_args(&mut args, "--uidmap", &self.uidmap); + extend_args(&mut args, "--ulimit", &self.ulimit); extend_args(&mut args, "--umask", &self.umask); diff --git a/src/cli/container/quadlet.rs b/src/cli/container/quadlet.rs index c3685e6..e00fa98 100644 --- a/src/cli/container/quadlet.rs +++ b/src/cli/container/quadlet.rs @@ -219,18 +219,6 @@ pub struct QuadletOptions { #[arg(long)] read_only: bool, - /// Run the container in a new user namespace using the supplied UID mapping - /// - /// Converts to ""RemapUsers=manual" and "RemapUid=UID_MAP"" - #[arg(long, value_name = "CONTAINER_UID:FROM_UID:AMOUNT")] - uidmap: Option, - - /// Run the container in a new user namespace using the supplied GID mapping - /// - /// Converts to "RemapUsers=manual" and "RemapGid=GID_MAP" - #[arg(long, value_name = "CONTAINER_GID:HOST_GID:AMOUNT")] - gidmap: Option, - /// Run an init inside the container /// /// Converts to "RunInit=true" @@ -265,6 +253,12 @@ pub struct QuadletOptions { #[arg(short, long, value_name = "UID[:GID]")] user: Option, + /// Set the user namespace mode for the container + /// + /// Converts to "UserNS=MODE" + #[arg(long, value_name = "MODE")] + userns: Option, + /// Mount a volume in the container /// /// Converts to "Volume=VOLUME" @@ -414,18 +408,6 @@ impl Display for QuadletOptions { writeln!(f, "ReadOnly=true")?; } - if self.uidmap.is_some() || self.gidmap.is_some() { - writeln!(f, "RemapUsers=manual")?; - } - - if let Some(uidmap) = &self.uidmap { - writeln!(f, "RemapUid={uidmap}")?; - } - - if let Some(gidmap) = &self.gidmap { - writeln!(f, "RemapGid={gidmap}")?; - } - if self.init { writeln!(f, "RunInit=true")?; } @@ -455,6 +437,10 @@ impl Display for QuadletOptions { } } + if let Some(userns) = &self.userns { + writeln!(f, "UserNS={userns}")?; + } + for volume in &self.volume { writeln!(f, "Volume={volume}")?; } From 4b9c14a5ba32c28bce08e1470425bb8bdaf182ca Mon Sep 17 00:00:00 2001 From: Paul Nettleton Date: Sun, 9 Apr 2023 02:58:16 -0500 Subject: [PATCH 3/6] Add "UserNS=" quadlet option for `podman kube play` Replaces "RemapGid=", "RemapUid=", "RemapUidSize=", and "RemapUsers=" options --- README.md | 2 +- src/cli/container.rs | 1 - src/cli/container/user_namespace.rs | 431 ---------------------------- src/cli/kube.rs | 11 +- 4 files changed, 5 insertions(+), 440 deletions(-) delete mode 100644 src/cli/container/user_namespace.rs diff --git a/README.md b/README.md index a0b35ad..bd27765 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ $ podlet podman kube play --network pasta --userns auto kube.yaml [Kube] Yaml=kube.yaml Network=pasta -RemapUsers=auto +UserNS=auto ``` ## Contribution diff --git a/src/cli/container.rs b/src/cli/container.rs index 245465c..4ba8201 100644 --- a/src/cli/container.rs +++ b/src/cli/container.rs @@ -1,7 +1,6 @@ mod podman; mod quadlet; mod security_opt; -pub mod user_namespace; use std::fmt::{self, Display, Formatter}; diff --git a/src/cli/container/user_namespace.rs b/src/cli/container/user_namespace.rs deleted file mode 100644 index 7857c86..0000000 --- a/src/cli/container/user_namespace.rs +++ /dev/null @@ -1,431 +0,0 @@ -use std::{num::ParseIntError, str::FromStr}; - -use thiserror::Error; - -use super::Output; - -#[derive(Debug, Clone, PartialEq)] -pub enum Mode { - Auto { - uidmapping: Option, - gidmapping: Option, - size: Option, - }, - Container { - id: String, - }, - Host, - KeepId { - uid: Option, - gid: Option, - }, - Nomap, - Ns { - namespace: String, - }, -} - -impl FromStr for Mode { - type Err = ParseModeError; - - #[allow(clippy::similar_names)] - fn from_str(s: &str) -> Result { - match s { - s if s.starts_with("auto") => s.split_once(':').map_or( - Ok(Mode::Auto { - uidmapping: None, - gidmapping: None, - size: None, - }), - |(_, options)| { - let mut uidmapping = None; - let mut gidmapping = None; - let mut size = None; - for option in options.split(',') { - if option.starts_with("uidmapping=") { - let (_, option) = - option.split_once('=').expect("delimiter is in guard"); - uidmapping = Some(String::from(option)); - } else if option.starts_with("gidmapping=") { - let (_, option) = - option.split_once('=').expect("delimiter is in guard"); - gidmapping = Some(String::from(option)); - } else if option.starts_with("size=") { - let (_, option) = - option.split_once('=').expect("delimiter is in guard"); - size = Some(option.parse().map_err(|source| { - ParseModeError::AutoSizeParseError { - size: String::from(option), - source, - } - })?); - } else { - return Err(ParseModeError::InvalidAutoOption(String::from(option))); - } - } - Ok(Mode::Auto { - uidmapping, - gidmapping, - size, - }) - }, - ), - s if s.starts_with("container:") => { - let (_, id) = s.split_once(':').expect("delimiter is in guard"); - Ok(Mode::Container { - id: String::from(id), - }) - } - "host" => Ok(Mode::Host), - s if s.starts_with("keep-id") => s.split_once(':').map_or( - Ok(Mode::KeepId { - uid: None, - gid: None, - }), - |(_, options)| { - let mut uid = None; - let mut gid = None; - for option in options.split(',') { - if option.starts_with("uid=") { - let (_, option) = - option.split_once('=').expect("delimiter is in guard"); - uid = Some(option.parse().map_err(|source| { - ParseModeError::KeepIdUidParseError { - uid: String::from(option), - source, - } - })?); - } else if option.starts_with("gid=") { - let (_, option) = - option.split_once('=').expect("delimiter is in guard"); - gid = Some(option.parse().map_err(|source| { - ParseModeError::KeepIdGidParseError { - gid: String::from(option), - source, - } - })?); - } else { - return Err(ParseModeError::InvalidKeepIdOption(String::from(option))); - } - } - Ok(Mode::KeepId { uid, gid }) - }, - ), - "nomap" => Ok(Mode::Nomap), - s if s.starts_with("ns:") => { - let (_, namespace) = s.split_once(':').expect("delimiter is in guard"); - Ok(Mode::Ns { - namespace: String::from(namespace), - }) - } - _ => Err(ParseModeError::InvalidMode(String::from(s))), - } - } -} - -#[derive(Error, Debug, Clone, PartialEq)] -pub enum ParseModeError { - #[error("`{0}` is not a valid auto mode option")] - InvalidAutoOption(String), - - #[error("`{size}` is not a valid size: {source}")] - AutoSizeParseError { size: String, source: ParseIntError }, - - #[error("`{0}` is not a valid keep-id mode option")] - InvalidKeepIdOption(String), - - #[error("`{uid}` is not a valid UID: {source}")] - KeepIdUidParseError { uid: String, source: ParseIntError }, - - #[error("`{gid}` is not a valid GID: {source}")] - KeepIdGidParseError { gid: String, source: ParseIntError }, - - #[error("`{0}` is not a valid user namespace mode")] - InvalidMode(String), -} - -impl From for Output { - fn from(value: Mode) -> Self { - (&value).into() - } -} - -impl From<&Mode> for Output { - fn from(value: &Mode) -> Self { - match value { - Mode::Auto { - uidmapping, - gidmapping, - size, - } => { - let mut options = vec![String::from("RemapUsers=auto")]; - if let Some(uidmapping) = uidmapping { - options.push(format!("RemapUid={uidmapping}")); - } - if let Some(gidmapping) = gidmapping { - options.push(format!("RemapGid={gidmapping}")); - } - if let Some(size) = size { - options.push(format!("RemapUidSize={size}")); - } - Self::QuadletOptions(options.join("\n")) - } - Mode::Container { id } => Self::PodmanArg(format!("container:{id}")), - Mode::Host => Self::PodmanArg(String::from("host")), - Mode::KeepId { uid, gid } => { - let mut options = vec![String::from("RemapUsers=keep-id")]; - if let Some(uid) = uid { - options.push(format!("RemapUid={uid}")); - } - if let Some(gid) = gid { - options.push(format!("RemapGid={gid}")); - } - Self::QuadletOptions(options.join("\n")) - } - Mode::Nomap => Self::PodmanArg(String::from("nomap")), - Mode::Ns { namespace } => Self::PodmanArg(format!("ns:{namespace}")), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - mod parse { - use super::*; - - #[test] - fn auto_no_options() { - let sut = "auto".parse(); - assert_eq!( - sut, - Ok(Mode::Auto { - uidmapping: None, - gidmapping: None, - size: None - }) - ); - } - - #[test] - fn auto_all_options() { - let sut = "auto:uidmapping=100,gidmapping=200,size=300".parse(); - assert_eq!( - sut, - Ok(Mode::Auto { - uidmapping: Some(String::from("100")), - gidmapping: Some(String::from("200")), - size: Some(300) - }) - ); - } - - #[test] - fn container() { - let sut = "container:name".parse(); - assert_eq!( - sut, - Ok(Mode::Container { - id: String::from("name") - }) - ); - } - - #[test] - fn host() { - let sut = "host".parse(); - assert_eq!(sut, Ok(Mode::Host)); - } - - #[test] - fn keep_id_no_options() { - let sut = "keep-id".parse(); - assert_eq!( - sut, - Ok(Mode::KeepId { - uid: None, - gid: None - }) - ); - } - - #[test] - fn keep_id_all_options() { - let sut = "keep-id:uid=100,gid=200".parse(); - assert_eq!( - sut, - Ok(Mode::KeepId { - uid: Some(100), - gid: Some(200) - }) - ); - } - - #[test] - fn nomap() { - let sut = "nomap".parse(); - assert_eq!(sut, Ok(Mode::Nomap)); - } - - #[test] - fn ns() { - let sut = "ns:namespace".parse(); - assert_eq!( - sut, - Ok(Mode::Ns { - namespace: String::from("namespace") - }) - ); - } - - #[test] - fn invalid_auto_option() { - let sut: Result = "auto:".parse(); - assert_eq!(sut, Err(ParseModeError::InvalidAutoOption(String::new()))); - } - - #[test] - fn auto_size_parse_error() { - let sut: Result = "auto:size=".parse(); - assert!(matches!( - sut, - Err(ParseModeError::AutoSizeParseError { .. }) - )); - } - - #[test] - fn invalid_keep_id_option() { - let sut: Result = "keep-id:".parse(); - assert_eq!(sut, Err(ParseModeError::InvalidKeepIdOption(String::new()))); - } - - #[test] - fn keep_id_uid_parse_error() { - let sut: Result = "keep-id:uid=".parse(); - assert!(matches!( - sut, - Err(ParseModeError::KeepIdUidParseError { .. }) - )); - } - - #[test] - fn keep_id_gid_parse_error() { - let sut: Result = "keep-id:gid=".parse(); - assert!(matches!( - sut, - Err(ParseModeError::KeepIdGidParseError { .. }) - )); - } - - #[test] - fn invalid_mode() { - let sut: Result = "".parse(); - assert_eq!(sut, Err(ParseModeError::InvalidMode(String::new()))); - } - } - - mod output { - use super::*; - - #[test] - fn auto_no_options() { - let sut: Output = Mode::Auto { - uidmapping: None, - gidmapping: None, - size: None, - } - .into(); - assert_eq!(sut, Output::QuadletOptions(String::from("RemapUsers=auto"))); - } - - #[allow(clippy::similar_names)] - #[test] - fn auto_all_options() { - let uidmapping = "100"; - let gidmapping = "200"; - let size = 300; - let sut: Output = Mode::Auto { - uidmapping: Some(String::from(uidmapping)), - gidmapping: Some(String::from(gidmapping)), - size: Some(size), - } - .into(); - - assert_eq!( - sut, - Output::QuadletOptions(format!( - "RemapUsers=auto\n\ - RemapUid={uidmapping}\n\ - RemapGid={gidmapping}\n\ - RemapUidSize={size}" - )) - ); - } - - #[test] - fn container() { - let id = "name"; - let sut: Output = Mode::Container { - id: String::from(id), - } - .into(); - assert_eq!(sut, Output::PodmanArg(format!("container:{id}"))); - } - - #[test] - fn host() { - let sut: Output = Mode::Host.into(); - assert_eq!(sut, Output::PodmanArg(String::from("host"))); - } - - #[test] - fn keep_id_no_options() { - let sut: Output = Mode::KeepId { - uid: None, - gid: None, - } - .into(); - assert_eq!( - sut, - Output::QuadletOptions(String::from("RemapUsers=keep-id")) - ); - } - - #[allow(clippy::similar_names)] - #[test] - fn keep_id_all_options() { - let uid = 100; - let gid = 200; - let sut: Output = Mode::KeepId { - uid: Some(uid), - gid: Some(gid), - } - .into(); - assert_eq!( - sut, - Output::QuadletOptions(format!( - "RemapUsers=keep-id\n\ - RemapUid={uid}\n\ - RemapGid={gid}" - )) - ); - } - - #[test] - fn nomap() { - let sut: Output = Mode::Nomap.into(); - assert_eq!(sut, Output::PodmanArg(String::from("nomap"))); - } - - #[test] - fn ns() { - let namespace = "namespace"; - let sut: Output = Mode::Ns { - namespace: String::from(namespace), - } - .into(); - assert_eq!(sut, Output::PodmanArg(format!("ns:{namespace}"))); - } - } -} diff --git a/src/cli/kube.rs b/src/cli/kube.rs index 26c2b72..4d665ea 100644 --- a/src/cli/kube.rs +++ b/src/cli/kube.rs @@ -3,8 +3,6 @@ use std::{convert::Infallible, ffi::OsStr, fmt::Display, path::PathBuf, str::Fro use clap::{Args, Subcommand}; use url::Url; -use super::container::{user_namespace, Output}; - #[derive(Subcommand, Debug, Clone, PartialEq)] pub enum Kube { /// Generate a podman quadlet `.kube` file @@ -71,10 +69,9 @@ pub struct Play { /// Set the user namespace mode for the pod /// - /// Converts to "RemapUsers=MODE" - /// and potentially "RemapUid=UID" and "RemapGid=GID" + /// Converts to "UserNS=MODE" #[arg(long, value_name = "MODE")] - userns: Option, + userns: Option, /// The path to the Kubernetes YAML file to use /// @@ -102,8 +99,8 @@ impl Display for Play { writeln!(f, "PublishPort={port}")?; } - if let Some(Output::QuadletOptions(option)) = self.userns.as_ref().map(Output::from) { - writeln!(f, "{option}")?; + if let Some(userns) = &self.userns { + writeln!(f, "UserNS={userns}")?; } Ok(()) From e4dda6a6452ad2f4ca88fd5f5182acce957a8f3c Mon Sep 17 00:00:00 2001 From: Paul Nettleton Date: Fri, 14 Apr 2023 15:59:26 -0500 Subject: [PATCH 4/6] Update dependencies --- Cargo.lock | 260 ++++++++++++++++++++++++---------------------------- Cargo.toml | 10 +- src/main.rs | 6 +- 3 files changed, 126 insertions(+), 150 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dc70e3d..a5cf4cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,55 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "anstream" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e579a7752471abc2a8268df8b20005e3eadd975f585398f17efcfd8d4927371" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcd8291a340dd8ac70e18878bc4501dd7b4ff970cfa21c207d36ece51ea88fd" +dependencies = [ + "anstyle", + "windows-sys", +] + [[package]] name = "backtrace" version = "0.3.67" @@ -52,40 +101,45 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.1.8" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" +checksum = "9b802d85aaf3a1cdb02b224ba472ebdea62014fccfcb269b95a4d76443b5ee5a" dependencies = [ - "bitflags", + "clap_builder", "clap_derive", - "clap_lex", - "is-terminal", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14a1a858f532119338887a4b8e1af9c60de8249cd7bafd68036a489e261e37b6" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", "strsim", - "termcolor", ] [[package]] name = "clap_derive" -version = "4.1.8" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" +checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] name = "clap_lex" -version = "0.3.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" -dependencies = [ - "os_str_bytes", -] +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" [[package]] name = "color-eyre" @@ -114,15 +168,21 @@ dependencies = [ "tracing-error", ] +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "errno" -version = "0.2.8" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys", ] [[package]] @@ -190,10 +250,11 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "io-lifetimes" -version = "1.0.5" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" dependencies = [ + "hermit-abi", "libc", "windows-sys", ] @@ -206,9 +267,9 @@ checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" [[package]] name = "is-terminal" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi", "io-lifetimes", @@ -224,15 +285,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" [[package]] name = "memchr" @@ -264,12 +325,6 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" - [[package]] name = "owo-colors" version = "3.5.0" @@ -300,35 +355,11 @@ dependencies = [ "url", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" -version = "1.0.54" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -350,9 +381,9 @@ checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b" [[package]] name = "rustix" -version = "0.36.9" +version = "0.37.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" +checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" dependencies = [ "bitflags", "errno", @@ -385,35 +416,15 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.109" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "syn" -version = "2.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - [[package]] name = "thiserror" version = "1.0.40" @@ -431,7 +442,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.10", + "syn", ] [[package]] @@ -509,9 +520,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775c11906edafc97bc378816b94585fbd9a054eabaf86fdd0ced94af449efab7" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-normalization" @@ -534,62 +545,31 @@ dependencies = [ ] [[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[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" +name = "utf8parse" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "valuable" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -602,42 +582,42 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/Cargo.toml b/Cargo.toml index d4e5654..ce39f40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,12 +11,12 @@ keywords = ["podman", "quadlet"] categories = ["command-line-utilities"] [dependencies] -clap = { version = "4.1.8", features = ["derive"] } -color-eyre = "0.6.2" -ipnet = "2.7.2" -shlex = "1.1.0" +clap = { version = "4.2", features = ["derive"] } +color-eyre = "0.6" +ipnet = "2.7" +shlex = "1.1" thiserror = "1.0.40" -url = "2.3.1" +url = "2.3" # The profile that 'cargo dist' will build with [profile.dist] diff --git a/src/main.rs b/src/main.rs index 4023e0f..1f16b6b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,11 +12,7 @@ //! //! Run `podlet --help` for more information. -#![warn(clippy::pedantic)] -#![warn(clippy::cargo)] -// Different versions of syn used by clap and thiserror, -// this is ok for now -#![allow(clippy::multiple_crate_versions)] +#![warn(clippy::pedantic, clippy::cargo)] mod cli; From a98cc2fe6bf0df4a8036f83e0af8a83d44e07b50 Mon Sep 17 00:00:00 2001 From: Paul Nettleton Date: Fri, 14 Apr 2023 17:19:55 -0500 Subject: [PATCH 5/6] Minor cleanup --- src/cli.rs | 4 ++-- src/cli/container.rs | 16 ++++++++++------ src/cli/container/quadlet.rs | 2 -- src/cli/container/security_opt.rs | 28 ++++++++++++++-------------- src/cli/kube.rs | 4 ++-- src/cli/network.rs | 2 +- src/cli/volume.rs | 2 +- 7 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index a251ba3..78e4181 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -119,7 +119,7 @@ impl Cli { } #[derive(Subcommand, Debug, Clone, PartialEq)] -pub enum Commands { +enum Commands { /// Generate a podman quadlet file from a podman command Podman { #[command(subcommand)] @@ -128,7 +128,7 @@ pub enum Commands { } #[derive(Subcommand, Debug, Clone, PartialEq)] -pub enum PodmanCommands { +enum PodmanCommands { /// Generate a podman quadlet `.container` file /// /// For details on options see: diff --git a/src/cli/container.rs b/src/cli/container.rs index 4ba8201..770da19 100644 --- a/src/cli/container.rs +++ b/src/cli/container.rs @@ -6,19 +6,23 @@ use std::fmt::{self, Display, Formatter}; use clap::Args; -use self::security_opt::SecurityOpt; +use self::{podman::PodmanArgs, quadlet::QuadletOptions, security_opt::SecurityOpt}; #[derive(Args, Default, Debug, Clone, PartialEq)] pub struct Container { #[command(flatten)] - quadlet_options: quadlet::QuadletOptions, + quadlet_options: QuadletOptions, /// Converts to "PodmanArgs=ARGS" #[command(flatten)] - podman_args: podman::PodmanArgs, + podman_args: PodmanArgs, /// Security options /// + /// Converts to a number of different quadlet options or, + /// if a quadlet option for the specified security option doesn't exist, + /// is placed in "PodmanArgs=" + /// /// Can be specified multiple times #[arg(long, value_name = "OPTION")] security_opt: Vec, @@ -68,7 +72,7 @@ impl Container { .image .rsplit('/') .next() - .expect("Split will has at least one element"); + .expect("Split will have at least one element"); // Remove image tag image.split_once(':').map_or(image, |(name, _)| name) }) @@ -76,13 +80,13 @@ impl Container { } #[derive(Debug, Clone, PartialEq)] -pub enum Output { +enum Output { QuadletOptions(String), PodmanArg(String), } impl Output { - pub fn write_or_add_arg( + fn write_or_add_arg( &self, arg: &str, f: &mut Formatter, diff --git a/src/cli/container/quadlet.rs b/src/cli/container/quadlet.rs index e00fa98..68b9c75 100644 --- a/src/cli/container/quadlet.rs +++ b/src/cli/container/quadlet.rs @@ -167,8 +167,6 @@ pub struct QuadletOptions { /// Logging driver for the container /// - /// The default is `passthrough` - /// /// Converts to "LogDriver=DRIVER" #[arg(long, value_name = "DRIVER")] log_driver: Option, diff --git a/src/cli/container/security_opt.rs b/src/cli/container/security_opt.rs index 446389a..2225702 100644 --- a/src/cli/container/security_opt.rs +++ b/src/cli/container/security_opt.rs @@ -22,28 +22,28 @@ impl FromStr for SecurityOpt { match s { s if s.starts_with("apparmor=") => { let (_, policy) = s.split_once('=').expect("delimiter is in guard"); - Ok(SecurityOpt::Apparmor(String::from(policy))) + Ok(Self::Apparmor(String::from(policy))) } s if s.starts_with("label=") => { let (_, label) = s.split_once('=').expect("delimiter is in guard"); - Ok(SecurityOpt::Label(label.parse()?)) + Ok(Self::Label(label.parse()?)) } s if s.starts_with("mask=") => { let (_, mask) = s.split_once('=').expect("delimiter is in guard"); - Ok(SecurityOpt::Mask(String::from(mask))) + Ok(Self::Mask(String::from(mask))) } - "no-new-privileges" => Ok(SecurityOpt::NoNewPrivileges), + "no-new-privileges" => Ok(Self::NoNewPrivileges), s if s.starts_with("seccomp=") => { let (_, profile) = s.split_once('=').expect("delimiter is in guard"); - Ok(SecurityOpt::Seccomp(String::from(profile))) + Ok(Self::Seccomp(String::from(profile))) } s if s.starts_with("proc-opts=") => { let (_, opts) = s.split_once('=').expect("delimiter is in guard"); - Ok(SecurityOpt::ProcOpts(String::from(opts))) + Ok(Self::ProcOpts(String::from(opts))) } s if s.starts_with("unmask=") => { let (_, unmask) = s.split_once('=').expect("delimiter is in guard"); - Ok(SecurityOpt::Unmask(String::from(unmask))) + Ok(Self::Unmask(String::from(unmask))) } _ => Err(ParseSecurityOptError::InvalidSecurityOpt(String::from(s))), } @@ -100,26 +100,26 @@ impl FromStr for LabelOpt { match s { s if s.starts_with("user:") => { let (_, user) = s.split_once(':').expect("delimiter is in guard"); - Ok(LabelOpt::User(String::from(user))) + Ok(Self::User(String::from(user))) } s if s.starts_with("role:") => { let (_, role) = s.split_once(':').expect("delimiter is in guard"); - Ok(LabelOpt::Role(String::from(role))) + Ok(Self::Role(String::from(role))) } s if s.starts_with("type:") => { let (_, label_type) = s.split_once(':').expect("delimiter is in guard"); - Ok(LabelOpt::Type(String::from(label_type))) + Ok(Self::Type(String::from(label_type))) } s if s.starts_with("level:") => { let (_, level) = s.split_once(':').expect("delimiter is in guard"); - Ok(LabelOpt::Level(String::from(level))) + Ok(Self::Level(String::from(level))) } s if s.starts_with("filetype:") => { let (_, filetype) = s.split_once(':').expect("delimiter is in guard"); - Ok(LabelOpt::Filetype(String::from(filetype))) + Ok(Self::Filetype(String::from(filetype))) } - "disable" => Ok(LabelOpt::Disable), - "nested" => Ok(LabelOpt::Nested), + "disable" => Ok(Self::Disable), + "nested" => Ok(Self::Nested), _ => Err(InvalidLabelOpt(String::from(s))), } } diff --git a/src/cli/kube.rs b/src/cli/kube.rs index 4d665ea..d744bf8 100644 --- a/src/cli/kube.rs +++ b/src/cli/kube.rs @@ -125,8 +125,8 @@ impl FromStr for File { impl Display for File { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - File::Url(url) => write!(f, "{url}"), - File::Path(path) => write!(f, "{}", path.display()), + Self::Url(url) => write!(f, "{url}"), + Self::Path(path) => write!(f, "{}", path.display()), } } } diff --git a/src/cli/network.rs b/src/cli/network.rs index a054b61..8a0d6a1 100644 --- a/src/cli/network.rs +++ b/src/cli/network.rs @@ -31,7 +31,7 @@ impl Display for Network { impl Network { pub fn name(&self) -> &str { - let Network::Create { create } = self; + let Self::Create { create } = self; &create.name } } diff --git a/src/cli/volume.rs b/src/cli/volume.rs index 9248f55..55fa1af 100644 --- a/src/cli/volume.rs +++ b/src/cli/volume.rs @@ -33,7 +33,7 @@ impl Display for Volume { impl Volume { pub fn name(&self) -> &str { - let Volume::Create { create } = self; + let Self::Create { create } = self; &create.name } } From 8f4cc3a3dd522083f804bcf8f39aa0345a9675da Mon Sep 17 00:00:00 2001 From: Paul Nettleton Date: Fri, 14 Apr 2023 17:59:41 -0500 Subject: [PATCH 6/6] Update readme and changelog --- CHANGELOG.md | 4 ++-- README.md | 13 ++++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4626cb5..754b26f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [Unreleased] +## [0.1.0] - 2023-04-14 -The initial release of podlet! Designed for podman v4.5.0(?) and newer. +The initial release of podlet! Designed for podman v4.5.0 and newer. ### Initial Features diff --git a/README.md b/README.md index bd27765..53c3873 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,14 @@ Podlet generates [podman](https://podman.io/) [quadlet](https://docs.podman.io/e ## Features -- Write to stdout or to a file. +- Designed for podman v4.5.0 and newer - Supports the following podman commands: - `podman run` - `podman kube play` - `podman network create` - `podman volume create` -- Options for including common systemd unit options. +- Write to stdout or to a file +- Options for including common systemd unit options ## Install @@ -111,9 +112,15 @@ Network=pasta UserNS=auto ``` +Podlet is not (yet) a validator for podman commands. Some podman options are incompatible with each other and most options require specific formatting and/or only accept certain values. However, a few options are fully parsed and validated in order to facilitate creating the quadlet file. + +For the `kube play`, `network create`, and `volume create` commands, not all of podman's options are available as not all options are supported by quadlet. + +Podlet is meant to be used with podman v4.5.0 or newer. Some quadlet options are unavailable or behave differently with earlier versions of podman/quadlet. + ## Contribution -This is my (@k9withabone) first real rust project and is mostly meant as a learning project for myself. That said, contributions, suggestions, and/or comments are appreciated! +This is my (@k9withabone) first real rust project and is mostly meant as a learning project for myself. That said, contributions, suggestions, and/or comments are appreciated! Feel free to create an [issue](https://github.com/k9withabone/podlet/issues), [discussion](https://github.com/k9withabone/podlet/discussions), or [pull request](https://github.com/k9withabone/podlet/pulls). ## License