...
This commit is contained in:
51
lib/clients/traefik/factory.v
Normal file
51
lib/clients/traefik/factory.v
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
module traefik
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.core.texttools
|
||||||
|
import freeflowuniverse.herolib.core.redisclient
|
||||||
|
import freeflowuniverse.herolib.osal.traefik as osal_traefik
|
||||||
|
|
||||||
|
__global (
|
||||||
|
traefik_managers map[string]&TraefikManager
|
||||||
|
)
|
||||||
|
|
||||||
|
@[params]
|
||||||
|
pub struct FactoryArgs {
|
||||||
|
pub mut:
|
||||||
|
name string = 'default'
|
||||||
|
redis_url string = '127.0.0.1:6379'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(args FactoryArgs) !&TraefikManager {
|
||||||
|
name := texttools.name_fix(args.name)
|
||||||
|
if name in traefik_managers {
|
||||||
|
return traefik_managers[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
mut redis := redisclient.core_get(redisclient.get_redis_url(args.redis_url)!)!
|
||||||
|
|
||||||
|
mut manager := &TraefikManager{
|
||||||
|
name: name
|
||||||
|
redis: redis
|
||||||
|
config: osal_traefik.new_traefik_config()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set redis connection in config
|
||||||
|
manager.config.redis = redis
|
||||||
|
|
||||||
|
traefik_managers[name] = manager
|
||||||
|
return manager
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(args FactoryArgs) !&TraefikManager {
|
||||||
|
name := texttools.name_fix(args.name)
|
||||||
|
return traefik_managers[name] or {
|
||||||
|
return error('traefik manager with name "${name}" does not exist')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default() !&TraefikManager {
|
||||||
|
if traefik_managers.len == 0 {
|
||||||
|
return new(name: 'default')!
|
||||||
|
}
|
||||||
|
return get(name: 'default')!
|
||||||
|
}
|
||||||
154
lib/clients/traefik/manager.v
Normal file
154
lib/clients/traefik/manager.v
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
module traefik
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.core.redisclient
|
||||||
|
import freeflowuniverse.herolib.osal.traefik as osal_traefik
|
||||||
|
import freeflowuniverse.herolib.core.texttools
|
||||||
|
|
||||||
|
@[heap]
|
||||||
|
pub struct TraefikManager {
|
||||||
|
pub mut:
|
||||||
|
name string
|
||||||
|
redis &redisclient.Redis
|
||||||
|
config osal_traefik.TraefikConfig
|
||||||
|
entrypoints []EntryPointConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EntryPointConfig {
|
||||||
|
pub mut:
|
||||||
|
name string @[required]
|
||||||
|
address string @[required]
|
||||||
|
tls bool
|
||||||
|
}
|
||||||
|
|
||||||
|
@[params]
|
||||||
|
pub struct RouterAddArgs {
|
||||||
|
pub mut:
|
||||||
|
name string @[required]
|
||||||
|
rule string @[required]
|
||||||
|
service string @[required]
|
||||||
|
entrypoints []string
|
||||||
|
middlewares []string
|
||||||
|
tls bool
|
||||||
|
priority int
|
||||||
|
}
|
||||||
|
|
||||||
|
@[params]
|
||||||
|
pub struct ServiceAddArgs {
|
||||||
|
pub mut:
|
||||||
|
name string @[required]
|
||||||
|
servers []string @[required]
|
||||||
|
strategy string = 'wrr' // wrr or p2c
|
||||||
|
}
|
||||||
|
|
||||||
|
@[params]
|
||||||
|
pub struct MiddlewareAddArgs {
|
||||||
|
pub mut:
|
||||||
|
name string @[required]
|
||||||
|
typ string @[required]
|
||||||
|
settings map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
@[params]
|
||||||
|
pub struct EntryPointAddArgs {
|
||||||
|
pub mut:
|
||||||
|
name string @[required]
|
||||||
|
address string @[required]
|
||||||
|
tls bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add router configuration
|
||||||
|
pub fn (mut tm TraefikManager) router_add(args RouterAddArgs) ! {
|
||||||
|
tm.config.add_route(
|
||||||
|
name: texttools.name_fix(args.name)
|
||||||
|
rule: args.rule
|
||||||
|
service: texttools.name_fix(args.service)
|
||||||
|
middlewares: args.middlewares.map(texttools.name_fix(it))
|
||||||
|
priority: args.priority
|
||||||
|
tls: args.tls
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add service configuration
|
||||||
|
pub fn (mut tm TraefikManager) service_add(args ServiceAddArgs) ! {
|
||||||
|
mut servers := []osal_traefik.ServerConfig{}
|
||||||
|
for server_url in args.servers {
|
||||||
|
servers << osal_traefik.ServerConfig{
|
||||||
|
url: server_url.trim_space()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tm.config.add_service(
|
||||||
|
name: texttools.name_fix(args.name)
|
||||||
|
load_balancer: osal_traefik.LoadBalancerConfig{
|
||||||
|
servers: servers
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add middleware configuration
|
||||||
|
pub fn (mut tm TraefikManager) middleware_add(args MiddlewareAddArgs) ! {
|
||||||
|
tm.config.add_middleware(
|
||||||
|
name: texttools.name_fix(args.name)
|
||||||
|
typ: args.typ
|
||||||
|
settings: args.settings
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add entrypoint configuration (stored separately as these are typically static config)
|
||||||
|
pub fn (mut tm TraefikManager) entrypoint_add(args EntryPointAddArgs) ! {
|
||||||
|
entrypoint := EntryPointConfig{
|
||||||
|
name: texttools.name_fix(args.name)
|
||||||
|
address: args.address
|
||||||
|
tls: args.tls
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if entrypoint already exists
|
||||||
|
for mut ep in tm.entrypoints {
|
||||||
|
if ep.name == entrypoint.name {
|
||||||
|
ep.address = entrypoint.address
|
||||||
|
ep.tls = entrypoint.tls
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tm.entrypoints << entrypoint
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply all configurations to Redis
|
||||||
|
pub fn (mut tm TraefikManager) apply() ! {
|
||||||
|
// Apply dynamic configuration (routers, services, middlewares)
|
||||||
|
tm.config.set()!
|
||||||
|
|
||||||
|
// Store entrypoints separately (these would typically be in static config)
|
||||||
|
for ep in tm.entrypoints {
|
||||||
|
tm.redis.hset('traefik:entrypoints', ep.name, '${ep.address}|${ep.tls}')!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all entrypoints
|
||||||
|
pub fn (mut tm TraefikManager) entrypoints_get() ![]EntryPointConfig {
|
||||||
|
return tm.entrypoints.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear all configurations
|
||||||
|
pub fn (mut tm TraefikManager) clear() ! {
|
||||||
|
tm.config = osal_traefik.new_traefik_config()
|
||||||
|
tm.config.redis = tm.redis
|
||||||
|
tm.entrypoints = []EntryPointConfig{}
|
||||||
|
|
||||||
|
// Clear Redis keys
|
||||||
|
keys := tm.redis.keys('traefik/*')!
|
||||||
|
for key in keys {
|
||||||
|
tm.redis.del(key)!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get configuration status
|
||||||
|
pub fn (mut tm TraefikManager) status() !map[string]int {
|
||||||
|
return {
|
||||||
|
'routers': tm.config.routers.len
|
||||||
|
'services': tm.config.services.len
|
||||||
|
'middlewares': tm.config.middlewares.len
|
||||||
|
'entrypoints': tm.entrypoints.len
|
||||||
|
}
|
||||||
|
}
|
||||||
168
lib/clients/traefik/play.v
Normal file
168
lib/clients/traefik/play.v
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
module traefik
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.core.playbook { PlayBook }
|
||||||
|
import freeflowuniverse.herolib.core.texttools
|
||||||
|
import freeflowuniverse.herolib.ui.console
|
||||||
|
|
||||||
|
pub fn play(mut plbook PlayBook) ! {
|
||||||
|
if !plbook.exists(filter: 'traefik.') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get or create default traefik manager
|
||||||
|
mut manager := default()!
|
||||||
|
|
||||||
|
// Process entrypoints first
|
||||||
|
play_entrypoints(mut plbook, mut manager)!
|
||||||
|
|
||||||
|
// Process services (before routers that might reference them)
|
||||||
|
play_services(mut plbook, mut manager)!
|
||||||
|
|
||||||
|
// Process middlewares (before routers that might reference them)
|
||||||
|
play_middlewares(mut plbook, mut manager)!
|
||||||
|
|
||||||
|
// Process routers
|
||||||
|
play_routers(mut plbook, mut manager)!
|
||||||
|
|
||||||
|
// Apply all configurations to Redis
|
||||||
|
manager.apply()!
|
||||||
|
|
||||||
|
console.print_debug('Traefik configuration applied successfully')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn play_entrypoints(mut plbook PlayBook, mut manager TraefikManager) ! {
|
||||||
|
entrypoint_actions := plbook.find(filter: 'traefik.entrypoint')!
|
||||||
|
|
||||||
|
for mut action in entrypoint_actions {
|
||||||
|
mut p := action.params
|
||||||
|
|
||||||
|
manager.entrypoint_add(
|
||||||
|
name: p.get('name')!
|
||||||
|
address: p.get('address')!
|
||||||
|
tls: p.get_default_false('tls')
|
||||||
|
)!
|
||||||
|
|
||||||
|
action.done = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn play_routers(mut plbook PlayBook, mut manager TraefikManager) ! {
|
||||||
|
router_actions := plbook.find(filter: 'traefik.router')!
|
||||||
|
|
||||||
|
for mut action in router_actions {
|
||||||
|
mut p := action.params
|
||||||
|
|
||||||
|
// Parse entrypoints list
|
||||||
|
mut entrypoints := []string{}
|
||||||
|
if entrypoints_str := p.get_default('entrypoints', '') {
|
||||||
|
if entrypoints_str.len > 0 {
|
||||||
|
entrypoints = entrypoints_str.split(',').map(it.trim_space())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse middlewares list
|
||||||
|
mut middlewares := []string{}
|
||||||
|
if middlewares_str := p.get_default('middlewares', '') {
|
||||||
|
if middlewares_str.len > 0 {
|
||||||
|
middlewares = middlewares_str.split(',').map(it.trim_space())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.router_add(
|
||||||
|
name: p.get('name')!
|
||||||
|
rule: p.get('rule')!
|
||||||
|
service: p.get('service')!
|
||||||
|
entrypoints: entrypoints
|
||||||
|
middlewares: middlewares
|
||||||
|
tls: p.get_default_false('tls')
|
||||||
|
priority: p.get_int_default('priority', 0)
|
||||||
|
)!
|
||||||
|
|
||||||
|
action.done = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn play_services(mut plbook PlayBook, mut manager TraefikManager) ! {
|
||||||
|
service_actions := plbook.find(filter: 'traefik.service')!
|
||||||
|
|
||||||
|
for mut action in service_actions {
|
||||||
|
mut p := action.params
|
||||||
|
|
||||||
|
// Parse servers list
|
||||||
|
servers_str := p.get('servers')!
|
||||||
|
servers := servers_str.split(',').map(it.trim_space())
|
||||||
|
|
||||||
|
manager.service_add(
|
||||||
|
name: p.get('name')!
|
||||||
|
servers: servers
|
||||||
|
strategy: p.get_default('strategy', 'wrr')!
|
||||||
|
)!
|
||||||
|
|
||||||
|
action.done = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn play_middlewares(mut plbook PlayBook, mut manager TraefikManager) ! {
|
||||||
|
middleware_actions := plbook.find(filter: 'traefik.middleware')!
|
||||||
|
|
||||||
|
for mut action in middleware_actions {
|
||||||
|
mut p := action.params
|
||||||
|
|
||||||
|
// Build settings map from remaining parameters
|
||||||
|
mut settings := map[string]string{}
|
||||||
|
|
||||||
|
middleware_type := p.get('type')!
|
||||||
|
|
||||||
|
// Handle common middleware types
|
||||||
|
match middleware_type {
|
||||||
|
'basicAuth' {
|
||||||
|
if users := p.get_default('users', '') {
|
||||||
|
settings['users'] = '["${users}"]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'stripPrefix' {
|
||||||
|
if prefixes := p.get_default('prefixes', '') {
|
||||||
|
settings['prefixes'] = '["${prefixes}"]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'addPrefix' {
|
||||||
|
if prefix := p.get_default('prefix', '') {
|
||||||
|
settings['prefix'] = prefix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'headers' {
|
||||||
|
if custom_headers := p.get_default('customRequestHeaders', '') {
|
||||||
|
settings['customRequestHeaders'] = custom_headers
|
||||||
|
}
|
||||||
|
if custom_response_headers := p.get_default('customResponseHeaders', '') {
|
||||||
|
settings['customResponseHeaders'] = custom_response_headers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'rateLimit' {
|
||||||
|
if rate := p.get_default('rate', '') {
|
||||||
|
settings['rate'] = rate
|
||||||
|
}
|
||||||
|
if burst := p.get_default('burst', '') {
|
||||||
|
settings['burst'] = burst
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// For other middleware types, get all parameters as settings
|
||||||
|
param_map := p.get_map()
|
||||||
|
for key, value in param_map {
|
||||||
|
if key !in ['name', 'type'] {
|
||||||
|
settings[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.middleware_add(
|
||||||
|
name: p.get('name')!
|
||||||
|
typ: middleware_type
|
||||||
|
settings: settings
|
||||||
|
)!
|
||||||
|
|
||||||
|
action.done = true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
TMUX is a very capable process manager.
|
TMUX is a very capable process manager.
|
||||||
|
|
||||||
|
> TODO: TTYD, need to integrate with TMUX for exposing TMUX over http
|
||||||
|
|
||||||
### Concepts
|
### Concepts
|
||||||
|
|
||||||
- tmux = is the factory, it represents the tmux process manager, linked to a node
|
- tmux = is the factory, it represents the tmux process manager, linked to a node
|
||||||
|
|||||||
Reference in New Issue
Block a user