Merge branch 'development_nile_installers' into development
* development_nile_installers: fix ci feat: Add reset functionality to startup commands feat(cryptpad): Refactor installer configuration logic feat: Add PostgreSQL support for Gitea installer feat: Add Gitea Kubernetes installer feat(cryptpad): Refactor installer for dynamic configuration
This commit is contained in:
3
examples/installers/k8s/.gitignore
vendored
3
examples/installers/k8s/.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
cryptpad
|
||||
element_chat
|
||||
element_chat
|
||||
gitea
|
||||
@@ -11,13 +11,17 @@ mut installer := cryptpad.get(
|
||||
create: true
|
||||
)!
|
||||
|
||||
// 2. Install CryptPad.
|
||||
// This will generate the necessary Kubernetes YAML files and apply them to your cluster.
|
||||
// installer.install()!
|
||||
// cryptpad.delete()!
|
||||
// 2. Configure the installer (all settings are optional with sensible defaults)
|
||||
// installer.hostname = 'mycryptpad'
|
||||
// installer.namespace = 'cryptpad'
|
||||
|
||||
// 3. Install CryptPad.
|
||||
// This will generate the necessary Kubernetes YAML files and apply them to your cluster.
|
||||
installer.install()!
|
||||
|
||||
// println('CryptPad installation started.')
|
||||
// println('You can access it at https://${installer.hostname}.gent01.grid.tf')
|
||||
|
||||
// 3. To destroy the deployment, you can run the following:
|
||||
installer.destroy()!
|
||||
// 4. To destroy the deployment, you can run the following:
|
||||
// installer.destroy()!
|
||||
|
||||
44
examples/installers/k8s/gitea.vsh
Executable file
44
examples/installers/k8s/gitea.vsh
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import incubaid.herolib.installers.k8s.gitea
|
||||
|
||||
// This example demonstrates how to use the Gitea installer.
|
||||
|
||||
// 1. Create a new installer instance with a specific hostname.
|
||||
// Replace 'mygitea' with your desired hostname.
|
||||
// Note: Use only alphanumeric characters (no underscores or dashes).
|
||||
mut installer := gitea.get(
|
||||
name: 'kristof'
|
||||
create: true
|
||||
)!
|
||||
|
||||
// 2. Configure the installer (all settings are optional with sensible defaults)
|
||||
// installer.hostname = 'giteaapp' // Default: 'giteaapp'
|
||||
// installer.namespace = 'forge' // Default: 'forge'
|
||||
|
||||
// // Gitea server configuration
|
||||
// installer.http_port = 3000 // Default: 3000
|
||||
// installer.disable_registration = false // Default: false (allow new user registration)
|
||||
|
||||
// // Database configuration - Option 1: SQLite (default)
|
||||
// installer.db_type = 'sqlite3' // Default: 'sqlite3'
|
||||
// installer.db_path = '/data/gitea/gitea.db' // Default: '/data/gitea/gitea.db'
|
||||
|
||||
// // Database configuration - Option 2: PostgreSQL
|
||||
// // When using postgres, a PostgreSQL pod will be automatically deployed
|
||||
installer.db_type = 'postgres' // Use PostgreSQL instead of SQLite
|
||||
installer.db_host = 'postgres' // Default: 'postgres' (PostgreSQL service name)
|
||||
installer.db_name = 'gitea' // Default: 'gitea' (database name)
|
||||
installer.db_user = 'gitea' // Default: 'gitea' (database user)
|
||||
installer.db_password = 'gitea' // Default: 'gitea' (database password)
|
||||
installer.storage_size = '5Gi' // Default: '5Gi' (PVC storage size)
|
||||
|
||||
// 3. Install Gitea.
|
||||
// This will generate the necessary Kubernetes YAML files and apply them to your cluster.
|
||||
installer.install()!
|
||||
|
||||
// println('Gitea installation started.')
|
||||
// println('You can access it at: https://${installer.hostname}.gent01.grid.tf')
|
||||
|
||||
// 4. To destroy the deployment, you can run the following:
|
||||
// installer.destroy()!
|
||||
@@ -113,7 +113,11 @@ fn (mut m ModuleMeta) check() ! {
|
||||
}
|
||||
mut module_path := m.path.replace('/', '.')
|
||||
if module_path.contains('incubaid.herolib.lib.') {
|
||||
// Path is inside lib/ directory (e.g., lib/installers/horus/coordinator)
|
||||
module_path = module_path.split('incubaid.herolib.lib.')[1]
|
||||
} else if module_path.contains('incubaid.herolib.') {
|
||||
// Path is directly under herolib root (e.g., zeko)
|
||||
module_path = module_path.split('incubaid.herolib.')[1]
|
||||
} else {
|
||||
return error('path should be inside incubaid.herolib, so that module_path can be determined, now is: ${m.path}')
|
||||
}
|
||||
|
||||
@@ -20,19 +20,29 @@ import incubaid.herolib.installers.lang.python
|
||||
import os
|
||||
|
||||
@if args.startupmanager
|
||||
fn (self &${args.classname}) startupcmd() ![]startupmanager.ZProcessNewArgs {
|
||||
^^[params]
|
||||
pub struct StartArgs {
|
||||
pub mut:
|
||||
reset bool
|
||||
}
|
||||
|
||||
fn (self &${args.classname}) startupcmd(args StartArgs) ![]startupmanager.ZProcessNewArgs {
|
||||
mut res := []startupmanager.ZProcessNewArgs{}
|
||||
|
||||
reset := args.reset
|
||||
|
||||
//THIS IS EXAMPLE CODEAND NEEDS TO BE CHANGED
|
||||
// res << startupmanager.ZProcessNewArgs{
|
||||
// name: '${args.name}'
|
||||
// cmd: '${args.name} server'
|
||||
// reset: reset
|
||||
// env: {
|
||||
// 'HOME': '/root'
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
return res
|
||||
|
||||
|
||||
}
|
||||
|
||||
fn (self &${args.classname}) running_check() !bool {
|
||||
@@ -57,21 +67,20 @@ fn (self &${args.classname}) running_check() !bool {
|
||||
}
|
||||
|
||||
fn (self &${args.classname}) start_pre() ! {
|
||||
|
||||
|
||||
}
|
||||
|
||||
fn (self &${args.classname}) start_post() ! {
|
||||
|
||||
|
||||
}
|
||||
|
||||
fn (self &${args.classname}) stop_pre() ! {
|
||||
|
||||
|
||||
}
|
||||
|
||||
fn (self &${args.classname}) stop_post() ! {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@end
|
||||
|
||||
//////////////////// following actions are not specific to instance of the object
|
||||
|
||||
@@ -195,7 +195,7 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
@if args.startupmanager
|
||||
if other_action.name == "start"{
|
||||
console.print_debug("install action ${args.name}.??{other_action.name}")
|
||||
${args.name}_obj.start()!
|
||||
${args.name}_obj.start(reset: reset)!
|
||||
}
|
||||
if other_action.name == "stop"{
|
||||
console.print_debug("install action ${args.name}.??{other_action.name}")
|
||||
@@ -203,7 +203,7 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
}
|
||||
if other_action.name == "restart"{
|
||||
console.print_debug("install action ${args.name}.??{other_action.name}")
|
||||
${args.name}_obj.restart()!
|
||||
${args.name}_obj.restart(reset: reset)!
|
||||
}
|
||||
if other_action.name == "start_pre"{
|
||||
console.print_debug("install action ${args.name}.??{other_action.name}")
|
||||
@@ -273,10 +273,11 @@ pub fn (mut self ${args.classname}) reload() ! {
|
||||
@end
|
||||
|
||||
@if args.startupmanager
|
||||
pub fn (mut self ${args.classname}) start() ! {
|
||||
pub fn (mut self ${args.classname}) start(args StartArgs) ! {
|
||||
@if ! args.singleton
|
||||
switch(self.name)
|
||||
@end
|
||||
|
||||
if self.running()!{
|
||||
return
|
||||
}
|
||||
@@ -289,7 +290,7 @@ pub fn (mut self ${args.classname}) start() ! {
|
||||
|
||||
self.start_pre()!
|
||||
|
||||
for zprocess in self.startupcmd()!{
|
||||
for zprocess in self.startupcmd(args)!{
|
||||
mut sm:=startupmanager_get(zprocess.startuptype)!
|
||||
|
||||
console.print_debug('installer: ${args.name} starting with ??{zprocess.startuptype}...')
|
||||
@@ -314,7 +315,7 @@ pub fn (mut self ${args.classname}) start() ! {
|
||||
pub fn (mut self ${args.classname}) install_start(args InstallArgs) ! {
|
||||
switch(self.name)
|
||||
self.install(args)!
|
||||
self.start()!
|
||||
self.start(reset: false)!
|
||||
}
|
||||
|
||||
pub fn (mut self ${args.classname}) stop() ! {
|
||||
@@ -327,10 +328,10 @@ pub fn (mut self ${args.classname}) stop() ! {
|
||||
self.stop_post()!
|
||||
}
|
||||
|
||||
pub fn (mut self ${args.classname}) restart() ! {
|
||||
pub fn (mut self ${args.classname}) restart(args StartArgs) ! {
|
||||
switch(self.name)
|
||||
self.stop()!
|
||||
self.start()!
|
||||
self.start(args)!
|
||||
}
|
||||
|
||||
pub fn (mut self ${args.classname}) running() !bool {
|
||||
|
||||
@@ -71,12 +71,20 @@ fn cmd_generator_execute(cmd Command) ! {
|
||||
// Handle "." as current working directory
|
||||
if path == '.' {
|
||||
path = os.getwd()
|
||||
} else {
|
||||
} else if path != '' {
|
||||
// Expand home directory
|
||||
path = path.replace('~', os.home_dir())
|
||||
|
||||
// Convert relative paths to absolute paths
|
||||
if !os.is_abs_path(path) {
|
||||
path = os.join_path(os.getwd(), path)
|
||||
}
|
||||
|
||||
// Resolve to real path (handles symlinks and normalizes path)
|
||||
path = os.real_path(path)
|
||||
|
||||
// Validate that path exists
|
||||
if path != '' && !os.exists(path) {
|
||||
if !os.exists(path) {
|
||||
return error('Path does not exist: ${path}')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,13 +9,22 @@ import incubaid.herolib.installers.lang.rust
|
||||
import incubaid.herolib.develop.gittools
|
||||
import os
|
||||
|
||||
fn (self &Coordinator) startupcmd() ![]startupmanager.ZProcessNewArgs {
|
||||
@[params]
|
||||
pub struct StartArgs {
|
||||
pub mut:
|
||||
reset bool
|
||||
}
|
||||
|
||||
fn (self &Coordinator) startupcmd(args StartArgs) ![]startupmanager.ZProcessNewArgs {
|
||||
mut res := []startupmanager.ZProcessNewArgs{}
|
||||
|
||||
reset := args.reset
|
||||
|
||||
res << startupmanager.ZProcessNewArgs{
|
||||
name: 'coordinator'
|
||||
cmd: '${self.binary_path} --redis-addr ${self.redis_addr} --api-http-port ${self.http_port} --api-ws-port ${self.ws_port}'
|
||||
env: {
|
||||
name: 'coordinator'
|
||||
cmd: '${self.binary_path} --redis-addr ${self.redis_addr} --api-http-port ${self.http_port} --api-ws-port ${self.ws_port}'
|
||||
reset: reset
|
||||
env: {
|
||||
'HOME': os.home_dir()
|
||||
'RUST_LOG': self.log_level
|
||||
'RUST_LOG_STYLE': 'never'
|
||||
|
||||
@@ -176,7 +176,7 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
}
|
||||
if other_action.name == 'start' {
|
||||
console.print_debug('install action coordinator.${other_action.name}')
|
||||
coordinator_obj.start()!
|
||||
coordinator_obj.start(reset: reset)!
|
||||
}
|
||||
if other_action.name == 'stop' {
|
||||
console.print_debug('install action coordinator.${other_action.name}')
|
||||
@@ -184,7 +184,7 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
}
|
||||
if other_action.name == 'restart' {
|
||||
console.print_debug('install action coordinator.${other_action.name}')
|
||||
coordinator_obj.restart()!
|
||||
coordinator_obj.restart(reset: reset)!
|
||||
}
|
||||
if other_action.name == 'start_pre' {
|
||||
console.print_debug('install action coordinator.${other_action.name}')
|
||||
@@ -244,7 +244,7 @@ pub fn (mut self Coordinator) reload() ! {
|
||||
self = obj_init(self)!
|
||||
}
|
||||
|
||||
pub fn (mut self Coordinator) start() ! {
|
||||
pub fn (mut self Coordinator) start(args StartArgs) ! {
|
||||
switch(self.name)
|
||||
|
||||
if self.running()! {
|
||||
@@ -260,7 +260,7 @@ pub fn (mut self Coordinator) start() ! {
|
||||
self.configure()!
|
||||
|
||||
self.start_pre()!
|
||||
for zprocess in self.startupcmd()! {
|
||||
for zprocess in self.startupcmd(args)! {
|
||||
mut sm := startupmanager_get(zprocess.startuptype)!
|
||||
|
||||
console.print_debug('installer: coordinator starting with ${zprocess.startuptype}...')
|
||||
@@ -284,7 +284,7 @@ pub fn (mut self Coordinator) start() ! {
|
||||
pub fn (mut self Coordinator) install_start(args InstallArgs) ! {
|
||||
switch(self.name)
|
||||
self.install(args)!
|
||||
self.start()!
|
||||
self.start(reset: false)!
|
||||
}
|
||||
|
||||
pub fn (mut self Coordinator) stop() ! {
|
||||
@@ -297,10 +297,10 @@ pub fn (mut self Coordinator) stop() ! {
|
||||
self.stop_post()!
|
||||
}
|
||||
|
||||
pub fn (mut self Coordinator) restart() ! {
|
||||
pub fn (mut self Coordinator) restart(args StartArgs) ! {
|
||||
switch(self.name)
|
||||
self.stop()!
|
||||
self.start()!
|
||||
self.start(args)!
|
||||
}
|
||||
|
||||
pub fn (mut self Coordinator) running() !bool {
|
||||
|
||||
@@ -9,9 +9,17 @@ import incubaid.herolib.installers.lang.rust
|
||||
import incubaid.herolib.develop.gittools
|
||||
import os
|
||||
|
||||
fn (self &Herorunner) startupcmd() ![]startupmanager.ZProcessNewArgs {
|
||||
@[params]
|
||||
pub struct StartArgs {
|
||||
pub mut:
|
||||
reset bool
|
||||
}
|
||||
|
||||
fn (self &Herorunner) startupcmd(args StartArgs) ![]startupmanager.ZProcessNewArgs {
|
||||
mut res := []startupmanager.ZProcessNewArgs{}
|
||||
|
||||
reset := args.reset
|
||||
|
||||
// Ensure redis_addr has the redis:// prefix
|
||||
redis_url := if self.redis_addr.starts_with('redis://') {
|
||||
self.redis_addr
|
||||
@@ -20,9 +28,10 @@ fn (self &Herorunner) startupcmd() ![]startupmanager.ZProcessNewArgs {
|
||||
}
|
||||
|
||||
res << startupmanager.ZProcessNewArgs{
|
||||
name: 'herorunner'
|
||||
cmd: '${self.binary_path} --redis-url ${redis_url} 12001'
|
||||
env: {
|
||||
name: 'herorunner'
|
||||
cmd: '${self.binary_path} --redis-url ${redis_url} 12001'
|
||||
reset: reset
|
||||
env: {
|
||||
'HOME': os.home_dir()
|
||||
'RUST_LOG': self.log_level
|
||||
'RUST_LOG_STYLE': 'never'
|
||||
|
||||
@@ -164,7 +164,7 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
}
|
||||
if other_action.name == 'start' {
|
||||
console.print_debug('install action herorunner.${other_action.name}')
|
||||
herorunner_obj.start()!
|
||||
herorunner_obj.start(reset: reset)!
|
||||
}
|
||||
if other_action.name == 'stop' {
|
||||
console.print_debug('install action herorunner.${other_action.name}')
|
||||
@@ -172,7 +172,7 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
}
|
||||
if other_action.name == 'restart' {
|
||||
console.print_debug('install action herorunner.${other_action.name}')
|
||||
herorunner_obj.restart()!
|
||||
herorunner_obj.restart(reset: reset)!
|
||||
}
|
||||
if other_action.name == 'start_pre' {
|
||||
console.print_debug('install action herorunner.${other_action.name}')
|
||||
@@ -231,7 +231,7 @@ pub fn (mut self Herorunner) reload() ! {
|
||||
self = obj_init(self)!
|
||||
}
|
||||
|
||||
pub fn (mut self Herorunner) start() ! {
|
||||
pub fn (mut self Herorunner) start(args StartArgs) ! {
|
||||
switch(self.name)
|
||||
if self.running()! {
|
||||
return
|
||||
@@ -245,7 +245,7 @@ pub fn (mut self Herorunner) start() ! {
|
||||
|
||||
self.start_pre()!
|
||||
|
||||
for zprocess in self.startupcmd()! {
|
||||
for zprocess in self.startupcmd(args)! {
|
||||
mut sm := startupmanager_get(zprocess.startuptype)!
|
||||
|
||||
console.print_debug('installer: herorunner starting with ${zprocess.startuptype}...')
|
||||
@@ -269,7 +269,7 @@ pub fn (mut self Herorunner) start() ! {
|
||||
pub fn (mut self Herorunner) install_start(args InstallArgs) ! {
|
||||
switch(self.name)
|
||||
self.install(args)!
|
||||
self.start()!
|
||||
self.start(reset: false)!
|
||||
}
|
||||
|
||||
pub fn (mut self Herorunner) stop() ! {
|
||||
@@ -282,10 +282,10 @@ pub fn (mut self Herorunner) stop() ! {
|
||||
self.stop_post()!
|
||||
}
|
||||
|
||||
pub fn (mut self Herorunner) restart() ! {
|
||||
pub fn (mut self Herorunner) restart(args StartArgs) ! {
|
||||
switch(self.name)
|
||||
self.stop()!
|
||||
self.start()!
|
||||
self.start(args)!
|
||||
}
|
||||
|
||||
pub fn (mut self Herorunner) running() !bool {
|
||||
|
||||
@@ -9,9 +9,17 @@ import incubaid.herolib.installers.lang.rust
|
||||
import incubaid.herolib.develop.gittools
|
||||
import os
|
||||
|
||||
fn (self &Osirisrunner) startupcmd() ![]startupmanager.ZProcessNewArgs {
|
||||
@[params]
|
||||
pub struct StartArgs {
|
||||
pub mut:
|
||||
reset bool
|
||||
}
|
||||
|
||||
fn (self &Osirisrunner) startupcmd(args StartArgs) ![]startupmanager.ZProcessNewArgs {
|
||||
mut res := []startupmanager.ZProcessNewArgs{}
|
||||
|
||||
reset := args.reset
|
||||
|
||||
// Ensure redis_addr has the redis:// prefix
|
||||
redis_url := if self.redis_addr.starts_with('redis://') {
|
||||
self.redis_addr
|
||||
@@ -20,9 +28,10 @@ fn (self &Osirisrunner) startupcmd() ![]startupmanager.ZProcessNewArgs {
|
||||
}
|
||||
|
||||
res << startupmanager.ZProcessNewArgs{
|
||||
name: 'runner_osiris'
|
||||
cmd: '${self.binary_path} --redis-url ${redis_url} 12002'
|
||||
env: {
|
||||
name: 'runner_osiris'
|
||||
cmd: '${self.binary_path} --redis-url ${redis_url} 12002'
|
||||
reset: reset
|
||||
env: {
|
||||
'HOME': os.home_dir()
|
||||
'RUST_LOG': self.log_level
|
||||
'RUST_LOG_STYLE': 'never'
|
||||
|
||||
@@ -166,7 +166,7 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
}
|
||||
if other_action.name == 'start' {
|
||||
console.print_debug('install action osirisrunner.${other_action.name}')
|
||||
osirisrunner_obj.start()!
|
||||
osirisrunner_obj.start(reset: reset)!
|
||||
}
|
||||
if other_action.name == 'stop' {
|
||||
console.print_debug('install action osirisrunner.${other_action.name}')
|
||||
@@ -174,7 +174,7 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
}
|
||||
if other_action.name == 'restart' {
|
||||
console.print_debug('install action osirisrunner.${other_action.name}')
|
||||
osirisrunner_obj.restart()!
|
||||
osirisrunner_obj.restart(reset: reset)!
|
||||
}
|
||||
if other_action.name == 'start_pre' {
|
||||
console.print_debug('install action osirisrunner.${other_action.name}')
|
||||
@@ -233,7 +233,7 @@ pub fn (mut self Osirisrunner) reload() ! {
|
||||
self = obj_init(self)!
|
||||
}
|
||||
|
||||
pub fn (mut self Osirisrunner) start() ! {
|
||||
pub fn (mut self Osirisrunner) start(args StartArgs) ! {
|
||||
switch(self.name)
|
||||
if self.running()! {
|
||||
return
|
||||
@@ -247,7 +247,7 @@ pub fn (mut self Osirisrunner) start() ! {
|
||||
|
||||
self.start_pre()!
|
||||
|
||||
for zprocess in self.startupcmd()! {
|
||||
for zprocess in self.startupcmd(args)! {
|
||||
mut sm := startupmanager_get(zprocess.startuptype)!
|
||||
|
||||
console.print_debug('installer: osirisrunner starting with ${zprocess.startuptype}...')
|
||||
@@ -271,7 +271,7 @@ pub fn (mut self Osirisrunner) start() ! {
|
||||
pub fn (mut self Osirisrunner) install_start(args InstallArgs) ! {
|
||||
switch(self.name)
|
||||
self.install(args)!
|
||||
self.start()!
|
||||
self.start(reset: false)!
|
||||
}
|
||||
|
||||
pub fn (mut self Osirisrunner) stop() ! {
|
||||
@@ -284,10 +284,10 @@ pub fn (mut self Osirisrunner) stop() ! {
|
||||
self.stop_post()!
|
||||
}
|
||||
|
||||
pub fn (mut self Osirisrunner) restart() ! {
|
||||
pub fn (mut self Osirisrunner) restart(args StartArgs) ! {
|
||||
switch(self.name)
|
||||
self.stop()!
|
||||
self.start()!
|
||||
self.start(args)!
|
||||
}
|
||||
|
||||
pub fn (mut self Osirisrunner) running() !bool {
|
||||
|
||||
@@ -9,9 +9,17 @@ import incubaid.herolib.installers.lang.rust
|
||||
import incubaid.herolib.develop.gittools
|
||||
import os
|
||||
|
||||
fn (self &Salrunner) startupcmd() ![]startupmanager.ZProcessNewArgs {
|
||||
@[params]
|
||||
pub struct StartArgs {
|
||||
pub mut:
|
||||
reset bool
|
||||
}
|
||||
|
||||
fn (self &Salrunner) startupcmd(args StartArgs) ![]startupmanager.ZProcessNewArgs {
|
||||
mut res := []startupmanager.ZProcessNewArgs{}
|
||||
|
||||
reset := args.reset
|
||||
|
||||
// Ensure redis_addr has the redis:// prefix
|
||||
redis_url := if self.redis_addr.starts_with('redis://') {
|
||||
self.redis_addr
|
||||
@@ -20,9 +28,10 @@ fn (self &Salrunner) startupcmd() ![]startupmanager.ZProcessNewArgs {
|
||||
}
|
||||
|
||||
res << startupmanager.ZProcessNewArgs{
|
||||
name: 'runner_sal'
|
||||
cmd: '${self.binary_path} --redis-url ${redis_url} 12003'
|
||||
env: {
|
||||
name: 'runner_sal'
|
||||
cmd: '${self.binary_path} --redis-url ${redis_url} 12003'
|
||||
reset: reset
|
||||
env: {
|
||||
'HOME': os.home_dir()
|
||||
'RUST_LOG': self.log_level
|
||||
'RUST_LOG_STYLE': 'never'
|
||||
|
||||
@@ -166,7 +166,7 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
}
|
||||
if other_action.name == 'start' {
|
||||
console.print_debug('install action salrunner.${other_action.name}')
|
||||
salrunner_obj.start()!
|
||||
salrunner_obj.start(reset: reset)!
|
||||
}
|
||||
if other_action.name == 'stop' {
|
||||
console.print_debug('install action salrunner.${other_action.name}')
|
||||
@@ -174,7 +174,7 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
}
|
||||
if other_action.name == 'restart' {
|
||||
console.print_debug('install action salrunner.${other_action.name}')
|
||||
salrunner_obj.restart()!
|
||||
salrunner_obj.restart(reset: reset)!
|
||||
}
|
||||
if other_action.name == 'start_pre' {
|
||||
console.print_debug('install action salrunner.${other_action.name}')
|
||||
@@ -233,7 +233,7 @@ pub fn (mut self Salrunner) reload() ! {
|
||||
self = obj_init(self)!
|
||||
}
|
||||
|
||||
pub fn (mut self Salrunner) start() ! {
|
||||
pub fn (mut self Salrunner) start(args StartArgs) ! {
|
||||
switch(self.name)
|
||||
if self.running()! {
|
||||
return
|
||||
@@ -247,7 +247,7 @@ pub fn (mut self Salrunner) start() ! {
|
||||
|
||||
self.start_pre()!
|
||||
|
||||
for zprocess in self.startupcmd()! {
|
||||
for zprocess in self.startupcmd(args)! {
|
||||
mut sm := startupmanager_get(zprocess.startuptype)!
|
||||
|
||||
console.print_debug('installer: salrunner starting with ${zprocess.startuptype}...')
|
||||
@@ -271,7 +271,7 @@ pub fn (mut self Salrunner) start() ! {
|
||||
pub fn (mut self Salrunner) install_start(args InstallArgs) ! {
|
||||
switch(self.name)
|
||||
self.install(args)!
|
||||
self.start()!
|
||||
self.start(reset: false)!
|
||||
}
|
||||
|
||||
pub fn (mut self Salrunner) stop() ! {
|
||||
@@ -284,10 +284,10 @@ pub fn (mut self Salrunner) stop() ! {
|
||||
self.stop_post()!
|
||||
}
|
||||
|
||||
pub fn (mut self Salrunner) restart() ! {
|
||||
pub fn (mut self Salrunner) restart(args StartArgs) ! {
|
||||
switch(self.name)
|
||||
self.stop()!
|
||||
self.start()!
|
||||
self.start(args)!
|
||||
}
|
||||
|
||||
pub fn (mut self Salrunner) running() !bool {
|
||||
|
||||
@@ -10,9 +10,17 @@ import incubaid.herolib.installers.lang.rust
|
||||
import incubaid.herolib.develop.gittools
|
||||
import os
|
||||
|
||||
fn (self &Supervisor) startupcmd() ![]startupmanager.ZProcessNewArgs {
|
||||
@[params]
|
||||
pub struct StartArgs {
|
||||
pub mut:
|
||||
reset bool
|
||||
}
|
||||
|
||||
fn (self &Supervisor) startupcmd(args StartArgs) ![]startupmanager.ZProcessNewArgs {
|
||||
mut res := []startupmanager.ZProcessNewArgs{}
|
||||
|
||||
reset := args.reset
|
||||
|
||||
// Ensure redis_addr has the redis:// prefix
|
||||
redis_url := if self.redis_addr.starts_with('redis://') {
|
||||
self.redis_addr
|
||||
@@ -21,9 +29,10 @@ fn (self &Supervisor) startupcmd() ![]startupmanager.ZProcessNewArgs {
|
||||
}
|
||||
|
||||
res << startupmanager.ZProcessNewArgs{
|
||||
name: 'supervisor'
|
||||
cmd: '${self.binary_path} --redis-url ${redis_url} --port ${self.http_port} --admin-secret mysecret'
|
||||
env: {
|
||||
name: 'supervisor'
|
||||
cmd: '${self.binary_path} --redis-url ${redis_url} --port ${self.http_port} --admin-secret mysecret'
|
||||
reset: reset
|
||||
env: {
|
||||
'HOME': os.home_dir()
|
||||
'RUST_LOG': self.log_level
|
||||
'RUST_LOG_STYLE': 'never'
|
||||
|
||||
@@ -178,11 +178,12 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
'stop_post'] {
|
||||
mut p := other_action.params
|
||||
name := p.get('name')!
|
||||
reset := p.get_default_false('reset')
|
||||
mut supervisor_obj := get(name: name, create: true)!
|
||||
console.print_debug('action object:\n${supervisor_obj}')
|
||||
if other_action.name == 'start' {
|
||||
console.print_debug('install action supervisor.${other_action.name}')
|
||||
supervisor_obj.start()!
|
||||
supervisor_obj.start(reset: reset)!
|
||||
}
|
||||
if other_action.name == 'stop' {
|
||||
console.print_debug('install action supervisor.${other_action.name}')
|
||||
@@ -190,7 +191,7 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
}
|
||||
if other_action.name == 'restart' {
|
||||
console.print_debug('install action supervisor.${other_action.name}')
|
||||
supervisor_obj.restart()!
|
||||
supervisor_obj.restart(reset: reset)!
|
||||
}
|
||||
if other_action.name == 'start_pre' {
|
||||
console.print_debug('install action supervisor.${other_action.name}')
|
||||
@@ -249,7 +250,7 @@ pub fn (mut self Supervisor) reload() ! {
|
||||
self = obj_init(self)!
|
||||
}
|
||||
|
||||
pub fn (mut self Supervisor) start() ! {
|
||||
pub fn (mut self Supervisor) start(args StartArgs) ! {
|
||||
switch(self.name)
|
||||
if self.running()! {
|
||||
return
|
||||
@@ -265,7 +266,7 @@ pub fn (mut self Supervisor) start() ! {
|
||||
|
||||
self.start_pre()!
|
||||
|
||||
for zprocess in self.startupcmd()! {
|
||||
for zprocess in self.startupcmd(args)! {
|
||||
mut sm := startupmanager_get(zprocess.startuptype)!
|
||||
|
||||
console.print_debug('installer: supervisor starting with ${zprocess.startuptype}...')
|
||||
@@ -289,7 +290,7 @@ pub fn (mut self Supervisor) start() ! {
|
||||
pub fn (mut self Supervisor) install_start(args InstallArgs) ! {
|
||||
switch(self.name)
|
||||
self.install(args)!
|
||||
self.start()!
|
||||
self.start(reset: false)!
|
||||
}
|
||||
|
||||
pub fn (mut self Supervisor) stop() ! {
|
||||
@@ -302,10 +303,10 @@ pub fn (mut self Supervisor) stop() ! {
|
||||
self.stop_post()!
|
||||
}
|
||||
|
||||
pub fn (mut self Supervisor) restart() ! {
|
||||
pub fn (mut self Supervisor) restart(args StartArgs) ! {
|
||||
switch(self.name)
|
||||
self.stop()!
|
||||
self.start()!
|
||||
self.start(args)!
|
||||
}
|
||||
|
||||
pub fn (mut self Supervisor) running() !bool {
|
||||
|
||||
@@ -31,6 +31,16 @@ installer.install()!
|
||||
|
||||
## Usage
|
||||
|
||||
### Running the Installer
|
||||
|
||||
You can run the installer directly from the command line using the example script:
|
||||
|
||||
```bash
|
||||
./examples/installers/k8s/cryptpad.vsh
|
||||
```
|
||||
|
||||
This will install CryptPad with the default settings. To customize the installation, you can edit the `cryptpad.vsh` file.
|
||||
|
||||
### Create an Instance
|
||||
|
||||
```v
|
||||
|
||||
@@ -60,7 +60,7 @@ fn install() ! {
|
||||
|
||||
// 4. Apply the YAML files using kubernetes client
|
||||
console.print_info('Applying Gateway YAML file to the cluster...')
|
||||
res1 := k8s.apply_yaml('/tmp/tfgw-cryptpad.yaml')!
|
||||
res1 := k8s.apply_yaml(installer.tfgw_cryptpad_path)!
|
||||
if !res1.success {
|
||||
return error('Failed to apply tfgw-cryptpad.yaml: ${res1.stderr}')
|
||||
}
|
||||
@@ -72,7 +72,7 @@ fn install() ! {
|
||||
|
||||
// 6. Apply Cryptpad YAML
|
||||
console.print_info('Applying Cryptpad YAML file to the cluster...')
|
||||
res2 := k8s.apply_yaml('/tmp/cryptpad.yaml')!
|
||||
res2 := k8s.apply_yaml(installer.cryptpad_path)!
|
||||
if !res2.success {
|
||||
return error('Failed to apply cryptpad.yaml: ${res2.stderr}')
|
||||
}
|
||||
|
||||
@@ -156,8 +156,8 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
|
||||
// load from disk and make sure is properly intialized
|
||||
pub fn (mut self CryptpadServer) reload() ! {
|
||||
switch(self.name)
|
||||
self = obj_init(self)!
|
||||
set(self)!
|
||||
}
|
||||
|
||||
@[params]
|
||||
|
||||
@@ -15,6 +15,7 @@ pub mut:
|
||||
hostname string // The CryptPad hostname
|
||||
backends string // The backends for the TFGW
|
||||
namespace string // The namespace for the CryptPad deployment
|
||||
config_js string // Generated config.js content
|
||||
}
|
||||
|
||||
@[heap]
|
||||
@@ -23,8 +24,9 @@ pub mut:
|
||||
name string = 'cryptpad'
|
||||
hostname string
|
||||
namespace string
|
||||
cryptpad_path string = '/tmp/cryptpad.yaml'
|
||||
tfgw_cryptpad_path string = '/tmp/tfgw-cryptpad.yaml'
|
||||
cryptpad_path string = '/tmp/cryptpad/cryptpad.yaml'
|
||||
tfgw_cryptpad_path string = '/tmp/cryptpad/tfgw-cryptpad.yaml'
|
||||
config_js_path string = '/tmp/cryptpad/config.js'
|
||||
kube_client kubernetes.KubeClient @[skip]
|
||||
}
|
||||
|
||||
@@ -32,12 +34,26 @@ pub mut:
|
||||
fn obj_init(mycfg_ CryptpadServer) !CryptpadServer {
|
||||
mut mycfg := mycfg_
|
||||
|
||||
if mycfg.name == '' {
|
||||
mycfg.name = 'cryptpad'
|
||||
}
|
||||
|
||||
// Replace the dashes, dots, and underscores with nothing
|
||||
mycfg.name = mycfg.name.replace('_', '')
|
||||
mycfg.name = mycfg.name.replace('-', '')
|
||||
mycfg.name = mycfg.name.replace('.', '')
|
||||
|
||||
if mycfg.namespace == '' {
|
||||
mycfg.namespace = mycfg.name
|
||||
mycfg.namespace = '${mycfg.name}-cryptpad-namespace'
|
||||
}
|
||||
|
||||
if mycfg.namespace.contains('_') || mycfg.namespace.contains('.') {
|
||||
console.print_stderr('namespace cannot contain _, was: ${mycfg.namespace}, use dashes instead.')
|
||||
return error('namespace cannot contain _, was: ${mycfg.namespace}')
|
||||
}
|
||||
|
||||
if mycfg.hostname == '' {
|
||||
mycfg.hostname = mycfg.name
|
||||
mycfg.hostname = '${mycfg.name}cryptpad'
|
||||
}
|
||||
|
||||
mycfg.kube_client = kubernetes.get(create: true)!
|
||||
@@ -57,20 +73,40 @@ fn configure() ! {
|
||||
backends_str_builder.writeln(' - "http://[${ip}]:80"')
|
||||
}
|
||||
|
||||
config_values := ConfigValues{
|
||||
// Create config_values for template generation
|
||||
mut config_values := ConfigValues{
|
||||
hostname: installer.hostname
|
||||
backends: backends_str_builder.str()
|
||||
namespace: installer.namespace
|
||||
config_js: ''
|
||||
}
|
||||
|
||||
console.print_info('Generating YAML files from templates...')
|
||||
temp := $tmpl('./templates/tfgw-cryptpad.yaml')
|
||||
mut temp_path := pathlib.get_file(path: installer.tfgw_cryptpad_path, create: true)!
|
||||
temp_path.write(temp)!
|
||||
// Generate config.js
|
||||
config_js_raw := $tmpl('./templates/config.js')
|
||||
|
||||
temp2 := $tmpl('./templates/cryptpad.yaml')
|
||||
mut temp_path2 := pathlib.get_file(path: installer.cryptpad_path, create: true)!
|
||||
temp_path2.write(temp2)!
|
||||
// Indent the configs for proper YAML formatting (4 spaces for ConfigMap data)
|
||||
config_js_lines := config_js_raw.split('\n')
|
||||
mut config_js_indented := strings.new_builder(config_js_raw.len + 100)
|
||||
for line in config_js_lines {
|
||||
if line.len > 0 {
|
||||
config_js_indented.writeln(' ${line}')
|
||||
}
|
||||
}
|
||||
|
||||
// Update config_values with the generated and indented configs
|
||||
config_values.config_js = config_js_indented.str()
|
||||
|
||||
// Ensure the output directory exists
|
||||
_ := pathlib.get_dir(path: '/tmp/cryptpad', create: true)!
|
||||
|
||||
console.print_info('Generating YAML files from templates...')
|
||||
tfgw_yaml := $tmpl('./templates/tfgw-cryptpad.yaml')
|
||||
mut tfgw_path := pathlib.get_file(path: installer.tfgw_cryptpad_path, create: true)!
|
||||
tfgw_path.write(tfgw_yaml)!
|
||||
|
||||
cryptpad_yaml := $tmpl('./templates/cryptpad.yaml')
|
||||
mut cryptpad_path := pathlib.get_file(path: installer.cryptpad_path, create: true)!
|
||||
cryptpad_path.write(cryptpad_yaml)!
|
||||
|
||||
console.print_info('YAML files generated successfully.')
|
||||
}
|
||||
|
||||
16
lib/installers/k8s/cryptpad/templates/config.js
Normal file
16
lib/installers/k8s/cryptpad/templates/config.js
Normal file
@@ -0,0 +1,16 @@
|
||||
module.exports = {
|
||||
httpUnsafeOrigin: 'https://@{config_values.hostname}.gent01.grid.tf',
|
||||
httpSafeOrigin: 'https://@{config_values.hostname}sb.gent01.grid.tf',
|
||||
httpAddress: '0.0.0.0',
|
||||
httpPort: 80,
|
||||
|
||||
websocketPort: 3003,
|
||||
websocketPath: '/cryptpad_websocket',
|
||||
|
||||
blockPath: './block',
|
||||
blobPath: './blob',
|
||||
dataPath: './data',
|
||||
filePath: './datastore',
|
||||
logToStdout: true,
|
||||
logLevel: 'info',
|
||||
};
|
||||
@@ -10,22 +10,7 @@ metadata:
|
||||
namespace: @{config_values.namespace}
|
||||
data:
|
||||
config.js: |
|
||||
module.exports = {
|
||||
httpUnsafeOrigin: 'https://@{config_values.hostname}.gent01.grid.tf',
|
||||
httpSafeOrigin: 'https://@{config_values.hostname}sb.gent01.grid.tf',
|
||||
httpAddress: '0.0.0.0',
|
||||
httpPort: 80,
|
||||
|
||||
websocketPort: 3003,
|
||||
websocketPath: '/cryptpad_websocket',
|
||||
|
||||
blockPath: './block',
|
||||
blobPath: './blob',
|
||||
dataPath: './data',
|
||||
filePath: './datastore',
|
||||
logToStdout: true,
|
||||
logLevel: 'info',
|
||||
};
|
||||
@{config_values.config_js}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
|
||||
12
lib/installers/k8s/gitea/.heroscript
Normal file
12
lib/installers/k8s/gitea/.heroscript
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
!!hero_code.generate_installer
|
||||
name:''
|
||||
classname:'GiteaK8SInstaller'
|
||||
singleton:0
|
||||
templates:1
|
||||
default:0
|
||||
title:''
|
||||
supported_platforms:''
|
||||
startupmanager:0
|
||||
hasconfig:1
|
||||
build:0
|
||||
141
lib/installers/k8s/gitea/README.md
Normal file
141
lib/installers/k8s/gitea/README.md
Normal file
@@ -0,0 +1,141 @@
|
||||
# Gitea Kubernetes Installer
|
||||
|
||||
A Kubernetes installer for Gitea with TFGrid Gateway integration.
|
||||
|
||||
## Overview
|
||||
|
||||
This installer deploys a complete Git hosting solution:
|
||||
|
||||
- **Gitea**: A lightweight self-hosted Git service
|
||||
- **TFGW (ThreeFold Gateway)**: Provides public FQDNs with TLS termination
|
||||
|
||||
## Quick Start
|
||||
|
||||
```v
|
||||
import incubaid.herolib.installers.k8s.gitea
|
||||
|
||||
// Create and install Gitea with defaults
|
||||
mut installer := gitea.get(
|
||||
name: 'mygitea'
|
||||
create: true
|
||||
)!
|
||||
|
||||
installer.install()!
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
All configuration options are optional and have sensible defaults:
|
||||
|
||||
### Hostname and Namespace
|
||||
|
||||
```v
|
||||
installer.hostname = 'giteaapp' // Default: 'giteaapp'
|
||||
installer.namespace = 'forge' // Default: '${installer.name}-gitea-namespace'
|
||||
```
|
||||
|
||||
**Note**: Use only alphanumeric characters in hostnames (no underscores or dashes).
|
||||
|
||||
### Gitea Server Configuration
|
||||
|
||||
```v
|
||||
// Server port
|
||||
installer.http_port = 3000 // Default: 3000
|
||||
|
||||
// Database configuration
|
||||
installer.db_type = 'sqlite3' // Default: 'sqlite3' (options: 'sqlite3', 'postgres')
|
||||
installer.db_path = '/data/gitea/gitea.db' // Default: '/data/gitea/gitea.db' (for sqlite3)
|
||||
|
||||
// PostgreSQL configuration (only used when db_type = 'postgres')
|
||||
installer.db_host = 'postgres' // Default: 'postgres' (PostgreSQL service name)
|
||||
installer.db_name = 'gitea' // Default: 'gitea' (PostgreSQL database name)
|
||||
installer.db_user = 'gitea' // Default: 'gitea' (PostgreSQL user)
|
||||
installer.db_password = 'gitea' // Default: 'gitea' (PostgreSQL password)
|
||||
|
||||
// Registration
|
||||
installer.disable_registration = false // Default: false (allow new user registration)
|
||||
|
||||
// Storage
|
||||
installer.storage_size = '5Gi' // Default: '5Gi' (PVC storage size)
|
||||
```
|
||||
|
||||
**Note**: When using `db_type = 'postgres'`, a PostgreSQL pod will be automatically deployed in the same namespace. The installer only supports `sqlite3` and `postgres` database types.
|
||||
|
||||
## Full Example
|
||||
|
||||
```v
|
||||
import incubaid.herolib.installers.k8s.gitea
|
||||
|
||||
mut installer := gitea.get(
|
||||
name: 'mygitea'
|
||||
create: true
|
||||
)!
|
||||
|
||||
// Configure hostname and namespace
|
||||
installer.hostname = 'mygit'
|
||||
installer.namespace = 'forge'
|
||||
|
||||
// Configure Gitea
|
||||
installer.http_port = 3000
|
||||
installer.db_type = 'sqlite3'
|
||||
installer.disable_registration = true // Disable public registration
|
||||
installer.storage_size = '10Gi' // Increase storage
|
||||
|
||||
// Install
|
||||
installer.install()!
|
||||
|
||||
println('Gitea: https://${installer.hostname}.gent01.grid.tf')
|
||||
```
|
||||
|
||||
## PostgreSQL Example
|
||||
|
||||
To use PostgreSQL instead of SQLite:
|
||||
|
||||
```v
|
||||
import incubaid.herolib.installers.k8s.gitea
|
||||
|
||||
mut installer := gitea.get(
|
||||
name: 'mygitea'
|
||||
create: true
|
||||
)!
|
||||
|
||||
// Configure to use PostgreSQL
|
||||
installer.db_type = 'postgres' // Use PostgreSQL
|
||||
installer.storage_size = '10Gi' // Storage for both Gitea and PostgreSQL
|
||||
|
||||
// Optional: customize PostgreSQL settings
|
||||
installer.db_host = 'postgres' // PostgreSQL service name
|
||||
installer.db_name = 'gitea' // Database name
|
||||
installer.db_user = 'gitea' // Database user
|
||||
installer.db_password = 'securepassword' // Database password
|
||||
|
||||
// Install (PostgreSQL pod will be deployed automatically)
|
||||
installer.install()!
|
||||
|
||||
println('Gitea with PostgreSQL: https://${installer.hostname}.gent01.grid.tf')
|
||||
```
|
||||
|
||||
## Management
|
||||
|
||||
### Check Installation Status
|
||||
|
||||
```v
|
||||
if gitea.installed()! {
|
||||
println('Gitea is installed')
|
||||
} else {
|
||||
println('Gitea is not installed')
|
||||
}
|
||||
```
|
||||
|
||||
### Destroy Deployment
|
||||
|
||||
```v
|
||||
installer.destroy()!
|
||||
```
|
||||
|
||||
This will delete the entire namespace and all resources within it.
|
||||
|
||||
## See Also
|
||||
|
||||
- [Gitea Documentation](https://docs.gitea.io/)
|
||||
- [Gitea GitHub Repository](https://github.com/go-gitea/gitea)
|
||||
240
lib/installers/k8s/gitea/gitea_actions.v
Normal file
240
lib/installers/k8s/gitea/gitea_actions.v
Normal file
@@ -0,0 +1,240 @@
|
||||
module gitea
|
||||
|
||||
import incubaid.herolib.osal.core as osal
|
||||
import incubaid.herolib.ui.console
|
||||
import incubaid.herolib.installers.ulist
|
||||
import time
|
||||
|
||||
const max_deployment_retries = 30
|
||||
const deployment_check_interval_seconds = 2
|
||||
|
||||
//////////////////// following actions are not specific to instance of the object
|
||||
|
||||
// checks if a certain version or above is installed
|
||||
pub fn installed() !bool {
|
||||
installer := get()!
|
||||
mut k8s := installer.kube_client
|
||||
|
||||
// Try to get the gitea deployment
|
||||
deployments := k8s.get_deployments(installer.namespace) or {
|
||||
// If we can't get deployments, it's not running
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if gitea deployment exists
|
||||
for deployment in deployments {
|
||||
if deployment.name == 'gitea' {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 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() ! {
|
||||
// installers.upload(
|
||||
// cmdname: 'gitea'
|
||||
// source: '${gitpath}/target/x86_64-unknown-linux-musl/release/gitea'
|
||||
// )!
|
||||
}
|
||||
|
||||
fn install() ! {
|
||||
console.print_header('Installing Gitea...')
|
||||
|
||||
// Get installer config to access namespace
|
||||
installer := get()!
|
||||
mut k8s := installer.kube_client
|
||||
configure()!
|
||||
|
||||
// 1. Check for dependencies.
|
||||
console.print_info('Checking for kubectl...')
|
||||
kubectl_installed()!
|
||||
console.print_info('kubectl is installed and configured.')
|
||||
|
||||
// 2. Apply the YAML files using kubernetes client
|
||||
console.print_info('Applying Gateway YAML file to the cluster...')
|
||||
res1 := k8s.apply_yaml('/tmp/gitea/tfgw-gitea.yaml')!
|
||||
if !res1.success {
|
||||
return error('Failed to apply tfgw-gitea.yaml: ${res1.stderr}')
|
||||
}
|
||||
console.print_info('Gateway YAML file applied successfully.')
|
||||
|
||||
// 3. Verify TFGW deployment
|
||||
verify_tfgw_deployment(tfgw_name: 'gitea', namespace: installer.namespace)!
|
||||
|
||||
// 4. Apply PostgreSQL YAML if postgres is selected
|
||||
if installer.db_type == 'postgres' {
|
||||
console.print_info('Applying PostgreSQL YAML file to the cluster...')
|
||||
res_postgres := k8s.apply_yaml('/tmp/gitea/postgres.yaml')!
|
||||
if !res_postgres.success {
|
||||
return error('Failed to apply postgres.yaml: ${res_postgres.stderr}')
|
||||
}
|
||||
console.print_info('PostgreSQL YAML file applied successfully.')
|
||||
|
||||
// Verify PostgreSQL pod is ready
|
||||
verify_postgres_pod(namespace: installer.namespace)!
|
||||
}
|
||||
|
||||
// 5. Apply Gitea App YAML
|
||||
console.print_info('Applying Gitea App YAML file to the cluster...')
|
||||
res2 := k8s.apply_yaml('/tmp/gitea/gitea.yaml')!
|
||||
if !res2.success {
|
||||
return error('Failed to apply gitea.yaml: ${res2.stderr}')
|
||||
}
|
||||
console.print_info('Gitea App YAML file applied successfully.')
|
||||
|
||||
// 6. Verify deployment status
|
||||
console.print_info('Verifying deployment status...')
|
||||
mut is_running := false
|
||||
for i in 0 .. max_deployment_retries {
|
||||
if installed()! {
|
||||
is_running = true
|
||||
break
|
||||
}
|
||||
console.print_info('Waiting for Gitea deployment to be ready... (${i + 1}/${max_deployment_retries})')
|
||||
time.sleep(deployment_check_interval_seconds * time.second)
|
||||
}
|
||||
|
||||
if is_running {
|
||||
console.print_header('Gitea installation successful!')
|
||||
console.print_header('You can access Gitea at https://${installer.hostname}.gent01.grid.tf')
|
||||
} else {
|
||||
return error('Gitea deployment failed to start.')
|
||||
}
|
||||
}
|
||||
|
||||
// params for verifying the generating of the FQDN using tfgw crd
|
||||
@[params]
|
||||
struct VerifyTfgwDeployment {
|
||||
pub mut:
|
||||
tfgw_name string // tfgw serivce generating the FQDN
|
||||
namespace string // namespace name for gitea deployments/services
|
||||
}
|
||||
|
||||
// params for verifying postgres pod is ready
|
||||
@[params]
|
||||
struct VerifyPostgresPod {
|
||||
pub mut:
|
||||
namespace string // namespace name for postgres pod
|
||||
}
|
||||
|
||||
// Function for verifying postgres pod is ready
|
||||
fn verify_postgres_pod(args VerifyPostgresPod) ! {
|
||||
console.print_info('Verifying PostgreSQL pod is ready...')
|
||||
installer := get()!
|
||||
mut k8s := installer.kube_client
|
||||
mut is_ready := false
|
||||
|
||||
for i in 0 .. max_deployment_retries {
|
||||
// Check if postgres pod exists and is running
|
||||
result := k8s.kubectl_exec(
|
||||
command: 'get pod ${installer.db_host} -n ${args.namespace} -o jsonpath="{.status.phase}"'
|
||||
) or {
|
||||
console.print_info('Waiting for PostgreSQL pod to be created... (${i + 1}/${max_deployment_retries})')
|
||||
time.sleep(deployment_check_interval_seconds * time.second)
|
||||
continue
|
||||
}
|
||||
|
||||
if result.success && result.stdout == 'Running' {
|
||||
is_ready = true
|
||||
break
|
||||
}
|
||||
console.print_info('Waiting for PostgreSQL pod to be ready... (${i + 1}/${max_deployment_retries})')
|
||||
time.sleep(deployment_check_interval_seconds * time.second)
|
||||
}
|
||||
|
||||
if !is_ready {
|
||||
console.print_stderr('PostgreSQL pod failed to become ready.')
|
||||
return error('PostgreSQL pod failed to become ready.')
|
||||
}
|
||||
console.print_info('PostgreSQL pod is ready.')
|
||||
}
|
||||
|
||||
// Function for verifying the generating of of the FQDN using tfgw crd
|
||||
fn verify_tfgw_deployment(args VerifyTfgwDeployment) ! {
|
||||
console.print_info('Verifying TFGW deployment for ${args.tfgw_name}...')
|
||||
installer := get()!
|
||||
mut k8s := installer.kube_client
|
||||
mut is_fqdn_generated := false
|
||||
|
||||
for i in 0 .. max_deployment_retries {
|
||||
// Use kubectl_exec for custom resource (TFGW) with jsonpath
|
||||
result := k8s.kubectl_exec(
|
||||
command: 'get tfgw ${args.tfgw_name} -n ${args.namespace} -o jsonpath="{.status.fqdn}"'
|
||||
) or {
|
||||
console.print_info('Waiting for FQDN to be generated for ${args.tfgw_name}... (${i + 1}/${max_deployment_retries})')
|
||||
time.sleep(deployment_check_interval_seconds * time.second)
|
||||
continue
|
||||
}
|
||||
|
||||
if result.success && result.stdout != '' {
|
||||
is_fqdn_generated = true
|
||||
break
|
||||
}
|
||||
console.print_info('Waiting for FQDN to be generated for ${args.tfgw_name}... (${i + 1}/${max_deployment_retries})')
|
||||
time.sleep(deployment_check_interval_seconds * time.second)
|
||||
}
|
||||
|
||||
if !is_fqdn_generated {
|
||||
console.print_stderr('Failed to get FQDN for ${args.tfgw_name}.')
|
||||
// Use describe_resource to get detailed information about the TFGW resource
|
||||
result := k8s.describe_resource(
|
||||
resource: 'tfgw'
|
||||
resource_name: args.tfgw_name
|
||||
namespace: args.namespace
|
||||
) or { return error('TFGW deployment failed for ${args.tfgw_name}.') }
|
||||
console.print_stderr(result.stdout)
|
||||
return error('TFGW deployment failed for ${args.tfgw_name}.')
|
||||
}
|
||||
console.print_info('TFGW deployment for ${args.tfgw_name} verified successfully.')
|
||||
}
|
||||
|
||||
fn destroy() ! {
|
||||
console.print_header('Destroying Gitea...')
|
||||
installer := get()!
|
||||
mut k8s := installer.kube_client
|
||||
|
||||
console.print_debug('Attempting to delete namespace: ${installer.namespace}')
|
||||
|
||||
// Delete the namespace using kubernetes client
|
||||
result := k8s.delete_resource('namespace', installer.namespace, '') or {
|
||||
console.print_stderr('Failed to delete namespace ${installer.namespace}: ${err}')
|
||||
return error('Failed to delete namespace ${installer.namespace}: ${err}')
|
||||
}
|
||||
|
||||
console.print_debug('Delete command completed. Exit code: ${result.exit_code}, Success: ${result.success}')
|
||||
|
||||
if !result.success {
|
||||
// Namespace not found is OK - it means it's already deleted
|
||||
if result.stderr.contains('NotFound') {
|
||||
console.print_info('Namespace ${installer.namespace} does not exist (already deleted).')
|
||||
} else {
|
||||
console.print_stderr('Failed to delete namespace ${installer.namespace}: ${result.stderr}')
|
||||
return error('Failed to delete namespace ${installer.namespace}: ${result.stderr}')
|
||||
}
|
||||
} else {
|
||||
console.print_info('Namespace ${installer.namespace} deleted successfully.')
|
||||
}
|
||||
}
|
||||
|
||||
fn kubectl_installed() ! {
|
||||
// Check if kubectl command exists
|
||||
if !osal.cmd_exists('kubectl') {
|
||||
return error('kubectl is not installed. Please install it to continue.')
|
||||
}
|
||||
|
||||
// Check if kubectl is configured to connect to a cluster
|
||||
installer := get()!
|
||||
mut k8s := installer.kube_client
|
||||
|
||||
if !k8s.test_connection()! {
|
||||
return error('kubectl is not configured to connect to a Kubernetes cluster. Please check your kubeconfig.')
|
||||
}
|
||||
}
|
||||
188
lib/installers/k8s/gitea/gitea_factory_.v
Normal file
188
lib/installers/k8s/gitea/gitea_factory_.v
Normal file
@@ -0,0 +1,188 @@
|
||||
module gitea
|
||||
|
||||
import incubaid.herolib.core.base
|
||||
import incubaid.herolib.core.playbook { PlayBook }
|
||||
import incubaid.herolib.ui.console
|
||||
import json
|
||||
|
||||
__global (
|
||||
gitea_global map[string]&GiteaK8SInstaller
|
||||
gitea_default string
|
||||
)
|
||||
|
||||
/////////FACTORY
|
||||
|
||||
@[params]
|
||||
pub struct ArgsGet {
|
||||
pub mut:
|
||||
name string = 'gitea'
|
||||
fromdb bool // will load from filesystem
|
||||
create bool // default will not create if not exist
|
||||
}
|
||||
|
||||
pub fn new(args ArgsGet) !&GiteaK8SInstaller {
|
||||
mut obj := GiteaK8SInstaller{
|
||||
name: args.name
|
||||
}
|
||||
set(obj)!
|
||||
return get(name: args.name)!
|
||||
}
|
||||
|
||||
pub fn get(args_ ArgsGet) !&GiteaK8SInstaller {
|
||||
mut context := base.context()!
|
||||
mut args := args_
|
||||
if args.name == 'gitea' && gitea_default != '' {
|
||||
args.name = gitea_default
|
||||
}
|
||||
|
||||
if args.fromdb || args.name !in gitea_global {
|
||||
mut r := context.redis()!
|
||||
if r.hexists('context:gitea', args.name)! {
|
||||
data := r.hget('context:gitea', args.name)!
|
||||
if data.len == 0 {
|
||||
print_backtrace()
|
||||
return error('GiteaK8SInstaller with name: ${args.name} does not exist, prob bug.')
|
||||
}
|
||||
mut obj := json.decode(GiteaK8SInstaller, data)!
|
||||
set_in_mem(obj)!
|
||||
} else {
|
||||
if args.create {
|
||||
new(args)!
|
||||
} else {
|
||||
print_backtrace()
|
||||
return error("GiteaK8SInstaller with name '${args.name}' does not exist")
|
||||
}
|
||||
}
|
||||
return get(name: args.name)! // no longer from db nor create
|
||||
}
|
||||
return gitea_global[args.name] or {
|
||||
print_backtrace()
|
||||
return error('could not get config for gitea with name:${args.name}')
|
||||
}
|
||||
}
|
||||
|
||||
// register the config for the future
|
||||
pub fn set(o GiteaK8SInstaller) ! {
|
||||
mut o2 := set_in_mem(o)!
|
||||
gitea_default = o2.name
|
||||
mut context := base.context()!
|
||||
mut r := context.redis()!
|
||||
r.hset('context:gitea', 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:gitea', args.name)!
|
||||
}
|
||||
|
||||
pub fn delete(args ArgsGet) ! {
|
||||
mut context := base.context()!
|
||||
mut r := context.redis()!
|
||||
r.hdel('context:gitea', 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) ![]&GiteaK8SInstaller {
|
||||
mut res := []&GiteaK8SInstaller{}
|
||||
mut context := base.context()!
|
||||
if args.fromdb {
|
||||
// reset what is in mem
|
||||
gitea_global = map[string]&GiteaK8SInstaller{}
|
||||
gitea_default = ''
|
||||
}
|
||||
if args.fromdb {
|
||||
mut r := context.redis()!
|
||||
mut l := r.hkeys('context:gitea')!
|
||||
|
||||
for name in l {
|
||||
res << get(name: name, fromdb: true)!
|
||||
}
|
||||
return res
|
||||
} else {
|
||||
// load from memory
|
||||
for _, client in gitea_global {
|
||||
res << client
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// only sets in mem, does not set as config
|
||||
fn set_in_mem(o GiteaK8SInstaller) !GiteaK8SInstaller {
|
||||
mut o2 := obj_init(o)!
|
||||
gitea_global[o2.name] = &o2
|
||||
gitea_default = o2.name
|
||||
return o2
|
||||
}
|
||||
|
||||
pub fn play(mut plbook PlayBook) ! {
|
||||
if !plbook.exists(filter: 'gitea.') {
|
||||
return
|
||||
}
|
||||
mut install_actions := plbook.find(filter: 'gitea.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
|
||||
}
|
||||
}
|
||||
mut other_actions := plbook.find(filter: 'gitea.')!
|
||||
for mut 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 gitea.destroy')
|
||||
destroy()!
|
||||
}
|
||||
if other_action.name == 'install' {
|
||||
console.print_debug('install action gitea.install')
|
||||
install()!
|
||||
}
|
||||
}
|
||||
other_action.done = true
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////# LIVE CYCLE MANAGEMENT FOR INSTALLERS ///////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// load from disk and make sure is properly intialized
|
||||
pub fn (mut self GiteaK8SInstaller) reload() ! {
|
||||
switch(self.name)
|
||||
self = obj_init(self)!
|
||||
}
|
||||
|
||||
@[params]
|
||||
pub struct InstallArgs {
|
||||
pub mut:
|
||||
reset bool
|
||||
}
|
||||
|
||||
pub fn (mut self GiteaK8SInstaller) install(args InstallArgs) ! {
|
||||
switch(self.name)
|
||||
if args.reset || (!installed()!) {
|
||||
install()!
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut self GiteaK8SInstaller) destroy() ! {
|
||||
switch(self.name)
|
||||
destroy()!
|
||||
}
|
||||
|
||||
// switch instance to be used for gitea
|
||||
pub fn switch(name string) {
|
||||
gitea_default = name
|
||||
}
|
||||
185
lib/installers/k8s/gitea/gitea_model.v
Normal file
185
lib/installers/k8s/gitea/gitea_model.v
Normal file
@@ -0,0 +1,185 @@
|
||||
module gitea
|
||||
|
||||
import incubaid.herolib.ui.console
|
||||
import incubaid.herolib.data.encoderhero
|
||||
import incubaid.herolib.virt.kubernetes
|
||||
import incubaid.herolib.core.pathlib
|
||||
import strings
|
||||
|
||||
pub const version = '0.0.0'
|
||||
const singleton = false
|
||||
const default = false
|
||||
|
||||
struct ConfigValues {
|
||||
pub mut:
|
||||
hostname string // The Gitea hostname
|
||||
backends string // The backends for the TFGW
|
||||
namespace string // The namespace for the Gitea deployment
|
||||
root_url string // Gitea ROOT_URL
|
||||
domain string // Gitea domain
|
||||
http_port int // Gitea HTTP port
|
||||
disable_registration bool // Disable user registration
|
||||
db_type string // Database type (sqlite3, postgres, mysql)
|
||||
db_path string // Database path for SQLite
|
||||
storage_size string // PVC storage size
|
||||
// Postgres-specific settings
|
||||
db_host string // Database host (for postgres)
|
||||
db_name string // Database name (for postgres)
|
||||
db_user string // Database user (for postgres)
|
||||
db_password string // Database password (for postgres)
|
||||
}
|
||||
|
||||
@[heap]
|
||||
pub struct GiteaK8SInstaller {
|
||||
pub mut:
|
||||
name string = 'gitea'
|
||||
hostname string // Gitea hostname for TFGW
|
||||
namespace string // Kubernetes namespace
|
||||
// Gitea configuration
|
||||
root_url string
|
||||
domain string
|
||||
http_port int = 3000
|
||||
disable_registration bool
|
||||
db_type string = 'sqlite3'
|
||||
db_path string = '/data/gitea/gitea.db'
|
||||
storage_size string = '5Gi'
|
||||
// PostgreSQL configuration (only used when db_type = 'postgres')
|
||||
db_host string = 'postgres' // PostgreSQL host (service name)
|
||||
db_name string = 'gitea' // PostgreSQL database name
|
||||
db_user string = 'gitea' // PostgreSQL user
|
||||
db_password string = 'gitea' // PostgreSQL password
|
||||
// Internal paths
|
||||
gitea_app_path string = '/tmp/gitea/gitea.yaml'
|
||||
tfgw_path string = '/tmp/gitea/tfgw-gitea.yaml'
|
||||
postgres_path string = '/tmp/gitea/postgres.yaml'
|
||||
kube_client kubernetes.KubeClient @[skip]
|
||||
}
|
||||
|
||||
// your checking & initialization code if needed
|
||||
fn obj_init(mycfg_ GiteaK8SInstaller) !GiteaK8SInstaller {
|
||||
mut mycfg := mycfg_
|
||||
|
||||
if mycfg.name == '' {
|
||||
mycfg.name = 'gitea'
|
||||
}
|
||||
|
||||
// Replace the dashes, dots, and underscores with nothing
|
||||
mycfg.name = mycfg.name.replace('_', '')
|
||||
mycfg.name = mycfg.name.replace('-', '')
|
||||
mycfg.name = mycfg.name.replace('.', '')
|
||||
|
||||
if mycfg.namespace == '' {
|
||||
mycfg.namespace = '${mycfg.name}-gitea-namespace'
|
||||
}
|
||||
|
||||
if mycfg.namespace.contains('_') || mycfg.namespace.contains('.') {
|
||||
console.print_stderr('namespace cannot contain _, was: ${mycfg.namespace}, use dashes instead.')
|
||||
return error('namespace cannot contain _, was: ${mycfg.namespace}')
|
||||
}
|
||||
|
||||
if mycfg.hostname == '' {
|
||||
mycfg.hostname = '${mycfg.name}giteaapp'
|
||||
}
|
||||
|
||||
// Validate database type
|
||||
if mycfg.db_type !in ['sqlite3', 'postgres'] {
|
||||
console.print_stderr('Only sqlite3 and postgres databases are supported. Got: ${mycfg.db_type}')
|
||||
return error('Unsupported database type: ${mycfg.db_type}. Only sqlite3 and postgres are supported.')
|
||||
}
|
||||
|
||||
mycfg.kube_client = kubernetes.get(create: true)!
|
||||
mycfg.kube_client.config.namespace = mycfg.namespace
|
||||
return mycfg
|
||||
}
|
||||
|
||||
// called before start if done
|
||||
fn configure() ! {
|
||||
mut installer := get()!
|
||||
|
||||
master_ips := get_master_node_ips()!
|
||||
console.print_info('Master node IPs: ${master_ips}')
|
||||
|
||||
mut backends_str_builder := strings.new_builder(100)
|
||||
for ip in master_ips {
|
||||
backends_str_builder.writeln(' - "http://[${ip}]:80"')
|
||||
}
|
||||
|
||||
console.print_info('Generating configuration files from templates...')
|
||||
|
||||
// Get FQDN for root_url and domain
|
||||
fqdn := '${installer.hostname}.gent01.grid.tf'
|
||||
|
||||
// Create config_values for template generation
|
||||
mut config_values := ConfigValues{
|
||||
hostname: installer.hostname
|
||||
backends: backends_str_builder.str()
|
||||
namespace: installer.namespace
|
||||
root_url: 'https://${fqdn}/'
|
||||
domain: fqdn
|
||||
http_port: installer.http_port
|
||||
disable_registration: installer.disable_registration
|
||||
db_type: installer.db_type
|
||||
db_path: installer.db_path
|
||||
storage_size: installer.storage_size
|
||||
// Postgres connection details (use full DNS name for service)
|
||||
db_host: '${installer.db_host}.${installer.namespace}.svc.cluster.local'
|
||||
db_name: installer.db_name
|
||||
db_user: installer.db_user
|
||||
db_password: installer.db_password
|
||||
}
|
||||
|
||||
// Ensure the output directory exists
|
||||
_ := pathlib.get_dir(path: '/tmp/gitea', create: true)!
|
||||
|
||||
// Generate TFGW YAML
|
||||
tfgw_yaml := $tmpl('./templates/tfgw.yaml')
|
||||
mut tfgw_path := pathlib.get_file(
|
||||
path: installer.tfgw_path
|
||||
create: true
|
||||
check: true
|
||||
)!
|
||||
tfgw_path.write(tfgw_yaml)!
|
||||
|
||||
// Generate gitea-app YAML
|
||||
gitea_app_yaml := $tmpl('./templates/gitea.yaml')
|
||||
mut gitea_app_path := pathlib.get_file(path: installer.gitea_app_path, create: true)!
|
||||
gitea_app_path.write(gitea_app_yaml)!
|
||||
|
||||
// Generate postgres YAML if postgres is selected
|
||||
if installer.db_type == 'postgres' {
|
||||
postgres_yaml := $tmpl('./templates/postgres.yaml')
|
||||
mut postgres_path := pathlib.get_file(path: installer.postgres_path, create: true)!
|
||||
postgres_path.write(postgres_yaml)!
|
||||
console.print_info('PostgreSQL configuration file generated.')
|
||||
}
|
||||
|
||||
console.print_info('Configuration files generated successfully.')
|
||||
}
|
||||
|
||||
// Get Kubernetes master node IPs
|
||||
fn get_master_node_ips() ![]string {
|
||||
mut master_ips := []string{}
|
||||
installer := get()!
|
||||
|
||||
// Get all nodes using the kubernetes client
|
||||
mut k8s := installer.kube_client
|
||||
nodes := k8s.get_nodes()!
|
||||
|
||||
// Extract IPv6 internal IPs from all nodes (dual-stack support)
|
||||
for node in nodes {
|
||||
// Check all internal IPs (not just the first one) for IPv6 addresses
|
||||
for ip in node.internal_ips {
|
||||
if ip.len > 0 && ip.contains(':') {
|
||||
master_ips << ip
|
||||
}
|
||||
}
|
||||
}
|
||||
return master_ips
|
||||
}
|
||||
|
||||
/////////////NORMALLY NO NEED TO TOUCH
|
||||
|
||||
pub fn heroscript_loads(heroscript string) !GiteaK8SInstaller {
|
||||
mut obj := encoderhero.decode[GiteaK8SInstaller](heroscript)!
|
||||
return obj
|
||||
}
|
||||
109
lib/installers/k8s/gitea/templates/gitea.yaml
Normal file
109
lib/installers/k8s/gitea/templates/gitea.yaml
Normal file
@@ -0,0 +1,109 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: @{config_values.namespace}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: gitea-data
|
||||
namespace: @{config_values.namespace}
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
resources: { requests: { storage: @{config_values.storage_size} } }
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: @{config_values.namespace}
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels: { app: gitea }
|
||||
template:
|
||||
metadata:
|
||||
labels: { app: gitea }
|
||||
spec:
|
||||
securityContext:
|
||||
fsGroup: 1000
|
||||
containers:
|
||||
- name: gitea
|
||||
image: gitea/gitea:1.22-rootless
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: @{config_values.http_port}
|
||||
env:
|
||||
- name: GITEA__server__ROOT_URL
|
||||
value: "@{config_values.root_url}"
|
||||
- name: GITEA__server__PROTOCOL
|
||||
value: "http"
|
||||
- name: GITEA__server__HTTP_PORT
|
||||
value: "@{config_values.http_port}"
|
||||
- name: GITEA__server__DOMAIN
|
||||
value: "@{config_values.domain}"
|
||||
- name: GITEA__server__START_SSH_SERVER
|
||||
value: "false"
|
||||
- name: GITEA__database__DB_TYPE
|
||||
value: "@{config_values.db_type}"
|
||||
@if config_values.db_type == 'sqlite3'
|
||||
- name: GITEA__database__PATH
|
||||
value: "@{config_values.db_path}"
|
||||
@end
|
||||
@if config_values.db_type == 'postgres'
|
||||
- name: GITEA__database__HOST
|
||||
value: "@{config_values.db_host}"
|
||||
- name: GITEA__database__NAME
|
||||
value: "@{config_values.db_name}"
|
||||
- name: GITEA__database__USER
|
||||
value: "@{config_values.db_user}"
|
||||
- name: GITEA__database__PASSWD
|
||||
value: "@{config_values.db_password}"
|
||||
@end
|
||||
- name: GITEA__service__DISABLE_REGISTRATION
|
||||
value: "@{config_values.disable_registration}"
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
readinessProbe:
|
||||
httpGet: { path: /, port: @{config_values.http_port} }
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 10
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: gitea-data
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: @{config_values.namespace}
|
||||
spec:
|
||||
selector: { app: gitea }
|
||||
ports:
|
||||
- name: http
|
||||
port: @{config_values.http_port}
|
||||
targetPort: @{config_values.http_port}
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: @{config_values.namespace}
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
rules:
|
||||
- host: @{config_values.domain}
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: gitea
|
||||
port:
|
||||
number: @{config_values.http_port}
|
||||
|
||||
56
lib/installers/k8s/gitea/templates/postgres.yaml
Normal file
56
lib/installers/k8s/gitea/templates/postgres.yaml
Normal file
@@ -0,0 +1,56 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: postgres-data
|
||||
namespace: @{config_values.namespace}
|
||||
spec:
|
||||
accessModes: [ReadWriteOnce]
|
||||
resources:
|
||||
requests:
|
||||
storage: @{config_values.storage_size}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: @{config_values.db_host}
|
||||
namespace: @{config_values.namespace}
|
||||
labels:
|
||||
app: @{config_values.db_host}
|
||||
spec:
|
||||
containers:
|
||||
- name: postgres
|
||||
image: postgres:16-alpine
|
||||
env:
|
||||
- name: POSTGRES_DB
|
||||
value: @{config_values.db_name}
|
||||
- name: POSTGRES_USER
|
||||
value: @{config_values.db_user}
|
||||
- name: POSTGRES_PASSWORD
|
||||
value: @{config_values.db_password}
|
||||
- name: PGDATA
|
||||
value: /var/lib/postgresql/data/pgdata
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
name: postgres
|
||||
volumeMounts:
|
||||
- name: postgres-storage
|
||||
mountPath: /var/lib/postgresql/data
|
||||
volumes:
|
||||
- name: postgres-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: postgres-data
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: @{config_values.db_host}
|
||||
namespace: @{config_values.namespace}
|
||||
spec:
|
||||
selector:
|
||||
app: @{config_values.db_host}
|
||||
ports:
|
||||
- port: 5432
|
||||
targetPort: 5432
|
||||
name: postgres
|
||||
type: ClusterIP
|
||||
|
||||
15
lib/installers/k8s/gitea/templates/tfgw.yaml
Normal file
15
lib/installers/k8s/gitea/templates/tfgw.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: @{config_values.namespace}
|
||||
---
|
||||
apiVersion: ingress.grid.tf/v1
|
||||
kind: TFGW
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: @{config_values.namespace}
|
||||
spec:
|
||||
hostname: "@{config_values.hostname}"
|
||||
backends:
|
||||
@{config_values.backends}
|
||||
|
||||
@@ -22,6 +22,7 @@ pub mut:
|
||||
oneshot bool
|
||||
start bool = true
|
||||
restart bool = true // whether the process should be restarted on failure
|
||||
reset bool // if true, will delete and recreate existing service; if false, will skip if config matches or error if config differs
|
||||
description string // not used in zinit
|
||||
startuptype StartupManagerType
|
||||
}
|
||||
|
||||
@@ -105,20 +105,54 @@ pub fn (mut sm StartupManager) new(args ZProcessNewArgs) ! {
|
||||
// Check if service already exists
|
||||
existing_service := zinit_client.service_get(args.name) or { zinit.ServiceConfig{} }
|
||||
|
||||
// If service exists, stop monitoring, stop, and delete it first
|
||||
// Smart service creation logic based on reset flag
|
||||
if existing_service.exec.len > 0 {
|
||||
console.print_debug('startupmanager: service ${args.name} already exists, cleaning up...')
|
||||
// Stop the service first
|
||||
zinit_client.service_stop(args.name) or {
|
||||
console.print_debug('startupmanager: failed to stop service ${args.name}: ${err}')
|
||||
}
|
||||
// Forget (stop monitoring) the service
|
||||
zinit_client.service_forget(args.name) or {
|
||||
console.print_debug('startupmanager: failed to forget service ${args.name}: ${err}')
|
||||
}
|
||||
// Delete the service configuration
|
||||
zinit_client.service_delete(args.name) or {
|
||||
console.print_debug('startupmanager: failed to delete service ${args.name}: ${err}')
|
||||
// Service exists - check if configuration matches
|
||||
configs_match := existing_service.exec == service_config.exec
|
||||
&& existing_service.test == service_config.test
|
||||
&& existing_service.oneshot == service_config.oneshot
|
||||
&& existing_service.dir == service_config.dir
|
||||
&& existing_service.log == service_config.log
|
||||
&& existing_service.after.len == service_config.after.len
|
||||
&& existing_service.env.len == service_config.env.len
|
||||
|
||||
if configs_match {
|
||||
// Configuration is the same - idempotent, just skip creation
|
||||
console.print_debug('startupmanager: service ${args.name} already exists with same configuration, skipping creation.')
|
||||
// If start is requested and service is not running, start it
|
||||
if args.start {
|
||||
status := zinit_client.service_status(args.name) or {
|
||||
console.print_debug('startupmanager: failed to get status of ${args.name}: ${err}')
|
||||
zinit.ServiceStatus{}
|
||||
}
|
||||
if status.state != 'Running' {
|
||||
console.print_debug('startupmanager: service ${args.name} is not running, starting it...')
|
||||
zinit_client.service_monitor(args.name) or {
|
||||
console.print_debug('startupmanager: failed to monitor service ${args.name}: ${err}')
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
} else {
|
||||
// Configuration is different
|
||||
if !args.reset {
|
||||
// reset is false - return error to protect user customizations
|
||||
return error('service ${args.name} already exists with different configuration. Use reset:true to overwrite it.')
|
||||
}
|
||||
// reset is true - delete and recreate
|
||||
console.print_debug('startupmanager: service ${args.name} exists with different configuration, recreating (reset:true)...')
|
||||
// Stop the service first
|
||||
zinit_client.service_stop(args.name) or {
|
||||
console.print_debug('startupmanager: failed to stop service ${args.name}: ${err}')
|
||||
}
|
||||
// Forget (stop monitoring) the service
|
||||
zinit_client.service_forget(args.name) or {
|
||||
console.print_debug('startupmanager: failed to forget service ${args.name}: ${err}')
|
||||
}
|
||||
// Delete the service configuration
|
||||
zinit_client.service_delete(args.name) or {
|
||||
console.print_debug('startupmanager: failed to delete service ${args.name}: ${err}')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,18 +76,14 @@ pub fn (mut t UnixSocketTransport) send(request string, params SendParams) !stri
|
||||
// Append the newly read data to the total response
|
||||
res_total << res[..n]
|
||||
|
||||
// here we need to check we are at end
|
||||
if res.bytestr().contains('\n') {
|
||||
// Check if we have received a complete response (ends with newline)
|
||||
if res_total.bytestr().contains('\n') {
|
||||
break
|
||||
}
|
||||
}
|
||||
unix.shutdown(socket.sock.handle)
|
||||
socket.close() or {}
|
||||
|
||||
// println(res_total.bytestr().trim_space())
|
||||
|
||||
// println(19)
|
||||
|
||||
// Convert response to string and trim whitespace
|
||||
mut response := res_total.bytestr().trim_space()
|
||||
// console.print_debug('Received ${response.len} bytes')
|
||||
|
||||
Reference in New Issue
Block a user