use crate::{
error::OciSpecError,
runtime::{Capabilities, Capability},
};
use derive_builder::Builder;
use getset::{CopyGetters, Getters, MutGetters, Setters};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use strum_macros::{Display as StrumDisplay, EnumString};
#[derive(
Builder,
Clone,
CopyGetters,
Debug,
Deserialize,
Getters,
MutGetters,
Setters,
Eq,
PartialEq,
Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
pub struct Process {
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
terminal: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
console_size: Option<Box>,
#[getset(get_mut = "pub", get = "pub", set = "pub")]
user: User,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
args: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
command_line: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
env: Option<Vec<String>>,
#[getset(get = "pub", set = "pub")]
cwd: PathBuf,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
capabilities: Option<LinuxCapabilities>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
#[cfg(any(target_os = "linux", target_os = "solaris"))]
rlimits: Option<Vec<PosixRlimit>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
no_new_privileges: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
apparmor_profile: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
oom_score_adj: Option<i32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
selinux_label: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
io_priority: Option<LinuxIOPriority>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
scheduler: Option<Scheduler>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
exec_cpu_affinity: Option<ExecCPUAffinity>,
}
impl Default for Process {
fn default() -> Self {
Process {
terminal: false.into(),
console_size: Default::default(),
user: Default::default(),
args: vec!["sh".to_string()].into(),
env: vec![
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin".into(),
"TERM=xterm".into(),
]
.into(),
cwd: "/".into(),
no_new_privileges: true.into(),
apparmor_profile: Default::default(),
selinux_label: Default::default(),
scheduler: Default::default(),
capabilities: Some(Default::default()),
#[cfg(any(target_os = "linux", target_os = "solaris"))]
rlimits: vec![PosixRlimit {
typ: PosixRlimitType::RlimitNofile,
hard: 1024,
soft: 1024,
}]
.into(),
oom_score_adj: None,
command_line: None,
io_priority: Default::default(),
exec_cpu_affinity: Default::default(),
}
}
}
#[derive(
Builder, Clone, Copy, CopyGetters, Debug, Default, Deserialize, Eq, PartialEq, Serialize,
)]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
#[getset(get_copy = "pub", set = "pub")]
pub struct Box {
#[serde(default)]
height: u64,
#[serde(default)]
width: u64,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[cfg(any(target_os = "linux", target_os = "solaris"))]
pub enum PosixRlimitType {
RlimitCpu,
RlimitFsize,
RlimitData,
RlimitStack,
RlimitCore,
#[cfg(target_os = "linux")]
RlimitRss,
#[cfg(target_os = "linux")]
RlimitNproc,
RlimitNofile,
#[cfg(target_os = "linux")]
RlimitMemlock,
RlimitAs,
#[cfg(target_os = "linux")]
RlimitLocks,
#[cfg(target_os = "linux")]
RlimitSigpending,
#[cfg(target_os = "linux")]
RlimitMsgqueue,
#[cfg(target_os = "linux")]
RlimitNice,
#[cfg(target_os = "linux")]
RlimitRtprio,
#[cfg(target_os = "linux")]
RlimitRttime,
}
#[cfg(any(target_os = "linux", target_os = "solaris"))]
impl Default for PosixRlimitType {
fn default() -> Self {
Self::RlimitCpu
}
}
#[derive(
Builder, Clone, Copy, CopyGetters, Debug, Default, Deserialize, Eq, PartialEq, Serialize,
)]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
#[getset(get_copy = "pub", set = "pub")]
#[cfg(any(target_os = "linux", target_os = "solaris"))]
pub struct PosixRlimit {
#[serde(rename = "type")]
typ: PosixRlimitType,
#[serde(default)]
hard: u64,
#[serde(default)]
soft: u64,
}
#[derive(
Builder,
Clone,
CopyGetters,
Debug,
Default,
Deserialize,
Getters,
MutGetters,
Setters,
Eq,
PartialEq,
Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
pub struct User {
#[serde(default)]
#[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
uid: u32,
#[serde(default)]
#[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
gid: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
umask: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
additional_gids: Option<Vec<u32>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
username: Option<String>,
}
#[derive(Builder, Clone, Debug, Deserialize, Getters, Setters, Eq, PartialEq, Serialize)]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
#[getset(get = "pub", set = "pub")]
pub struct LinuxCapabilities {
#[serde(default, skip_serializing_if = "Option::is_none")]
bounding: Option<Capabilities>,
#[serde(default, skip_serializing_if = "Option::is_none")]
effective: Option<Capabilities>,
#[serde(default, skip_serializing_if = "Option::is_none")]
inheritable: Option<Capabilities>,
#[serde(default, skip_serializing_if = "Option::is_none")]
permitted: Option<Capabilities>,
#[serde(default, skip_serializing_if = "Option::is_none")]
ambient: Option<Capabilities>,
}
impl Default for LinuxCapabilities {
fn default() -> Self {
let audit_write = Capability::AuditWrite;
let cap_kill = Capability::Kill;
let net_bind = Capability::NetBindService;
let default_vec = vec![audit_write, cap_kill, net_bind]
.into_iter()
.collect::<Capabilities>();
LinuxCapabilities {
bounding: default_vec.clone().into(),
effective: default_vec.clone().into(),
inheritable: default_vec.clone().into(),
permitted: default_vec.clone().into(),
ambient: default_vec.into(),
}
}
}
#[derive(
Builder, Clone, Copy, CopyGetters, Debug, Default, Deserialize, Eq, PartialEq, Serialize,
)]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
#[getset(get_copy = "pub", set = "pub")]
pub struct LinuxIOPriority {
#[serde(default)]
class: IOPriorityClass,
#[serde(default)]
priority: i64,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum IOPriorityClass {
IoprioClassRt,
IoprioClassBe,
IoprioClassIdle,
}
impl Default for IOPriorityClass {
fn default() -> Self {
Self::IoprioClassBe
}
}
#[derive(Builder, Clone, Debug, Deserialize, Getters, Setters, Eq, PartialEq, Serialize)]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
#[getset(get = "pub", set = "pub")]
pub struct Scheduler {
policy: LinuxSchedulerPolicy,
#[serde(default, skip_serializing_if = "Option::is_none")]
nice: Option<i32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
priority: Option<i32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
flags: Option<Vec<LinuxSchedulerFlag>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
runtime: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
deadline: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
period: Option<u64>,
}
impl Default for Scheduler {
fn default() -> Self {
Self {
policy: LinuxSchedulerPolicy::default(),
nice: None,
priority: None,
flags: None,
runtime: None,
deadline: None,
period: None,
}
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum LinuxSchedulerPolicy {
SchedOther,
SchedFifo,
SchedRr,
SchedBatch,
SchedIso,
SchedIdle,
SchedDeadline,
}
impl Default for LinuxSchedulerPolicy {
fn default() -> Self {
LinuxSchedulerPolicy::SchedOther
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum LinuxSchedulerFlag {
SchedResetOnFork,
SchedFlagReclaim,
SchedFlagDLOverrun,
SchedFlagKeepPolicy,
SchedFlagKeepParams,
SchedFlagUtilClampMin,
SchedFlagUtilClampMax,
}
impl Default for LinuxSchedulerFlag {
fn default() -> Self {
LinuxSchedulerFlag::SchedResetOnFork
}
}
#[derive(
Builder, Clone, Debug, Default, Deserialize, Getters, Setters, Eq, PartialEq, Serialize,
)]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
#[getset(get = "pub", set = "pub")]
pub struct ExecCPUAffinity {
#[serde(default, skip_serializing_if = "Option::is_none")]
cpu_affinity_initial: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
cpu_affinity_final: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn posix_rlimit_type_enum_to_string() {
let type_a = PosixRlimitType::RlimitCpu;
assert_eq!(type_a.to_string(), "RLIMIT_CPU");
let type_b = PosixRlimitType::RlimitData;
assert_eq!(type_b.to_string(), "RLIMIT_DATA");
let type_c = PosixRlimitType::RlimitNofile;
assert_eq!(type_c.to_string(), "RLIMIT_NOFILE");
}
#[test]
fn posix_rlimit_type_string_to_enum() {
let posix_rlimit_type_str = "RLIMIT_CPU";
let posix_rlimit_type_enum: PosixRlimitType = posix_rlimit_type_str.parse().unwrap();
assert_eq!(posix_rlimit_type_enum, PosixRlimitType::RlimitCpu);
let posix_rlimit_type_str = "RLIMIT_DATA";
let posix_rlimit_type_enum: PosixRlimitType = posix_rlimit_type_str.parse().unwrap();
assert_eq!(posix_rlimit_type_enum, PosixRlimitType::RlimitData);
let posix_rlimit_type_str = "RLIMIT_NOFILE";
let posix_rlimit_type_enum: PosixRlimitType = posix_rlimit_type_str.parse().unwrap();
assert_eq!(posix_rlimit_type_enum, PosixRlimitType::RlimitNofile);
let invalid_posix_rlimit_type_str = "x";
let unknown_rlimit = invalid_posix_rlimit_type_str.parse::<PosixRlimitType>();
assert!(unknown_rlimit.is_err());
}
}