refactor: Rename ContainerFactory to HeroPods
- Rename ContainerFactory struct to HeroPods - Update method names and receiver types accordingly - Adjust imports and internal references
This commit is contained in:
7
lib/virt/heropods/.heroscript
Normal file
7
lib/virt/heropods/.heroscript
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
!!hero_code.generate_client
|
||||||
|
name:''
|
||||||
|
classname:'HeroPods'
|
||||||
|
singleton:0
|
||||||
|
default:1
|
||||||
|
hasconfig:1
|
||||||
@@ -15,7 +15,7 @@ pub mut:
|
|||||||
node ?&builder.Node
|
node ?&builder.Node
|
||||||
tmux_pane ?&tmux.Pane
|
tmux_pane ?&tmux.Pane
|
||||||
crun_config ?&crun.CrunConfig
|
crun_config ?&crun.CrunConfig
|
||||||
factory &ContainerFactory
|
factory &HeroPods
|
||||||
}
|
}
|
||||||
|
|
||||||
// Struct to parse JSON output of `crun state`
|
// Struct to parse JSON output of `crun state`
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ pub:
|
|||||||
reset bool
|
reset bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut self ContainerFactory) new(args ContainerNewArgs) !&Container {
|
pub fn (mut self HeroPods) container_new(args ContainerNewArgs) !&Container {
|
||||||
if args.name in self.containers && !args.reset {
|
if args.name in self.containers && !args.reset {
|
||||||
return self.containers[args.name] or { panic('bug: container should exist') }
|
return self.containers[args.name] or { panic('bug: container should exist') }
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ pub fn (mut self ContainerFactory) new(args ContainerNewArgs) !&Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create crun configuration using the crun module
|
// Create crun configuration using the crun module
|
||||||
fn (mut self ContainerFactory) create_crun_config(container_name string, rootfs_path string) !&crun.CrunConfig {
|
fn (mut self HeroPods) create_crun_config(container_name string, rootfs_path string) !&crun.CrunConfig {
|
||||||
// Create crun configuration using the factory pattern
|
// Create crun configuration using the factory pattern
|
||||||
mut config := crun.new(mut self.crun_configs, name: container_name)!
|
mut config := crun.new(mut self.crun_configs, name: container_name)!
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ fn (mut self ContainerFactory) create_crun_config(container_name string, rootfs_
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use podman to pull image and extract rootfs
|
// Use podman to pull image and extract rootfs
|
||||||
fn (self ContainerFactory) podman_pull_and_export(docker_url string, image_name string, rootfs_path string) ! {
|
fn (self HeroPods) podman_pull_and_export(docker_url string, image_name string, rootfs_path string) ! {
|
||||||
// Pull image
|
// Pull image
|
||||||
osal.exec(
|
osal.exec(
|
||||||
cmd: 'podman pull ${docker_url}'
|
cmd: 'podman pull ${docker_url}'
|
||||||
|
|||||||
@@ -2,10 +2,8 @@ module heropods
|
|||||||
|
|
||||||
import incubaid.herolib.ui.console
|
import incubaid.herolib.ui.console
|
||||||
import incubaid.herolib.osal.core as osal
|
import incubaid.herolib.osal.core as osal
|
||||||
import incubaid.herolib.core.pathlib
|
|
||||||
import incubaid.herolib.core.texttools
|
import incubaid.herolib.core.texttools
|
||||||
import os
|
import os
|
||||||
import json
|
|
||||||
|
|
||||||
@[heap]
|
@[heap]
|
||||||
pub struct ContainerImage {
|
pub struct ContainerImage {
|
||||||
@@ -15,7 +13,7 @@ pub mut:
|
|||||||
rootfs_path string // path to the extracted rootfs
|
rootfs_path string // path to the extracted rootfs
|
||||||
size_mb f64 // size in MB
|
size_mb f64 // size in MB
|
||||||
created_at string // creation timestamp
|
created_at string // creation timestamp
|
||||||
factory &ContainerFactory @[skip; str: skip]
|
factory &HeroPods @[skip; str: skip]
|
||||||
}
|
}
|
||||||
|
|
||||||
@[params]
|
@[params]
|
||||||
@@ -41,7 +39,7 @@ pub mut:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create new image or get existing
|
// Create new image or get existing
|
||||||
pub fn (mut self ContainerFactory) image_new(args ContainerImageArgs) !&ContainerImage {
|
pub fn (mut self HeroPods) image_new(args ContainerImageArgs) !&ContainerImage {
|
||||||
mut image_name := texttools.name_fix(args.image_name)
|
mut image_name := texttools.name_fix(args.image_name)
|
||||||
rootfs_path := '${self.base_dir}/images/${image_name}/rootfs'
|
rootfs_path := '${self.base_dir}/images/${image_name}/rootfs'
|
||||||
|
|
||||||
@@ -138,7 +136,7 @@ fn (mut self ContainerImage) update_metadata() ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// List all available images
|
// List all available images
|
||||||
pub fn (mut self ContainerFactory) images_list() ![]&ContainerImage {
|
pub fn (mut self HeroPods) images_list() ![]&ContainerImage {
|
||||||
mut images := []&ContainerImage{}
|
mut images := []&ContainerImage{}
|
||||||
|
|
||||||
images_base_dir := '${self.base_dir}/images'
|
images_base_dir := '${self.base_dir}/images'
|
||||||
@@ -194,7 +192,7 @@ pub fn (mut self ContainerImage) export(args ImageExportArgs) ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Import image from .tgz file
|
// Import image from .tgz file
|
||||||
pub fn (mut self ContainerFactory) image_import(args ImageImportArgs) !&ContainerImage {
|
pub fn (mut self HeroPods) image_import(args ImageImportArgs) !&ContainerImage {
|
||||||
if !os.exists(args.source_path) {
|
if !os.exists(args.source_path) {
|
||||||
return error('Source file not found: ${args.source_path}')
|
return error('Source file not found: ${args.source_path}')
|
||||||
}
|
}
|
||||||
|
|||||||
143
lib/virt/heropods/heropods_factory_.v
Normal file
143
lib/virt/heropods/heropods_factory_.v
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
module heropods
|
||||||
|
|
||||||
|
import incubaid.herolib.core.base
|
||||||
|
import incubaid.herolib.core.playbook { PlayBook }
|
||||||
|
import json
|
||||||
|
|
||||||
|
__global (
|
||||||
|
heropods_global map[string]&HeroPods
|
||||||
|
heropods_default string
|
||||||
|
)
|
||||||
|
|
||||||
|
/////////FACTORY
|
||||||
|
|
||||||
|
@[params]
|
||||||
|
pub struct ArgsGet {
|
||||||
|
pub mut:
|
||||||
|
name string = 'default' // name of the heropods
|
||||||
|
fromdb bool // will load from filesystem
|
||||||
|
create bool // default will not create if not exist
|
||||||
|
reset bool // will reset the heropods
|
||||||
|
use_podman bool = true // will use podman for image management
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(args ArgsGet) !&HeroPods {
|
||||||
|
mut obj := HeroPods{
|
||||||
|
name: args.name
|
||||||
|
reset: args.reset
|
||||||
|
use_podman: args.use_podman
|
||||||
|
}
|
||||||
|
set(obj)!
|
||||||
|
return get(name: args.name)!
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(args ArgsGet) !&HeroPods {
|
||||||
|
mut context := base.context()!
|
||||||
|
heropods_default = args.name
|
||||||
|
if args.fromdb || args.name !in heropods_global {
|
||||||
|
mut r := context.redis()!
|
||||||
|
if r.hexists('context:heropods', args.name)! {
|
||||||
|
data := r.hget('context:heropods', args.name)!
|
||||||
|
if data.len == 0 {
|
||||||
|
print_backtrace()
|
||||||
|
return error('HeroPods with name: ${args.name} does not exist, prob bug.')
|
||||||
|
}
|
||||||
|
mut obj := json.decode(HeroPods, data)!
|
||||||
|
set_in_mem(obj)!
|
||||||
|
} else {
|
||||||
|
if args.create {
|
||||||
|
new(args)!
|
||||||
|
} else {
|
||||||
|
print_backtrace()
|
||||||
|
return error("HeroPods with name '${args.name}' does not exist")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return get(args)! // no longer from db nor create
|
||||||
|
}
|
||||||
|
return heropods_global[args.name] or {
|
||||||
|
print_backtrace()
|
||||||
|
return error('could not get config for heropods with name:${args.name}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// register the config for the future
|
||||||
|
pub fn set(o HeroPods) ! {
|
||||||
|
mut o2 := set_in_mem(o)!
|
||||||
|
heropods_default = o2.name
|
||||||
|
mut context := base.context()!
|
||||||
|
mut r := context.redis()!
|
||||||
|
r.hset('context:heropods', o2.name, json.encode(o2))!
|
||||||
|
}
|
||||||
|
|
||||||
|
// does the config exists?
|
||||||
|
pub fn exists(args ArgsGet) !bool {
|
||||||
|
mut context := base.context()!
|
||||||
|
mut r := context.redis()!
|
||||||
|
return r.hexists('context:heropods', args.name)!
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete(args ArgsGet) ! {
|
||||||
|
mut context := base.context()!
|
||||||
|
mut r := context.redis()!
|
||||||
|
r.hdel('context:heropods', args.name)!
|
||||||
|
}
|
||||||
|
|
||||||
|
@[params]
|
||||||
|
pub struct ArgsList {
|
||||||
|
pub mut:
|
||||||
|
fromdb bool // will load from filesystem
|
||||||
|
}
|
||||||
|
|
||||||
|
// if fromdb set: load from filesystem, and not from mem, will also reset what is in mem
|
||||||
|
pub fn list(args ArgsList) ![]&HeroPods {
|
||||||
|
mut res := []&HeroPods{}
|
||||||
|
mut context := base.context()!
|
||||||
|
if args.fromdb {
|
||||||
|
// reset what is in mem
|
||||||
|
heropods_global = map[string]&HeroPods{}
|
||||||
|
heropods_default = ''
|
||||||
|
}
|
||||||
|
if args.fromdb {
|
||||||
|
mut r := context.redis()!
|
||||||
|
mut l := r.hkeys('context:heropods')!
|
||||||
|
|
||||||
|
for name in l {
|
||||||
|
res << get(name: name, fromdb: true)!
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
} else {
|
||||||
|
// load from memory
|
||||||
|
for _, client in heropods_global {
|
||||||
|
res << client
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// only sets in mem, does not set as config
|
||||||
|
fn set_in_mem(o HeroPods) !HeroPods {
|
||||||
|
mut o2 := obj_init(o)!
|
||||||
|
heropods_global[o2.name] = &o2
|
||||||
|
heropods_default = o2.name
|
||||||
|
return o2
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn play(mut plbook PlayBook) ! {
|
||||||
|
if !plbook.exists(filter: 'heropods.') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mut install_actions := plbook.find(filter: 'heropods.configure')!
|
||||||
|
if install_actions.len > 0 {
|
||||||
|
for mut install_action in install_actions {
|
||||||
|
heroscript := install_action.heroscript()
|
||||||
|
mut obj2 := heroscript_loads(heroscript)!
|
||||||
|
set(obj2)!
|
||||||
|
install_action.done = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch instance to be used for heropods
|
||||||
|
pub fn switch(name string) {
|
||||||
|
heropods_default = name
|
||||||
|
}
|
||||||
@@ -1,39 +1,39 @@
|
|||||||
module heropods
|
module heropods
|
||||||
|
|
||||||
import incubaid.herolib.ui.console
|
import incubaid.herolib.data.encoderhero
|
||||||
import incubaid.herolib.osal.core as osal
|
import incubaid.herolib.osal.core as osal
|
||||||
|
import incubaid.herolib.ui.console
|
||||||
import incubaid.herolib.virt.crun
|
import incubaid.herolib.virt.crun
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
pub const version = '0.0.0'
|
||||||
|
const singleton = false
|
||||||
|
const default = true
|
||||||
|
|
||||||
|
// THIS THE THE SOURCE OF THE INFORMATION OF THIS FILE, HERE WE HAVE THE CONFIG OBJECT CONFIGURED AND MODELLED
|
||||||
|
|
||||||
@[heap]
|
@[heap]
|
||||||
pub struct ContainerFactory {
|
pub struct HeroPods {
|
||||||
pub mut:
|
pub mut:
|
||||||
tmux_session string
|
tmux_session string // tmux session name
|
||||||
containers map[string]&Container
|
containers map[string]&Container // name -> container mapping
|
||||||
images map[string]&ContainerImage
|
images map[string]&ContainerImage // name -> image mapping
|
||||||
crun_configs map[string]&crun.CrunConfig
|
crun_configs map[string]&crun.CrunConfig // name -> crun config mapping
|
||||||
base_dir string
|
base_dir string // base directory for all container data
|
||||||
|
reset bool // will reset the heropods
|
||||||
|
use_podman bool = true // will use podman for image management
|
||||||
|
name string // name of the heropods
|
||||||
}
|
}
|
||||||
|
|
||||||
@[params]
|
// your checking & initialization code if needed
|
||||||
pub struct FactoryInitArgs {
|
fn obj_init(mycfg_ HeroPods) !HeroPods {
|
||||||
pub:
|
mut args := mycfg_
|
||||||
reset bool
|
|
||||||
use_podman bool = true
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(args FactoryInitArgs) !ContainerFactory {
|
|
||||||
mut f := ContainerFactory{}
|
|
||||||
f.init(args)!
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut self ContainerFactory) init(args FactoryInitArgs) ! {
|
|
||||||
// Ensure base directories exist
|
// Ensure base directories exist
|
||||||
self.base_dir = os.getenv_opt('CONTAINERS_DIR') or { os.home_dir() + '/.containers' }
|
args.base_dir = os.getenv_opt('CONTAINERS_DIR') or { os.home_dir() + '/.containers' }
|
||||||
|
|
||||||
osal.exec(
|
osal.exec(
|
||||||
cmd: 'mkdir -p ${self.base_dir}/images ${self.base_dir}/configs ${self.base_dir}/runtime'
|
cmd: 'mkdir -p ${args.base_dir}/images ${args.base_dir}/configs ${args.base_dir}/runtime'
|
||||||
stdout: false
|
stdout: false
|
||||||
)!
|
)!
|
||||||
|
|
||||||
@@ -46,21 +46,41 @@ fn (mut self ContainerFactory) init(args FactoryInitArgs) ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mut heropods := HeroPods{
|
||||||
|
tmux_session: args.name
|
||||||
|
containers: map[string]&Container{}
|
||||||
|
images: map[string]&ContainerImage{}
|
||||||
|
crun_configs: map[string]&crun.CrunConfig{}
|
||||||
|
base_dir: args.base_dir
|
||||||
|
reset: args.reset
|
||||||
|
use_podman: args.use_podman
|
||||||
|
name: args.name
|
||||||
|
}
|
||||||
|
|
||||||
// Clean up any leftover crun state if reset is requested
|
// Clean up any leftover crun state if reset is requested
|
||||||
if args.reset {
|
if args.reset {
|
||||||
self.cleanup_crun_state()!
|
heropods.cleanup_crun_state()!
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load existing images into cache
|
// Load existing images into cache
|
||||||
self.load_existing_images()!
|
heropods.load_existing_images()!
|
||||||
|
|
||||||
// Setup default images if not using podman
|
// Setup default images if not using podman
|
||||||
if !args.use_podman {
|
if !args.use_podman {
|
||||||
self.setup_default_images(args.reset)!
|
heropods.setup_default_images(args.reset)!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut self ContainerFactory) setup_default_images(reset bool) ! {
|
/////////////NORMALLY NO NEED TO TOUCH
|
||||||
|
|
||||||
|
pub fn heroscript_loads(heroscript string) !HeroPods {
|
||||||
|
mut obj := encoderhero.decode[HeroPods](heroscript)!
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut self HeroPods) setup_default_images(reset bool) ! {
|
||||||
console.print_header('Setting up default images...')
|
console.print_header('Setting up default images...')
|
||||||
|
|
||||||
default_images := [ContainerImageType.alpine_3_20, .ubuntu_24_04, .ubuntu_25_04]
|
default_images := [ContainerImageType.alpine_3_20, .ubuntu_24_04, .ubuntu_25_04]
|
||||||
@@ -78,7 +98,7 @@ fn (mut self ContainerFactory) setup_default_images(reset bool) ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load existing images from filesystem into cache
|
// Load existing images from filesystem into cache
|
||||||
fn (mut self ContainerFactory) load_existing_images() ! {
|
fn (mut self HeroPods) load_existing_images() ! {
|
||||||
images_base_dir := '${self.base_dir}/containers/images'
|
images_base_dir := '${self.base_dir}/containers/images'
|
||||||
if !os.is_dir(images_base_dir) {
|
if !os.is_dir(images_base_dir) {
|
||||||
return
|
return
|
||||||
@@ -106,7 +126,7 @@ fn (mut self ContainerFactory) load_existing_images() ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut self ContainerFactory) get(args ContainerNewArgs) !&Container {
|
pub fn (mut self HeroPods) get(args ContainerNewArgs) !&Container {
|
||||||
if args.name !in self.containers {
|
if args.name !in self.containers {
|
||||||
return error('Container "${args.name}" does not exist. Use factory.new() to create it first.')
|
return error('Container "${args.name}" does not exist. Use factory.new() to create it first.')
|
||||||
}
|
}
|
||||||
@@ -114,7 +134,7 @@ pub fn (mut self ContainerFactory) get(args ContainerNewArgs) !&Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get image by name
|
// Get image by name
|
||||||
pub fn (mut self ContainerFactory) image_get(name string) !&ContainerImage {
|
pub fn (mut self HeroPods) image_get(name string) !&ContainerImage {
|
||||||
if name !in self.images {
|
if name !in self.images {
|
||||||
return error('Image "${name}" not found in cache. Try importing or downloading it.')
|
return error('Image "${name}" not found in cache. Try importing or downloading it.')
|
||||||
}
|
}
|
||||||
@@ -122,7 +142,7 @@ pub fn (mut self ContainerFactory) image_get(name string) !&ContainerImage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// List all containers currently managed by crun
|
// List all containers currently managed by crun
|
||||||
pub fn (self ContainerFactory) list() ![]Container {
|
pub fn (self HeroPods) list() ![]Container {
|
||||||
mut containers := []Container{}
|
mut containers := []Container{}
|
||||||
result := osal.exec(cmd: 'crun list --format json', stdout: false)!
|
result := osal.exec(cmd: 'crun list --format json', stdout: false)!
|
||||||
|
|
||||||
@@ -144,7 +164,7 @@ pub fn (self ContainerFactory) list() ![]Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clean up any leftover crun state
|
// Clean up any leftover crun state
|
||||||
fn (mut self ContainerFactory) cleanup_crun_state() ! {
|
fn (mut self HeroPods) cleanup_crun_state() ! {
|
||||||
console.print_debug('Cleaning up leftover crun state...')
|
console.print_debug('Cleaning up leftover crun state...')
|
||||||
crun_root := '${self.base_dir}/runtime'
|
crun_root := '${self.base_dir}/runtime'
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# heropods
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
To get started
|
||||||
|
|
||||||
|
```v
|
||||||
|
|
||||||
|
|
||||||
|
import incubaid.herolib.clients. heropods
|
||||||
|
|
||||||
|
mut client:= heropods.get()!
|
||||||
|
|
||||||
|
client...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## example heroscript
|
||||||
|
|
||||||
|
|
||||||
|
```hero
|
||||||
|
!!heropods.configure
|
||||||
|
secret: '...'
|
||||||
|
host: 'localhost'
|
||||||
|
port: 8888
|
||||||
|
```
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user