Skip to main content
Glama

microsandbox

by microsandbox
rlimit.rs14.5 kB
use crate::MicrosandboxError; use getset::Getters; use serde::{Deserialize, Serialize}; use std::{convert::TryFrom, fmt, str::FromStr}; //-------------------------------------------------------------------------------------------------- // Types //-------------------------------------------------------------------------------------------------- /// Represents the available Linux resource limits. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] #[allow(non_camel_case_types)] pub enum LinuxRLimitResource { /// CPU time in seconds RLIMIT_CPU = 0, /// Maximum size of files created by the process RLIMIT_FSIZE = 1, /// Maximum size of the data segment RLIMIT_DATA = 2, /// Maximum size of the stack segment RLIMIT_STACK = 3, /// Maximum size of core dumps RLIMIT_CORE = 4, /// Maximum resident set size (not enforced on Linux) RLIMIT_RSS = 5, /// Maximum number of processes RLIMIT_NPROC = 6, /// Maximum number of open file descriptors RLIMIT_NOFILE = 7, /// Maximum locked memory size RLIMIT_MEMLOCK = 8, /// Maximum size of the address space RLIMIT_AS = 9, /// Maximum number of file locks RLIMIT_LOCKS = 10, /// Maximum number of signals that can be queued RLIMIT_SIGPENDING = 11, /// Maximum number of bytes in POSIX message queues RLIMIT_MSGQUEUE = 12, /// Maximum nice priority RLIMIT_NICE = 13, /// Maximum real-time priority RLIMIT_RTPRIO = 14, /// Maximum seconds to sleep in real time RLIMIT_RTTIME = 15, } /// Represents a resource limit for a Linux process. /// /// This struct encapsulates a resource type and its corresponding soft and hard limits. /// The soft limit is the value that the kernel enforces for the corresponding resource. /// The hard limit acts as a ceiling for the soft limit. /// /// ## Examples /// /// ``` /// use microsandbox_core::vm::{LinuxRlimit, LinuxRLimitResource}; /// /// // Create a new resource limit for CPU time /// let cpu_limit = LinuxRlimit::new(LinuxRLimitResource::RLIMIT_CPU, 10, 20); /// /// assert_eq!(cpu_limit.get_resource(), &LinuxRLimitResource::RLIMIT_CPU); /// assert_eq!(cpu_limit.get_soft(), &10); /// assert_eq!(cpu_limit.get_hard(), &20); /// /// // Parse a resource limit from a string /// let nofile_limit: LinuxRlimit = "RLIMIT_NOFILE=1000:2000".parse().unwrap(); /// /// assert_eq!(nofile_limit.get_resource(), &LinuxRLimitResource::RLIMIT_NOFILE); /// assert_eq!(nofile_limit.get_soft(), &1000); /// assert_eq!(nofile_limit.get_hard(), &2000); /// ``` #[derive(Debug, Clone, PartialEq, Eq, Getters)] #[getset(get = "pub with_prefix")] pub struct LinuxRlimit { /// The resource to limit. resource: LinuxRLimitResource, /// The soft limit of the resource. /// /// This is the value that the kernel enforces for the corresponding resource. soft: u64, /// The hard limit of the resource. /// /// This acts as a ceiling for the soft limit. hard: u64, } //-------------------------------------------------------------------------------------------------- // Methods //-------------------------------------------------------------------------------------------------- impl LinuxRLimitResource { /// Get the corresponding enum integer value pub fn as_int(&self) -> u32 { *self as u32 } } impl LinuxRlimit { /// Creates a new `LinuxRlimit` instance with the specified resource, soft limit, and hard limit. /// /// # Arguments /// /// * `resource` - The resource type to limit. /// * `soft` - The soft limit value. /// * `hard` - The hard limit value. /// /// ## Examples /// /// ``` /// use microsandbox_core::vm::{LinuxRlimit, LinuxRLimitResource}; /// /// let cpu_limit = LinuxRlimit::new(LinuxRLimitResource::RLIMIT_CPU, 10, 20); /// assert_eq!(cpu_limit.get_resource(), &LinuxRLimitResource::RLIMIT_CPU); /// assert_eq!(cpu_limit.get_soft(), &10); /// assert_eq!(cpu_limit.get_hard(), &20); /// ``` pub fn new(resource: LinuxRLimitResource, soft: u64, hard: u64) -> Self { Self { resource, soft, hard, } } } //-------------------------------------------------------------------------------------------------- // Trait Implementations //-------------------------------------------------------------------------------------------------- impl TryFrom<u32> for LinuxRLimitResource { type Error = MicrosandboxError; fn try_from(value: u32) -> Result<Self, Self::Error> { match value { 0 => Ok(Self::RLIMIT_CPU), 1 => Ok(Self::RLIMIT_FSIZE), 2 => Ok(Self::RLIMIT_DATA), 3 => Ok(Self::RLIMIT_STACK), 4 => Ok(Self::RLIMIT_CORE), 5 => Ok(Self::RLIMIT_RSS), 6 => Ok(Self::RLIMIT_NPROC), 7 => Ok(Self::RLIMIT_NOFILE), 8 => Ok(Self::RLIMIT_MEMLOCK), 9 => Ok(Self::RLIMIT_AS), 10 => Ok(Self::RLIMIT_LOCKS), 11 => Ok(Self::RLIMIT_SIGPENDING), 12 => Ok(Self::RLIMIT_MSGQUEUE), 13 => Ok(Self::RLIMIT_NICE), 14 => Ok(Self::RLIMIT_RTPRIO), 15 => Ok(Self::RLIMIT_RTTIME), _ => Err(MicrosandboxError::InvalidRLimitResource(value.to_string())), } } } impl FromStr for LinuxRLimitResource { type Err = MicrosandboxError; fn from_str(s: &str) -> Result<Self, Self::Err> { match s { "RLIMIT_CPU" => Ok(Self::RLIMIT_CPU), "RLIMIT_FSIZE" => Ok(Self::RLIMIT_FSIZE), "RLIMIT_DATA" => Ok(Self::RLIMIT_DATA), "RLIMIT_STACK" => Ok(Self::RLIMIT_STACK), "RLIMIT_CORE" => Ok(Self::RLIMIT_CORE), "RLIMIT_RSS" => Ok(Self::RLIMIT_RSS), "RLIMIT_NPROC" => Ok(Self::RLIMIT_NPROC), "RLIMIT_NOFILE" => Ok(Self::RLIMIT_NOFILE), "RLIMIT_MEMLOCK" => Ok(Self::RLIMIT_MEMLOCK), "RLIMIT_AS" => Ok(Self::RLIMIT_AS), "RLIMIT_LOCKS" => Ok(Self::RLIMIT_LOCKS), "RLIMIT_SIGPENDING" => Ok(Self::RLIMIT_SIGPENDING), "RLIMIT_MSGQUEUE" => Ok(Self::RLIMIT_MSGQUEUE), "RLIMIT_NICE" => Ok(Self::RLIMIT_NICE), "RLIMIT_RTPRIO" => Ok(Self::RLIMIT_RTPRIO), "RLIMIT_RTTIME" => Ok(Self::RLIMIT_RTTIME), _ => Err(MicrosandboxError::InvalidRLimitResource(s.to_string())), } } } impl fmt::Display for LinuxRLimitResource { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::RLIMIT_CPU => write!(f, "RLIMIT_CPU"), Self::RLIMIT_FSIZE => write!(f, "RLIMIT_FSIZE"), Self::RLIMIT_DATA => write!(f, "RLIMIT_DATA"), Self::RLIMIT_STACK => write!(f, "RLIMIT_STACK"), Self::RLIMIT_CORE => write!(f, "RLIMIT_CORE"), Self::RLIMIT_RSS => write!(f, "RLIMIT_RSS"), Self::RLIMIT_NPROC => write!(f, "RLIMIT_NPROC"), Self::RLIMIT_NOFILE => write!(f, "RLIMIT_NOFILE"), Self::RLIMIT_MEMLOCK => write!(f, "RLIMIT_MEMLOCK"), Self::RLIMIT_AS => write!(f, "RLIMIT_AS"), Self::RLIMIT_LOCKS => write!(f, "RLIMIT_LOCKS"), Self::RLIMIT_SIGPENDING => write!(f, "RLIMIT_SIGPENDING"), Self::RLIMIT_MSGQUEUE => write!(f, "RLIMIT_MSGQUEUE"), Self::RLIMIT_NICE => write!(f, "RLIMIT_NICE"), Self::RLIMIT_RTPRIO => write!(f, "RLIMIT_RTPRIO"), Self::RLIMIT_RTTIME => write!(f, "RLIMIT_RTTIME"), } } } impl FromStr for LinuxRlimit { type Err = MicrosandboxError; fn from_str(s: &str) -> Result<Self, Self::Err> { let parts: Vec<&str> = s.split('=').collect(); if parts.len() != 2 { return Err(MicrosandboxError::InvalidRLimitFormat(s.to_string())); } let resource = if let Ok(resource_num) = parts[0].parse::<u32>() { LinuxRLimitResource::try_from(resource_num)? } else { parts[0].parse()? }; let limits: Vec<&str> = parts[1].split(':').collect(); if limits.len() != 2 { return Err(MicrosandboxError::InvalidRLimitFormat(s.to_string())); } let soft = limits[0] .parse() .map_err(|_| MicrosandboxError::InvalidRLimitValue(limits[0].to_string()))?; let hard = limits[1] .parse() .map_err(|_| MicrosandboxError::InvalidRLimitValue(limits[1].to_string()))?; Ok(Self::new(resource, soft, hard)) } } impl fmt::Display for LinuxRlimit { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}={}:{}", self.resource.as_int(), self.soft, self.hard) } } impl Serialize for LinuxRlimit { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer, { serializer.serialize_str(&self.to_string()) } } impl<'de> Deserialize<'de> for LinuxRlimit { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de>, { let s = String::deserialize(deserializer)?; Self::from_str(&s).map_err(serde::de::Error::custom) } } //-------------------------------------------------------------------------------------------------- // Tests //-------------------------------------------------------------------------------------------------- #[cfg(test)] mod tests { use super::*; #[test] fn test_linux_rlimit_resource_from_u32() -> anyhow::Result<()> { assert_eq!( LinuxRLimitResource::try_from(0)?, LinuxRLimitResource::RLIMIT_CPU ); assert_eq!( LinuxRLimitResource::try_from(7)?, LinuxRLimitResource::RLIMIT_NOFILE ); assert_eq!( LinuxRLimitResource::try_from(15)?, LinuxRLimitResource::RLIMIT_RTTIME ); assert!(LinuxRLimitResource::try_from(16).is_err()); Ok(()) } #[test] fn test_linux_rlimit_resource_as_int() { assert_eq!(LinuxRLimitResource::RLIMIT_CPU.as_int(), 0); assert_eq!(LinuxRLimitResource::RLIMIT_NOFILE.as_int(), 7); assert_eq!(LinuxRLimitResource::RLIMIT_RTTIME.as_int(), 15); } #[test] fn test_linux_rlimit_resource_from_str() -> anyhow::Result<()> { assert_eq!( "RLIMIT_CPU".parse::<LinuxRLimitResource>()?, LinuxRLimitResource::RLIMIT_CPU ); assert_eq!( "RLIMIT_NOFILE".parse::<LinuxRLimitResource>()?, LinuxRLimitResource::RLIMIT_NOFILE ); assert_eq!( "RLIMIT_RTTIME".parse::<LinuxRLimitResource>()?, LinuxRLimitResource::RLIMIT_RTTIME ); assert!("RLIMIT_INVALID".parse::<LinuxRLimitResource>().is_err()); Ok(()) } #[test] fn test_linux_rlimit_resource_display() { assert_eq!(LinuxRLimitResource::RLIMIT_CPU.to_string(), "RLIMIT_CPU"); assert_eq!( LinuxRLimitResource::RLIMIT_NOFILE.to_string(), "RLIMIT_NOFILE" ); assert_eq!( LinuxRLimitResource::RLIMIT_RTTIME.to_string(), "RLIMIT_RTTIME" ); } #[test] fn test_linux_rlimit_new() { let rlimit = LinuxRlimit::new(LinuxRLimitResource::RLIMIT_CPU, 10, 20); assert_eq!(rlimit.resource, LinuxRLimitResource::RLIMIT_CPU); assert_eq!(rlimit.soft, 10); assert_eq!(rlimit.hard, 20); let rlimit = LinuxRlimit::new(LinuxRLimitResource::RLIMIT_NOFILE, 1000, 2000); assert_eq!(rlimit.resource, LinuxRLimitResource::RLIMIT_NOFILE); assert_eq!(rlimit.soft, 1000); assert_eq!(rlimit.hard, 2000); } #[test] fn test_linux_rlimit_from_str_with_rlimit_syntax() -> anyhow::Result<()> { let rlimit: LinuxRlimit = "RLIMIT_CPU=10:20".parse()?; assert_eq!(rlimit.resource, LinuxRLimitResource::RLIMIT_CPU); assert_eq!(rlimit.soft, 10); assert_eq!(rlimit.hard, 20); let rlimit: LinuxRlimit = "RLIMIT_NOFILE=1000:2000".parse()?; assert_eq!(rlimit.resource, LinuxRLimitResource::RLIMIT_NOFILE); assert_eq!(rlimit.soft, 1000); assert_eq!(rlimit.hard, 2000); let rlimit: LinuxRlimit = "RLIMIT_AS=1048576:2097152".parse()?; assert_eq!(rlimit.resource, LinuxRLimitResource::RLIMIT_AS); assert_eq!(rlimit.soft, 1048576); assert_eq!(rlimit.hard, 2097152); assert!("RLIMIT_INVALID=10:20".parse::<LinuxRlimit>().is_err()); assert!("RLIMIT_CPU=10".parse::<LinuxRlimit>().is_err()); assert!("RLIMIT_CPU=10:".parse::<LinuxRlimit>().is_err()); assert!("RLIMIT_CPU=:20".parse::<LinuxRlimit>().is_err()); Ok(()) } #[test] fn test_linux_rlimit_from_str_mixed_syntax() -> anyhow::Result<()> { let rlimit: LinuxRlimit = "0=10:20".parse()?; assert_eq!(rlimit.resource, LinuxRLimitResource::RLIMIT_CPU); assert_eq!(rlimit.soft, 10); assert_eq!(rlimit.hard, 20); let rlimit: LinuxRlimit = "RLIMIT_NOFILE=1000:2000".parse()?; assert_eq!(rlimit.resource, LinuxRLimitResource::RLIMIT_NOFILE); assert_eq!(rlimit.soft, 1000); assert_eq!(rlimit.hard, 2000); Ok(()) } #[test] fn test_linux_rlimit_display() { let rlimit = LinuxRlimit::new(LinuxRLimitResource::RLIMIT_CPU, 10, 20); assert_eq!(rlimit.to_string(), "0=10:20"); let rlimit = LinuxRlimit::new(LinuxRLimitResource::RLIMIT_NOFILE, 1000, 2000); assert_eq!(rlimit.to_string(), "7=1000:2000"); } #[test] fn test_linux_rlimit_serialize_deserialize() -> anyhow::Result<()> { let rlimit = LinuxRlimit::new(LinuxRLimitResource::RLIMIT_CPU, 10, 20); let serialized = serde_json::to_string(&rlimit)?; assert_eq!(serialized, "\"0=10:20\""); let deserialized: LinuxRlimit = serde_json::from_str(&serialized)?; assert_eq!(deserialized, rlimit); let rlimit = LinuxRlimit::new(LinuxRLimitResource::RLIMIT_NOFILE, 1000, 2000); let serialized = serde_json::to_string(&rlimit)?; assert_eq!(serialized, "\"7=1000:2000\""); let deserialized: LinuxRlimit = serde_json::from_str(&serialized)?; assert_eq!(deserialized, rlimit); Ok(()) } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/microsandbox/microsandbox'

If you have feedback or need assistance with the MCP directory API, please join our Discord server