From 67d13d081b718ada3e69292eade5baddeac0c3c8 Mon Sep 17 00:00:00 2001 From: kristof de spiegeleer Date: Tue, 21 Oct 2025 09:30:37 +0200 Subject: [PATCH] ... --- lib/virt/kubernetes_notgood/.heroscript | 12 - lib/virt/kubernetes_notgood/kubernetes.v | 151 ----- .../kubernetes_notgood/kubernetes_actions.v | 265 -------- .../kubernetes_notgood/kubernetes_client.v | 223 ------- .../kubernetes_notgood/kubernetes_config.v | 65 -- .../kubernetes_notgood/kubernetes_errors.v | 42 -- .../kubernetes_notgood/kubernetes_factory_.v | 312 --------- .../kubernetes_notgood/kubernetes_model.v | 48 -- .../kubernetes_notgood/kubernetes_models.v | 622 ------------------ lib/virt/kubernetes_notgood/kubernetes_yaml.v | 53 -- lib/virt/kubernetes_notgood/readme.md | 44 -- .../templates/atemplate.yaml | 5 - .../templates/configmap.yaml | 7 - .../templates/deployment.yaml | 22 - .../templates/namespace.yaml | 4 - .../kubernetes_notgood/templates/pod.yaml | 13 - .../kubernetes_notgood/templates/service.yaml | 15 - .../kubernetes_notgood/test/kubernetes_test.v | 213 ------ .../kubernetes_notgood/test/models_test.v | 295 --------- 19 files changed, 2411 deletions(-) delete mode 100644 lib/virt/kubernetes_notgood/.heroscript delete mode 100644 lib/virt/kubernetes_notgood/kubernetes.v delete mode 100644 lib/virt/kubernetes_notgood/kubernetes_actions.v delete mode 100644 lib/virt/kubernetes_notgood/kubernetes_client.v delete mode 100644 lib/virt/kubernetes_notgood/kubernetes_config.v delete mode 100644 lib/virt/kubernetes_notgood/kubernetes_errors.v delete mode 100644 lib/virt/kubernetes_notgood/kubernetes_factory_.v delete mode 100644 lib/virt/kubernetes_notgood/kubernetes_model.v delete mode 100644 lib/virt/kubernetes_notgood/kubernetes_models.v delete mode 100644 lib/virt/kubernetes_notgood/kubernetes_yaml.v delete mode 100644 lib/virt/kubernetes_notgood/readme.md delete mode 100644 lib/virt/kubernetes_notgood/templates/atemplate.yaml delete mode 100644 lib/virt/kubernetes_notgood/templates/configmap.yaml delete mode 100644 lib/virt/kubernetes_notgood/templates/deployment.yaml delete mode 100644 lib/virt/kubernetes_notgood/templates/namespace.yaml delete mode 100644 lib/virt/kubernetes_notgood/templates/pod.yaml delete mode 100644 lib/virt/kubernetes_notgood/templates/service.yaml delete mode 100644 lib/virt/kubernetes_notgood/test/kubernetes_test.v delete mode 100644 lib/virt/kubernetes_notgood/test/models_test.v diff --git a/lib/virt/kubernetes_notgood/.heroscript b/lib/virt/kubernetes_notgood/.heroscript deleted file mode 100644 index e20a7408..00000000 --- a/lib/virt/kubernetes_notgood/.heroscript +++ /dev/null @@ -1,12 +0,0 @@ - -!!hero_code.generate_installer - name:'' - classname:'Kubernetes' - singleton:0 - templates:1 - default:1 - title:'' - supported_platforms:'' - startupmanager:1 - hasconfig:1 - build:1 \ No newline at end of file diff --git a/lib/virt/kubernetes_notgood/kubernetes.v b/lib/virt/kubernetes_notgood/kubernetes.v deleted file mode 100644 index df94ccb9..00000000 --- a/lib/virt/kubernetes_notgood/kubernetes.v +++ /dev/null @@ -1,151 +0,0 @@ -module kubernetes - -import incubaid.herolib.core.base -import incubaid.herolib.core.playbook { PlayBook } -import json - -__global ( - kubernetes_clients map[string]&KubernetesClient - default_client_name string -) - -@[params] -pub struct ClientGetArgs { -pub mut: - name string = 'default' - config ?KubernetesConfig - create bool = true -} - -// Get or create a Kubernetes client -pub fn get_client(args ClientGetArgs) !&KubernetesClient { - if args.name in kubernetes_clients { - return kubernetes_clients[args.name] or { - return error('Failed to retrieve client: ${args.name}') - } - } - - if args.config != none { - mut cfg := args.config! - cfg.name = args.name - mut client := new(cfg)! - kubernetes_clients[args.name] = client - default_client_name = args.name - return client - } - - // Try to load from kubeconfig - cfg := load_kubeconfig(args.name) or { - if args.create { - return error('No kubeconfig found and create=false') - } - return err - } - - mut client := new(cfg)! - kubernetes_clients[args.name] = client - default_client_name = args.name - return client -} - -// Use a specific client as default -pub fn use_client(name string) ! { - if name !in kubernetes_clients { - return error('Client ${name} not found') - } - default_client_name = name -} - -// Get default client -pub fn client() !&KubernetesClient { - if default_client_name == '' { - default_client_name = 'default' - } - - if default_client_name !in kubernetes_clients { - // Try to load default from kubeconfig - return get_client(name: 'default', create: true)! - } - - return kubernetes_clients[default_client_name] or { - return error('Default client not available') - } -} - -// Register a client -pub fn register_client(name string, cfg KubernetesConfig) !&KubernetesClient { - mut client := new(cfg)! - kubernetes_clients[name] = client - return client -} - -// List all registered clients -pub fn list_clients() []string { - mut result := []string{} - for name, _ in kubernetes_clients { - result << name - } - return result -} - -// Play HeroScript for Kubernetes -pub fn play(mut plbook PlayBook) ! { - if !plbook.exists(filter: 'kubernetes.') { - return - } - - // Handle configuration actions - configure_actions := plbook.find(filter: 'kubernetes.configure')! - for mut action in configure_actions { - mut p := action.params - name := p.get_default('name', 'default')! - server := p.get('server')! - token := p.get_default('token', '')! - - cfg := KubernetesConfig{ - name: name - server: server - token: token - } - - register_client(name, cfg)! - action.done = true - } - - // Handle resource actions (create, delete, scale, etc.) - resource_actions := plbook.find(filter: 'kubernetes.')! - for mut action in resource_actions { - mut p := action.params - client_name := p.get_default('client', 'default')! - mut client := get_client(name: client_name)! - - match action.name { - 'deploy' { - // Handle deployment - // yaml_content := p.get('yaml')! - // deployment := from_yaml[Deployment](yaml_content)! - // client.deploy(deployment: deployment)! - } - 'delete' { - resource_type := p.get('resource_type')! - resource_name := p.get('name')! - namespace := p.get_default('namespace', 'default')! - client.delete_resource( - resource_type: resource_type - name: resource_name - namespace: namespace - )! - } - 'scale' { - deployment_name := p.get('deployment')! - replicas := p.get_int('replicas')! - client.scale_deployment( - deployment_name: deployment_name - replicas: replicas - )! - } - else {} - } - action.done = true - } -} \ No newline at end of file diff --git a/lib/virt/kubernetes_notgood/kubernetes_actions.v b/lib/virt/kubernetes_notgood/kubernetes_actions.v deleted file mode 100644 index 4a2f6a40..00000000 --- a/lib/virt/kubernetes_notgood/kubernetes_actions.v +++ /dev/null @@ -1,265 +0,0 @@ -module kubernetes - -import incubaid.herolib.ui.console -import incubaid.herolib.core.texttools -import time - -@[params] -pub struct DeployArgs { -pub mut: - deployment Deployment - wait bool = true - timeout_seconds int = 300 - poll_interval_ms int = 5000 -} - -// Deploy a Deployment resource -pub fn (mut c KubernetesClient) deploy(args DeployArgs) !Deployment { - console.print_header('Deploying ${args.deployment.metadata.name}') - - // Check if deployment already exists - existing := c.get[Deployment]( - resource_type: 'deployments' - name: args.deployment.metadata.name - namespace: args.deployment.metadata.namespace - ) or { none } - - mut deployed_deployment := match existing { - Deployment { c.update[Deployment](args.deployment)! } - else { c.create[Deployment](args.deployment)! } - } - - console.print_green('Deployment created/updated: ${args.deployment.metadata.name}') - - if args.wait { - c.wait_for_deployment_ready( - name: args.deployment.metadata.name - namespace: args.deployment.metadata.namespace - timeout_seconds: args.timeout_seconds - )! - } - - return deployed_deployment -} - -@[params] -pub struct WaitForDeploymentArgs { -pub mut: - name string - namespace string = 'default' - timeout_seconds int = 300 - poll_interval_ms int = 5000 -} - -// Wait for deployment to be ready -pub fn (mut c KubernetesClient) wait_for_deployment_ready(args WaitForDeploymentArgs) ! { - start_time := time.now() - - for { - deployment := c.get[Deployment]( - resource_type: 'deployments' - name: args.name - namespace: args.namespace - )! - - if deployment.status != none { - status := deployment.status! - if status.observed_generation >= deployment.metadata.resource_version.int() { - if status.updated_replicas == deployment.spec.replicas { - if status.ready_replicas == deployment.spec.replicas { - console.print_green('Deployment ${args.name} is ready') - return - } - } - } - } - - elapsed := time.now().unix_time() - start_time.unix_time() - if elapsed > args.timeout_seconds { - return error('Timeout waiting for deployment ${args.name} to be ready') - } - - console.print_debug('Waiting for deployment ${args.name}...') - time.sleep(args.poll_interval_ms * time.millisecond) - } -} - -@[params] -pub struct DeleteArgs { -pub mut: - resource_type string // 'pods', 'deployments', 'services', etc. - name string - namespace string = 'default' - grace_period_seconds int = 30 - wait bool = true - timeout_seconds int = 300 -} - -// Delete a resource -pub fn (mut c KubernetesClient) delete_resource(args DeleteArgs) ! { - console.print_header('Deleting ${args.resource_type}/${args.name}') - - c.delete( - resource_type: args.resource_type - name: args.name - namespace: args.namespace - )! - - console.print_green('${args.resource_type}/${args.name} deleted') - - if args.wait { - start_time := time.now() - for { - c.get[map[string]interface{}]( - resource_type: args.resource_type - name: args.name - namespace: args.namespace - ) or { - console.print_green('${args.resource_type}/${args.name} fully removed') - return - } - - elapsed := time.now().unix_time() - start_time.unix_time() - if elapsed > args.timeout_seconds { - return error('Timeout waiting for ${args.resource_type}/${args.name} to be deleted') - } - - time.sleep(5000 * time.millisecond) - } - } -} - -@[params] -pub struct ScaleArgs { -pub mut: - deployment_name string - namespace string = 'default' - replicas int - wait bool = true - timeout_seconds int = 300 -} - -// Scale a deployment -pub fn (mut c KubernetesClient) scale_deployment(args ScaleArgs) !Deployment { - console.print_header('Scaling ${args.deployment_name} to ${args.replicas} replicas') - - // Patch the deployment spec.replicas field - patch_data := { - 'spec': { - 'replicas': args.replicas - } - } - - mut deployment := c.patch[Deployment]( - resource_type: 'deployments' - name: args.deployment_name - namespace: args.namespace - patch_data: patch_data - )! - - if args.wait { - c.wait_for_deployment_ready( - name: args.deployment_name - namespace: args.namespace - timeout_seconds: args.timeout_seconds - )! - } - - return deployment -} - -@[params] -pub struct RollingRestartArgs { -pub mut: - deployment_name string - namespace string = 'default' - wait bool = true - timeout_seconds int = 600 -} - -// Perform rolling restart of a deployment -pub fn (mut c KubernetesClient) rolling_restart(args RollingRestartArgs) ! { - console.print_header('Rolling restart of ${args.deployment_name}') - - now_timestamp := time.now().format_rfc3339() - patch_data := { - 'spec': { - 'template': { - 'metadata': { - 'annotations': { - 'kubectl.kubernetes.io/restartedAt': now_timestamp - } - } - } - } - } - - c.patch[Deployment]( - resource_type: 'deployments' - name: args.deployment_name - namespace: args.namespace - patch_data: patch_data - )! - - if args.wait { - c.wait_for_deployment_ready( - name: args.deployment_name - namespace: args.namespace - timeout_seconds: args.timeout_seconds - )! - } - - console.print_green('${args.deployment_name} rolling restart completed') -} - -@[params] -pub struct GetLogsArgs { -pub mut: - pod_name string - container_name string - namespace string = 'default' - tail_lines int = 100 - follow bool -} - -// Get pod logs -pub fn (mut c KubernetesClient) get_pod_logs(args GetLogsArgs) !string { - mut prefix := '/api/v1/namespaces/${args.namespace}/pods/${args.pod_name}/log' - prefix += '?tailLines=${args.tail_lines}' - if args.container_name.len > 0 { - prefix += '&container=${args.container_name}' - } - - conn := c.connection()! - return conn.get_text(prefix: prefix)! -} - -@[params] -pub struct ExecArgs { -pub mut: - pod_name string - container_name string - command []string - namespace string = 'default' -} - -// Execute command in pod (requires WebSocket support - future enhancement) -pub fn (mut c KubernetesClient) exec_in_pod(args ExecArgs) ! { - // TODO: Implement WebSocket-based exec - return error('exec_in_pod requires WebSocket support - not yet implemented') -} - -@[params] -pub struct PortForwardArgs { -pub mut: - pod_name string - namespace string = 'default' - local_port int - remote_port int -} - -// Port forward to pod (requires WebSocket support - future enhancement) -pub fn (mut c KubernetesClient) port_forward(args PortForwardArgs) ! { - // TODO: Implement WebSocket-based port forward - return error('port_forward requires WebSocket support - not yet implemented') -} diff --git a/lib/virt/kubernetes_notgood/kubernetes_client.v b/lib/virt/kubernetes_notgood/kubernetes_client.v deleted file mode 100644 index 3a86fe3a..00000000 --- a/lib/virt/kubernetes_notgood/kubernetes_client.v +++ /dev/null @@ -1,223 +0,0 @@ -module kubernetes - -import incubaid.herolib.core.httpconnection -import net.http -import json -import encoding.base64 - -@[heap] -pub struct KubernetesClient { -pub mut: - config KubernetesConfig - http_conn ?&httpconnection.HTTPConnection - api_groups map[string]APIGroupVersion -} - -pub struct APIGroupVersion { -pub: - group_version string - resources []APIResource -} - -pub struct APIResource { -pub: - name string - singularname string - namespaced bool - kind string - verbs []string // get, list, create, update, delete, patch, watch, etc. -} - -pub struct APIResponse { -pub: - kind string - api_version string - metadata map[string]interface{} - items []json.Any -} - -// Create new Kubernetes client -pub fn new(config KubernetesConfig) !&KubernetesClient { - mut cfg := config - cfg.validate()! - - mut client := KubernetesClient{ - config: cfg - } - client.http_conn = http_connection_create(cfg)! - - return &client -} - -// Create HTTP connection with proper auth -fn http_connection_create(cfg KubernetesConfig) !&httpconnection.HTTPConnection { - mut conn := httpconnection.new( - name: 'kubernetes-${cfg.name}' - url: cfg.server - retry: 3 - cache: false - )! - - // Setup authentication - if cfg.token.len > 0 { - mut header := http.new_header() - header.add(.authorization, 'Bearer ${cfg.token}') - conn.default_header = header - } else if cfg.username.len > 0 && cfg.password.len > 0 { - conn.basic_auth(cfg.username, cfg.password) - } - - // TLS configuration - if cfg.insecure_skip_verify { - // Skip verification (development only) - } else if cfg.certificate_authority.len > 0 { - // Load CA certificate - // TODO: Configure TLS with CA cert - } - - return conn -} - -// Get HTTP connection -pub fn (mut c KubernetesClient) connection() !&httpconnection.HTTPConnection { - if c.http_conn == none { - c.http_conn = http_connection_create(c.config)! - } - return c.http_conn! -} - -// ==================== DISCOVERY API ==================== - -// Get available API groups -pub fn (mut c KubernetesClient) get_api_groups() ![]APIGroupVersion { - conn := c.connection()! - response := conn.get_json_generic[map[string]interface{}]( - prefix: '/apis' - )! - // Parse and return API groups - return []APIGroupVersion{} -} - -// ==================== CORE API METHODS ==================== - -// Generic GET for any resource -pub fn (mut c KubernetesClient) get[T]( - resource_type string - name string - namespace string = '' -) !T { - mut prefix := build_api_path(resource_type, name, namespace) - conn := c.connection()! - return conn.get_json_generic[T](prefix: prefix)! -} - -// Generic LIST for any resource -pub fn (mut c KubernetesClient) list[T]( - resource_type string - namespace string = '' - label_selector string = '' -) ![]T { - mut prefix := build_api_list_path(resource_type, namespace) - if label_selector.len > 0 { - prefix += '?labelSelector=${label_selector}' - } - conn := c.connection()! - response := conn.get_json_generic[map[string]interface{}](prefix: prefix)! - // Parse items array - return []T{} -} - -// Generic CREATE for any resource -pub fn (mut c KubernetesClient) create[T](resource T) !T { - resource_type := get_resource_type[T]() - namespace := get_namespace[T](resource) - mut prefix := build_api_path_create(resource_type, namespace) - - conn := c.connection()! - return conn.post_json_generic[T]( - prefix: prefix - params: json.decode_object(json.encode(resource))! - )! -} - -// Generic UPDATE (PUT) for any resource -pub fn (mut c KubernetesClient) update[T](resource T) !T { - resource_type := get_resource_type[T]() - name := get_resource_name[T](resource) - namespace := get_namespace[T](resource) - mut prefix := build_api_path(resource_type, name, namespace) - - conn := c.connection()! - return conn.put_json_generic[T]( - prefix: prefix - params: json.decode_object(json.encode(resource))! - )! -} - -// Generic PATCH for any resource -pub fn (mut c KubernetesClient) patch[T]( - resource_type string - name string - namespace string - patch_data map[string]interface{} -) !T { - mut prefix := build_api_path(resource_type, name, namespace) - - conn := c.connection()! - mut header := http.new_header() - header.add(.content_type, 'application/merge-patch+json') - - return conn.patch_json_generic[T]( - prefix: prefix - params: patch_data - header: header - )! -} - -// Generic DELETE for any resource -pub fn (mut c KubernetesClient) delete( - resource_type string - name string - namespace string = '' -) ! { - mut prefix := build_api_path(resource_type, name, namespace) - conn := c.connection()! - conn.delete(prefix: prefix)! -} - -// Helper functions for building API paths -fn build_api_path(resource_type string, name string, namespace string) string { - if namespace.len > 0 { - return '/api/v1/namespaces/${namespace}/${resource_type}/${name}' - } else { - return '/api/v1/${resource_type}/${name}' - } -} - -fn build_api_list_path(resource_type string, namespace string) string { - if namespace.len > 0 { - return '/api/v1/namespaces/${namespace}/${resource_type}' - } else { - return '/api/v1/${resource_type}' - } -} - -fn build_api_path_create(resource_type string, namespace string) string { - return build_api_list_path(resource_type, namespace) -} - -// Helper functions to extract metadata from generic types -fn get_resource_type[T]() string { - // TODO: Use compile-time reflection to get Kind from T - return 'pods' -} - -fn get_resource_name[T](resource T) string { - // TODO: Extract metadata.name from resource - return '' -} - -fn get_namespace[T](resource T) string { - // TODO: Extract metadata.namespace from resource - return 'default' -} \ No newline at end of file diff --git a/lib/virt/kubernetes_notgood/kubernetes_config.v b/lib/virt/kubernetes_notgood/kubernetes_config.v deleted file mode 100644 index ceed0ab1..00000000 --- a/lib/virt/kubernetes_notgood/kubernetes_config.v +++ /dev/null @@ -1,65 +0,0 @@ -module kubernetes - -import incubaid.herolib.core.pathlib -import os - -@[params] -pub struct KubernetesConfig { -pub mut: - name string = 'default' - server string // API server URL (e.g., https://localhost:6443) - certificate_authority string // Path to CA cert - client_certificate string // Path to client cert - client_key string // Path to client key - username string - password string @[secret] - token string @[secret] - insecure_skip_verify bool // Skip TLS verification (not recommended) - namespace string = 'default' - timeout_seconds int = 30 - context_name string = 'default' - cluster_name string = 'default' -} - -pub struct KubernetesContext { -pub mut: - config KubernetesConfig - client &KubernetesClient -} - -// Load kubeconfig from standard location (~/.kube/config) -pub fn load_kubeconfig(name string) !KubernetesConfig { - mut config_path := pathlib.get('~/.kube/config')! - if !config_path.exists() { - return error('kubeconfig not found at ${config_path.path}') - } - - // Parse YAML kubeconfig file - content := config_path.read()! - // TODO: Parse YAML and extract config for specified context - - return KubernetesConfig{name: name} -} - -// Load from in-memory config -pub fn load_config(cfg KubernetesConfig) !KubernetesConfig { - if cfg.server == '' { - return error('server URL must be provided') - } - return cfg -} - -// Validate configuration -pub fn (cfg KubernetesConfig) validate() ! { - if cfg.server == '' { - return error('server URL is required') - } - if !cfg.insecure_skip_verify { - if cfg.certificate_authority == '' { - return error('certificate_authority is required when insecure_skip_verify is false') - } - } - if cfg.token == '' && (cfg.username == '' || cfg.password == '') { - return error('either token or username/password must be provided') - } -} \ No newline at end of file diff --git a/lib/virt/kubernetes_notgood/kubernetes_errors.v b/lib/virt/kubernetes_notgood/kubernetes_errors.v deleted file mode 100644 index 96023bc2..00000000 --- a/lib/virt/kubernetes_notgood/kubernetes_errors.v +++ /dev/null @@ -1,42 +0,0 @@ -module kubernetes - -pub struct KubernetesError { - Error -pub: - code int // HTTP status code - reason string // Kubernetes reason field - message string // Descriptive error message - namespace string - resource string -} - -pub fn (err KubernetesError) msg() string { - return '${err.reason} (${err.code}): ${err.message} in ${err.namespace}/${err.resource}' -} - -pub fn (err KubernetesError) code() int { - return err.code -} - -pub struct ResourceNotFoundError { - Error -pub: - resource_type string - resource_name string - namespace string -} - -pub struct ConnectionError { - Error -pub: - host string - port int - details string -} - -pub struct ValidationError { - Error -pub: - field string - message string -} \ No newline at end of file diff --git a/lib/virt/kubernetes_notgood/kubernetes_factory_.v b/lib/virt/kubernetes_notgood/kubernetes_factory_.v deleted file mode 100644 index 698642b0..00000000 --- a/lib/virt/kubernetes_notgood/kubernetes_factory_.v +++ /dev/null @@ -1,312 +0,0 @@ -module kubernetes - -import incubaid.herolib.core.base -import incubaid.herolib.core.playbook { PlayBook } -import incubaid.herolib.ui.console -import json -import incubaid.herolib.osal.startupmanager -import time - -__global ( - kubernetes_global map[string]&Kubernetes - kubernetes_default string -) - -/////////FACTORY - -@[params] -pub struct ArgsGet { -pub mut: - name string = 'default' - fromdb bool // will load from filesystem - create bool // default will not create if not exist -} - -pub fn new(args ArgsGet) !&Kubernetes { - mut obj := Kubernetes{ - name: args.name - } - set(obj)! - return get(name: args.name)! -} - -pub fn get(args ArgsGet) !&Kubernetes { - mut context := base.context()! - kubernetes_default = args.name - if args.fromdb || args.name !in kubernetes_global { - mut r := context.redis()! - if r.hexists('context:kubernetes', args.name)! { - data := r.hget('context:kubernetes', args.name)! - if data.len == 0 { - print_backtrace() - return error('Kubernetes with name: kubernetes does not exist, prob bug.') - } - mut obj := json.decode(Kubernetes, data)! - set_in_mem(obj)! - } else { - if args.create { - new(args)! - } else { - print_backtrace() - return error("Kubernetes with name 'kubernetes' does not exist") - } - } - return get(name: args.name)! // no longer from db nor create - } - return kubernetes_global[args.name] or { - print_backtrace() - return error('could not get config for kubernetes with name:kubernetes') - } -} - -// register the config for the future -pub fn set(o Kubernetes) ! { - mut o2 := set_in_mem(o)! - kubernetes_default = o2.name - mut context := base.context()! - mut r := context.redis()! - r.hset('context:kubernetes', 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:kubernetes', args.name)! -} - -pub fn delete(args ArgsGet) ! { - mut context := base.context()! - mut r := context.redis()! - r.hdel('context:kubernetes', 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) ![]&Kubernetes { - mut res := []&Kubernetes{} - mut context := base.context()! - if args.fromdb { - // reset what is in mem - kubernetes_global = map[string]&Kubernetes{} - kubernetes_default = '' - } - if args.fromdb { - mut r := context.redis()! - mut l := r.hkeys('context:kubernetes')! - - for name in l { - res << get(name: name, fromdb: true)! - } - return res - } else { - // load from memory - for _, client in kubernetes_global { - res << client - } - } - return res -} - -// only sets in mem, does not set as config -fn set_in_mem(o Kubernetes) !Kubernetes { - mut o2 := obj_init(o)! - kubernetes_global[o2.name] = &o2 - kubernetes_default = o2.name - return o2 -} - -pub fn play(mut plbook PlayBook) ! { - if !plbook.exists(filter: 'kubernetes.') { - return - } - mut install_actions := plbook.find(filter: 'kubernetes.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: 'kubernetes.')! - 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 kubernetes.destroy') - destroy()! - } - if other_action.name == 'install' { - console.print_debug('install action kubernetes.install') - install()! - } - } - if other_action.name in ['start', 'stop', 'restart'] { - mut p := other_action.params - name := p.get('name')! - mut kubernetes_obj := get(name: name)! - console.print_debug('action object:\n${kubernetes_obj}') - if other_action.name == 'start' { - console.print_debug('install action kubernetes.${other_action.name}') - kubernetes_obj.start()! - } - - if other_action.name == 'stop' { - console.print_debug('install action kubernetes.${other_action.name}') - kubernetes_obj.stop()! - } - if other_action.name == 'restart' { - console.print_debug('install action kubernetes.${other_action.name}') - kubernetes_obj.restart()! - } - } - other_action.done = true - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////# LIVE CYCLE MANAGEMENT FOR INSTALLERS /////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// - -fn startupmanager_get(cat startupmanager.StartupManagerType) !startupmanager.StartupManager { - // unknown - // screen - // zinit - // tmux - // systemd - match cat { - .screen { - console.print_debug("installer: kubernetes' startupmanager get screen") - return startupmanager.get(.screen)! - } - .zinit { - console.print_debug("installer: kubernetes' startupmanager get zinit") - return startupmanager.get(.zinit)! - } - .systemd { - console.print_debug("installer: kubernetes' startupmanager get systemd") - return startupmanager.get(.systemd)! - } - else { - console.print_debug("installer: kubernetes' startupmanager get auto") - return startupmanager.get(.auto)! - } - } -} - -// load from disk and make sure is properly intialized -pub fn (mut self Kubernetes) reload() ! { - switch(self.name) - self = obj_init(self)! -} - -pub fn (mut self Kubernetes) start() ! { - switch(self.name) - if self.running()! { - return - } - - console.print_header('installer: kubernetes start') - - if !installed()! { - install()! - } - - configure()! - - start_pre()! - - for zprocess in startupcmd()! { - mut sm := startupmanager_get(zprocess.startuptype)! - - console.print_debug('installer: kubernetes starting with ${zprocess.startuptype}...') - - sm.new(zprocess)! - - sm.start(zprocess.name)! - } - - start_post()! - - for _ in 0 .. 50 { - if self.running()! { - return - } - time.sleep(100 * time.millisecond) - } - return error('kubernetes did not install properly.') -} - -pub fn (mut self Kubernetes) install_start(args InstallArgs) ! { - switch(self.name) - self.install(args)! - self.start()! -} - -pub fn (mut self Kubernetes) stop() ! { - 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 Kubernetes) restart() ! { - switch(self.name) - self.stop()! - self.start()! -} - -pub fn (mut self Kubernetes) running() !bool { - switch(self.name) - - // walk over the generic processes, if not running return - for zprocess in startupcmd()! { - if zprocess.startuptype != .screen { - mut sm := startupmanager_get(zprocess.startuptype)! - r := sm.running(zprocess.name)! - if r == false { - return false - } - } - } - return running()! -} - -@[params] -pub struct InstallArgs { -pub mut: - reset bool -} - -pub fn (mut self Kubernetes) install(args InstallArgs) ! { - switch(self.name) - if args.reset || (!installed()!) { - install()! - } -} - -pub fn (mut self Kubernetes) build() ! { - switch(self.name) - build()! -} - -pub fn (mut self Kubernetes) destroy() ! { - switch(self.name) - self.stop() or {} - destroy()! -} - -// switch instance to be used for kubernetes -pub fn switch(name string) { - kubernetes_default = name -} diff --git a/lib/virt/kubernetes_notgood/kubernetes_model.v b/lib/virt/kubernetes_notgood/kubernetes_model.v deleted file mode 100644 index 9accd75f..00000000 --- a/lib/virt/kubernetes_notgood/kubernetes_model.v +++ /dev/null @@ -1,48 +0,0 @@ -module kubernetes - -import incubaid.herolib.data.paramsparser -import incubaid.herolib.data.encoderhero -import os - -pub const version = '0.0.0' -const singleton = false -const default = true - -// THIS THE THE SOURCE OF THE INFORMATION OF THIS FILE, HERE WE HAVE THE CONFIG OBJECT CONFIGURED AND MODELLED -@[heap] -pub struct Kubernetes { -pub mut: - name string = 'default' - homedir string - configpath string - username string - password string @[secret] - title string - host string - port int -} - -// your checking & initialization code if needed -fn obj_init(mycfg_ Kubernetes) !Kubernetes { - mut mycfg := mycfg_ - // if mycfg.password == '' && mycfg.secret == '' { - // return error('password or secret needs to be filled in for ${mycfg.name}') - //} - return mycfg -} - -// 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) -} - -/////////////NORMALLY NO NEED TO TOUCH - -pub fn heroscript_loads(heroscript string) !Kubernetes { - mut obj := encoderhero.decode[Kubernetes](heroscript)! - return obj -} diff --git a/lib/virt/kubernetes_notgood/kubernetes_models.v b/lib/virt/kubernetes_notgood/kubernetes_models.v deleted file mode 100644 index 5ade719e..00000000 --- a/lib/virt/kubernetes_notgood/kubernetes_models.v +++ /dev/null @@ -1,622 +0,0 @@ -module kubernetes - -import incubaid.herolib.data.ourtime - -// ==================== METADATA ==================== - -@[params] -pub struct ObjectMeta { -pub mut: - name string - namespace string = 'default' - uid string - resource_version string - creation_timestamp ourtime.OurTime - deletion_timestamp ?ourtime.OurTime - labels map[string]string - annotations map[string]string - owner_references []OwnerReference - finalizers []string -} - -pub struct OwnerReference { -pub: - api_version string - kind string - name string - uid string - controller bool -} - -pub struct TypeMeta { -pub: - api_version string = 'v1' - kind string -} - -// ==================== POD ==================== - -@[params] -pub struct Pod { -pub mut: - api_version string = 'v1' - kind string = 'Pod' - metadata ObjectMeta - spec PodSpec - status ?PodStatus -} - -@[params] -pub struct PodSpec { -pub mut: - containers []Container - init_containers []Container - restart_policy string = 'Always' // Always, OnFailure, Never - termination_grace_period_seconds int = 30 - dns_policy string = 'ClusterFirst' - service_account_name string - node_selector map[string]string - tolerations []Toleration - affinity ?Affinity - volumes []Volume - image_pull_secrets []LocalObjectReference -} - -@[params] -pub struct Container { -pub mut: - name string - image string - image_pull_policy string = 'IfNotPresent' - ports []ContainerPort - env []EnvVar - resources ?ResourceRequirements - volume_mounts []VolumeMount - liveness_probe ?Probe - readiness_probe ?Probe - startup_probe ?Probe - security_context ?SecurityContext - stdin bool - tty bool - working_dir string - command []string - args []string -} - -pub struct ContainerPort { -pub mut: - name string - container_port int - host_port ?int - protocol string = 'TCP' // TCP, UDP -} - -@[params] -pub struct EnvVar { -pub: - name string - value ?string - value_from ?EnvVarSource -} - -pub struct EnvVarSource { -pub: - config_map_key_ref ?ConfigMapKeySelector - secret_key_ref ?SecretKeySelector -} - -pub struct ConfigMapKeySelector { -pub: - name string - key string -} - -pub struct SecretKeySelector { -pub: - name string - key string -} - -pub struct VolumeMount { -pub: - name string - mount_path string - read_only bool - sub_path string -} - -pub struct ResourceRequirements { -pub: - limits map[string]string // e.g. {"cpu": "500m", "memory": "512Mi"} - requests map[string]string -} - -pub struct Probe { -pub: - exec ?ExecAction - http_get ?HTTPGetAction - tcp_socket ?TCPSocketAction - initial_delay_seconds int = 0 - timeout_seconds int = 1 - period_seconds int = 10 - success_threshold int = 1 - failure_threshold int = 3 -} - -pub struct ExecAction { -pub: - command []string -} - -pub struct HTTPGetAction { -pub: - path string - port int - scheme string = 'HTTP' -} - -pub struct TCPSocketAction { -pub: - port int -} - -pub struct SecurityContext { -pub: - run_as_user ?int - run_as_group ?int - fs_group ?int - read_only_root_fs bool - allow_privilege_escalation bool -} - -pub struct Toleration { -pub: - key string - operator string // Equal, Exists - value string - effect string // NoSchedule, NoExecute, PreferNoSchedule - toleration_seconds ?int -} - -pub struct Affinity { -pub: - pod_affinity ?PodAffinity - pod_anti_affinity ?PodAntiAffinity - node_affinity ?NodeAffinity -} - -pub struct PodAffinity { -pub: - required_during_scheduling []PodAffinityTerm - preferred_during_scheduling []WeightedPodAffinityTerm -} - -pub struct PodAffinityTerm { -pub: - label_selector map[string]string - topology_key string -} - -pub struct WeightedPodAffinityTerm { -pub: - weight int - pod_affinity_term PodAffinityTerm -} - -pub struct PodAntiAffinity { -pub: - required_during_scheduling []PodAffinityTerm - preferred_during_scheduling []WeightedPodAffinityTerm -} - -pub struct NodeAffinity { -pub: - required_during_scheduling ?NodeSelector - preferred_during_scheduling []PreferredSchedulingTerm -} - -pub struct NodeSelector { -pub: - node_selector_terms []NodeSelectorTerm -} - -pub struct NodeSelectorTerm { -pub: - match_expressions []NodeSelectorRequirement -} - -pub struct NodeSelectorRequirement { -pub: - key string - operator string // In, NotIn, Exists, NotExists, Gt, Lt - values []string -} - -pub struct PreferredSchedulingTerm { -pub: - weight int - preference NodeSelectorTerm -} - -pub struct Volume { -pub mut: - name string - empty_dir ?EmptyDirVolumeSource - config_map ?ConfigMapVolumeSource - secret ?SecretVolumeSource - persistent_volume_claim ?PersistentVolumeClaimVolumeSource - host_path ?HostPathVolumeSource -} - -pub struct EmptyDirVolumeSource { -pub: - medium string - size_limit string -} - -pub struct ConfigMapVolumeSource { -pub: - name string - default_mode int - items []KeyToPath -} - -pub struct SecretVolumeSource { -pub: - secret_name string - default_mode int - items []KeyToPath -} - -pub struct KeyToPath { -pub: - key string - path string - mode int -} - -pub struct PersistentVolumeClaimVolumeSource { -pub: - claim_name string - read_only bool -} - -pub struct HostPathVolumeSource { -pub: - path string - type string // Directory, File, Socket, CharDevice, BlockDevice -} - -pub struct LocalObjectReference { -pub: - name string -} - -pub struct PodStatus { -pub: - phase string // Pending, Running, Succeeded, Failed, Unknown - conditions []PodCondition - host_ip string - pod_ip string - container_statuses []ContainerStatus -} - -pub struct PodCondition { -pub: - type_ string // Initialized, Ready, ContainersReady, PodScheduled - status string // True, False, Unknown - reason string - message string - last_probe_time ourtime.OurTime - last_transition_time ourtime.OurTime -} - -pub struct ContainerStatus { -pub: - name string - state ContainerState - ready bool - restart_count int - image string - image_id string -} - -pub struct ContainerState { -pub: - waiting ?ContainerStateWaiting - running ?ContainerStateRunning - terminated ?ContainerStateTerminated -} - -pub struct ContainerStateWaiting { -pub: - reason string - message string -} - -pub struct ContainerStateRunning { -pub: - started_at ourtime.OurTime -} - -pub struct ContainerStateTerminated { -pub: - exit_code int - signal int - reason string - message string - started_at ourtime.OurTime - finished_at ourtime.OurTime - container_id string -} - -// ==================== DEPLOYMENT ==================== - -@[params] -pub struct Deployment { -pub mut: - api_version string = 'apps/v1' - kind string = 'Deployment' - metadata ObjectMeta - spec DeploymentSpec - status ?DeploymentStatus -} - -@[params] -pub struct DeploymentSpec { -pub mut: - replicas int = 1 - selector ?LabelSelector - template PodTemplateSpec - strategy ?DeploymentStrategy - min_ready_seconds int - revision_history_limit int - paused bool - progress_deadline_seconds int -} - -pub struct PodTemplateSpec { -pub: - metadata ObjectMeta - spec PodSpec -} - -pub struct LabelSelector { -pub: - match_labels map[string]string - match_expressions []LabelSelectorRequirement -} - -pub struct LabelSelectorRequirement { -pub: - key string - operator string // In, NotIn, Exists, DoesNotExist - values []string -} - -pub struct DeploymentStrategy { -pub: - type_ string // RollingUpdate, Recreate - rolling_update ?RollingUpdateDeploymentStrategy -} - -pub struct RollingUpdateDeploymentStrategy { -pub: - max_surge string - max_unavailable string -} - -pub struct DeploymentStatus { -pub: - observed_generation int - replicas int - updated_replicas int - ready_replicas int - available_replicas int - unavailable_replicas int - conditions []DeploymentCondition -} - -pub struct DeploymentCondition { -pub: - type_ string // Progressing, Available, ReplicaFailure - status string // True, False, Unknown - reason string - message string - last_update_time ourtime.OurTime - last_transition_time ourtime.OurTime -} - -// ==================== SERVICE ==================== - -@[params] -pub struct Service { -pub mut: - api_version string = 'v1' - kind string = 'Service' - metadata ObjectMeta - spec ServiceSpec - status ?ServiceStatus -} - -@[params] -pub struct ServiceSpec { -pub mut: - service_type string = 'ClusterIP' // ClusterIP, NodePort, LoadBalancer, ExternalName - selector map[string]string - ports []ServicePort - cluster_ip string - external_ips []string - load_balancer_ip string - external_name string - session_affinity string // None, ClientIP - session_affinity_timeout int -} - -pub struct ServicePort { -pub: - name string - protocol string = 'TCP' - port int - target_port string // can be int or string - node_port ?int -} - -pub struct ServiceStatus { -pub: - load_balancer ?LoadBalancerStatus -} - -pub struct LoadBalancerStatus { -pub: - ingress []LoadBalancerIngress -} - -pub struct LoadBalancerIngress { -pub: - ip string - hostname string -} - -// ==================== CONFIGMAP ==================== - -@[params] -pub struct ConfigMap { -pub mut: - api_version string = 'v1' - kind string = 'ConfigMap' - metadata ObjectMeta - data map[string]string - binary_data map[string][]u8 -} - -// ==================== SECRET ==================== - -@[params] -pub struct Secret { -pub mut: - api_version string = 'v1' - kind string = 'Secret' - metadata ObjectMeta - type_ string = 'Opaque' // Opaque, kubernetes.io/service-account-token, etc. - data map[string][]u8 - string_data map[string]string -} - -// ==================== NAMESPACE ==================== - -@[params] -pub struct Namespace { -pub mut: - api_version string = 'v1' - kind string = 'Namespace' - metadata ObjectMeta - spec NamespaceSpec - status ?NamespaceStatus -} - -pub struct NamespaceSpec { -pub: - finalizers []string -} - -pub struct NamespaceStatus { -pub: - phase string // Active, Terminating -} - -// ==================== PERSISTENT VOLUME CLAIM ==================== - -@[params] -pub struct PersistentVolumeClaim { -pub mut: - api_version string = 'v1' - kind string = 'PersistentVolumeClaim' - metadata ObjectMeta - spec PersistentVolumeClaimSpec - status ?PersistentVolumeClaimStatus -} - -@[params] -pub struct PersistentVolumeClaimSpec { -pub mut: - access_modes []string // ReadWriteOnce, ReadOnlyMany, ReadWriteMany - resources ResourceRequirements - storage_class_name string - selector ?LabelSelector - volume_name string -} - -pub struct PersistentVolumeClaimStatus { -pub: - phase string // Pending, Bound, Lost - access_modes []string - capacity map[string]string -} - -// ==================== INGRESS ==================== - -@[params] -pub struct Ingress { -pub mut: - api_version string = 'networking.k8s.io/v1' - kind string = 'Ingress' - metadata ObjectMeta - spec IngressSpec - status ?IngressStatus -} - -@[params] -pub struct IngressSpec { -pub mut: - ingress_class_name string - rules []IngressRule - tls []IngressTLS - default_backend ?IngressBackend -} - -pub struct IngressRule { -pub: - host string - http ?HTTPIngressRuleValue -} - -pub struct HTTPIngressRuleValue { -pub: - paths []HTTPIngressPath -} - -pub struct HTTPIngressPath { -pub: - path string - path_type string // Exact, Prefix - backend IngressBackend -} - -pub struct IngressBackend { -pub: - service ?IngressServiceBackend -} - -pub struct IngressServiceBackend { -pub: - name string - port IngressServiceBackendPort -} - -pub struct IngressServiceBackendPort { -pub: - number int - name string -} - -pub struct IngressTLS { -pub: - hosts []string - secret_name string -} - -pub struct IngressStatus { -pub: - load_balancer LoadBalancerStatus -} \ No newline at end of file diff --git a/lib/virt/kubernetes_notgood/kubernetes_yaml.v b/lib/virt/kubernetes_notgood/kubernetes_yaml.v deleted file mode 100644 index c89dd944..00000000 --- a/lib/virt/kubernetes_notgood/kubernetes_yaml.v +++ /dev/null @@ -1,53 +0,0 @@ -module kubernetes - -import encoding.yaml - -// Serialize Kubernetes resource to YAML -pub fn to_yaml[T](resource T) !string { - // TODO: Use V's YAML encoding to serialize - return encode_to_yaml(resource)! -} - -// Deserialize YAML to Kubernetes resource -pub fn from_yaml[T](content string) !T { - // TODO: Use V's YAML decoding to parse - return decode_from_yaml[T](content)! -} - -// Helper to handle YAML document conversion -fn encode_to_yaml[T](resource T) !string { - return yaml.encode(resource)! -} - -fn decode_from_yaml[T](content string) !T { - return yaml.decode[T](content)! -} - -// Multi-document YAML support -pub fn to_yaml_multi[T](resources []T) !string { - mut result := '' - for i, resource in resources { - result += '---\n' - result += to_yaml(resource)! - if i < resources.len - 1 { - result += '\n' - } - } - return result -} - -pub fn from_yaml_multi[T](content string) ![]T { - mut result := []T{} - docs := content.split('---') - - for doc in docs { - trimmed := doc.trim_space() - if trimmed.len == 0 { - continue - } - resource := from_yaml[T](trimmed)! - result << resource - } - - return result -} \ No newline at end of file diff --git a/lib/virt/kubernetes_notgood/readme.md b/lib/virt/kubernetes_notgood/readme.md deleted file mode 100644 index 4bad7995..00000000 --- a/lib/virt/kubernetes_notgood/readme.md +++ /dev/null @@ -1,44 +0,0 @@ -# kubernetes - - - -To get started - -```v - - -import incubaid.herolib.installers.something.kubernetes as kubernetes_installer - -heroscript:=" -!!kubernetes.configure name:'test' - password: '1234' - port: 7701 - -!!kubernetes.start name:'test' reset:1 -" - -kubernetes_installer.play(heroscript=heroscript)! - -//or we can call the default and do a start with reset -//mut installer:= kubernetes_installer.get()! -//installer.start(reset:true)! - - - - -``` - -## example heroscript - - -```hero -!!kubernetes.configure - homedir: '/home/user/kubernetes' - username: 'admin' - password: 'secretpassword' - title: 'Some Title' - host: 'localhost' - port: 8888 - -``` - diff --git a/lib/virt/kubernetes_notgood/templates/atemplate.yaml b/lib/virt/kubernetes_notgood/templates/atemplate.yaml deleted file mode 100644 index a4c386dd..00000000 --- a/lib/virt/kubernetes_notgood/templates/atemplate.yaml +++ /dev/null @@ -1,5 +0,0 @@ - - -name: ${cfg.configpath} - - diff --git a/lib/virt/kubernetes_notgood/templates/configmap.yaml b/lib/virt/kubernetes_notgood/templates/configmap.yaml deleted file mode 100644 index 8ceb5104..00000000 --- a/lib/virt/kubernetes_notgood/templates/configmap.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{.Name}} - namespace: {{.Namespace}} -data: - {{.Key}}: {{.Value}} \ No newline at end of file diff --git a/lib/virt/kubernetes_notgood/templates/deployment.yaml b/lib/virt/kubernetes_notgood/templates/deployment.yaml deleted file mode 100644 index 55383b73..00000000 --- a/lib/virt/kubernetes_notgood/templates/deployment.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{.Name}} - namespace: {{.Namespace}} - labels: - app: {{.AppLabel}} -spec: - replicas: {{.Replicas}} - selector: - matchLabels: - app: {{.AppLabel}} - template: - metadata: - labels: - app: {{.AppLabel}} - spec: - containers: - - name: {{.ContainerName}} - image: {{.Image}} - ports: - - containerPort: {{.ContainerPort}} \ No newline at end of file diff --git a/lib/virt/kubernetes_notgood/templates/namespace.yaml b/lib/virt/kubernetes_notgood/templates/namespace.yaml deleted file mode 100644 index 296ef8d6..00000000 --- a/lib/virt/kubernetes_notgood/templates/namespace.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: {{.Name}} \ No newline at end of file diff --git a/lib/virt/kubernetes_notgood/templates/pod.yaml b/lib/virt/kubernetes_notgood/templates/pod.yaml deleted file mode 100644 index beb5a4ab..00000000 --- a/lib/virt/kubernetes_notgood/templates/pod.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: {{.Name}} - namespace: {{.Namespace}} - labels: - app: {{.AppLabel}} -spec: - containers: - - name: {{.ContainerName}} - image: {{.Image}} - ports: - - containerPort: {{.ContainerPort}} \ No newline at end of file diff --git a/lib/virt/kubernetes_notgood/templates/service.yaml b/lib/virt/kubernetes_notgood/templates/service.yaml deleted file mode 100644 index c9a4be00..00000000 --- a/lib/virt/kubernetes_notgood/templates/service.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{.Name}} - namespace: {{.Namespace}} - labels: - app: {{.AppLabel}} -spec: - selector: - app: {{.AppLabel}} - ports: - - protocol: TCP - port: {{.Port}} - targetPort: {{.TargetPort}} - type: {{.ServiceType}} \ No newline at end of file diff --git a/lib/virt/kubernetes_notgood/test/kubernetes_test.v b/lib/virt/kubernetes_notgood/test/kubernetes_test.v deleted file mode 100644 index 97023bcc..00000000 --- a/lib/virt/kubernetes_notgood/test/kubernetes_test.v +++ /dev/null @@ -1,213 +0,0 @@ -module kubernetes - -import os -import json -import net.http -import incubaid.herolib.core.pathlib -import incubaid.herolib.core.httpconnection -import incubaid.herolib.lib.virt.kubernetes -import incubaid.herolib.lib.virt.kubernetes.kubernetes_models as km -import incubaid.herolib.lib.virt.kubernetes.kubernetes_errors as ke -import incubaid.herolib.lib.virt.kubernetes.kubernetes_yaml as ky -import incubaid.herolib.lib.virt.kubernetes.kubernetes_config as kc -import incubaid.herolib.lib.virt.kubernetes.kubernetes_client as kcl -import incubaid.herolib.lib.virt.kubernetes.kubernetes_actions as ka - -// Mock HTTPConnection for testing -struct MockHTTPConnection { - httpconnection.HTTPConnection -pub mut: - mock_responses map[string]string // path -> json_response - mock_status_codes map[string]int // path -> status_code -} - -fn (mut m MockHTTPConnection) get_json_generic[T](prefix string, params map[string]string) !T { - if prefix in m.mock_responses { - return json.decode[T](m.mock_responses[prefix])! - } - return error('No mock response for GET ${prefix}') -} - -fn (mut m MockHTTPConnection) post_json_generic[T](prefix string, params json.Any, header http.Header) !T { - if prefix in m.mock_responses { - return json.decode[T](m.mock_responses[prefix])! - } - return error('No mock response for POST ${prefix}') -} - -fn (mut m MockHTTPConnection) put_json_generic[T](prefix string, params json.Any, header http.Header) !T { - if prefix in m.mock_responses { - return json.decode[T](m.mock_responses[prefix])! - } - return error('No mock response for PUT ${prefix}') -} - -fn (mut m MockHTTPConnection) patch_json_generic[T](prefix string, params map[string]interface{}, header http.Header) !T { - if prefix in m.mock_responses { - return json.decode[T](m.mock_responses[prefix])! - } - return error('No mock response for PATCH ${prefix}') -} - -fn (mut m MockHTTPConnection) delete(prefix string, params map[string]string) ! { - if prefix in m.mock_responses { - return - } - return error('No mock response for DELETE ${prefix}') -} - -fn (mut m MockHTTPConnection) get_text(prefix string, params map[string]string) !string { - if prefix in m.mock_responses { - return m.mock_responses[prefix] - } - return error('No mock response for GET text ${prefix}') -} - -// Helper to create a mock client -fn create_mock_client(mock_responses map[string]string) !&kcl.KubernetesClient { - mut config := kc.KubernetesConfig{ - server: 'http://mock-server' - insecure_skip_verify: true - token: 'mock-token' - } - mut client := kcl.new(config)! - client.http_conn = &MockHTTPConnection{ - mock_responses: mock_responses - } - return client -} - -// Test cases for kubernetes_errors.v -fn test_kubernetes_error() { - err := ke.KubernetesError{ - code: 404 - reason: 'NotFound' - message: 'Pod not found' - namespace: 'default' - resource: 'my-pod' - } - assert err.msg() == 'NotFound (404): Pod not found in default/my-pod' - assert err.code() == 404 -} - -fn test_resource_not_found_error() { - err := ke.ResourceNotFoundError{ - resource_type: 'Pod' - resource_name: 'non-existent-pod' - namespace: 'test-ns' - } - assert err.resource_type == 'Pod' - assert err.resource_name == 'non-existent-pod' - assert err.namespace == 'test-ns' -} - -// Test cases for kubernetes_models.v (basic serialization/deserialization) -fn test_pod_model_yaml_serialization() { - mut pod := km.Pod{ - metadata: km.ObjectMeta{ - name: 'test-pod' - namespace: 'default' - } - spec: km.PodSpec{ - containers: [ - km.Container{ - name: 'test-container' - image: 'nginx:latest' - ports: [km.ContainerPort{ container_port: 80 }] - } - ] - } - } - - yaml_str := ky.to_yaml(pod)! - assert yaml_str.contains('name: test-pod') - assert yaml_str.contains('image: nginx:latest') - - decoded_pod := ky.from_yaml[km.Pod](yaml_str)! - assert decoded_pod.metadata.name == 'test-pod' - assert decoded_pod.spec.containers[0].image == 'nginx:latest' -} - -// Test cases for kubernetes_config.v -fn test_config_validation() { - // Valid config - cfg := kc.KubernetesConfig{ - server: 'https://localhost:6443' - token: 'test-token' - insecure_skip_verify: true - } - cfg.validate()! - - // Invalid config (missing server) - mut invalid_cfg := kc.KubernetesConfig{ - token: 'test-token' - } - assert invalid_cfg.validate() is error - - // Invalid config (missing auth) - mut invalid_cfg2 := kc.KubernetesConfig{ - server: 'https://localhost:6443' - } - assert invalid_cfg2.validate() is error -} - -// Test cases for kubernetes_client.v -fn test_client_get_pod() { - mock_responses := { - '/api/v1/namespaces/default/pods/my-pod': '{ "kind": "Pod", "apiVersion": "v1", "metadata": { "name": "my-pod", "namespace": "default" }, "spec": {}, "status": {} }' - } - mut client := create_mock_client(mock_responses)! - - pod := client.get[km.Pod]( - resource_type: 'pods' - name: 'my-pod' - namespace: 'default' - )! - assert pod.metadata.name == 'my-pod' -} - -fn test_client_list_deployments() { - mock_responses := { - '/apis/apps/v1/namespaces/default/deployments': '{ "kind": "DeploymentList", "apiVersion": "apps/v1", "items": [ { "kind": "Deployment", "apiVersion": "apps/v1", "metadata": { "name": "dep1" }, "spec": {}, "status": {} } ] }' - } - mut client := create_mock_client(mock_responses)! - - // This test will currently fail because the list function in kubernetes_client.v - // returns an empty array. The TODO needs to be implemented. - // deployments := client.list[km.Deployment]( - // resource_type: 'deployments' - // namespace: 'default' - // )! - // assert deployments.len == 1 - // assert deployments[0].metadata.name == 'dep1' -} - -// Test cases for kubernetes_actions.v -fn test_deploy_new_deployment() { - mock_responses := { - '/apis/apps/v1/namespaces/default/deployments/new-dep': '{ "kind": "Deployment", "apiVersion": "apps/v1", "metadata": { "name": "new-dep", "namespace": "default", "resourceVersion": "1" }, "spec": { "replicas": 1 }, "status": { "observedGeneration": 1, "updatedReplicas": 1, "readyReplicas": 1 } }', - '/apis/apps/v1/namespaces/default/deployments': '{ "kind": "DeploymentList", "apiVersion": "apps/v1", "items": [] }' // No existing deployment - } - mut client := create_mock_client(mock_responses)! - - mut deployment := km.Deployment{ - metadata: km.ObjectMeta{ - name: 'new-dep' - namespace: 'default' - } - spec: km.DeploymentSpec{ - replicas: 1 - template: km.PodTemplateSpec{ - spec: km.PodSpec{ - containers: [km.Container{ name: 'app', image: 'img' }] - } - } - } - } - - // This test will currently fail because the deploy function in kubernetes_actions.v - // calls client.get which is mocked to return none, but the match statement expects Deployment. - // Also, the wait_for_deployment_ready will loop indefinitely without proper mock for get. - // deployed := client.deploy(deployment: deployment, wait: false)! - // assert deployed.metadata.name == 'new-dep' -} \ No newline at end of file diff --git a/lib/virt/kubernetes_notgood/test/models_test.v b/lib/virt/kubernetes_notgood/test/models_test.v deleted file mode 100644 index 7ea11616..00000000 --- a/lib/virt/kubernetes_notgood/test/models_test.v +++ /dev/null @@ -1,295 +0,0 @@ -module kubernetes - -import incubaid.herolib.lib.virt.kubernetes.kubernetes_models as km -import incubaid.herolib.lib.virt.kubernetes.kubernetes_yaml as ky -import incubaid.herolib.data.ourtime - -fn test_object_meta_serialization() { - mut meta := km.ObjectMeta{ - name: 'my-object' - namespace: 'default' - labels: { - 'app': 'test' - 'env': 'dev' - } - annotations: { - 'note': 'some annotation' - } - } - - yaml_str := ky.to_yaml(meta)! - assert yaml_str.contains('name: my-object') - assert yaml_str.contains('namespace: default') - assert yaml_str.contains('app: test') - assert yaml_str.contains('note: some annotation') - - decoded_meta := ky.from_yaml[km.ObjectMeta](yaml_str)! - assert decoded_meta.name == 'my-object' - assert decoded_meta.namespace == 'default' - assert decoded_meta.labels['app'] == 'test' - assert decoded_meta.annotations['note'] == 'some annotation' -} - -fn test_pod_full_serialization() { - mut pod := km.Pod{ - metadata: km.ObjectMeta{ - name: 'full-pod' - namespace: 'test-ns' - labels: { 'run': 'full-pod' } - } - spec: km.PodSpec{ - containers: [ - km.Container{ - name: 'main-container' - image: 'ubuntu:latest' - ports: [km.ContainerPort{ container_port: 8080, protocol: 'TCP' }] - env: [ - km.EnvVar{ name: 'ENV_VAR_1', value: 'value1' }, - km.EnvVar{ name: 'ENV_VAR_2', value_from: km.EnvVarSource{ config_map_key_ref: km.ConfigMapKeySelector{ name: 'my-config', key: 'key1' } } } - ] - resources: km.ResourceRequirements{ - limits: { 'cpu': '100m', 'memory': '128Mi' } - requests: { 'cpu': '50m', 'memory': '64Mi' } - } - liveness_probe: km.Probe{ - http_get: km.HTTPGetAction{ path: '/healthz', port: 8080 } - initial_delay_seconds: 5 - } - } - ] - volumes: [ - km.Volume{ - name: 'config-volume' - config_map: km.ConfigMapVolumeSource{ - name: 'my-config' - items: [km.KeyToPath{ key: 'config.txt', path: 'config.txt' }] - } - } - ] - } - } - - yaml_str := ky.to_yaml(pod)! - assert yaml_str.contains('name: full-pod') - assert yaml_str.contains('image: ubuntu:latest') - assert yaml_str.contains('containerPort: 8080') - assert yaml_str.contains('ENV_VAR_1') - assert yaml_str.contains('cpu: 100m') - assert yaml_str.contains('path: /healthz') - assert yaml_str.contains('name: config-volume') - - decoded_pod := ky.from_yaml[km.Pod](yaml_str)! - assert decoded_pod.metadata.name == 'full-pod' - assert decoded_pod.spec.containers[0].name == 'main-container' - assert decoded_pod.spec.containers[0].env[0].name == 'ENV_VAR_1' - assert decoded_pod.spec.containers[0].resources!.limits['cpu'] == '100m' - assert decoded_pod.spec.volumes[0].name == 'config-volume' -} - -fn test_deployment_serialization() { - mut deployment := km.Deployment{ - metadata: km.ObjectMeta{ - name: 'my-deployment' - namespace: 'default' - } - spec: km.DeploymentSpec{ - replicas: 3 - selector: km.LabelSelector{ - match_labels: { 'app': 'my-app' } - } - template: km.PodTemplateSpec{ - metadata: km.ObjectMeta{ - labels: { 'app': 'my-app' } - } - spec: km.PodSpec{ - containers: [ - km.Container{ - name: 'web' - image: 'my-image:1.0' - } - ] - } - } - } - } - - yaml_str := ky.to_yaml(deployment)! - assert yaml_str.contains('name: my-deployment') - assert yaml_str.contains('replicas: 3') - assert yaml_str.contains('app: my-app') - assert yaml_str.contains('image: my-image:1.0') - - decoded_deployment := ky.from_yaml[km.Deployment](yaml_str)! - assert decoded_deployment.metadata.name == 'my-deployment' - assert decoded_deployment.spec.replicas == 3 - assert decoded_deployment.spec.selector!.match_labels['app'] == 'my-app' -} - -fn test_service_serialization() { - mut service := km.Service{ - metadata: km.ObjectMeta{ - name: 'my-service' - namespace: 'default' - } - spec: km.ServiceSpec{ - service_type: 'NodePort' - selector: { 'app': 'my-app' } - ports: [ - km.ServicePort{ - port: 80 - target_port: '8080' - node_port: 30000 - } - ] - } - } - - yaml_str := ky.to_yaml(service)! - assert yaml_str.contains('name: my-service') - assert yaml_str.contains('type: NodePort') - assert yaml_str.contains('port: 80') - assert yaml_str.contains('targetPort: "8080"') - assert yaml_str.contains('nodePort: 30000') - - decoded_service := ky.from_yaml[km.Service](yaml_str)! - assert decoded_service.metadata.name == 'my-service' - assert decoded_service.spec.service_type == 'NodePort' - assert decoded_service.spec.ports[0].port == 80 - assert decoded_service.spec.ports[0].target_port == '8080' - assert decoded_service.spec.ports[0].node_port == 30000 -} - -fn test_configmap_serialization() { - mut configmap := km.ConfigMap{ - metadata: km.ObjectMeta{ - name: 'my-configmap' - namespace: 'default' - } - data: { - 'key1': 'value1' - 'key2': 'value2' - } - } - - yaml_str := ky.to_yaml(configmap)! - assert yaml_str.contains('name: my-configmap') - assert yaml_str.contains('key1: value1') - - decoded_configmap := ky.from_yaml[km.ConfigMap](yaml_str)! - assert decoded_configmap.metadata.name == 'my-configmap' - assert decoded_configmap.data['key1'] == 'value1' -} - -fn test_secret_serialization() { - mut secret := km.Secret{ - metadata: km.ObjectMeta{ - name: 'my-secret' - namespace: 'default' - } - string_data: { - 'username': 'admin' - 'password': 'password123' - } - } - - yaml_str := ky.to_yaml(secret)! - assert yaml_str.contains('name: my-secret') - assert yaml_str.contains('username: admin') - - decoded_secret := ky.from_yaml[km.Secret](yaml_str)! - assert decoded_secret.metadata.name == 'my-secret' - assert decoded_secret.string_data['username'] == 'admin' -} - -fn test_namespace_serialization() { - mut namespace := km.Namespace{ - metadata: km.ObjectMeta{ - name: 'my-namespace' - } - } - - yaml_str := ky.to_yaml(namespace)! - assert yaml_str.contains('name: my-namespace') - - decoded_namespace := ky.from_yaml[km.Namespace](yaml_str)! - assert decoded_namespace.metadata.name == 'my-namespace' -} - -fn test_persistent_volume_claim_serialization() { - mut pvc := km.PersistentVolumeClaim{ - metadata: km.ObjectMeta{ - name: 'my-pvc' - namespace: 'default' - } - spec: km.PersistentVolumeClaimSpec{ - access_modes: ['ReadWriteOnce'] - resources: km.ResourceRequirements{ - requests: { 'storage': '1Gi' } - } - storage_class_name: 'standard' - } - } - - yaml_str := ky.to_yaml(pvc)! - assert yaml_str.contains('name: my-pvc') - assert yaml_str.contains('accessModes:') - assert yaml_str.contains('- ReadWriteOnce') - assert yaml_str.contains('storage: 1Gi') - - decoded_pvc := ky.from_yaml[km.PersistentVolumeClaim](yaml_str)! - assert decoded_pvc.metadata.name == 'my-pvc' - assert decoded_pvc.spec.access_modes[0] == 'ReadWriteOnce' - assert decoded_pvc.spec.resources.requests['storage'] == '1Gi' -} - -fn test_ingress_serialization() { - mut ingress := km.Ingress{ - metadata: km.ObjectMeta{ - name: 'my-ingress' - namespace: 'default' - } - spec: km.IngressSpec{ - ingress_class_name: 'nginx' - rules: [ - km.IngressRule{ - host: 'example.com' - http: km.HTTPIngressRuleValue{ - paths: [ - km.HTTPIngressPath{ - path: '/' - path_type: 'Prefix' - backend: km.IngressBackend{ - service: km.IngressServiceBackend{ - name: 'my-service' - port: km.IngressServiceBackendPort{ number: 80 } - } - } - } - ] - } - } - ] - tls: [ - km.IngressTLS{ - hosts: ['example.com'] - secret_name: 'example-tls' - } - ] - } - } - - yaml_str := ky.to_yaml(ingress)! - assert yaml_str.contains('name: my-ingress') - assert yaml_str.contains('host: example.com') - assert yaml_str.contains('path: /') - assert yaml_str.contains('service:') - assert yaml_str.contains('name: my-service') - assert yaml_str.contains('number: 80') - assert yaml_str.contains('secretName: example-tls') - - decoded_ingress := ky.from_yaml[km.Ingress](yaml_str)! - assert decoded_ingress.metadata.name == 'my-ingress' - assert decoded_ingress.spec.rules[0].host == 'example.com' - assert decoded_ingress.spec.rules[0].http!.paths[0].backend.service!.name == 'my-service' - assert decoded_ingress.spec.tls[0].secret_name == 'example-tls' -} \ No newline at end of file