feat: add docker installer

- Add a new docker installer.
- Includes functionality for installing, starting, stopping, and removing docker.

Co-authored-by: mariobassem12 <mariobassem12@gmail.com>
Co-authored-by: omda  <mahmmoud.hassanein@gmail.com>
This commit is contained in:
2025-01-28 16:17:33 +01:00
parent 8b0f692673
commit 0f095a691d
7 changed files with 342 additions and 64 deletions

11
examples/installers/docker.vsh Executable file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/env -S v -n -w -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.virt.docker as docker_installer
mut docker := docker_installer.get()!
// To install
docker.install()!
// To remove
docker.destroy()!

View File

@@ -0,0 +1,13 @@
!!hero_code.generate_installer
name:'docker'
classname:'DockerInstaller'
singleton:0
templates:0
default:1
title:''
supported_platforms:''
reset:0
startupmanager:1
hasconfig:0
build:0

View File

@@ -1,64 +0,0 @@
module docker
import freeflowuniverse.herolib.osal
import freeflowuniverse.herolib.installers.base
import freeflowuniverse.herolib.ui.console
// install docker will return true if it was already installed
pub fn install_() ! {
console.print_header('package install install docker')
if core.platform() != .ubuntu {
return error('only support ubuntu for now')
}
base.install()!
if !osal.done_exists('install_docker') && !osal.cmd_exists('docker') {
// osal.upgrade()!
osal.package_install('mc,wget,htop,apt-transport-https,ca-certificates,curl,software-properties-common')!
cmd := '
rm -f /usr/share/keyrings/docker-archive-keyring.gpg
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt-cache policy docker-ce
#systemctl status docker
'
osal.execute_silent(cmd)!
osal.package_install('docker-ce')!
check()!
osal.done_set('install_docker', 'OK')!
}
console.print_header('docker already done')
}
pub fn check() ! {
// todo: do a monitoring check to see if it works
cmd := '
# Check if docker command exists
if ! command -v docker &> /dev/null; then
echo "Error: Docker command-line tool is not installed."
exit 1
fi
# Check if Docker daemon is running
if ! pgrep -f "dockerd" &> /dev/null; then
echo "Error: Docker daemon is not running."
exit 1
fi
# Run the hello-world Docker container
output=$(docker run hello-world 2>&1)
if [[ "\$output" == *"Hello from Docker!"* ]]; then
echo "Docker is installed and running properly."
else
echo "Error: Failed to run the Docker hello-world container."
echo "Output: \$output"
exit 1
fi
'
r := osal.execute_silent(cmd)!
console.print_debug(r)
}

View File

@@ -0,0 +1,106 @@
module docker
import freeflowuniverse.herolib.core
import freeflowuniverse.herolib.osal
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.osal.zinit
import freeflowuniverse.herolib.installers.ulist
fn startupcmd() ![]zinit.ZProcessNewArgs {
mut res := []zinit.ZProcessNewArgs{}
res << zinit.ZProcessNewArgs{
name: 'docker'
cmd: 'dockerd'
}
return res
}
fn running() !bool {
console.print_header('Checking if Docker is running')
is_installed := installed() or {
return error('Cannot execute command docker, check if the docker is installed or call the `install()` method: ${err}')
}
if !is_installed {
return false
}
// Checking if the docker server responed
cmd := 'docker ps'
osal.execute_stdout(cmd) or { return false }
console.print_header('Docker is running')
return true
}
fn start_pre() ! {
}
fn start_post() ! {
}
fn stop_pre() ! {
}
fn stop_post() ! {
}
//////////////////// following actions are not specific to instance of the object
// checks if a certain version or above is installed
fn installed() !bool {
console.print_header('Checking if Docker is installed')
cmd := 'docker -v'
osal.execute_stdout(cmd) or { return false }
console.print_header('Docker is installed')
return true
}
// get the Upload List of the files
fn ulist_get() !ulist.UList {
return ulist.UList{}
}
// uploads to S3 server if configured
fn upload() ! {}
fn install() ! {
console.print_header('Installing Docker')
if core.platform()! != .ubuntu {
return error('only support ubuntu for now')
}
mut cmd := '
sudo apt-get update -y
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "\$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update -y
'
osal.execute_stdout(cmd) or { return error('Cannot install docker due to: ${err}') }
cmd = 'sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin'
osal.execute_stdout(cmd) or { return error('Cannot install docker due to: ${err}') }
console.print_header('Docker installed sucessfully')
}
fn destroy() ! {
console.print_header('Removing Docker')
// Uninstall the Docker Engine, CLI, containerd, and Docker Compose packages:
mut cmd := 'sudo apt-get purge -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras'
osal.execute_stdout(cmd) or { return error('Cannot uninstall docker due to: ${err}') }
// Images, containers, volumes, or custom configuration files on your host aren't automatically removed. To delete all images, containers, and volumes:
cmd = 'sudo rm -rf /var/lib/docker && sudo rm -rf /var/lib/containerd'
osal.execute_stdout(cmd) or { return error('Cannot uninstall docker due to: ${err}') }
// Remove source list and keyrings
cmd = 'sudo rm /etc/apt/sources.list.d/docker.list && sudo rm /etc/apt/keyrings/docker.asc'
osal.execute_stdout(cmd) or { return error('Cannot uninstall docker due to: ${err}') }
console.print_header('Docker is removed')
}

View File

@@ -0,0 +1,147 @@
module docker
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.sysadmin.startupmanager
import freeflowuniverse.herolib.osal.zinit
import time
__global (
docker_global map[string]&DockerInstaller
docker_default string
)
/////////FACTORY
@[params]
pub struct ArgsGet {
pub mut:
name string
}
pub fn get(args_ ArgsGet) !&DockerInstaller {
return &DockerInstaller{}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////# LIVE CYCLE MANAGEMENT FOR INSTALLERS ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
fn startupmanager_get(cat zinit.StartupManagerType) !startupmanager.StartupManager {
// unknown
// screen
// zinit
// tmux
// systemd
match cat {
.zinit {
console.print_debug('startupmanager: zinit')
return startupmanager.get(cat: .zinit)!
}
.systemd {
console.print_debug('startupmanager: systemd')
return startupmanager.get(cat: .systemd)!
}
else {
console.print_debug('startupmanager: auto')
return startupmanager.get()!
}
}
}
pub fn (mut self DockerInstaller) start() ! {
switch(self.name)
if self.running()! {
return
}
console.print_header('docker start')
if !installed()! {
install()!
}
configure()!
start_pre()!
for zprocess in startupcmd()! {
mut sm := startupmanager_get(zprocess.startuptype)!
console.print_debug('starting docker with ${zprocess.startuptype}...')
sm.new(zprocess)!
sm.start(zprocess.name)!
}
start_post()!
for _ in 0 .. 50 {
if self.running()! {
return
}
time.sleep(100 * time.millisecond)
}
return error('docker did not install properly.')
}
pub fn (mut self DockerInstaller) install_start(args InstallArgs) ! {
switch(self.name)
self.install(args)!
self.start()!
}
pub fn (mut self DockerInstaller) stop() ! {
switch(self.name)
stop_pre()!
for zprocess in startupcmd()! {
mut sm := startupmanager_get(zprocess.startuptype)!
sm.stop(zprocess.name)!
}
stop_post()!
}
pub fn (mut self DockerInstaller) restart() ! {
switch(self.name)
self.stop()!
self.start()!
}
pub fn (mut self DockerInstaller) running() !bool {
switch(self.name)
// walk over the generic processes, if not running return
for zprocess in startupcmd()! {
mut sm := startupmanager_get(zprocess.startuptype)!
r := sm.running(zprocess.name)!
if r == false {
return false
}
}
return running()!
}
@[params]
pub struct InstallArgs {
pub mut:
reset bool
}
pub fn (mut self DockerInstaller) install(args InstallArgs) ! {
switch(self.name)
if args.reset || (!installed()!) {
install()!
}
}
pub fn (mut self DockerInstaller) destroy() ! {
switch(self.name)
self.stop() or {}
destroy()!
}
// switch instance to be used for docker
pub fn switch(name string) {
docker_default = name
}

View File

@@ -0,0 +1,23 @@
module docker
pub const version = '1.14.3'
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]
pub struct DockerInstaller {
pub mut:
name string = 'default'
}
fn obj_init(obj_ DockerInstaller) !DockerInstaller {
// never call get here, only thing we can do here is work on object itself
mut obj := obj_
return obj
}
// called before start if done
fn configure() ! {
// mut installer := get()!
}

View File

@@ -0,0 +1,42 @@
# docker
To get started
```vlang
import freeflowuniverse.herolib.installers.something.docker as docker_installer
heroscript:="
!!docker.configure name:'test'
password: '1234'
port: 7701
!!docker.start name:'test' reset:1
"
docker_installer.play(heroscript=heroscript)!
//or we can call the default and do a start with reset
//mut installer:= docker_installer.get()!
//installer.start(reset:true)!
```
## example heroscript
```hero
!!docker.configure
homedir: '/home/user/docker'
username: 'admin'
password: 'secretpassword'
title: 'Some Title'
host: 'localhost'
port: 8888
```