diff --git a/src/libs/Cargo.toml b/src/libs/Cargo.toml index 4f9b423a3f..e1a7b3de98 100644 --- a/src/libs/Cargo.toml +++ b/src/libs/Cargo.toml @@ -3,7 +3,6 @@ members = [ "kata-sys-util", "kata-types", "logging", - "oci", "runtime-spec", "protocols", "safe-path", diff --git a/src/libs/oci/.gitignore b/src/libs/oci/.gitignore deleted file mode 100644 index 03314f77b5..0000000000 --- a/src/libs/oci/.gitignore +++ /dev/null @@ -1 +0,0 @@ -Cargo.lock diff --git a/src/libs/oci/Cargo.toml b/src/libs/oci/Cargo.toml deleted file mode 100644 index 8c08705a3d..0000000000 --- a/src/libs/oci/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "oci" -version = "0.1.0" -authors = ["The Kata Containers community "] -edition = "2018" -license = "Apache-2.0" - -[dependencies] -serde = "1.0.131" -serde_derive = "1.0.131" -serde_json = "1.0.73" -libc = "0.2.112" diff --git a/src/libs/oci/src/lib.rs b/src/libs/oci/src/lib.rs deleted file mode 100644 index d48ad40400..0000000000 --- a/src/libs/oci/src/lib.rs +++ /dev/null @@ -1,1650 +0,0 @@ -// Copyright (c) 2019 Ant Financial -// -// SPDX-License-Identifier: Apache-2.0 -// - -extern crate serde; -#[macro_use] -extern crate serde_derive; -extern crate serde_json; - -use libc::{self, mode_t}; -use std::collections::HashMap; - -mod serialize; -pub use serialize::{to_string, to_writer, Error, Result}; - -pub const OCI_SPEC_CONFIG_FILE_NAME: &str = "config.json"; - -#[allow(dead_code)] -fn is_false(b: bool) -> bool { - !b -} - -#[allow(dead_code)] -fn is_default(d: &T) -> bool -where - T: Default + PartialEq, -{ - *d == T::default() -} - -fn default_seccomp_errno() -> u32 { - libc::EPERM as u32 -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct Spec { - #[serde( - default, - rename = "ociVersion", - skip_serializing_if = "String::is_empty" - )] - pub version: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub process: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub root: Option, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub hostname: String, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub mounts: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub hooks: Option, - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub annotations: HashMap, - #[serde(skip_serializing_if = "Option::is_none")] - pub linux: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub solaris: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub windows: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - pub vm: Option, -} - -impl Spec { - pub fn load(path: &str) -> Result { - serialize::deserialize(path) - } - - pub fn save(&self, path: &str) -> Result<()> { - serialize::serialize(self, path) - } -} - -pub type LinuxRlimit = PosixRlimit; - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct Process { - #[serde(default)] - pub terminal: bool, - #[serde( - default, - rename = "consoleSize", - skip_serializing_if = "Option::is_none" - )] - pub console_size: Option, - pub user: User, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub args: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub env: Vec, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub cwd: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub capabilities: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub rlimits: Vec, - #[serde(default, rename = "noNewPrivileges")] - pub no_new_privileges: bool, - #[serde( - default, - rename = "apparmorProfile", - skip_serializing_if = "String::is_empty" - )] - pub apparmor_profile: String, - #[serde( - default, - rename = "oomScoreAdj", - skip_serializing_if = "Option::is_none" - )] - pub oom_score_adj: Option, - #[serde( - default, - rename = "selinuxLabel", - skip_serializing_if = "String::is_empty" - )] - pub selinux_label: String, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxCapabilities { - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub bounding: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub effective: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub inheritable: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub permitted: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub ambient: Vec, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct Box { - #[serde(default)] - pub height: u32, - #[serde(default)] - pub width: u32, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct User { - #[serde(default)] - pub uid: u32, - #[serde(default)] - pub gid: u32, - #[serde( - default, - rename = "additionalGids", - skip_serializing_if = "Vec::is_empty" - )] - pub additional_gids: Vec, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub username: String, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct Root { - #[serde(default, skip_serializing_if = "String::is_empty")] - pub path: String, - #[serde(default)] - pub readonly: bool, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct Mount { - #[serde(default)] - pub destination: String, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub r#type: String, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub source: String, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub options: Vec, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct Hook { - #[serde(default, skip_serializing_if = "String::is_empty")] - pub path: String, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub args: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub env: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub timeout: Option, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct Hooks { - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub prestart: Vec, - #[serde( - rename = "createRuntime", - default, - skip_serializing_if = "Vec::is_empty" - )] - pub create_runtime: Vec, - #[serde( - rename = "createContainer", - default, - skip_serializing_if = "Vec::is_empty" - )] - pub create_container: Vec, - #[serde( - rename = "startContainer", - default, - skip_serializing_if = "Vec::is_empty" - )] - pub start_container: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub poststart: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub poststop: Vec, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct Linux { - #[serde(default, rename = "uidMappings", skip_serializing_if = "Vec::is_empty")] - pub uid_mappings: Vec, - #[serde(default, rename = "gidMappings", skip_serializing_if = "Vec::is_empty")] - pub gid_mappings: Vec, - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub sysctl: HashMap, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub resources: Option, - #[serde( - default, - rename = "cgroupsPath", - skip_serializing_if = "String::is_empty" - )] - pub cgroups_path: String, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub namespaces: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub devices: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub seccomp: Option, - #[serde( - default, - rename = "rootfsPropagation", - skip_serializing_if = "String::is_empty" - )] - pub rootfs_propagation: String, - #[serde(default, rename = "maskedPaths", skip_serializing_if = "Vec::is_empty")] - pub masked_paths: Vec, - #[serde( - default, - rename = "readonlyPaths", - skip_serializing_if = "Vec::is_empty" - )] - pub readonly_paths: Vec, - #[serde( - default, - rename = "mountLabel", - skip_serializing_if = "String::is_empty" - )] - pub mount_label: String, - #[serde(default, rename = "intelRdt", skip_serializing_if = "Option::is_none")] - pub intel_rdt: Option, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxNamespace { - #[serde(default, skip_serializing_if = "String::is_empty")] - pub r#type: LinuxNamespaceType, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub path: String, -} - -pub type LinuxNamespaceType = String; - -pub const PIDNAMESPACE: &str = "pid"; -pub const NETWORKNAMESPACE: &str = "network"; -pub const MOUNTNAMESPACE: &str = "mount"; -pub const IPCNAMESPACE: &str = "ipc"; -pub const USERNAMESPACE: &str = "user"; -pub const UTSNAMESPACE: &str = "uts"; -pub const CGROUPNAMESPACE: &str = "cgroup"; - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxIdMapping { - #[serde(default, rename = "containerID")] - pub container_id: u32, - #[serde(default, rename = "hostID")] - pub host_id: u32, - #[serde(default)] - pub size: u32, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct PosixRlimit { - #[serde(default)] - pub r#type: String, - #[serde(default)] - pub hard: u64, - #[serde(default)] - pub soft: u64, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxHugepageLimit { - #[serde(default, rename = "pageSize", skip_serializing_if = "String::is_empty")] - pub page_size: String, - #[serde(default)] - pub limit: u64, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxInterfacePriority { - #[serde(default, skip_serializing_if = "String::is_empty")] - pub name: String, - #[serde(default)] - pub priority: u32, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxBlockIoDevice { - #[serde(default)] - pub major: i64, - #[serde(default)] - pub minor: i64, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxWeightDevice { - #[serde(flatten)] - pub blk: LinuxBlockIoDevice, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub weight: Option, - #[serde( - default, - rename = "leafWeight", - skip_serializing_if = "Option::is_none" - )] - pub leaf_weight: Option, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxThrottleDevice { - #[serde(flatten)] - pub blk: LinuxBlockIoDevice, - #[serde(default)] - pub rate: u64, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxBlockIo { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub weight: Option, - #[serde( - default, - rename = "leafWeight", - skip_serializing_if = "Option::is_none" - )] - pub leaf_weight: Option, - #[serde( - default, - rename = "weightDevice", - skip_serializing_if = "Vec::is_empty" - )] - pub weight_device: Vec, - #[serde( - default, - skip_serializing_if = "Vec::is_empty", - rename = "throttleReadBpsDevice" - )] - pub throttle_read_bps_device: Vec, - #[serde( - default, - skip_serializing_if = "Vec::is_empty", - rename = "throttleWriteBpsDevice" - )] - pub throttle_write_bps_device: Vec, - #[serde( - default, - skip_serializing_if = "Vec::is_empty", - rename = "throttleReadIOPSDevice" - )] - pub throttle_read_iops_device: Vec, - #[serde( - default, - skip_serializing_if = "Vec::is_empty", - rename = "throttleWriteIOPSDevice" - )] - pub throttle_write_iops_device: Vec, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxMemory { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub limit: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub reservation: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub swap: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub kernel: Option, - #[serde(default, skip_serializing_if = "Option::is_none", rename = "kernelTCP")] - pub kernel_tcp: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub swappiness: Option, - #[serde( - default, - skip_serializing_if = "Option::is_none", - rename = "disableOOMKiller" - )] - pub disable_oom_killer: Option, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxCpu { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub shares: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub quota: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub period: Option, - #[serde( - default, - skip_serializing_if = "Option::is_none", - rename = "realtimeRuntime" - )] - pub realtime_runtime: Option, - #[serde( - default, - skip_serializing_if = "Option::is_none", - rename = "realtimePeriod" - )] - pub realtime_period: Option, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub cpus: String, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub mems: String, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxPids { - #[serde(default)] - pub limit: i64, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxNetwork { - #[serde(default, skip_serializing_if = "Option::is_none", rename = "classID")] - pub class_id: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub priorities: Vec, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxRdma { - #[serde( - default, - skip_serializing_if = "Option::is_none", - rename = "hcaHandles" - )] - pub hca_handles: Option, - #[serde( - default, - skip_serializing_if = "Option::is_none", - rename = "hcaObjects" - )] - pub hca_objects: Option, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxResources { - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub devices: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub memory: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub cpu: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub pids: Option, - #[serde(skip_serializing_if = "Option::is_none", rename = "blockIO")] - pub block_io: Option, - #[serde( - default, - skip_serializing_if = "Vec::is_empty", - rename = "hugepageLimits" - )] - pub hugepage_limits: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub network: Option, - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub rdma: HashMap, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxDevice { - #[serde(default, skip_serializing_if = "String::is_empty")] - pub path: String, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub r#type: String, - #[serde(default)] - pub major: i64, - #[serde(default)] - pub minor: i64, - #[serde(default, skip_serializing_if = "Option::is_none", rename = "fileMode")] - pub file_mode: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub uid: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub gid: Option, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxDeviceCgroup { - #[serde(default)] - pub allow: bool, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub r#type: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub major: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub minor: Option, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub access: String, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct Solaris { - #[serde(default, skip_serializing_if = "String::is_empty")] - pub milestone: String, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub limitpriv: String, - #[serde( - default, - skip_serializing_if = "String::is_empty", - rename = "maxShmMemory" - )] - pub max_shm_memory: String, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub anet: Vec, - #[serde(default, skip_serializing_if = "Option::is_none", rename = "cappedCPU")] - pub capped_cpu: Option, - #[serde( - default, - skip_serializing_if = "Option::is_none", - rename = "cappedMemory" - )] - pub capped_memory: Option, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct SolarisCappedCpu { - #[serde(default, skip_serializing_if = "String::is_empty")] - pub ncpus: String, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct SolarisCappedMemory { - #[serde(default, skip_serializing_if = "String::is_empty")] - pub physical: String, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub swap: String, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct SolarisAnet { - #[serde(default, skip_serializing_if = "String::is_empty", rename = "linkname")] - pub link_name: String, - #[serde( - default, - skip_serializing_if = "String::is_empty", - rename = "lowerLink" - )] - pub lower_link: String, - #[serde( - default, - skip_serializing_if = "String::is_empty", - rename = "allowdAddress" - )] - pub allowed_addr: String, - #[serde( - default, - skip_serializing_if = "String::is_empty", - rename = "configureAllowedAddress" - )] - pub config_allowed_addr: String, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub defrouter: String, - #[serde( - default, - skip_serializing_if = "String::is_empty", - rename = "linkProtection" - )] - pub link_protection: String, - #[serde( - default, - skip_serializing_if = "String::is_empty", - rename = "macAddress" - )] - pub mac_address: String, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct Windows { - #[serde( - default, - skip_serializing_if = "Vec::is_empty", - rename = "layerFolders" - )] - pub layer_folders: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub resources: Option, - #[serde(default, rename = "credentialSpec")] - pub credential_spec: T, - #[serde(default)] - pub servicing: bool, - #[serde(default, rename = "ignoreFlushesDuringBoot")] - pub ignore_flushes_during_boot: bool, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub hyperv: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub network: Option, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct WindowsResources { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub memory: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub cpu: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub storage: Option, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct WindowsMemoryResources { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub limit: Option, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct WindowsCpuResources { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub count: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub shares: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub maximum: Option, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct WindowsStorageResources { - #[serde(default, skip_serializing_if = "Option::is_none")] - pub iops: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub bps: Option, - #[serde( - default, - skip_serializing_if = "Option::is_none", - rename = "sandboxSize" - )] - pub sandbox_size: Option, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct WindowsNetwork { - #[serde( - default, - skip_serializing_if = "Vec::is_empty", - rename = "endpointList" - )] - pub endpoint_list: Vec, - #[serde(default, rename = "allowUnqualifiedDNSQuery")] - pub allow_unqualified_dns_query: bool, - #[serde( - default, - skip_serializing_if = "Vec::is_empty", - rename = "DNSSearchList" - )] - pub dns_search_list: Vec, - #[serde( - default, - skip_serializing_if = "String::is_empty", - rename = "networkSharedContainerName" - )] - pub network_shared_container_name: String, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct WindowsHyperV { - #[serde( - default, - skip_serializing_if = "String::is_empty", - rename = "utilityVMPath" - )] - pub utility_vm_path: String, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct Vm { - pub hypervisor: VmHypervisor, - pub kernel: VmKernel, - pub image: VmImage, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct VmHypervisor { - #[serde(default)] - pub path: String, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub parameters: String, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct VmKernel { - #[serde(default)] - pub path: String, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub parameters: String, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub initrd: String, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct VmImage { - #[serde(default)] - pub path: String, - #[serde(default)] - pub format: String, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxSeccomp { - #[serde(default, rename = "defaultAction")] - pub default_action: LinuxSeccompAction, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub architectures: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub flags: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub syscalls: Vec, -} - -pub type Arch = String; - -pub const ARCHX86: &str = "SCMP_ARCH_X86"; -pub const ARCHX86_64: &str = "SCMP_ARCH_X86_64"; -pub const ARCHX32: &str = "SCMP_ARCH_X32"; -pub const ARCHARM: &str = "SCMP_ARCH_ARM"; -pub const ARCHAARCH64: &str = "SCMP_ARCH_AARCH64"; -pub const ARCHMIPS: &str = "SCMP_ARCH_MIPS"; -pub const ARCHMIPS64: &str = "SCMP_ARCH_MIPS64"; -pub const ARCHMIPS64N32: &str = "SCMP_ARCH_MIPS64N32"; -pub const ARCHMIPSEL: &str = "SCMP_ARCH_MIPSEL"; -pub const ARCHMIPSEL64: &str = "SCMP_ARCH_MIPSEL64"; -pub const ARCHMIPSEL64N32: &str = "SCMP_ARCH_MIPSEL64N32"; -pub const ARCHPPC: &str = "SCMP_ARCH_PPC"; -pub const ARCHPPC64: &str = "SCMP_ARCH_PPC64"; -pub const ARCHPPC64LE: &str = "SCMP_ARCH_PPC64LE"; -pub const ARCHS390: &str = "SCMP_ARCH_S390"; -pub const ARCHS390X: &str = "SCMP_ARCH_S390X"; -pub const ARCHPARISC: &str = "SCMP_ARCH_PARISC"; -pub const ARCHPARISC64: &str = "SCMP_ARCH_PARISC64"; -pub const ARCHRISCV64: &str = "SCMP_ARCH_RISCV64"; - -pub type LinuxSeccompFlag = String; - -pub type LinuxSeccompAction = String; - -pub const ACTKILL: &str = "SCMP_ACT_KILL"; -pub const ACTKILLPROCESS: &str = "SCMP_ACT_KILL_PROCESS"; -pub const ACTKILLTHREAD: &str = "SCMP_ACT_KILL_THREAD"; -pub const ACTTRAP: &str = "SCMP_ACT_TRAP"; -pub const ACTERRNO: &str = "SCMP_ACT_ERRNO"; -pub const ACTTRACE: &str = "SCMP_ACT_TRACE"; -pub const ACTALLOW: &str = "SCMP_ACT_ALLOW"; -pub const ACTLOG: &str = "SCMP_ACT_LOG"; - -pub type LinuxSeccompOperator = String; - -pub const OPNOTEQUAL: &str = "SCMP_CMP_NE"; -pub const OPLESSTHAN: &str = "SCMP_CMP_LT"; -pub const OPLESSEQUAL: &str = "SCMP_CMP_LE"; -pub const OPEQUALTO: &str = "SCMP_CMP_EQ"; -pub const OPGREATEREQUAL: &str = "SCMP_CMP_GE"; -pub const OPGREATERTHAN: &str = "SCMP_CMP_GT"; -pub const OPMASKEDEQUAL: &str = "SCMP_CMP_MASKED_EQ"; - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxSeccompArg { - #[serde(default)] - pub index: u32, - #[serde(default)] - pub value: u64, - #[serde(default, rename = "valueTwo")] - pub value_two: u64, - #[serde(default)] - pub op: LinuxSeccompOperator, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxSyscall { - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub names: Vec, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub action: LinuxSeccompAction, - #[serde(default = "default_seccomp_errno", rename = "errnoRet")] - pub errno_ret: u32, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub args: Vec, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -pub struct LinuxIntelRdt { - #[serde( - default, - skip_serializing_if = "String::is_empty", - rename = "l3CacheSchema" - )] - pub l3_cache_schema: String, -} - -#[derive(Debug, Serialize, Deserialize, Copy, Clone, PartialEq)] -#[serde(rename_all = "lowercase")] -pub enum ContainerState { - Creating, - Created, - Running, - Stopped, - Paused, -} - -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] -pub struct State { - #[serde( - default, - skip_serializing_if = "String::is_empty", - rename = "ociVersion" - )] - pub version: String, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub id: String, - pub status: ContainerState, - #[serde(default)] - pub pid: i32, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub bundle: String, - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub annotations: HashMap, -} - -#[cfg(test)] -mod tests { - use std::vec; - - use super::*; - - #[test] - fn test_deserialize_state() { - let data = r#"{ - "ociVersion": "0.2.0", - "id": "oci-container1", - "status": "running", - "pid": 4422, - "bundle": "/containers/redis", - "annotations": { - "myKey": "myValue" - } - }"#; - let expected = State { - version: "0.2.0".to_string(), - id: "oci-container1".to_string(), - status: ContainerState::Running, - pid: 4422, - bundle: "/containers/redis".to_string(), - annotations: [("myKey".to_string(), "myValue".to_string())] - .iter() - .cloned() - .collect(), - }; - - let current: crate::State = serde_json::from_str(data).unwrap(); - assert_eq!(expected, current); - } - - #[test] - fn test_deserialize_spec() { - let data = r#"{ - "ociVersion": "1.0.1", - "process": { - "terminal": true, - "user": { - "uid": 1, - "gid": 1, - "additionalGids": [ - 5, - 6 - ] - }, - "args": [ - "sh" - ], - "env": [ - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "TERM=xterm" - ], - "cwd": "/", - "capabilities": { - "bounding": [ - "CAP_AUDIT_WRITE", - "CAP_KILL", - "CAP_NET_BIND_SERVICE" - ], - "permitted": [ - "CAP_AUDIT_WRITE", - "CAP_KILL", - "CAP_NET_BIND_SERVICE" - ], - "inheritable": [ - "CAP_AUDIT_WRITE", - "CAP_KILL", - "CAP_NET_BIND_SERVICE" - ], - "effective": [ - "CAP_AUDIT_WRITE", - "CAP_KILL" - ], - "ambient": [ - "CAP_NET_BIND_SERVICE" - ] - }, - "rlimits": [ - { - "type": "RLIMIT_CORE", - "hard": 1024, - "soft": 1024 - }, - { - "type": "RLIMIT_NOFILE", - "hard": 1024, - "soft": 1024 - } - ], - "apparmorProfile": "acme_secure_profile", - "oomScoreAdj": 100, - "selinuxLabel": "system_u:system_r:svirt_lxc_net_t:s0:c124,c675", - "noNewPrivileges": true - }, - "root": { - "path": "rootfs", - "readonly": true - }, - "hostname": "slartibartfast", - "mounts": [ - { - "destination": "/proc", - "type": "proc", - "source": "proc" - }, - { - "destination": "/dev", - "type": "tmpfs", - "source": "tmpfs", - "options": [ - "nosuid", - "strictatime", - "mode=755", - "size=65536k" - ] - }, - { - "destination": "/dev/pts", - "type": "devpts", - "source": "devpts", - "options": [ - "nosuid", - "noexec", - "newinstance", - "ptmxmode=0666", - "mode=0620", - "gid=5" - ] - }, - { - "destination": "/dev/shm", - "type": "tmpfs", - "source": "shm", - "options": [ - "nosuid", - "noexec", - "nodev", - "mode=1777", - "size=65536k" - ] - }, - { - "destination": "/dev/mqueue", - "type": "mqueue", - "source": "mqueue", - "options": [ - "nosuid", - "noexec", - "nodev" - ] - }, - { - "destination": "/sys", - "type": "sysfs", - "source": "sysfs", - "options": [ - "nosuid", - "noexec", - "nodev" - ] - }, - { - "destination": "/sys/fs/cgroup", - "type": "cgroup", - "source": "cgroup", - "options": [ - "nosuid", - "noexec", - "nodev", - "relatime", - "ro" - ] - } - ], - "hooks": { - "prestart": [ - { - "path": "/usr/bin/fix-mounts", - "args": [ - "fix-mounts", - "arg1", - "arg2" - ], - "env": [ - "key1=value1" - ] - }, - { - "path": "/usr/bin/setup-network" - } - ], - "createRuntime": [ - { - "path": "/usr/local/bin/nerdctl" - } - ], - "poststart": [ - { - "path": "/usr/bin/notify-start", - "timeout": 5 - } - ], - "poststop": [ - { - "path": "/usr/sbin/cleanup.sh", - "args": [ - "cleanup.sh", - "-f" - ] - } - ] - }, - "linux": { - "devices": [ - { - "path": "/dev/fuse", - "type": "c", - "major": 10, - "minor": 229, - "fileMode": 438, - "uid": 0, - "gid": 0 - }, - { - "path": "/dev/sda", - "type": "b", - "major": 8, - "minor": 0, - "fileMode": 432, - "uid": 0, - "gid": 0 - } - ], - "uidMappings": [ - { - "containerID": 0, - "hostID": 1000, - "size": 32000 - } - ], - "gidMappings": [ - { - "containerID": 0, - "hostID": 1000, - "size": 32000 - } - ], - "sysctl": { - "net.ipv4.ip_forward": "1", - "net.core.somaxconn": "256" - }, - "cgroupsPath": "/myRuntime/myContainer", - "resources": { - "network": { - "classID": 1048577, - "priorities": [ - { - "name": "eth0", - "priority": 500 - }, - { - "name": "eth1", - "priority": 1000 - } - ] - }, - "pids": { - "limit": 32771 - }, - "hugepageLimits": [ - { - "pageSize": "2MB", - "limit": 9223372036854772000 - }, - { - "pageSize": "64KB", - "limit": 1000000 - } - ], - "memory": { - "limit": 536870912, - "reservation": 536870912, - "swap": 536870912, - "kernel": -1, - "kernelTCP": -1, - "swappiness": 0, - "disableOOMKiller": false - }, - "cpu": { - "shares": 1024, - "quota": 1000000, - "period": 500000, - "realtimeRuntime": 950000, - "realtimePeriod": 1000000, - "cpus": "2-3", - "mems": "0-7" - }, - "devices": [ - { - "allow": false, - "access": "rwm" - }, - { - "allow": true, - "type": "c", - "major": 10, - "minor": 229, - "access": "rw" - }, - { - "allow": true, - "type": "b", - "major": 8, - "minor": 0, - "access": "r" - } - ], - "blockIO": { - "weight": 10, - "leafWeight": 10, - "weightDevice": [ - { - "major": 8, - "minor": 0, - "weight": 500, - "leafWeight": 300 - }, - { - "major": 8, - "minor": 16, - "weight": 500 - } - ], - "throttleReadBpsDevice": [ - { - "major": 8, - "minor": 0, - "rate": 600 - } - ], - "throttleWriteIOPSDevice": [ - { - "major": 8, - "minor": 16, - "rate": 300 - } - ] - } - }, - "rootfsPropagation": "slave", - "seccomp": { - "defaultAction": "SCMP_ACT_ALLOW", - "architectures": [ - "SCMP_ARCH_X86", - "SCMP_ARCH_X32" - ], - "syscalls": [ - { - "names": [ - "getcwd", - "chmod" - ], - "action": "SCMP_ACT_ERRNO" - } - ] - }, - "namespaces": [ - { - "type": "pid" - }, - { - "type": "network" - }, - { - "type": "ipc" - }, - { - "type": "uts" - }, - { - "type": "mount" - }, - { - "type": "user" - }, - { - "type": "cgroup" - } - ], - "maskedPaths": [ - "/proc/kcore", - "/proc/latency_stats", - "/proc/timer_stats", - "/proc/sched_debug" - ], - "readonlyPaths": [ - "/proc/asound", - "/proc/bus", - "/proc/fs", - "/proc/irq", - "/proc/sys", - "/proc/sysrq-trigger" - ], - "mountLabel": "system_u:object_r:svirt_sandbox_file_t:s0:c715,c811" - }, - "annotations": { - "com.example.key1": "value1", - "com.example.key2": "value2" - } - }"#; - let expected = crate::Spec { - version: "1.0.1".to_string(), - process: Option::from(crate::Process { - terminal: true, - console_size: None, - user: crate::User { - uid: 1, - gid: 1, - // incompatible with oci - additional_gids: vec![5, 6], - username: "".to_string(), - }, - args: vec!["sh".to_string()], - env: vec![ - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin".to_string(), - "TERM=xterm".to_string(), - ], - cwd: "/".to_string(), - capabilities: Some(crate::LinuxCapabilities { - bounding: vec![ - "CAP_AUDIT_WRITE".to_string(), - "CAP_KILL".to_string(), - "CAP_NET_BIND_SERVICE".to_string(), - ], - effective: vec!["CAP_AUDIT_WRITE".to_string(), "CAP_KILL".to_string()], - inheritable: vec![ - "CAP_AUDIT_WRITE".to_string(), - "CAP_KILL".to_string(), - "CAP_NET_BIND_SERVICE".to_string(), - ], - permitted: vec![ - "CAP_AUDIT_WRITE".to_string(), - "CAP_KILL".to_string(), - "CAP_NET_BIND_SERVICE".to_string(), - ], - ambient: vec!["CAP_NET_BIND_SERVICE".to_string()], - }), - rlimits: vec![ - crate::PosixRlimit { - r#type: "RLIMIT_CORE".to_string(), - hard: 1024, - soft: 1024, - }, - crate::PosixRlimit { - r#type: "RLIMIT_NOFILE".to_string(), - hard: 1024, - soft: 1024, - }, - ], - no_new_privileges: true, - apparmor_profile: "acme_secure_profile".to_string(), - oom_score_adj: Some(100), - selinux_label: "system_u:system_r:svirt_lxc_net_t:s0:c124,c675".to_string(), - }), - root: Some(crate::Root { - path: "rootfs".to_string(), - readonly: true, - }), - hostname: "slartibartfast".to_string(), - mounts: vec![ - crate::Mount { - destination: "/proc".to_string(), - r#type: "proc".to_string(), - source: "proc".to_string(), - options: vec![], - }, - crate::Mount { - destination: "/dev".to_string(), - r#type: "tmpfs".to_string(), - source: "tmpfs".to_string(), - options: vec![ - "nosuid".to_string(), - "strictatime".to_string(), - "mode=755".to_string(), - "size=65536k".to_string(), - ], - }, - crate::Mount { - destination: "/dev/pts".to_string(), - r#type: "devpts".to_string(), - source: "devpts".to_string(), - options: vec![ - "nosuid".to_string(), - "noexec".to_string(), - "newinstance".to_string(), - "ptmxmode=0666".to_string(), - "mode=0620".to_string(), - "gid=5".to_string(), - ], - }, - crate::Mount { - destination: "/dev/shm".to_string(), - r#type: "tmpfs".to_string(), - source: "shm".to_string(), - options: vec![ - "nosuid".to_string(), - "noexec".to_string(), - "nodev".to_string(), - "mode=1777".to_string(), - "size=65536k".to_string(), - ], - }, - crate::Mount { - destination: "/dev/mqueue".to_string(), - r#type: "mqueue".to_string(), - source: "mqueue".to_string(), - options: vec![ - "nosuid".to_string(), - "noexec".to_string(), - "nodev".to_string(), - ], - }, - crate::Mount { - destination: "/sys".to_string(), - r#type: "sysfs".to_string(), - source: "sysfs".to_string(), - options: vec![ - "nosuid".to_string(), - "noexec".to_string(), - "nodev".to_string(), - ], - }, - crate::Mount { - destination: "/sys/fs/cgroup".to_string(), - r#type: "cgroup".to_string(), - source: "cgroup".to_string(), - options: vec![ - "nosuid".to_string(), - "noexec".to_string(), - "nodev".to_string(), - "relatime".to_string(), - "ro".to_string(), - ], - }, - ], - hooks: Some(crate::Hooks { - prestart: vec![ - crate::Hook { - path: "/usr/bin/fix-mounts".to_string(), - args: vec![ - "fix-mounts".to_string(), - "arg1".to_string(), - "arg2".to_string(), - ], - env: vec!["key1=value1".to_string()], - timeout: None, - }, - crate::Hook { - path: "/usr/bin/setup-network".to_string(), - args: vec![], - env: vec![], - timeout: None, - }, - ], - create_runtime: vec![crate::Hook { - path: "/usr/local/bin/nerdctl".to_string(), - args: vec![], - env: vec![], - timeout: None, - }], - poststart: vec![crate::Hook { - path: "/usr/bin/notify-start".to_string(), - args: vec![], - env: vec![], - timeout: Some(5), - }], - poststop: vec![crate::Hook { - path: "/usr/sbin/cleanup.sh".to_string(), - args: vec!["cleanup.sh".to_string(), "-f".to_string()], - env: vec![], - timeout: None, - }], - ..Default::default() - }), - annotations: [ - ("com.example.key1".to_string(), "value1".to_string()), - ("com.example.key2".to_string(), "value2".to_string()), - ] - .iter() - .cloned() - .collect(), - linux: Some(crate::Linux { - uid_mappings: vec![crate::LinuxIdMapping { - container_id: 0, - host_id: 1000, - size: 32000, - }], - gid_mappings: vec![crate::LinuxIdMapping { - container_id: 0, - host_id: 1000, - size: 32000, - }], - sysctl: [ - ("net.ipv4.ip_forward".to_string(), "1".to_string()), - ("net.core.somaxconn".to_string(), "256".to_string()), - ] - .iter() - .cloned() - .collect(), - resources: Some(crate::LinuxResources { - devices: vec![ - crate::LinuxDeviceCgroup { - allow: false, - r#type: "".to_string(), - major: None, - minor: None, - access: "rwm".to_string(), - }, - crate::LinuxDeviceCgroup { - allow: true, - r#type: "c".to_string(), - major: Some(10), - minor: Some(229), - access: "rw".to_string(), - }, - crate::LinuxDeviceCgroup { - allow: true, - r#type: "b".to_string(), - major: Some(8), - minor: Some(0), - access: "r".to_string(), - }, - ], - memory: Some(crate::LinuxMemory { - limit: Some(536870912), - reservation: Some(536870912), - swap: Some(536870912), - kernel: Some(-1), - kernel_tcp: Some(-1), - swappiness: Some(0), - disable_oom_killer: Some(false), - }), - cpu: Some(crate::LinuxCpu { - shares: Some(1024), - quota: Some(1000000), - period: Some(500000), - realtime_runtime: Some(950000), - realtime_period: Some(1000000), - cpus: "2-3".to_string(), - mems: "0-7".to_string(), - }), - pids: Some(crate::LinuxPids { limit: 32771 }), - block_io: Some(crate::LinuxBlockIo { - weight: Some(10), - leaf_weight: Some(10), - weight_device: vec![ - crate::LinuxWeightDevice { - blk: crate::LinuxBlockIoDevice { major: 8, minor: 0 }, - weight: Some(500), - leaf_weight: Some(300), - }, - crate::LinuxWeightDevice { - blk: crate::LinuxBlockIoDevice { - major: 8, - minor: 16, - }, - weight: Some(500), - leaf_weight: None, - }, - ], - throttle_read_bps_device: vec![crate::LinuxThrottleDevice { - blk: crate::LinuxBlockIoDevice { major: 8, minor: 0 }, - rate: 600, - }], - throttle_write_bps_device: vec![], - throttle_read_iops_device: vec![], - throttle_write_iops_device: vec![crate::LinuxThrottleDevice { - blk: crate::LinuxBlockIoDevice { - major: 8, - minor: 16, - }, - rate: 300, - }], - }), - hugepage_limits: vec![ - crate::LinuxHugepageLimit { - page_size: "2MB".to_string(), - limit: 9223372036854772000, - }, - crate::LinuxHugepageLimit { - page_size: "64KB".to_string(), - limit: 1000000, - }, - ], - network: Some(crate::LinuxNetwork { - class_id: Some(1048577), - priorities: vec![ - crate::LinuxInterfacePriority { - name: "eth0".to_string(), - priority: 500, - }, - crate::LinuxInterfacePriority { - name: "eth1".to_string(), - priority: 1000, - }, - ], - }), - rdma: Default::default(), - }), - cgroups_path: "/myRuntime/myContainer".to_string(), - namespaces: vec![ - crate::LinuxNamespace { - r#type: "pid".to_string(), - path: "".to_string(), - }, - crate::LinuxNamespace { - r#type: "network".to_string(), - path: "".to_string(), - }, - crate::LinuxNamespace { - r#type: "ipc".to_string(), - path: "".to_string(), - }, - crate::LinuxNamespace { - r#type: "uts".to_string(), - path: "".to_string(), - }, - crate::LinuxNamespace { - r#type: "mount".to_string(), - path: "".to_string(), - }, - crate::LinuxNamespace { - r#type: "user".to_string(), - path: "".to_string(), - }, - crate::LinuxNamespace { - r#type: "cgroup".to_string(), - path: "".to_string(), - }, - ], - devices: vec![ - crate::LinuxDevice { - path: "/dev/fuse".to_string(), - r#type: "c".to_string(), - major: 10, - minor: 229, - file_mode: Some(438), - uid: Some(0), - gid: Some(0), - }, - crate::LinuxDevice { - path: "/dev/sda".to_string(), - r#type: "b".to_string(), - major: 8, - minor: 0, - file_mode: Some(432), - uid: Some(0), - gid: Some(0), - }, - ], - seccomp: Some(crate::LinuxSeccomp { - default_action: "SCMP_ACT_ALLOW".to_string(), - architectures: vec!["SCMP_ARCH_X86".to_string(), "SCMP_ARCH_X32".to_string()], - flags: vec![], - syscalls: vec![crate::LinuxSyscall { - names: vec!["getcwd".to_string(), "chmod".to_string()], - action: "SCMP_ACT_ERRNO".to_string(), - errno_ret: crate::default_seccomp_errno(), - args: vec![], - }], - }), - rootfs_propagation: "slave".to_string(), - masked_paths: vec![ - "/proc/kcore".to_string(), - "/proc/latency_stats".to_string(), - "/proc/timer_stats".to_string(), - "/proc/sched_debug".to_string(), - ], - readonly_paths: vec![ - "/proc/asound".to_string(), - "/proc/bus".to_string(), - "/proc/fs".to_string(), - "/proc/irq".to_string(), - "/proc/sys".to_string(), - "/proc/sysrq-trigger".to_string(), - ], - mount_label: "system_u:object_r:svirt_sandbox_file_t:s0:c715,c811".to_string(), - intel_rdt: None, - }), - solaris: None, - windows: None, - vm: None, - }; - - let current: crate::Spec = serde_json::from_str(data).unwrap(); - assert_eq!(expected, current); - } -} diff --git a/src/libs/oci/src/serialize.rs b/src/libs/oci/src/serialize.rs deleted file mode 100644 index fb7b237530..0000000000 --- a/src/libs/oci/src/serialize.rs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2019 Ant Financial -// -// SPDX-License-Identifier: Apache-2.0 -// - -use serde::{Deserialize, Serialize}; - -use std::error; -use std::fmt::{Display, Formatter, Result as FmtResult}; -use std::fs::File; -use std::io; - -pub type Result = std::result::Result; - -#[derive(Debug)] -pub enum Error { - Io(io::Error), - Json(serde_json::Error), -} - -impl Display for Error { - fn fmt(&self, f: &mut Formatter) -> FmtResult { - match *self { - Error::Io(ref e) => e.fmt(f), - Error::Json(ref e) => e.fmt(f), - } - } -} - -impl error::Error for Error { - fn cause(&self) -> Option<&dyn error::Error> { - match *self { - Error::Io(ref e) => Some(e), - Error::Json(ref e) => Some(e), - } - } -} - -impl From for Error { - fn from(e: io::Error) -> Error { - Error::Io(e) - } -} - -impl From for Error { - fn from(e: serde_json::Error) -> Error { - Error::Json(e) - } -} - -pub fn to_writer(o: &T, w: W) -> Result<()> -where - W: io::Write, - T: Serialize, -{ - Ok(serde_json::to_writer(w, o)?) -} - -pub fn serialize(o: &T, path: &str) -> Result<()> -where - T: Serialize, -{ - let f = File::create(path)?; - Ok(serde_json::to_writer(f, o)?) -} - -pub fn to_string(o: &T) -> Result -where - T: Serialize, -{ - Ok(serde_json::to_string(o)?) -} - -pub fn deserialize(path: &str) -> Result -where - for<'a> T: Deserialize<'a>, -{ - let f = File::open(path)?; - Ok(serde_json::from_reader(f)?) -}