use std::collections::HashMap;
use std::time::Duration;
use firkin_types::Size;
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
pub struct SandboxResources {
pub vcpus: u32,
pub memory_bytes: u64,
}
impl SandboxResources {
#[must_use]
pub const fn new(vcpus: u32, memory: Size) -> Self {
Self {
vcpus,
memory_bytes: memory.as_bytes(),
}
}
#[must_use]
pub const fn cpu_count(&self) -> u32 {
self.vcpus
}
#[must_use]
pub const fn memory(&self) -> Size {
Size::bytes(self.memory_bytes)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum SingleNodeRuntimeMode {
#[default]
SingleVmBackedContainer,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SingleNodeCreateRequest {
sandbox_id: String,
template_id: String,
resources: SandboxResources,
runtime_mode: SingleNodeRuntimeMode,
timeout: Option<Duration>,
env: HashMap<String, String>,
}
impl SingleNodeCreateRequest {
#[must_use]
pub fn new(
sandbox_id: impl Into<String>,
template_id: impl Into<String>,
resources: SandboxResources,
) -> Self {
Self {
sandbox_id: sandbox_id.into(),
template_id: template_id.into(),
resources,
runtime_mode: SingleNodeRuntimeMode::SingleVmBackedContainer,
timeout: None,
env: HashMap::new(),
}
}
#[must_use]
pub fn sandbox_id(&self) -> &str {
&self.sandbox_id
}
#[must_use]
pub fn template_id(&self) -> &str {
&self.template_id
}
#[must_use]
pub const fn resources(&self) -> &SandboxResources {
&self.resources
}
#[must_use]
pub const fn runtime_mode(&self) -> SingleNodeRuntimeMode {
self.runtime_mode
}
#[must_use]
pub const fn timeout(&self) -> Option<Duration> {
self.timeout
}
#[must_use]
pub fn env(&self) -> &HashMap<String, String> {
&self.env
}
#[must_use]
pub const fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
#[must_use]
pub fn with_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.env.insert(key.into(), value.into());
self
}
#[must_use]
pub fn with_envs(mut self, env: HashMap<String, String>) -> Self {
self.env = env;
self
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub enum SandboxSessionState {
Creating,
#[default]
Running,
Stopping,
Stopped,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SandboxSession {
sandbox_id: String,
state: SandboxSessionState,
}
impl SandboxSession {
#[must_use]
pub fn new(sandbox_id: impl Into<String>, state: SandboxSessionState) -> Self {
Self {
sandbox_id: sandbox_id.into(),
state,
}
}
#[must_use]
pub fn sandbox_id(&self) -> &str {
&self.sandbox_id
}
#[must_use]
pub const fn state(&self) -> SandboxSessionState {
self.state
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct RuntimeCreatedSandbox {
pub sandbox_id: String,
pub client_id: String,
pub envd_access_token: Option<String>,
pub traffic_access_token: Option<String>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum SnapshotKind {
Template,
Continuation,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
pub struct SnapshotRecord {
pub snapshot_id: String,
pub source_sandbox_id: String,
pub names: Vec<String>,
pub location: Option<String>,
pub staging_dir: Option<String>,
pub machine_identifier: Option<Vec<u8>>,
pub network_macs: Option<Vec<String>>,
#[serde(default)]
pub template_metadata: TemplateMetadata,
}
impl SnapshotRecord {
#[must_use]
pub fn new(snapshot_id: impl Into<String>, source_sandbox_id: impl Into<String>) -> Self {
Self {
snapshot_id: snapshot_id.into(),
source_sandbox_id: source_sandbox_id.into(),
names: Vec::new(),
location: None,
staging_dir: None,
machine_identifier: None,
network_macs: None,
template_metadata: TemplateMetadata::default(),
}
}
#[must_use]
pub fn snapshot_id(&self) -> &str {
&self.snapshot_id
}
#[must_use]
pub fn source_sandbox_id(&self) -> &str {
&self.source_sandbox_id
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct RuntimeSnapshotRef {
pub snapshot_id: String,
pub source_sandbox_id: Option<String>,
pub location: Option<String>,
pub staging_dir: Option<String>,
pub machine_identifier: Option<Vec<u8>>,
pub network_macs: Option<Vec<String>>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
pub struct TemplateMetadata {
#[serde(default)]
pub envs: HashMap<String, String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub start_cmd: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ready_cmd: Option<String>,
}
impl TemplateMetadata {
#[must_use]
pub fn envs(&self) -> &HashMap<String, String> {
&self.envs
}
#[must_use]
pub fn start_command(&self) -> Option<&str> {
self.start_cmd.as_deref()
}
#[must_use]
pub fn ready_command(&self) -> Option<&str> {
self.ready_cmd.as_deref()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.envs.is_empty() && self.start_cmd.is_none() && self.ready_cmd.is_none()
}
#[must_use]
pub fn with_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.envs.insert(key.into(), value.into());
self
}
#[must_use]
pub fn with_start_command(mut self, command: impl Into<String>) -> Self {
self.start_cmd = Some(command.into());
self
}
#[must_use]
pub fn with_ready_command(mut self, command: impl Into<String>) -> Self {
self.ready_cmd = Some(command.into());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct CommandRequest {
pub command: String,
pub cwd: Option<String>,
pub envs: HashMap<String, String>,
pub user: Option<String>,
pub stdin: Vec<u8>,
}
impl CommandRequest {
#[must_use]
pub fn new(command: impl Into<String>) -> Self {
Self {
command: command.into(),
cwd: None,
envs: HashMap::new(),
user: None,
stdin: Vec::new(),
}
}
#[must_use]
pub fn command(&self) -> &str {
&self.command
}
#[must_use]
pub fn cwd(&self) -> Option<&str> {
self.cwd.as_deref()
}
#[must_use]
pub fn env(&self) -> &HashMap<String, String> {
&self.envs
}
#[must_use]
pub fn stdin(&self) -> Option<&[u8]> {
(!self.stdin.is_empty()).then_some(self.stdin.as_slice())
}
#[must_use]
pub fn with_cwd(mut self, cwd: impl Into<String>) -> Self {
self.cwd = Some(cwd.into());
self
}
#[must_use]
pub fn with_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.envs.insert(key.into(), value.into());
self
}
#[must_use]
pub fn with_user(mut self, user: impl Into<String>) -> Self {
self.user = Some(user.into());
self
}
#[must_use]
pub fn with_stdin(mut self, stdin: Vec<u8>) -> Self {
self.stdin = stdin;
self
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CommandOutput {
pub stdout: Vec<u8>,
pub stderr: Vec<u8>,
pub exit_code: i32,
}
impl CommandOutput {
#[must_use]
pub const fn new(stdout: Vec<u8>, stderr: Vec<u8>, exit_code: i32) -> Self {
Self {
stdout,
stderr,
exit_code,
}
}
#[must_use]
pub fn stdout(&self) -> &[u8] {
&self.stdout
}
#[must_use]
pub fn stderr(&self) -> &[u8] {
&self.stderr
}
#[must_use]
pub const fn exit_code(&self) -> i32 {
self.exit_code
}
#[must_use]
pub const fn success(&self) -> bool {
self.exit_code == 0
}
}
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
pub struct LogEvent {
pub timestamp_unix_seconds: i64,
pub message: String,
pub source: String,
}
impl LogEvent {
#[must_use]
pub fn new(message: impl Into<String>) -> Self {
Self {
timestamp_unix_seconds: time::OffsetDateTime::now_utc().unix_timestamp(),
message: message.into(),
source: "single-node".to_owned(),
}
}
#[must_use]
pub fn message(&self) -> &str {
&self.message
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PortRoute {
sandbox_id: String,
port: u16,
}
impl PortRoute {
#[must_use]
pub fn new(sandbox_id: impl Into<String>, port: u16) -> Self {
Self {
sandbox_id: sandbox_id.into(),
port,
}
}
#[must_use]
pub fn sandbox_id(&self) -> &str {
&self.sandbox_id
}
#[must_use]
pub const fn port(&self) -> u16 {
self.port
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RuntimeIdentity {
vm_id: String,
container_id: String,
}
impl RuntimeIdentity {
#[must_use]
pub fn new(vm_id: impl Into<String>, container_id: impl Into<String>) -> Self {
Self {
vm_id: vm_id.into(),
container_id: container_id.into(),
}
}
#[must_use]
pub fn vm_id(&self) -> &str {
&self.vm_id
}
#[must_use]
pub fn container_id(&self) -> &str {
&self.container_id
}
}