...
This commit is contained in:
39
lib/osal/startupmanager/model.v
Normal file
39
lib/osal/startupmanager/model.v
Normal file
@@ -0,0 +1,39 @@
|
||||
module startupmanager
|
||||
|
||||
pub enum StartupManagerType {
|
||||
unknown
|
||||
screen
|
||||
zinit
|
||||
tmux
|
||||
systemd
|
||||
auto
|
||||
}
|
||||
|
||||
@[params]
|
||||
pub struct ZProcessNewArgs {
|
||||
pub mut:
|
||||
name string @[required]
|
||||
cmd string @[required]
|
||||
cmd_stop string // command to stop (optional)
|
||||
cmd_test string // command line to test service is running
|
||||
workdir string // where to execute the commands
|
||||
after []string // list of service we depend on
|
||||
env map[string]string
|
||||
oneshot bool
|
||||
start bool = true
|
||||
restart bool = true // whether the process should be restarted on failure
|
||||
description string // not used in zinit
|
||||
startuptype StartupManagerType
|
||||
}
|
||||
|
||||
fn startup_manager_type_get(c string) StartupManagerType {
|
||||
match c {
|
||||
"unknown" { return .unknown }
|
||||
"screen" { return .screen }
|
||||
"zinit" { return .zinit }
|
||||
"tmux" { return .tmux }
|
||||
"systemd" { return .systemd }
|
||||
"auto" { return .auto }
|
||||
else { return .unknown }
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,232 @@
|
||||
# startup manager
|
||||
# Startup Manager
|
||||
|
||||
```go
|
||||
The `startupmanager` module provides a unified interface for managing processes across different underlying startup systems like `screen`, `systemd`, and `zinit`. It abstracts away the complexities of each system, allowing you to start, stop, restart, delete, and query the status of processes using a consistent API.
|
||||
|
||||
## How it Works
|
||||
|
||||
The `StartupManager` struct acts as a facade, delegating calls to the appropriate underlying startup system based on the `StartupManagerType` configured or automatically detected.
|
||||
|
||||
When you create a new `StartupManager` instance using `startupmanager.get()`, it attempts to detect if `zinit` is available on the system. If `zinit` is found, it will be used as the default startup manager. Otherwise, it falls back to `screen`. You can also explicitly specify the desired `StartupManagerType` during initialization.
|
||||
|
||||
The `ZProcessNewArgs` struct defines the parameters for creating and managing a new process.
|
||||
|
||||
## Usage
|
||||
|
||||
### Initializing the Startup Manager
|
||||
|
||||
You can initialize the `StartupManager` in a few ways:
|
||||
|
||||
1. **Automatic Detection (Recommended):**
|
||||
The manager will automatically detect if `zinit` is available and use it, otherwise it defaults to `screen`.
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.osal.startupmanager
|
||||
|
||||
fn main() {
|
||||
mut sm := startupmanager.get(cat:.screen)!
|
||||
// sm.cat will be .zinit or .screen
|
||||
println("Using startup manager: ${sm.cat}")
|
||||
}
|
||||
```
|
||||
|
||||
2. **Explicitly Specify Type:**
|
||||
You can force the manager to use a specific type.
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.osal.startupmanager
|
||||
|
||||
fn main() {
|
||||
mut sm_zinit := startupmanager.get(cat: .zinit)!
|
||||
println("Using startup manager: ${sm_zinit.cat}")
|
||||
|
||||
mut sm_screen := startupmanager.get(cat: .screen)!
|
||||
println("Using startup manager: ${sm_screen.cat}")
|
||||
|
||||
mut sm_systemd := startupmanager.get(cat: .systemd)!
|
||||
println("Using startup manager: ${sm_systemd.cat}")
|
||||
}
|
||||
```
|
||||
|
||||
### Managing Processes
|
||||
|
||||
The following examples demonstrate how to use the `StartupManager` to interact with processes. The `new` method takes a `ZProcessNewArgs` struct to define the process.
|
||||
|
||||
#### `new(args ZProcessNewArgs)`: Launch a new process
|
||||
|
||||
This method creates and optionally starts a new process.
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.osal.startupmanager
|
||||
mut sm:=startupmanager.get()!
|
||||
|
||||
fn main() {
|
||||
mut sm := startupmanager.get()!
|
||||
|
||||
sm.start(
|
||||
name: 'myscreen'
|
||||
cmd: 'htop'
|
||||
description: '...'
|
||||
)!
|
||||
// Example: Starting a simple web server with zinit
|
||||
sm.new(
|
||||
name: "my_web_server"
|
||||
cmd: "python3 -m http.server 8000"
|
||||
start: true
|
||||
restart: true
|
||||
description: "A simple Python HTTP server"
|
||||
startuptype: .zinit // Explicitly use zinit for this process
|
||||
)!
|
||||
println("Web server 'my_web_server' started with ${sm.cat}")
|
||||
|
||||
// Example: Starting a long-running script with screen
|
||||
sm.new(
|
||||
name: "my_background_script"
|
||||
cmd: "bash -c 'while true; do echo Hello from script; sleep 5; done'"
|
||||
start: true
|
||||
restart: true
|
||||
startuptype: .screen // Explicitly use screen for this process
|
||||
)!
|
||||
println("Background script 'my_background_script' started with ${sm.cat}")
|
||||
|
||||
// Example: Starting a systemd service (requires root privileges and proper systemd setup)
|
||||
// This assumes you have a systemd unit file configured for 'my_systemd_service'
|
||||
// For example, a file like /etc/systemd/system/my_systemd_service.service
|
||||
// [Unit]
|
||||
// Description=My Systemd Service
|
||||
// After=network.target
|
||||
//
|
||||
// [Service]
|
||||
// ExecStart=/usr/bin/python3 -m http.server 8080
|
||||
// Restart=always
|
||||
//
|
||||
// [Install]
|
||||
// WantedBy=multi-user.target
|
||||
sm.new(
|
||||
name: "my_systemd_service"
|
||||
cmd: "python3 -m http.server 8080" // This command is used to generate the unit file if it doesn't exist
|
||||
start: true
|
||||
restart: true
|
||||
startuptype: .systemd
|
||||
)!
|
||||
println("Systemd service 'my_systemd_service' created/started with ${sm.cat}")
|
||||
}
|
||||
```
|
||||
|
||||
#### `start(name string)`: Start a process
|
||||
|
||||
Starts an existing process.
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.osal.startupmanager
|
||||
|
||||
fn main() {
|
||||
mut sm := startupmanager.get()!
|
||||
sm.start("my_web_server")!
|
||||
println("Process 'my_web_server' started.")
|
||||
}
|
||||
```
|
||||
|
||||
#### `stop(name string)`: Stop a process
|
||||
|
||||
Stops a running process.
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.osal.startupmanager
|
||||
|
||||
fn main() {
|
||||
mut sm := startupmanager.get()!
|
||||
sm.stop("my_web_server")!
|
||||
println("Process 'my_web_server' stopped.")
|
||||
}
|
||||
```
|
||||
|
||||
#### `restart(name string)`: Restart a process
|
||||
|
||||
Restarts a process.
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.osal.startupmanager
|
||||
|
||||
fn main() {
|
||||
mut sm := startupmanager.get()!
|
||||
sm.restart("my_web_server")!
|
||||
println("Process 'my_web_server' restarted.")
|
||||
}
|
||||
```
|
||||
|
||||
#### `delete(name string)`: Delete a process
|
||||
|
||||
Removes a process from the startup manager.
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.osal.startupmanager
|
||||
|
||||
fn main() {
|
||||
mut sm := startupmanager.get()!
|
||||
sm.delete("my_web_server")!
|
||||
println("Process 'my_web_server' deleted.")
|
||||
}
|
||||
```
|
||||
|
||||
#### `status(name string) !ProcessStatus`: Get process status
|
||||
|
||||
Returns the current status of a process.
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.osal.startupmanager
|
||||
|
||||
fn main() {
|
||||
mut sm := startupmanager.get()!
|
||||
status := sm.status("my_web_server")!
|
||||
println("Status of 'my_web_server': ${status}")
|
||||
}
|
||||
```
|
||||
|
||||
#### `running(name string) !bool`: Check if process is running
|
||||
|
||||
Returns `true` if the process is active, `false` otherwise.
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.osal.startupmanager
|
||||
|
||||
fn main() {
|
||||
mut sm := startupmanager.get()!
|
||||
is_running := sm.running("my_web_server")!
|
||||
println("Is 'my_web_server' running? ${is_running}")
|
||||
}
|
||||
```
|
||||
|
||||
#### `output(name string) !string`: Get process output
|
||||
|
||||
Retrieves the output (logs) of a process. Currently supported for `systemd`.
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.osal.startupmanager
|
||||
|
||||
fn main() {
|
||||
mut sm := startupmanager.get(startupmanager.StartupManagerArgs{cat: .systemd})!
|
||||
output := sm.output("my_systemd_service")!
|
||||
println("Output of 'my_systemd_service':\n${output}")
|
||||
}
|
||||
```
|
||||
|
||||
#### `exists(name string) !bool`: Check if process exists
|
||||
|
||||
Returns `true` if the process is known to the startup manager, `false` otherwise.
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.osal.startupmanager
|
||||
|
||||
fn main() {
|
||||
mut sm := startupmanager.get()!
|
||||
does_exist := sm.exists("my_web_server")!
|
||||
println("Does 'my_web_server' exist? ${does_exist}")
|
||||
}
|
||||
```
|
||||
|
||||
#### `list() ![]string`: List all managed services
|
||||
|
||||
Returns a list of names of all services managed by the startup manager.
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.osal.startupmanager
|
||||
|
||||
fn main() {
|
||||
mut sm := startupmanager.get()!
|
||||
services := sm.list()!
|
||||
println("Managed services: ${services}")
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import freeflowuniverse.herolib.osal.zinit
|
||||
|
||||
// // TODO: check if using this interface would simplify things
|
||||
// pub interface StartupManagerI {
|
||||
// new(args zinit.ZProcessNewArgs)!
|
||||
// new(args startupmanager.ZProcessNewArgs)!
|
||||
// start(name string)!
|
||||
// stop(name string)!
|
||||
// restart(name string)!
|
||||
@@ -19,35 +19,32 @@ import freeflowuniverse.herolib.osal.zinit
|
||||
// list_services() ![]string
|
||||
// }
|
||||
|
||||
pub enum StartupManagerType {
|
||||
unknown
|
||||
screen
|
||||
zinit
|
||||
tmux
|
||||
systemd
|
||||
}
|
||||
|
||||
pub struct StartupManager {
|
||||
pub mut:
|
||||
cat StartupManagerType
|
||||
}
|
||||
|
||||
@[params]
|
||||
pub struct StartupManagerArgs {
|
||||
pub mut:
|
||||
cat StartupManagerType
|
||||
}
|
||||
// @[params]
|
||||
// pub struct StartupManagerArgs {
|
||||
// pub mut:
|
||||
// cat StartupManagerType
|
||||
// }
|
||||
|
||||
pub fn get(args StartupManagerArgs) !StartupManager {
|
||||
pub fn get(cat StartupManagerType) !StartupManager {
|
||||
console.print_debug('startupmanager get ${cat}')
|
||||
mut sm := StartupManager{
|
||||
cat: args.cat
|
||||
cat: cat
|
||||
}
|
||||
if args.cat == .unknown {
|
||||
if sm.cat == .auto {
|
||||
if zinit.check() {
|
||||
sm.cat = .zinit
|
||||
} else {
|
||||
sm.cat = .screen
|
||||
}
|
||||
}
|
||||
if sm.cat == .unknown {
|
||||
print_backtrace()
|
||||
return error("can't determine startup manager type, need to be a known one.")
|
||||
}
|
||||
return sm
|
||||
}
|
||||
@@ -67,12 +64,9 @@ pub fn get(args StartupManagerArgs) !StartupManager {
|
||||
// restart bool = true // whether the process should be restarted on failure
|
||||
// description string //not used in zinit
|
||||
//```
|
||||
pub fn (mut sm StartupManager) new(args zinit.ZProcessNewArgs) ! {
|
||||
pub fn (mut sm StartupManager) new(args ZProcessNewArgs) ! {
|
||||
console.print_debug("startupmanager start:${args.name} cmd:'${args.cmd}' restart:${args.restart}")
|
||||
mut mycat := sm.cat
|
||||
if args.startuptype == .systemd {
|
||||
mycat = .systemd
|
||||
}
|
||||
match mycat {
|
||||
.screen {
|
||||
mut scr := screen.new(reset: false)!
|
||||
@@ -83,40 +77,33 @@ pub fn (mut sm StartupManager) new(args zinit.ZProcessNewArgs) ! {
|
||||
// console.print_debug('systemd start ${args.name}')
|
||||
mut systemdfactory := systemd.new()!
|
||||
systemdfactory.new(
|
||||
cmd: args.cmd
|
||||
name: args.name
|
||||
description: args.description
|
||||
start: args.start
|
||||
restart: args.restart
|
||||
env: args.env
|
||||
cmd: args.cmd
|
||||
name: args.name
|
||||
start: args.start
|
||||
restart: args.restart
|
||||
env: args.env
|
||||
)!
|
||||
}
|
||||
.zinit {
|
||||
console.print_debug('zinit start ${args.name}')
|
||||
mut zinitfactory := zinit.new()!
|
||||
// pub struct ZProcessNewArgs {
|
||||
// name string @[required]
|
||||
// cmd string @[required]
|
||||
// cmd_stop string
|
||||
// cmd_test string
|
||||
// cmd_file bool // if we wanna force to run it as a file which is given to bash -c (not just a cmd in zinit)
|
||||
// test string
|
||||
// test_file bool
|
||||
// after []string
|
||||
// env map[string]string
|
||||
// oneshot bool
|
||||
// }
|
||||
zinitfactory.new(args)!
|
||||
zinitfactory.new(
|
||||
name: args.name
|
||||
cmd: args.cmd
|
||||
cmd_stop: args.cmd_stop
|
||||
cmd_test: args.cmd_test
|
||||
workdir: args.workdir
|
||||
after: args.after
|
||||
env: args.env
|
||||
oneshot: args.oneshot
|
||||
start: args.start
|
||||
restart: args.restart
|
||||
)!
|
||||
}
|
||||
else {
|
||||
panic('to implement, startup manager only support screen & systemd for now: ${mycat}')
|
||||
}
|
||||
}
|
||||
// if args.start {
|
||||
// sm.start(args.name)!
|
||||
// } else if args.restart {
|
||||
// sm.restart(args.name)!
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn (mut sm StartupManager) start(name string) ! {
|
||||
@@ -309,7 +296,7 @@ pub fn (mut sm StartupManager) output(name string) !string {
|
||||
}
|
||||
|
||||
pub fn (mut sm StartupManager) exists(name string) !bool {
|
||||
println(sm.cat)
|
||||
|
||||
if sm.cat == .unknown {
|
||||
if zinit.check() {
|
||||
sm.cat = .zinit
|
||||
@@ -359,30 +346,3 @@ pub fn (mut sm StartupManager) list() ![]string {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// THIS IS PROBABLY PART OF OTHER MODULE NOW
|
||||
|
||||
// pub struct SecretArgs {
|
||||
// pub mut:
|
||||
// name string @[required]
|
||||
// cat SecretType
|
||||
// }
|
||||
|
||||
// pub enum SecretType {
|
||||
// normal
|
||||
// }
|
||||
|
||||
// // creates a secret if it doesn exist yet
|
||||
// pub fn (mut sm StartupManager) secret(args SecretArgs) !string {
|
||||
// if !(sm.exists(args.name)) {
|
||||
// return error("can't find screen with name ${args.name}, for secret")
|
||||
// }
|
||||
// key := 'secrets:startup:${args.name}'
|
||||
// mut redis := redisclient.core_get()!
|
||||
// mut secret := redis.get(key)!
|
||||
// if secret.len == 0 {
|
||||
// secret = rand.hex(16)
|
||||
// redis.set(key, secret)!
|
||||
// }
|
||||
// return secret
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user