From f6e764428445a82e5c42c9bb8676260ed6917b77 Mon Sep 17 00:00:00 2001 From: Mahmoud Emad Date: Wed, 12 Feb 2025 12:07:38 +0000 Subject: [PATCH] refactor: Improve dagu, meilisearch, and postgres installers - Remove redundant code and improve the overall structure of the installer actions. - Add more robust error handling and logging. - Update the postgres and dagu `destroy` function to properly remove all related services. - Improve the `install` function to ensure all necessary components are installed. --- examples/installers/dagu.vsh | 11 +- examples/installers/postgresql.vsh | 12 +- .../meilisearch_installer_actions.v | 4 - .../db/postgresql/postgresql_actions.v | 83 ++-- lib/installers/db/postgresql/postgresql_db.v | 103 ----- .../db/postgresql/postgresql_factory_.v | 373 +++++++++--------- .../db/postgresql/postgresql_model.v | 79 ++-- .../daguserver/daguserver_actions.v | 19 + 8 files changed, 314 insertions(+), 370 deletions(-) delete mode 100644 lib/installers/db/postgresql/postgresql_db.v diff --git a/examples/installers/dagu.vsh b/examples/installers/dagu.vsh index 5d2787f0..2b33db7d 100755 --- a/examples/installers/dagu.vsh +++ b/examples/installers/dagu.vsh @@ -3,14 +3,7 @@ import freeflowuniverse.herolib.installers.sysadmintools.daguserver import freeflowuniverse.herolib.installers.infra.zinit_installer -// make sure zinit is there and running, will restart it if needed -// mut z := zinit_installer.get()! -// z.destroy()! -// z.install()! -// z.start()! - mut ds := daguserver.get()! -// ds.destroy()! +ds.install()! ds.start()! - -println(ds) +ds.destroy()! diff --git a/examples/installers/postgresql.vsh b/examples/installers/postgresql.vsh index b826d972..7cd5d819 100755 --- a/examples/installers/postgresql.vsh +++ b/examples/installers/postgresql.vsh @@ -1,13 +1,9 @@ #!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run -import time -import freeflowuniverse.herolib.installers.db.postgresql +import freeflowuniverse.herolib.installers.db.postgresql as postgresql_installer -mut db := postgresql.get()! +mut db := postgresql_installer.get()! -// db.destroy()! +db.install()! db.start()! - -// db.db_create('my_new_db')! -// db.stop()! -// db.start()! +db.destroy()! diff --git a/lib/installers/db/meilisearch_installer/meilisearch_installer_actions.v b/lib/installers/db/meilisearch_installer/meilisearch_installer_actions.v index 56cd660f..d0051092 100644 --- a/lib/installers/db/meilisearch_installer/meilisearch_installer_actions.v +++ b/lib/installers/db/meilisearch_installer/meilisearch_installer_actions.v @@ -174,9 +174,5 @@ fn destroy() ! { } } - // osal.process_kill_recursive(name: 'meilisearch') or { - // return error('Could not kill meilisearch due to: ${err}') - // } - console.print_header('meilisearch is destroyed') } diff --git a/lib/installers/db/postgresql/postgresql_actions.v b/lib/installers/db/postgresql/postgresql_actions.v index 1f9d0a3a..bc3ba663 100644 --- a/lib/installers/db/postgresql/postgresql_actions.v +++ b/lib/installers/db/postgresql/postgresql_actions.v @@ -4,29 +4,9 @@ import freeflowuniverse.herolib.osal import freeflowuniverse.herolib.ui.console import freeflowuniverse.herolib.installers.virt.podman as podman_installer import freeflowuniverse.herolib.osal.zinit +import freeflowuniverse.herolib.installers.ulist import os -fn installed_() !bool { - mut cfg := get()! - mut podman := podman_installer.get()! - podman.install()! - - cmd := 'podman healthcheck run ${cfg.container_name}' - result := os.execute(cmd) - - if result.exit_code != 0 { - return false - } - return true -} - -fn install_() ! { - console.print_header('install postgresql') - mut podman := podman_installer.get()! - podman.install()! - osal.execute_silent('podman pull docker.io/library/postgres:latest')! -} - fn startupcmd() ![]zinit.ZProcessNewArgs { mut cfg := get()! mut res := []zinit.ZProcessNewArgs{} @@ -43,9 +23,14 @@ fn startupcmd() ![]zinit.ZProcessNewArgs { return res } -fn running_() !bool { - mut mydb := get()! - mydb.check() or { return false } +fn running() !bool { + cfg := get()! + cmd := 'podman healthcheck run ${cfg.container_name}' + result := os.execute(cmd) + + if result.exit_code != 0 { + return false + } return true } @@ -61,7 +46,40 @@ fn stop_pre() ! { fn stop_post() ! { } -fn destroy_() ! { +//////////////////// following actions are not specific to instance of the object + +// checks if a certain version or above is installed +fn installed() !bool { + mut cfg := get()! + mut podman := podman_installer.get()! + podman.install()! + + cmd := 'podman healthcheck run ${cfg.container_name}' + result := os.execute(cmd) + + if result.exit_code != 0 { + return false + } + return true +} + +// get the Upload List of the files +fn ulist_get() !ulist.UList { + // optionally build a UList which is all paths which are result of building, is then used e.g. in upload + return ulist.UList{} +} + +// uploads to S3 server if configured +fn upload() ! {} + +fn install() ! { + console.print_header('install postgresql') + mut podman := podman_installer.get()! + podman.install()! + osal.execute_silent('podman pull docker.io/library/postgres:latest')! +} + +fn destroy() ! { // remove the podman postgresql container mut cfg := get()! cmd := 'podman rm -f ${cfg.container_name}' @@ -70,5 +88,20 @@ fn destroy_() ! { if result.exit_code != 0 { return error("Postgresql container isn't running: ${result.output}") } + + // Remove podman + mut podman := podman_installer.get()! + podman.destroy()! + + // Remove zinit service, Q: Do we really need to run the postgresql inside a zinit service? it's already running in a container + mut zinit_factory := zinit.new()! + if zinit_factory.exists('postgresql') { + zinit_factory.stop('postgresql') or { + return error('Could not stop postgresql service due to: ${err}') + } + zinit_factory.delete('postgresql') or { + return error('Could not delete postgresql service due to: ${err}') + } + } console.print_header('Postgresql container removed') } diff --git a/lib/installers/db/postgresql/postgresql_db.v b/lib/installers/db/postgresql/postgresql_db.v deleted file mode 100644 index f024f13e..00000000 --- a/lib/installers/db/postgresql/postgresql_db.v +++ /dev/null @@ -1,103 +0,0 @@ -module postgresql - -import freeflowuniverse.herolib.core.pathlib -import freeflowuniverse.herolib.ui.console -import freeflowuniverse.herolib.core.texttools -import db.pg -import os -import net - -pub fn (mut server Postgresql) path_config() !pathlib.Path { - return pathlib.get_dir(path: '${server.volume_path}/config', create: true)! -} - -pub fn (mut server Postgresql) path_data() !pathlib.Path { - return pathlib.get_dir(path: '${server.volume_path}/data', create: true)! -} - -pub fn (mut server Postgresql) path_export() !pathlib.Path { - return pathlib.get_dir(path: '${server.volume_path}/exports', create: true)! -} - -fn is_port_open(host string, port int) bool { - mut socket := net.dial_tcp('${host}:${port}') or { return false } - socket.close() or { return false } - return true -} - -pub fn (mut server Postgresql) db() !pg.DB { - if is_port_open('localhost', 5432) == false { - return error('PostgreSQL is not listening on port 5432') - } - - conn_string := 'postgresql://${server.user}:${server.password}@${server.host}:${server.port}/postgres?connect_timeout=5' - mut db := pg.connect_with_conninfo(conn_string)! - // console.print_header("Database connected: ${db}") - return db -} - -pub fn (mut server Postgresql) check() ! { - mut db := server.db() or { return error('failed to check server: ${err}') } - - db.exec('SELECT version();') or { return error('postgresql could not do select version') } - - cmd := 'podman healthcheck run ${server.container_name}' - result := os.execute(cmd) - - if result.exit_code != 0 { - return error("Postgresql container isn't healthy: ${result.output}") - } - - container_id := 'podman container inspect ${server.container_name} --format {{.Id}}' - container_id_result := os.execute(container_id) - if container_id_result.exit_code != 0 { - return error('Cannot get the container ID: ${result.output}') - } - - server.container_id = container_id - console.print_header('Container ID: ${container_id_result.output}') -} - -pub fn (mut server Postgresql) db_exists(name_ string) !bool { - mut db := server.db()! - // SELECT datname FROM pg_database WHERE datname='gitea'; - r := db.exec("SELECT datname FROM pg_database WHERE datname='${name_}';")! - if r.len == 1 { - console.print_header('db exists: ${name_}') - return true - } - if r.len > 1 { - return error('should not have more than 1 db with name ${name_}') - } - return false -} - -pub fn (mut server Postgresql) db_create(name_ string) ! { - name := texttools.name_fix(name_) - server.check()! - mut db := server.db()! - db_exists := server.db_exists(name_)! - if !db_exists { - console.print_header('db create: ${name_}') - db.exec('CREATE DATABASE ${name};')! - } - db_exists2 := server.db_exists(name_)! - if !db_exists2 { - return error('Could not create db: ${name_}, could not find in DB.') - } -} - -pub fn (mut server Postgresql) db_delete(name_ string) ! { - name := texttools.name_fix(name_) - server.check()! - mut db := server.db()! - db_exists := server.db_exists(name_)! - if db_exists { - console.print_header('db delete: ${name_}') - db.exec('DROP DATABASE ${name};')! - } - db_exists2 := server.db_exists(name_)! - if db_exists2 { - return error('Could not delete db: ${name_}, could not find in DB.') - } -} diff --git a/lib/installers/db/postgresql/postgresql_factory_.v b/lib/installers/db/postgresql/postgresql_factory_.v index 4c23c67f..36463d61 100644 --- a/lib/installers/db/postgresql/postgresql_factory_.v +++ b/lib/installers/db/postgresql/postgresql_factory_.v @@ -3,285 +3,272 @@ module postgresql import freeflowuniverse.herolib.core.base import freeflowuniverse.herolib.core.playbook import freeflowuniverse.herolib.ui.console -import freeflowuniverse.herolib.data.paramsparser - import freeflowuniverse.herolib.sysadmin.startupmanager import freeflowuniverse.herolib.osal.zinit import time __global ( - postgresql_global map[string]&Postgresql - postgresql_default string + postgresql_global map[string]&Postgresql + postgresql_default string ) /////////FACTORY @[params] -pub struct ArgsGet{ +pub struct ArgsGet { pub mut: - name string + name string } -fn args_get (args_ ArgsGet) ArgsGet { - mut args:=args_ - if args.name == ""{ - args.name = "default" - } - return args +fn args_get(args_ ArgsGet) ArgsGet { + mut args := args_ + if args.name == '' { + args.name = 'default' + } + return args } -pub fn get(args_ ArgsGet) !&Postgresql { - mut context:=base.context()! - mut args := args_get(args_) - mut obj := Postgresql{} - if !(args.name in postgresql_global) { - if ! exists(args)!{ - set(obj)! - }else{ - heroscript := context.hero_config_get("postgresql",args.name)! - mut obj_:=heroscript_loads(heroscript)! - set_in_mem(obj_)! - } - } - return postgresql_global[args.name] or { - println(postgresql_global) - //bug if we get here because should be in globals - panic("could not get config for postgresql with name, is bug:${args.name}") - } +pub fn get(args_ ArgsGet) !&Postgresql { + mut context := base.context()! + mut args := args_get(args_) + mut obj := Postgresql{} + if args.name !in postgresql_global { + if !exists(args)! { + set(obj)! + } else { + heroscript := context.hero_config_get('postgresql', args.name)! + mut obj_ := heroscript_loads(heroscript)! + set_in_mem(obj_)! + } + } + return postgresql_global[args.name] or { + println(postgresql_global) + // bug if we get here because should be in globals + panic('could not get config for postgresql with name, is bug:${args.name}') + } } -//register the config for the future -pub fn set(o Postgresql)! { - set_in_mem(o)! - mut context := base.context()! - heroscript := heroscript_dumps(o)! - context.hero_config_set("postgresql", o.name, heroscript)! +// register the config for the future +pub fn set(o Postgresql) ! { + set_in_mem(o)! + mut context := base.context()! + heroscript := heroscript_dumps(o)! + context.hero_config_set('postgresql', o.name, heroscript)! } -//does the config exists? -pub fn exists(args_ ArgsGet)! bool { - mut context := base.context()! - mut args := args_get(args_) - return context.hero_config_exists("postgresql", args.name) +// does the config exists? +pub fn exists(args_ ArgsGet) !bool { + mut context := base.context()! + mut args := args_get(args_) + return context.hero_config_exists('postgresql', args.name) } -pub fn delete(args_ ArgsGet)! { - mut args := args_get(args_) - mut context:=base.context()! - context.hero_config_delete("postgresql",args.name)! - if args.name in postgresql_global { - //del postgresql_global[args.name] - } +pub fn delete(args_ ArgsGet) ! { + mut args := args_get(args_) + mut context := base.context()! + context.hero_config_delete('postgresql', args.name)! + if args.name in postgresql_global { + // del postgresql_global[args.name] + } } -//only sets in mem, does not set as config -fn set_in_mem(o Postgresql)! { - mut o2:=obj_init(o)! - postgresql_global[o.name] = &o2 - postgresql_default = o.name +// only sets in mem, does not set as config +fn set_in_mem(o Postgresql) ! { + mut o2 := obj_init(o)! + postgresql_global[o.name] = &o2 + postgresql_default = o.name } - @[params] pub struct PlayArgs { pub mut: - heroscript string //if filled in then plbook will be made out of it - plbook ?playbook.PlayBook - reset bool + heroscript string // if filled in then plbook will be made out of it + plbook ?playbook.PlayBook + reset bool } pub fn play(args_ PlayArgs) ! { - - mut args:=args_ + mut args := args_ + mut plbook := args.plbook or { playbook.new(text: args.heroscript)! } - mut plbook := args.plbook or { - playbook.new(text: args.heroscript)! - } - - mut install_actions := plbook.find(filter: 'postgresql.configure')! - if install_actions.len > 0 { - for install_action in install_actions { - heroscript:=install_action.heroscript() - mut obj2:=heroscript_loads(heroscript)! - set(obj2)! - } - } + mut install_actions := plbook.find(filter: 'postgresql.configure')! + if install_actions.len > 0 { + for install_action in install_actions { + heroscript := install_action.heroscript() + mut obj2 := heroscript_loads(heroscript)! + set(obj2)! + } + } - mut other_actions := plbook.find(filter: 'postgresql.')! - for other_action in other_actions { - if other_action.name in ["destroy","install","build"]{ - mut p := other_action.params - reset:=p.get_default_false("reset") - if other_action.name == "destroy" || reset{ - console.print_debug("install action postgresql.destroy") - destroy()! - } - if other_action.name == "install"{ - console.print_debug("install action postgresql.install") - install()! - } - } - if other_action.name in ["start","stop","restart"]{ - mut p := other_action.params - name := p.get('name')! - mut postgresql_obj:=get(name:name)! - console.print_debug("action object:\n${postgresql_obj}") - if other_action.name == "start"{ - console.print_debug("install action postgresql.${other_action.name}") - postgresql_obj.start()! - } - - if other_action.name == "stop"{ - console.print_debug("install action postgresql.${other_action.name}") - postgresql_obj.stop()! - } - if other_action.name == "restart"{ - console.print_debug("install action postgresql.${other_action.name}") - postgresql_obj.restart()! - } - } - } + mut other_actions := plbook.find(filter: 'postgresql.')! + for other_action in other_actions { + if other_action.name in ['destroy', 'install', 'build'] { + mut p := other_action.params + reset := p.get_default_false('reset') + if other_action.name == 'destroy' || reset { + console.print_debug('install action postgresql.destroy') + destroy()! + } + if other_action.name == 'install' { + console.print_debug('install action postgresql.install') + install()! + } + } + if other_action.name in ['start', 'stop', 'restart'] { + mut p := other_action.params + name := p.get('name')! + mut postgresql_obj := get(name: name)! + console.print_debug('action object:\n${postgresql_obj}') + if other_action.name == 'start' { + console.print_debug('install action postgresql.${other_action.name}') + postgresql_obj.start()! + } + if other_action.name == 'stop' { + console.print_debug('install action postgresql.${other_action.name}') + postgresql_obj.stop()! + } + if other_action.name == 'restart' { + console.print_debug('install action postgresql.${other_action.name}') + postgresql_obj.restart()! + } + } + } } - //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////# 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()! - } - } + // 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()! + } + } } -//load from disk and make sure is properly intialized +// load from disk and make sure is properly intialized pub fn (mut self Postgresql) reload() ! { - switch(self.name) - self=obj_init(self)! + switch(self.name) + self = obj_init(self)! } pub fn (mut self Postgresql) start() ! { - switch(self.name) - if self.running()!{ - return - } + switch(self.name) + if self.running()! { + return + } - console.print_header('postgresql start') + console.print_header('postgresql start') - if ! installed()!{ - install()! - } + if !installed()! { + install()! + } - configure()! + configure()! - start_pre()! + start_pre()! - for zprocess in startupcmd()!{ - mut sm:=startupmanager_get(zprocess.startuptype)! + for zprocess in startupcmd()! { + mut sm := startupmanager_get(zprocess.startuptype)! - console.print_debug('starting postgresql with ${zprocess.startuptype}...') + console.print_debug('starting postgresql with ${zprocess.startuptype}...') - sm.new(zprocess)! + sm.new(zprocess)! - sm.start(zprocess.name)! - } + sm.start(zprocess.name)! + } - start_post()! - - for _ in 0 .. 50 { - if self.running()! { - return - } - time.sleep(100 * time.millisecond) - } - return error('postgresql did not install properly.') + start_post()! + for _ in 0 .. 50 { + if self.running()! { + return + } + time.sleep(100 * time.millisecond) + } + return error('postgresql did not install properly.') } pub fn (mut self Postgresql) install_start(args InstallArgs) ! { - switch(self.name) - self.install(args)! - self.start()! + switch(self.name) + self.install(args)! + self.start()! } pub fn (mut self Postgresql) stop() ! { - switch(self.name) - stop_pre()! - for zprocess in startupcmd()!{ - mut sm:=startupmanager_get(zprocess.startuptype)! - sm.stop(zprocess.name)! - } - stop_post()! + 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 Postgresql) restart() ! { - switch(self.name) - self.stop()! - self.start()! + switch(self.name) + self.stop()! + self.start()! } pub fn (mut self Postgresql) running() !bool { - switch(self.name) + 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()! + // 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 struct InstallArgs { pub mut: - reset bool + reset bool } pub fn (mut self Postgresql) install(args InstallArgs) ! { - switch(self.name) - if args.reset || (!installed()!) { - install()! - } + switch(self.name) + if args.reset || (!installed()!) { + install()! + } } - pub fn (mut self Postgresql) destroy() ! { - switch(self.name) - self.stop() or {} - destroy()! + switch(self.name) + self.stop() or {} + destroy()! } - - -//switch instance to be used for postgresql +// switch instance to be used for postgresql pub fn switch(name string) { - postgresql_default = name + postgresql_default = name } - -//helpers +// helpers @[params] -pub struct DefaultConfigArgs{ - instance string = 'default' +pub struct DefaultConfigArgs { + instance string = 'default' } diff --git a/lib/installers/db/postgresql/postgresql_model.v b/lib/installers/db/postgresql/postgresql_model.v index 3b0856c3..42ad84a2 100644 --- a/lib/installers/db/postgresql/postgresql_model.v +++ b/lib/installers/db/postgresql/postgresql_model.v @@ -1,25 +1,14 @@ module postgresql -import freeflowuniverse.herolib.data.paramsparser +import freeflowuniverse.herolib.data.encoderhero -pub const version = '1.14.3' + +pub const version = '0.0.0' const singleton = true const default = true -pub fn heroscript_default() !string { - heroscript := " - !!postgresql.configure - name:'postgresql' - user: 'postgres' - password: 'postgres' - host: 'localhost' - port: 5432 - volume_path:'/var/lib/postgresql/data' - container_name: 'herocontainer_postgresql' - " - return heroscript -} +@[heap] pub struct Postgresql { pub mut: name string = 'default' @@ -32,22 +21,56 @@ pub mut: container_id string } -fn cfg_play(p paramsparser.Params) !Postgresql { - mut mycfg := Postgresql{ - name: p.get_default('name', 'default')! - user: p.get_default('user', 'postgres')! - password: p.get_default('password', 'postgres')! - host: p.get_default('host', 'localhost')! - port: p.get_int_default('port', 5432)! - volume_path: p.get_default('path', '/var/lib/postgresql/data')! - container_name: p.get_default('container_name', 'herocontainer_postgresql')! +// your checking & initialization code if needed +fn obj_init(mycfg_ Postgresql) !Postgresql { + mut mycfg := mycfg_ + if mycfg.name == '' { + mycfg.name = 'default' } + + if mycfg.user == '' { + mycfg.user = 'postgres' + } + + if mycfg.password == '' { + mycfg.password = 'postgres' + } + + if mycfg.host == '' { + mycfg.host = 'localhost' + } + + if mycfg.volume_path == '' { + mycfg.volume_path = '/var/lib/postgresql/data' + } + + if mycfg.container_name == '' { + mycfg.container_name = 'herocontainer_postgresql' + } + + if mycfg.port == 0 { + mycfg.port = 5432 + } + return mycfg } -fn obj_init(obj_ Postgresql) !Postgresql { - mut obj := obj_ - return obj +// called before start if done +fn configure() ! { + // mut installer := get()! + // mut mycode := $tmpl('templates/atemplate.yaml') + // mut path := pathlib.get_file(path: cfg.configpath, create: true)! + // path.write(mycode)! + // console.print_debug(mycode) } -fn configure() ! {} +/////////////NORMALLY NO NEED TO TOUCH + +pub fn heroscript_dumps(obj Postgresql) !string { + return encoderhero.encode[Postgresql](obj)! +} + +pub fn heroscript_loads(heroscript string) !Postgresql { + mut obj := encoderhero.decode[Postgresql](heroscript)! + return obj +} diff --git a/lib/installers/sysadmintools/daguserver/daguserver_actions.v b/lib/installers/sysadmintools/daguserver/daguserver_actions.v index caef4804..1823ce77 100644 --- a/lib/installers/sysadmintools/daguserver/daguserver_actions.v +++ b/lib/installers/sysadmintools/daguserver/daguserver_actions.v @@ -136,4 +136,23 @@ fn destroy() ! { ' osal.execute_silent(cmd) or {} + mut zinit_factory := zinit.new()! + + if zinit_factory.exists('dagu') { + zinit_factory.stop('dagu') or { + return error('Could not stop dagu service due to: ${err}') + } + zinit_factory.delete('dagu') or { + return error('Could not delete dagu service due to: ${err}') + } + } + + if zinit_factory.exists('dagu_scheduler') { + zinit_factory.stop('dagu_scheduler') or { + return error('Could not stop dagu_scheduler service due to: ${err}') + } + zinit_factory.delete('dagu_scheduler') or { + return error('Could not delete dagu_scheduler service due to: ${err}') + } + } }