use cri_api::v1::{ContainerMetadata, Device, ImageSpec, KeyValue, LinuxContainerConfig, Mount, WindowsContainerConfig, ContainerConfig, PodSandboxMetadata, DnsConfig, PortMapping, LinuxPodSandboxConfig, WindowsPodSandboxConfig, PodSandboxConfig, LinuxContainerResources, LinuxContainerSecurityContext, HugepageLimit, Capability, NamespaceOption, SeLinuxOption, Int64Value, SecurityProfile, LinuxSandboxSecurityContext};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct ContainerConfigPartial {
pub metadata: Option<ContainerMetadataPartial>,
pub image: ImageSpecPartial,
pub command: Option<Vec<String>>,
pub args: Option<Vec<String>>,
pub working_dir: Option<String>,
pub envs: Option<Vec<KeyValue>>,
pub mounts: Option<Vec<MountPartial>>,
pub devices: Option<Vec<DevicePartial>>,
pub labels: Option<std::collections::HashMap<String, String>>,
pub annotations: Option<std::collections::HashMap<String, String>>,
pub log_path: Option<String>,
pub stdin: Option<bool>,
pub stdin_once: Option<bool>,
pub tty: Option<bool>,
pub linux: Option<LinuxContainerConfigPartial>,
pub windows: Option<WindowsContainerConfig>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct ImageSpecPartial {
pub image: Option<String>,
pub annotations: Option<std::collections::HashMap<String, String>>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct ContainerMetadataPartial {
pub name: Option<String>,
pub attempt: Option<u32>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct MountPartial {
pub container_path: Option<String>,
pub host_path: Option<String>,
pub readonly: Option<bool>,
pub selinux_relabel: Option<bool>,
pub propagation: Option<i32>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct DevicePartial {
pub container_path: Option<String>,
pub host_path: Option<String>,
pub permissions: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct LinuxContainerConfigPartial {
pub resources: Option<LinuxContainerResourcesPartial>,
pub security_context: Option<LinuxContainerSecurityContextPartial>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct LinuxContainerResourcesPartial {
pub cpu: String,
pub memory: String,
pub cpu_shares: Option<i64>,
pub oom_score_adj: Option<i64>,
pub cpuset_cpus: Option<String>,
pub cpuset_mems: Option<String>,
pub hugepage_limits: Option<Vec<HugepageLimit>>,
pub unified: Option<std::collections::HashMap<String, String>>,
pub memory_swap_limit_in_bytes: Option<i64>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct LinuxContainerSecurityContextPartial {
pub capabilities: Option<Capability>,
pub privileged: Option<bool>,
pub namespace_options: Option<NamespaceOption>,
pub selinux_options: Option<SeLinuxOption>,
pub run_as_user: Option<Int64Value>,
pub run_as_group: Option<Int64Value>,
pub run_as_username: Option<String>,
pub readonly_rootfs: Option<bool>,
pub supplemental_groups: Option<Vec<i64>>,
pub no_new_privs: Option<bool>,
pub masked_paths: Option<Vec<String>>,
pub readonly_paths: Option<Vec<String>>,
pub seccomp: Option<SecurityProfile>,
pub apparmor: Option<SecurityProfile>,
pub apparmor_profile: Option<String>,
pub seccomp_profile_path: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct PodSandboxConfigPartial {
pub metadata: Option<PodSandboxMetadataPartial>,
pub hostname: Option<String>,
pub log_directory: Option<String>,
pub dns_config: Option<DnsConfigPartial>,
pub port_mappings: Option<Vec<PortMappingPartial>>,
pub labels: Option<std::collections::HashMap<String, String>>,
pub annotations: Option<std::collections::HashMap<String, String>>,
pub linux: Option<LinuxPodSandboxConfigPartial>,
pub windows: Option<WindowsPodSandboxConfig>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct PodSandboxMetadataPartial {
pub name: Option<String>,
pub uid: Option<String>,
pub namespace: Option<String>,
pub attempt: Option<u32>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct DnsConfigPartial {
pub servers: Option<Vec<String>>,
pub searches: Option<Vec<String>>,
pub options: Option<Vec<String>>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct PortMappingPartial {
pub container_port: i32,
pub host_port: i32,
pub protocol: Option<i32>,
pub host_ip: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct LinuxPodSandboxConfigPartial {
pub cgroup_parent: Option<String>,
pub security_context: Option<LinuxSandboxSecurityContextPartial>,
pub sysctls: Option<std::collections::HashMap<String, String>>,
pub overhead: Option<LinuxContainerResourcesPartial>,
pub resources: Option<LinuxContainerResourcesPartial>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct LinuxSandboxSecurityContextPartial {
pub namespace_options: Option<NamespaceOption>,
pub selinux_options: Option<SeLinuxOption>,
pub run_as_user: Option<Int64Value>,
pub run_as_group: Option<Int64Value>,
pub readonly_rootfs: Option<bool>,
pub supplemental_groups: Option<Vec<i64>>,
pub privileged: Option<bool>,
pub seccomp: Option<SecurityProfile>,
pub apparmor: Option<SecurityProfile>,
pub seccomp_profile_path: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct CriConfigPartial {
pub container_config_partial: ContainerConfigPartial,
pub pod_sandbox_config_partial: Option<PodSandboxConfigPartial>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct CriConfig {
pub container_config: ContainerConfig,
pub pod_sandbox_config: Option<PodSandboxConfig>,
}
impl From<ImageSpec> for ImageSpecPartial {
fn from(spec: ImageSpec) -> Self {
ImageSpecPartial {
image: Some(spec.image),
annotations: Some(spec.annotations),
}
}
}
impl From<ImageSpecPartial> for ImageSpec {
fn from(partial: ImageSpecPartial) -> Self {
ImageSpec {
image: partial.image.unwrap_or_else(|| String::new()),
annotations: partial.annotations.unwrap_or_else(std::collections::HashMap::new),
}
}
}
impl From<ContainerMetadata> for ContainerMetadataPartial {
fn from(metadata: ContainerMetadata) -> Self {
ContainerMetadataPartial {
name: Some(metadata.name),
attempt: Some(metadata.attempt),
}
}
}
impl From<ContainerMetadataPartial> for ContainerMetadata {
fn from(partial: ContainerMetadataPartial) -> Self {
ContainerMetadata {
name: partial.name.unwrap_or_else(|| String::new()),
attempt: partial.attempt.unwrap_or(5),
}
}
}
impl From<MountPartial> for Mount {
fn from(partial: MountPartial) -> Self {
Mount {
container_path: partial.container_path.unwrap_or_default(),
host_path: partial.host_path.unwrap_or_default(),
readonly: partial.readonly.unwrap_or(false),
selinux_relabel: partial.selinux_relabel.unwrap_or(false),
propagation: partial.propagation.unwrap_or(0),
}
}
}
impl From<Mount> for MountPartial {
fn from(mount: Mount) -> Self {
MountPartial {
container_path: Some(mount.container_path),
host_path: Some(mount.host_path),
readonly: Some(mount.readonly),
selinux_relabel: Some(mount.selinux_relabel),
propagation: Some(mount.propagation),
}
}
}
impl From<DevicePartial> for Device {
fn from(partial: DevicePartial) -> Self {
Device {
container_path: partial.container_path.unwrap_or_default(),
host_path: partial.host_path.unwrap_or_default(),
permissions: partial.permissions.unwrap_or_else(|| "rwm".to_string()),
}
}
}
impl From<Device> for DevicePartial {
fn from(device: Device) -> Self {
DevicePartial {
container_path: Some(device.container_path),
host_path: Some(device.host_path),
permissions: Some(device.permissions),
}
}
}
impl From<LinuxContainerResourcesPartial> for LinuxContainerResources {
fn from(partial: LinuxContainerResourcesPartial) -> Self {
let (cpu_period, cpu_quota) = LinuxContainerResourcesPartial::parse_cpu(&partial.cpu);
let memory_limit_in_bytes = LinuxContainerResourcesPartial::parse_memory(&partial.memory);
LinuxContainerResources {
cpu_period: cpu_period,
cpu_quota: cpu_quota,
cpu_shares: partial.cpu_shares.unwrap_or(0),
memory_limit_in_bytes: memory_limit_in_bytes,
oom_score_adj: partial.oom_score_adj.unwrap_or(0),
cpuset_cpus: partial.cpuset_cpus.unwrap_or_default(),
cpuset_mems: partial.cpuset_mems.unwrap_or_default(),
hugepage_limits: partial.hugepage_limits.unwrap_or_default(),
unified: partial.unified.unwrap_or_default(),
memory_swap_limit_in_bytes: partial.memory_swap_limit_in_bytes.unwrap_or(0),
}
}
}
impl From<LinuxContainerResources> for LinuxContainerResourcesPartial {
fn from(resources: LinuxContainerResources) -> Self {
let cpu = LinuxContainerResourcesPartial::format_cpu(resources.cpu_period, resources.cpu_quota);
let memory = LinuxContainerResourcesPartial::format_memory(resources.memory_limit_in_bytes);
LinuxContainerResourcesPartial {
cpu,
memory,
cpu_shares: Some(resources.cpu_shares),
oom_score_adj: Some(resources.oom_score_adj),
cpuset_cpus: Some(resources.cpuset_cpus),
cpuset_mems: Some(resources.cpuset_mems),
hugepage_limits: Some(resources.hugepage_limits),
unified: Some(resources.unified),
memory_swap_limit_in_bytes: Some(resources.memory_swap_limit_in_bytes),
}
}
}
impl From<LinuxContainerSecurityContextPartial> for LinuxContainerSecurityContext {
#[allow(deprecated)]
fn from(partial: LinuxContainerSecurityContextPartial) -> Self {
LinuxContainerSecurityContext {
capabilities: partial.capabilities,
privileged: partial.privileged.unwrap_or(false),
namespace_options: partial.namespace_options,
selinux_options: partial.selinux_options,
run_as_user: partial.run_as_user,
run_as_group: partial.run_as_group,
run_as_username: partial.run_as_username.unwrap_or_default(),
readonly_rootfs: partial.readonly_rootfs.unwrap_or(false),
supplemental_groups: partial.supplemental_groups.unwrap_or_default(),
no_new_privs: partial.no_new_privs.unwrap_or(false),
masked_paths: partial.masked_paths.unwrap_or_default(),
readonly_paths: partial.readonly_paths.unwrap_or_default(),
seccomp: partial.seccomp,
apparmor: partial.apparmor,
apparmor_profile: partial.apparmor_profile.unwrap_or_default(),
seccomp_profile_path: partial.seccomp_profile_path.unwrap_or_default(),
}
}
}
impl From<LinuxContainerSecurityContext> for LinuxContainerSecurityContextPartial {
#[allow(deprecated)]
fn from(context: LinuxContainerSecurityContext) -> Self {
LinuxContainerSecurityContextPartial {
capabilities: context.capabilities,
privileged: Some(context.privileged),
namespace_options: context.namespace_options,
selinux_options: context.selinux_options,
run_as_user: context.run_as_user,
run_as_group: context.run_as_group,
run_as_username: Some(context.run_as_username),
readonly_rootfs: Some(context.readonly_rootfs),
supplemental_groups: Some(context.supplemental_groups),
no_new_privs: Some(context.no_new_privs),
masked_paths: Some(context.masked_paths),
readonly_paths: Some(context.readonly_paths),
seccomp: context.seccomp,
apparmor: context.apparmor,
apparmor_profile: Some(context.apparmor_profile),
seccomp_profile_path: Some(context.seccomp_profile_path),
}
}
}
impl From<LinuxContainerConfigPartial> for LinuxContainerConfig {
fn from(partial: LinuxContainerConfigPartial) -> Self {
LinuxContainerConfig {
resources: partial.resources.map(Into::into),
security_context: partial.security_context.map(Into::into),
}
}
}
impl From<LinuxContainerConfig> for LinuxContainerConfigPartial {
fn from(config: LinuxContainerConfig) -> Self {
LinuxContainerConfigPartial {
resources: config.resources.map(Into::into),
security_context: config.security_context.map(Into::into),
}
}
}
impl From<PodSandboxMetadataPartial> for PodSandboxMetadata {
fn from(partial: PodSandboxMetadataPartial) -> Self {
PodSandboxMetadata {
name: partial.name.unwrap_or_default(),
uid: partial.uid.unwrap_or_default(),
namespace: partial.namespace.unwrap_or_default(),
attempt: partial.attempt.unwrap_or(0),
}
}
}
impl From<PodSandboxMetadata> for PodSandboxMetadataPartial {
fn from(metadata: PodSandboxMetadata) -> Self {
PodSandboxMetadataPartial {
name: Some(metadata.name),
uid: Some(metadata.uid),
namespace: Some(metadata.namespace),
attempt: Some(metadata.attempt),
}
}
}
impl From<LinuxSandboxSecurityContextPartial> for LinuxSandboxSecurityContext {
#[allow(deprecated)]
fn from(partial: LinuxSandboxSecurityContextPartial) -> Self {
LinuxSandboxSecurityContext {
namespace_options: partial.namespace_options,
selinux_options: partial.selinux_options,
run_as_user: partial.run_as_user,
run_as_group: partial.run_as_group,
readonly_rootfs: partial.readonly_rootfs.unwrap_or(false),
supplemental_groups: partial.supplemental_groups.unwrap_or_default(),
privileged: partial.privileged.unwrap_or(false),
seccomp: partial.seccomp,
apparmor: partial.apparmor,
seccomp_profile_path: partial.seccomp_profile_path.unwrap_or_default(),
}
}
}
impl From<LinuxSandboxSecurityContext> for LinuxSandboxSecurityContextPartial {
#[allow(deprecated)]
fn from(context: LinuxSandboxSecurityContext) -> Self {
LinuxSandboxSecurityContextPartial {
namespace_options: context.namespace_options,
selinux_options: context.selinux_options,
run_as_user: context.run_as_user,
run_as_group: context.run_as_group,
readonly_rootfs: Some(context.readonly_rootfs),
supplemental_groups: Some(context.supplemental_groups),
privileged: Some(context.privileged),
seccomp: context.seccomp,
apparmor: context.apparmor,
seccomp_profile_path: Some(context.seccomp_profile_path),
}
}
}
impl From<LinuxPodSandboxConfigPartial> for LinuxPodSandboxConfig {
fn from(partial: LinuxPodSandboxConfigPartial) -> Self {
LinuxPodSandboxConfig {
cgroup_parent: partial.cgroup_parent.unwrap_or_default(),
security_context: partial.security_context.map(Into::into),
sysctls: partial.sysctls.unwrap_or_default(),
overhead: partial.overhead.map(Into::into),
resources: partial.resources.map(Into::into),
}
}
}
impl From<LinuxPodSandboxConfig> for LinuxPodSandboxConfigPartial {
fn from(config: LinuxPodSandboxConfig) -> Self {
LinuxPodSandboxConfigPartial {
cgroup_parent: Some(config.cgroup_parent),
security_context: config.security_context.map(Into::into),
sysctls: Some(config.sysctls),
overhead: config.overhead.map(Into::into),
resources: config.resources.map(Into::into),
}
}
}
impl From<DnsConfigPartial> for DnsConfig {
fn from(partial: DnsConfigPartial) -> Self {
DnsConfig {
servers: partial.servers.unwrap_or_default(),
searches: partial.searches.unwrap_or_default(),
options: partial.options.unwrap_or_default(),
}
}
}
impl From<DnsConfig> for DnsConfigPartial {
fn from(config: DnsConfig) -> Self {
DnsConfigPartial {
servers: Some(config.servers),
searches: Some(config.searches),
options: Some(config.options),
}
}
}
impl From<PortMappingPartial> for PortMapping {
fn from(partial: PortMappingPartial) -> Self {
PortMapping {
protocol: partial.protocol.unwrap_or(0),
container_port: partial.container_port,
host_port: partial.host_port,
host_ip: partial.host_ip.unwrap_or_default(),
}
}
}
impl From<PortMapping> for PortMappingPartial {
fn from(mapping: PortMapping) -> Self {
PortMappingPartial {
protocol: Some(mapping.protocol),
container_port: mapping.container_port,
host_port: mapping.host_port,
host_ip: Some(mapping.host_ip),
}
}
}
impl LinuxContainerResourcesPartial {
pub fn parse_memory(memory: &str) -> i64 {
if memory.is_empty() {
return 0;
}
let mut value_str = memory;
let mut multiplier = 1;
if memory.ends_with("Ki") {
value_str = &memory[..memory.len() - 2];
multiplier = 1024;
} else if memory.ends_with("Mi") {
value_str = &memory[..memory.len() - 2];
multiplier = 1024 * 1024;
} else if memory.ends_with("Gi") {
value_str = &memory[..memory.len() - 2];
multiplier = 1024 * 1024 * 1024;
} else if memory.ends_with("Kb") {
value_str = &memory[..memory.len() - 2];
multiplier = 1000;
} else if memory.ends_with("Mb") {
value_str = &memory[..memory.len() - 2];
multiplier = 1000 * 1000;
} else if memory.ends_with("Gb") {
value_str = &memory[..memory.len() - 2];
multiplier = 1000 * 1000 * 1000;
} else if memory.ends_with('K') {
value_str = &memory[..memory.len() - 1];
multiplier = 1000;
} else if memory.ends_with('M') {
value_str = &memory[..memory.len() - 1];
multiplier = 1000 * 1000;
} else if memory.ends_with('G') {
value_str = &memory[..memory.len() - 1];
multiplier = 1000 * 1000 * 1000;
}
match value_str.parse::<i64>() {
Ok(value) => value * multiplier,
Err(_) => 0,
}
}
pub fn parse_cpu(cpu: &str) -> (i64, i64) {
if cpu.is_empty() {
return (0, 0);
}
const PERIOD: i64 = 100000;
let mut quota = 0;
if cpu.ends_with('m') {
if let Ok(millicores) = cpu[..cpu.len() - 1].parse::<i64>() {
quota = PERIOD * millicores / 1000;
}
} else {
if let Ok(cores) = cpu.parse::<f64>() {
quota = (cores * PERIOD as f64) as i64;
}
}
(PERIOD, quota)
}
pub fn format_memory(bytes: i64) -> String {
if bytes == 0 {
return "0".to_string();
}
let gib = 1024 * 1024 * 1024;
let mib = 1024 * 1024;
let kib = 1024;
if bytes % gib == 0 {
format!("{}Gi", bytes / gib)
} else if bytes % mib == 0 {
format!("{}Mi", bytes / mib)
} else if bytes % kib == 0 {
format!("{}Ki", bytes / kib)
} else {
bytes.to_string()
}
}
pub fn format_cpu(period: i64, quota: i64) -> String {
if period == 0 || quota == 0 {
return "0".to_string();
}
let cores = quota as f64 / period as f64;
if (cores * 1000.0).round() % 1000.0 == 0.0 {
return format!("{}", cores as i64);
}
let millicores = (cores * 1000.0).round() as i64;
format!("{}m", millicores)
}
}
impl ContainerConfigPartial {
pub fn to_container_config(self) -> ContainerConfig {
ContainerConfig {
metadata: self.metadata.as_ref().cloned().map(From::from),
image: Some(self.image.clone().into()),
command: self.command.unwrap_or_default(),
args: self.args.unwrap_or_default(),
working_dir: self.working_dir.unwrap_or_default(),
envs: self.envs.unwrap_or_default(),
mounts: self.mounts.unwrap_or_default().iter().cloned().map(From::from).collect(),
devices: self.devices.unwrap_or_default().iter().cloned().map(From::from).collect(),
labels: self.labels.unwrap_or_default(),
annotations: self.annotations.unwrap_or_default(),
log_path: self.log_path.unwrap_or_default(),
stdin: self.stdin.unwrap_or(false),
stdin_once: self.stdin_once.unwrap_or(false),
tty: self.tty.unwrap_or(false),
linux: self.linux.as_ref().cloned().map(From::from),
windows: self.windows,
}
}
pub fn from_container_config(config: ContainerConfig) -> Self {
Self {
metadata: config.metadata.as_ref().cloned().map(From::from),
image: config.image.as_ref().cloned().map(From::from).unwrap(),
command: if config.command.is_empty() {
None
} else {
Some(config.command)
},
args: if config.args.is_empty() {
None
} else {
Some(config.args)
},
working_dir: if config.working_dir.is_empty() {
None
} else {
Some(config.working_dir)
},
envs: if config.envs.is_empty() {
None
} else {
Some(config.envs)
},
mounts: if config.mounts.is_empty() {
None
} else {
Some(config.mounts.iter().cloned().map(From::from).collect())
},
devices: if config.devices.is_empty() {
None
} else {
Some(config.devices.iter().cloned().map(From::from).collect())
},
labels: if config.labels.is_empty() {
None
} else {
Some(config.labels)
},
annotations: if config.annotations.is_empty() {
None
} else {
Some(config.annotations)
},
log_path: if config.log_path.is_empty() {
None
} else {
Some(config.log_path)
},
stdin: if config.stdin { Some(true) } else { None },
stdin_once: if config.stdin_once { Some(true) } else { None },
tty: if config.tty { Some(true) } else { None },
linux: config.linux.as_ref().cloned().map(From::from),
windows: config.windows,
}
}
}
impl PodSandboxConfigPartial {
pub fn to_pod_sandbox_config(self) -> PodSandboxConfig {
PodSandboxConfig {
metadata: self.metadata.as_ref().cloned().map(From::from),
hostname: self.hostname.unwrap_or_default(),
log_directory: self.log_directory.unwrap_or_default(),
dns_config: self.dns_config.as_ref().cloned().map(From::from),
port_mappings: self.port_mappings
.as_ref()
.map(|mappings| mappings.iter().cloned().map(From::from).collect())
.unwrap_or_default(),
labels: self.labels.unwrap_or_default(),
annotations: self.annotations.unwrap_or_default(),
linux: self.linux.as_ref().cloned().map(From::from),
windows: self.windows,
}
}
pub fn from_pod_sandbox_config(config: PodSandboxConfig) -> Self {
Self {
metadata: config.metadata.as_ref().cloned().map(From::from),
hostname: if config.hostname.is_empty() {
None
} else {
Some(config.hostname)
},
log_directory: if config.log_directory.is_empty() {
None
} else {
Some(config.log_directory)
},
dns_config: config.dns_config.as_ref().cloned().map(From::from),
port_mappings: if config.port_mappings.is_empty() {
None
} else {
Some(config.port_mappings.iter().cloned().map(From::from).collect())
},
labels: if config.labels.is_empty() {
None
} else {
Some(config.labels)
},
annotations: if config.annotations.is_empty() {
None
} else {
Some(config.annotations)
},
linux: config.linux.as_ref().cloned().map(From::from),
windows: config.windows,
}
}
}
impl CriConfigPartial {
pub fn to_cri_config(self) -> CriConfig {
CriConfig {
container_config: self.container_config_partial.to_container_config(),
pod_sandbox_config: self.pod_sandbox_config_partial.map(|p| p.to_pod_sandbox_config()),
}
}
pub fn from_cri_config(config: CriConfig) -> Self {
Self {
container_config_partial: ContainerConfigPartial::from_container_config(config.container_config),
pod_sandbox_config_partial: config.pod_sandbox_config.map(|p| PodSandboxConfigPartial::from_pod_sandbox_config(p)),
}
}
}
impl CriConfig {
pub fn from_partial(partial: CriConfigPartial) -> Self {
partial.to_cri_config()
}
}