Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "podlet"
version = "0.3.2-alpha.3"
version = "0.3.2-alpha.4"
authors = ["Paul Nettleton <k9@k9withabone.dev>"]
edition = "2024"
rust-version = "1.85"
Expand Down
13 changes: 12 additions & 1 deletion src/cli/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ impl From<NetworkInspect> for Network {
.collect(),
driver: Some(driver),
gateway,
interface_name: Some(network_interface),
internal,
ipam_driver: Some(ipam_driver),
ip_range,
Expand All @@ -638,7 +639,6 @@ impl From<NetworkInspect> for Network {
.collect(),
subnet,
podman_args: network::PodmanArgs {
interface_name: Some(network_interface),
route: routes.iter().map(NetworkRoute::to_route_value).collect(),
},
name,
Expand All @@ -662,6 +662,14 @@ struct VolumeInspect {

/// --opt
options: IndexMap<String, String>,

/// --uid
#[serde(rename = "UID", default)]
uid: Option<u32>,

/// --gid
#[serde(rename = "GID", default)]
gid: Option<u32>,
}

impl VolumeInspect {
Expand Down Expand Up @@ -706,6 +714,8 @@ impl From<VolumeInspect> for Volume {
driver,
labels,
options,
uid,
gid,
}: VolumeInspect,
) -> Self {
Volume::Create {
Expand All @@ -721,6 +731,7 @@ impl From<VolumeInspect> for Volume {
.into_iter()
.map(|(label, value)| format!("{label}={value}"))
.collect(),
podman_args: volume::PodmanArgs { uid, gid },
name,
},
}
Expand Down
12 changes: 11 additions & 1 deletion src/cli/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{path::PathBuf, str::FromStr};
use clap::{Args, Subcommand};
use thiserror::Error;

use crate::quadlet::{self, image::DecryptionKey};
use crate::quadlet::{self, container::PullPolicy, image::DecryptionKey};

use super::image_to_name;

Expand Down Expand Up @@ -107,6 +107,14 @@ pub struct Pull {
#[arg(long, conflicts_with_all = ["os", "arch"], value_name = "OS/ARCH")]
pub platform: Option<Platform>,

/// Pull image policy.
///
/// Converts to "Policy=POLICY".
///
/// Default is `always`.
#[arg(long)]
pub policy: Option<PullPolicy>,

/// Number of times to retry pulling or pushing images between the registry and local storage.
///
/// Converts to "Retry=ATTEMPTS".
Expand Down Expand Up @@ -154,6 +162,7 @@ impl From<Pull> for quadlet::Image {
disable_content_trust: _,
os,
platform,
policy,
retry,
retry_delay,
tls_verify,
Expand All @@ -176,6 +185,7 @@ impl From<Pull> for quadlet::Image {
image_tag: None,
os,
podman_args: None,
policy,
retry,
retry_delay,
tls_verify,
Expand Down
33 changes: 10 additions & 23 deletions src/cli/k8s.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ mod volume;

use color_eyre::eyre::{OptionExt, WrapErr, ensure};
use compose_spec::{Compose, Resource};
use k8s_openapi::{
api::core::v1::{PersistentVolumeClaim, Pod, PodSpec},
apimachinery::pkg::apis::meta::v1::ObjectMeta,
};
use k8s_openapi::api::core::v1::{PersistentVolumeClaim, Pod};

use self::service::Service;

Expand Down Expand Up @@ -87,26 +84,16 @@ impl TryFrom<Compose> for File {

let name = name.map(String::from).ok_or_eyre("`name` is required")?;

let spec =
services
.into_iter()
.try_fold(PodSpec::default(), |mut spec, (name, service)| {
Service::from_compose(&name, service)
.add_to_pod_spec(&mut spec)
.wrap_err_with(|| {
format!("error adding service `{name}` to Kubernetes pod spec")
})
.map(|()| spec)
})?;
let mut pod = Pod::default();
pod.metadata.name = Some(name.clone());

let pod = Pod {
metadata: ObjectMeta {
name: Some(name.clone()),
..ObjectMeta::default()
},
spec: Some(spec),
status: None,
};
for (name, service) in services {
Service::from_compose(&name, service)
.add_to_pod(&mut pod)
.wrap_err_with(|| {
format!("error adding service `{name}` to Kubernetes pod spec")
})?;
}

let persistent_volume_claims = volumes
.into_iter()
Expand Down
51 changes: 35 additions & 16 deletions src/cli/k8s/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use compose_spec::{
use indexmap::{IndexMap, IndexSet};
use k8s_openapi::{
api::core::v1::{
Capabilities, Container, ContainerPort, EnvVar, ExecAction, PodSpec, Probe,
Capabilities, Container, ContainerPort, EnvVar, ExecAction, Lifecycle, Pod, Probe,
ResourceRequirements, SELinuxOptions, SecurityContext,
},
apimachinery::pkg::api::resource::Quantity,
Expand All @@ -47,13 +47,16 @@ pub(super) struct Service {
resources: ContainerResources,
security_context: ContainerSecurityContext,
command: Option<Command>,
cpuset: CpuSet,
entrypoint: Option<Command>,
environment: ListOrMap,
healthcheck: Option<Healthcheck>,
image: Option<Image>,
pids_limit: Option<Limit<u32>>,
ports: Ports,
pull_policy: Option<PullPolicy>,
stdin_open: bool,
stop_signal: Option<String>,
tmpfs: Option<ItemOrList<AbsolutePath>>,
tty: bool,
volumes: Volumes,
Expand Down Expand Up @@ -163,7 +166,6 @@ impl Service {
cpu_quota,
cpu_rt_runtime,
cpu_rt_period,
cpuset,
cgroup,
cgroup_parent,
configs,
Expand Down Expand Up @@ -199,7 +201,6 @@ impl Service {
oom_kill_disable,
oom_score_adj,
pid,
pids_limit,
platform,
profiles,
restart,
Expand All @@ -208,7 +209,6 @@ impl Service {
secrets,
shm_size,
stop_grace_period,
stop_signal,
storage_opt,
sysctls,
ulimits,
Expand All @@ -231,39 +231,46 @@ impl Service {
user,
},
command,
cpuset,
entrypoint,
environment,
healthcheck,
image,
pids_limit,
ports,
pull_policy,
stdin_open,
stop_signal,
tmpfs,
tty,
volumes,
working_dir,
}
}

/// Add the service to a [`PodSpec`]'s [`Container`]s and [`Volume`]s.
/// Add the service to a [`Pod`]'s [`Container`]s and [`Volume`]s.
///
/// # Errors
///
/// Returns an error if an unsupported option was used or conversion of one of the fields fails.
pub(super) fn add_to_pod_spec(self, spec: &mut PodSpec) -> color_eyre::Result<()> {
#[expect(clippy::too_many_lines, reason = "`Self` expansion")]
pub(super) fn add_to_pod(self, pod: &mut Pod) -> color_eyre::Result<()> {
let Self {
unsupported,
name,
resources,
security_context,
command,
cpuset,
entrypoint,
environment,
healthcheck,
image,
pids_limit,
ports,
pull_policy,
stdin_open,
stop_signal,
tmpfs,
tty,
volumes,
Expand All @@ -272,13 +279,15 @@ impl Service {

unsupported.ensure_empty()?;

let spec = pod.spec.get_or_insert_default();

let volume_mounts =
tmpfs_and_volumes_try_into_volume_mounts(tmpfs, volumes, &name, &mut spec.volumes)
// converting `tmpfs` always succeeds
.wrap_err("error converting `volumes`")?;

spec.containers.push(Container {
name: name.into(),
name: name.clone().into(),
resources: resources.into_resource_requirements(),
security_context: security_context.try_into_security_context()?,
args: command
Expand Down Expand Up @@ -306,6 +315,11 @@ impl Service {
})
.transpose()
.wrap_err("error converting `environment`")?,
lifecycle: stop_signal.map(|stop_signal| Lifecycle {
post_start: None,
pre_stop: None,
stop_signal: Some(stop_signal),
}),
liveness_probe: healthcheck
.and_then(|healthcheck| match healthcheck {
Healthcheck::Command(command) => {
Expand Down Expand Up @@ -348,6 +362,20 @@ impl Service {
..Container::default()
});

if let Some(pids_limit) = pids_limit {
pod.metadata.annotations.get_or_insert_default().insert(
format!("io.podman.annotations.pids-limit/{name}"),
pids_limit.to_string(),
);
}

if !cpuset.is_empty() {
pod.metadata.annotations.get_or_insert_default().insert(
format!("io.podman.annotations.cpuset/{name}"),
cpuset.to_string(),
);
}

Ok(())
}
}
Expand Down Expand Up @@ -688,7 +716,6 @@ struct Unsupported {
cpu_quota: Option<Duration>,
cpu_rt_runtime: Option<Duration>,
cpu_rt_period: Option<Duration>,
cpuset: CpuSet,
cgroup: Option<Cgroup>,
cgroup_parent: Option<String>,
configs: Vec<ShortOrLong<Identifier, ConfigOrSecret>>,
Expand Down Expand Up @@ -724,7 +751,6 @@ struct Unsupported {
oom_kill_disable: bool,
oom_score_adj: Option<OomScoreAdj>,
pid: Option<String>,
pids_limit: Option<Limit<u32>>,
platform: Option<Platform>,
profiles: IndexSet<Identifier>,
restart: Option<Restart>,
Expand All @@ -733,7 +759,6 @@ struct Unsupported {
secrets: Vec<ShortOrLong<Identifier, ConfigOrSecret>>,
shm_size: Option<ByteValue>,
stop_grace_period: Option<Duration>,
stop_signal: Option<String>,
storage_opt: Map,
sysctls: ListOrMap,
ulimits: Ulimits,
Expand Down Expand Up @@ -761,7 +786,6 @@ impl Unsupported {
cpu_quota,
cpu_rt_runtime,
cpu_rt_period,
cpuset,
cgroup,
cgroup_parent,
configs,
Expand Down Expand Up @@ -797,7 +821,6 @@ impl Unsupported {
oom_kill_disable,
oom_score_adj,
pid,
pids_limit,
platform,
profiles,
restart,
Expand All @@ -806,7 +829,6 @@ impl Unsupported {
secrets,
shm_size,
stop_grace_period,
stop_signal,
storage_opt,
sysctls,
ulimits,
Expand All @@ -826,7 +848,6 @@ impl Unsupported {
("cpu_quota", cpu_quota.is_none()),
("cpu_rt_runtime", cpu_rt_runtime.is_none()),
("cpu_rt_period", cpu_rt_period.is_none()),
("cpuset", cpuset.is_empty()),
("cgroup", cgroup.is_none()),
("cgroup_parent", cgroup_parent.is_none()),
("configs", configs.is_empty()),
Expand Down Expand Up @@ -858,14 +879,12 @@ impl Unsupported {
("memswap_limit", memswap_limit.is_none()),
("oom_kill_disable", !oom_kill_disable),
("oom_score_adj", oom_score_adj.is_none()),
("pids_limit", pids_limit.is_none()),
("platform", platform.is_none()),
("profiles", profiles.is_empty()),
("runtime", runtime.is_none()),
("scale", scale.is_none()),
("secrets", secrets.is_empty()),
("shm_size", shm_size.is_none()),
("stop_signal", stop_signal.is_none()),
("storage_opt", storage_opt.is_empty()),
("ulimits", ulimits.is_empty()),
("userns_mode", userns_mode.is_none()),
Expand Down
Loading
Loading