This commit is contained in:
2025-08-24 16:42:07 +02:00
parent a2a9b07238
commit 4e20df3eb8
4 changed files with 375 additions and 0 deletions

View 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')!
}

View 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
View 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
}
}