391 lines
10 KiB
V
391 lines
10 KiB
V
module crun
|
|
|
|
import incubaid.herolib.core.texttools
|
|
|
|
@[params]
|
|
pub struct FactoryArgs {
|
|
pub mut:
|
|
name string = 'default'
|
|
}
|
|
|
|
pub struct CrunConfig {
|
|
pub mut:
|
|
name string
|
|
spec Spec
|
|
}
|
|
|
|
// Convert enum values to their string representations
|
|
pub fn (mount_type MountType) to_string() string {
|
|
return match mount_type {
|
|
.bind { 'bind' }
|
|
.tmpfs { 'tmpfs' }
|
|
.proc { 'proc' }
|
|
.sysfs { 'sysfs' }
|
|
.devpts { 'devpts' }
|
|
.mqueue { 'mqueue' }
|
|
.cgroup { 'cgroup' }
|
|
.nfs { 'nfs' }
|
|
.overlay { 'overlay' }
|
|
}
|
|
}
|
|
|
|
pub fn (option MountOption) to_string() string {
|
|
return match option {
|
|
.rw { 'rw' }
|
|
.ro { 'ro' }
|
|
.noexec { 'noexec' }
|
|
.nosuid { 'nosuid' }
|
|
.nodev { 'nodev' }
|
|
.rbind { 'rbind' }
|
|
.relatime { 'relatime' }
|
|
.strictatime { 'strictatime' }
|
|
.mode { 'mode=755' } // Default mode, can be customized
|
|
.size { 'size=65536k' } // Default size, can be customized
|
|
}
|
|
}
|
|
|
|
pub fn (cap Capability) to_string() string {
|
|
return match cap {
|
|
.cap_chown { 'CAP_CHOWN' }
|
|
.cap_dac_override { 'CAP_DAC_OVERRIDE' }
|
|
.cap_dac_read_search { 'CAP_DAC_READ_SEARCH' }
|
|
.cap_fowner { 'CAP_FOWNER' }
|
|
.cap_fsetid { 'CAP_FSETID' }
|
|
.cap_kill { 'CAP_KILL' }
|
|
.cap_setgid { 'CAP_SETGID' }
|
|
.cap_setuid { 'CAP_SETUID' }
|
|
.cap_setpcap { 'CAP_SETPCAP' }
|
|
.cap_linux_immutable { 'CAP_LINUX_IMMUTABLE' }
|
|
.cap_net_bind_service { 'CAP_NET_BIND_SERVICE' }
|
|
.cap_net_broadcast { 'CAP_NET_BROADCAST' }
|
|
.cap_net_admin { 'CAP_NET_ADMIN' }
|
|
.cap_net_raw { 'CAP_NET_RAW' }
|
|
.cap_ipc_lock { 'CAP_IPC_LOCK' }
|
|
.cap_ipc_owner { 'CAP_IPC_OWNER' }
|
|
.cap_sys_module { 'CAP_SYS_MODULE' }
|
|
.cap_sys_rawio { 'CAP_SYS_RAWIO' }
|
|
.cap_sys_chroot { 'CAP_SYS_CHROOT' }
|
|
.cap_sys_ptrace { 'CAP_SYS_PTRACE' }
|
|
.cap_sys_pacct { 'CAP_SYS_PACCT' }
|
|
.cap_sys_admin { 'CAP_SYS_ADMIN' }
|
|
.cap_sys_boot { 'CAP_SYS_BOOT' }
|
|
.cap_sys_nice { 'CAP_SYS_NICE' }
|
|
.cap_sys_resource { 'CAP_SYS_RESOURCE' }
|
|
.cap_sys_time { 'CAP_SYS_TIME' }
|
|
.cap_sys_tty_config { 'CAP_SYS_TTY_CONFIG' }
|
|
.cap_mknod { 'CAP_MKNOD' }
|
|
.cap_lease { 'CAP_LEASE' }
|
|
.cap_audit_write { 'CAP_AUDIT_WRITE' }
|
|
.cap_audit_control { 'CAP_AUDIT_CONTROL' }
|
|
.cap_setfcap { 'CAP_SETFCAP' }
|
|
.cap_mac_override { 'CAP_MAC_OVERRIDE' }
|
|
.cap_mac_admin { 'CAP_MAC_ADMIN' }
|
|
.cap_syslog { 'CAP_SYSLOG' }
|
|
.cap_wake_alarm { 'CAP_WAKE_ALARM' }
|
|
.cap_block_suspend { 'CAP_BLOCK_SUSPEND' }
|
|
.cap_audit_read { 'CAP_AUDIT_READ' }
|
|
}
|
|
}
|
|
|
|
pub fn (rlimit RlimitType) to_string() string {
|
|
return match rlimit {
|
|
.rlimit_cpu { 'RLIMIT_CPU' }
|
|
.rlimit_fsize { 'RLIMIT_FSIZE' }
|
|
.rlimit_data { 'RLIMIT_DATA' }
|
|
.rlimit_stack { 'RLIMIT_STACK' }
|
|
.rlimit_core { 'RLIMIT_CORE' }
|
|
.rlimit_rss { 'RLIMIT_RSS' }
|
|
.rlimit_nproc { 'RLIMIT_NPROC' }
|
|
.rlimit_nofile { 'RLIMIT_NOFILE' }
|
|
.rlimit_memlock { 'RLIMIT_MEMLOCK' }
|
|
.rlimit_as { 'RLIMIT_AS' }
|
|
.rlimit_lock { 'RLIMIT_LOCK' }
|
|
.rlimit_sigpending { 'RLIMIT_SIGPENDING' }
|
|
.rlimit_msgqueue { 'RLIMIT_MSGQUEUE' }
|
|
.rlimit_nice { 'RLIMIT_NICE' }
|
|
.rlimit_rtprio { 'RLIMIT_RTPRIO' }
|
|
.rlimit_rttime { 'RLIMIT_RTTIME' }
|
|
}
|
|
}
|
|
|
|
// Configuration methods with builder pattern
|
|
pub fn (mut config CrunConfig) set_command(args []string) &CrunConfig {
|
|
config.spec.process.args = args.clone()
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) set_working_dir(cwd string) &CrunConfig {
|
|
config.spec.process.cwd = cwd
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) set_user(uid u32, gid u32, additional_gids []u32) &CrunConfig {
|
|
config.spec.process.user = User{
|
|
uid: uid
|
|
gid: gid
|
|
additional_gids: additional_gids.clone()
|
|
}
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) add_env(key string, value string) &CrunConfig {
|
|
// Remove existing env var with same key to avoid duplicates
|
|
config.spec.process.env = config.spec.process.env.filter(!it.starts_with('${key}='))
|
|
config.spec.process.env << '${key}=${value}'
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) set_rootfs(path string, readonly bool) &CrunConfig {
|
|
config.spec.root = Root{
|
|
path: path
|
|
readonly: readonly
|
|
}
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) set_hostname(hostname string) &CrunConfig {
|
|
config.spec.hostname = hostname
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) set_memory_limit(limit_bytes u64) &CrunConfig {
|
|
config.spec.linux_config.resources.memory.limit = limit_bytes
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) set_cpu_limits(period u64, quota i64, shares u64) &CrunConfig {
|
|
config.spec.linux_config.resources.cpu.period = period
|
|
config.spec.linux_config.resources.cpu.quota = quota
|
|
config.spec.linux_config.resources.cpu.shares = shares
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) set_pids_limit(limit i64) &CrunConfig {
|
|
config.spec.linux_config.resources.pids.limit = limit
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) add_mount(destination string, source string, typ MountType, options []MountOption) &CrunConfig {
|
|
config.spec.mounts << Mount{
|
|
destination: destination
|
|
typ: typ.to_string()
|
|
source: source
|
|
options: options.map(it.to_string())
|
|
}
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) add_capability(cap Capability) &CrunConfig {
|
|
cap_str := cap.to_string()
|
|
|
|
if cap_str !in config.spec.process.capabilities.bounding {
|
|
config.spec.process.capabilities.bounding << cap_str
|
|
}
|
|
if cap_str !in config.spec.process.capabilities.effective {
|
|
config.spec.process.capabilities.effective << cap_str
|
|
}
|
|
if cap_str !in config.spec.process.capabilities.permitted {
|
|
config.spec.process.capabilities.permitted << cap_str
|
|
}
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) remove_capability(cap Capability) &CrunConfig {
|
|
cap_str := cap.to_string()
|
|
|
|
config.spec.process.capabilities.bounding = config.spec.process.capabilities.bounding.filter(it != cap_str)
|
|
config.spec.process.capabilities.effective = config.spec.process.capabilities.effective.filter(it != cap_str)
|
|
config.spec.process.capabilities.permitted = config.spec.process.capabilities.permitted.filter(it != cap_str)
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) add_rlimit(typ RlimitType, hard u64, soft u64) &CrunConfig {
|
|
// Remove existing rlimit with same type to avoid duplicates
|
|
typ_str := typ.to_string()
|
|
config.spec.process.rlimits = config.spec.process.rlimits.filter(it.typ != typ_str)
|
|
config.spec.process.rlimits << Rlimit{
|
|
typ: typ_str
|
|
hard: hard
|
|
soft: soft
|
|
}
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) set_no_new_privileges(value bool) &CrunConfig {
|
|
config.spec.process.no_new_privileges = value
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) set_terminal(value bool) &CrunConfig {
|
|
config.spec.process.terminal = value
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) add_masked_path(path string) &CrunConfig {
|
|
if path !in config.spec.linux_config.masked_paths {
|
|
config.spec.linux_config.masked_paths << path
|
|
}
|
|
return config
|
|
}
|
|
|
|
pub fn (mut config CrunConfig) add_readonly_path(path string) &CrunConfig {
|
|
if path !in config.spec.linux_config.readonly_paths {
|
|
config.spec.linux_config.readonly_paths << path
|
|
}
|
|
return config
|
|
}
|
|
|
|
pub fn new(mut configs map[string]&CrunConfig, args FactoryArgs) !&CrunConfig {
|
|
name := texttools.name_fix(args.name)
|
|
|
|
mut config := &CrunConfig{
|
|
name: name
|
|
spec: create_default_spec()
|
|
}
|
|
|
|
configs[name] = config
|
|
return config
|
|
}
|
|
|
|
pub fn get(configs map[string]&CrunConfig, args FactoryArgs) !&CrunConfig {
|
|
name := texttools.name_fix(args.name)
|
|
return configs[name] or { return error('crun config with name "${name}" does not exist') }
|
|
}
|
|
|
|
fn create_default_spec() Spec {
|
|
// Create default spec that matches the heropods template
|
|
mut spec := Spec{
|
|
oci_version: '1.0.2' // Set default here
|
|
platform: Platform{
|
|
os: 'linux'
|
|
arch: 'amd64'
|
|
}
|
|
process: Process{
|
|
terminal: true
|
|
user: User{
|
|
uid: 0
|
|
gid: 0
|
|
}
|
|
args: ['/bin/sh']
|
|
env: [
|
|
'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
|
|
'TERM=xterm',
|
|
]
|
|
cwd: '/'
|
|
capabilities: Capabilities{
|
|
bounding: ['CAP_AUDIT_WRITE', 'CAP_KILL', 'CAP_NET_BIND_SERVICE']
|
|
effective: ['CAP_AUDIT_WRITE', 'CAP_KILL', 'CAP_NET_BIND_SERVICE']
|
|
inheritable: ['CAP_AUDIT_WRITE', 'CAP_KILL', 'CAP_NET_BIND_SERVICE']
|
|
permitted: ['CAP_AUDIT_WRITE', 'CAP_KILL', 'CAP_NET_BIND_SERVICE']
|
|
}
|
|
rlimits: [
|
|
Rlimit{
|
|
typ: 'RLIMIT_NOFILE'
|
|
hard: 1024
|
|
soft: 1024
|
|
},
|
|
]
|
|
no_new_privileges: true // No JSON annotation needed here
|
|
}
|
|
root: Root{
|
|
path: 'rootfs'
|
|
readonly: false
|
|
}
|
|
hostname: 'container'
|
|
mounts: create_default_mounts()
|
|
linux_config: LinuxConfig{
|
|
namespaces: create_default_namespaces()
|
|
masked_paths: [
|
|
'/proc/acpi',
|
|
'/proc/kcore',
|
|
'/proc/keys',
|
|
'/proc/latency_stats',
|
|
'/proc/timer_list',
|
|
'/proc/timer_stats',
|
|
'/proc/sched_debug',
|
|
'/proc/scsi',
|
|
'/sys/firmware',
|
|
]
|
|
readonly_paths: [
|
|
'/proc/asound',
|
|
'/proc/bus',
|
|
'/proc/fs',
|
|
'/proc/irq',
|
|
'/proc/sys',
|
|
'/proc/sysrq-trigger',
|
|
]
|
|
}
|
|
}
|
|
|
|
return spec
|
|
}
|
|
|
|
fn create_default_namespaces() []LinuxNamespace {
|
|
return [
|
|
LinuxNamespace{
|
|
typ: 'pid'
|
|
},
|
|
LinuxNamespace{
|
|
typ: 'network'
|
|
},
|
|
LinuxNamespace{
|
|
typ: 'ipc'
|
|
},
|
|
LinuxNamespace{
|
|
typ: 'uts'
|
|
},
|
|
LinuxNamespace{
|
|
typ: 'cgroup'
|
|
},
|
|
LinuxNamespace{
|
|
typ: 'mount'
|
|
},
|
|
]
|
|
}
|
|
|
|
fn create_default_mounts() []Mount {
|
|
return [
|
|
Mount{
|
|
destination: '/proc'
|
|
typ: 'proc'
|
|
source: 'proc'
|
|
},
|
|
Mount{
|
|
destination: '/dev'
|
|
typ: 'tmpfs'
|
|
source: 'tmpfs'
|
|
options: ['nosuid', 'strictatime', 'mode=755', 'size=65536k']
|
|
},
|
|
Mount{
|
|
destination: '/dev/pts'
|
|
typ: 'devpts'
|
|
source: 'devpts'
|
|
options: ['nosuid', 'noexec', 'newinstance', 'ptmxmode=0666', 'mode=0620', 'gid=5']
|
|
},
|
|
Mount{
|
|
destination: '/dev/shm'
|
|
typ: 'tmpfs'
|
|
source: 'shm'
|
|
options: ['nosuid', 'noexec', 'nodev', 'mode=1777', 'size=65536k']
|
|
},
|
|
Mount{
|
|
destination: '/dev/mqueue'
|
|
typ: 'mqueue'
|
|
source: 'mqueue'
|
|
options: ['nosuid', 'noexec', 'nodev']
|
|
},
|
|
Mount{
|
|
destination: '/sys'
|
|
typ: 'sysfs'
|
|
source: 'sysfs'
|
|
options: ['nosuid', 'noexec', 'nodev', 'ro']
|
|
},
|
|
Mount{
|
|
destination: '/sys/fs/cgroup'
|
|
typ: 'cgroup'
|
|
source: 'cgroup'
|
|
options: ['nosuid', 'noexec', 'nodev', 'relatime', 'ro']
|
|
},
|
|
]
|
|
}
|