This commit is contained in:
2025-10-21 09:46:06 +02:00
parent 67d13d081b
commit 12c6aabed5
5 changed files with 275 additions and 237 deletions

View File

@@ -8,7 +8,7 @@ import incubaid.herolib.osal.startupmanager
import time
__global (
kubernetes_global map[string]&Kubernetes
kubernetes_global map[string]&KubeClient
kubernetes_default string
)
@@ -22,15 +22,15 @@ pub mut:
create bool // default will not create if not exist
}
pub fn new(args ArgsGet) !&Kubernetes {
mut obj := Kubernetes{
pub fn new(args ArgsGet) !&KubeClient {
mut obj := KubeClient{
name: args.name
}
set(obj)!
return get(name: args.name)!
}
pub fn get(args ArgsGet) !&Kubernetes {
pub fn get(args ArgsGet) !&KubeClient {
mut context := base.context()!
kubernetes_default = args.name
if args.fromdb || args.name !in kubernetes_global {
@@ -39,16 +39,16 @@ pub fn get(args ArgsGet) !&Kubernetes {
data := r.hget('context:kubernetes', args.name)!
if data.len == 0 {
print_backtrace()
return error('Kubernetes with name: kubernetes does not exist, prob bug.')
return error('KubeClient with name: kubernetes does not exist, prob bug.')
}
mut obj := json.decode(Kubernetes, data)!
mut obj := json.decode(KubeClient, data)!
set_in_mem(obj)!
} else {
if args.create {
new(args)!
} else {
print_backtrace()
return error("Kubernetes with name 'kubernetes' does not exist")
return error("KubeClient with name 'kubernetes' does not exist")
}
}
return get(name: args.name)! // no longer from db nor create
@@ -60,7 +60,7 @@ pub fn get(args ArgsGet) !&Kubernetes {
}
// register the config for the future
pub fn set(o Kubernetes) ! {
pub fn set(o KubeClient) ! {
mut o2 := set_in_mem(o)!
kubernetes_default = o2.name
mut context := base.context()!
@@ -88,12 +88,12 @@ pub mut:
}
// 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{}
pub fn list(args ArgsList) ![]&KubeClient {
mut res := []&KubeClient{}
mut context := base.context()!
if args.fromdb {
// reset what is in mem
kubernetes_global = map[string]&Kubernetes{}
kubernetes_global = map[string]&KubeClient{}
kubernetes_default = ''
}
if args.fromdb {
@@ -114,7 +114,7 @@ pub fn list(args ArgsList) ![]&Kubernetes {
}
// only sets in mem, does not set as config
fn set_in_mem(o Kubernetes) !Kubernetes {
fn set_in_mem(o KubeClient) !KubeClient {
mut o2 := obj_init(o)!
kubernetes_global[o2.name] = &o2
kubernetes_default = o2.name
@@ -202,12 +202,12 @@ fn startupmanager_get(cat startupmanager.StartupManagerType) !startupmanager.Sta
}
// load from disk and make sure is properly intialized
pub fn (mut self Kubernetes) reload() ! {
pub fn (mut self KubeClient) reload() ! {
switch(self.name)
self = obj_init(self)!
}
pub fn (mut self Kubernetes) start() ! {
pub fn (mut self KubeClient) start() ! {
switch(self.name)
if self.running()! {
return
@@ -244,13 +244,13 @@ pub fn (mut self Kubernetes) start() ! {
return error('kubernetes did not install properly.')
}
pub fn (mut self Kubernetes) install_start(args InstallArgs) ! {
pub fn (mut self KubeClient) install_start(args InstallArgs) ! {
switch(self.name)
self.install(args)!
self.start()!
}
pub fn (mut self Kubernetes) stop() ! {
pub fn (mut self KubeClient) stop() ! {
switch(self.name)
stop_pre()!
for zprocess in startupcmd()! {
@@ -260,13 +260,13 @@ pub fn (mut self Kubernetes) stop() ! {
stop_post()!
}
pub fn (mut self Kubernetes) restart() ! {
pub fn (mut self KubeClient) restart() ! {
switch(self.name)
self.stop()!
self.start()!
}
pub fn (mut self Kubernetes) running() !bool {
pub fn (mut self KubeClient) running() !bool {
switch(self.name)
// walk over the generic processes, if not running return
@@ -288,19 +288,19 @@ pub mut:
reset bool
}
pub fn (mut self Kubernetes) install(args InstallArgs) ! {
pub fn (mut self KubeClient) install(args InstallArgs) ! {
switch(self.name)
if args.reset || (!installed()!) {
install()!
}
}
pub fn (mut self Kubernetes) build() ! {
pub fn (mut self KubeClient) build() ! {
switch(self.name)
build()!
}
pub fn (mut self Kubernetes) destroy() ! {
pub fn (mut self KubeClient) destroy() ! {
switch(self.name)
self.stop() or {}
destroy()!

View File

@@ -2,173 +2,16 @@ module kubernetes
import incubaid.herolib.data.paramsparser
import incubaid.herolib.data.encoderhero
import incubaid.herolib.data.ourjson
import os
pub const version = '1.0.0'
pub const version = '0.0.0'
const singleton = false
const default = true
// K8s API Version and Kind tracking
@[params]
pub struct K8sMetadata {
pub mut:
name string
namespace string = 'default'
labels map[string]string
annotations map[string]string
owner_reference string
}
// Pod Specification
@[params]
pub struct ContainerSpec {
pub mut:
name string
image string
image_pull_policy string = 'IfNotPresent'
ports []ContainerPort
env []EnvVar
resources ResourceRequirements
volume_mounts []VolumeMount
command []string
args []string
}
@[params]
pub struct ContainerPort {
pub mut:
name string
container_port int
protocol string = 'TCP'
host_port int
}
@[params]
pub struct EnvVar {
pub mut:
name string
value string
}
@[params]
pub struct ResourceRequirements {
pub mut:
requests map[string]string // cpu, memory
limits map[string]string
}
@[params]
pub struct VolumeMount {
pub mut:
name string
mount_path string
read_only bool
}
@[params]
pub struct PodSpec {
pub mut:
metadata K8sMetadata
containers []ContainerSpec
restart_policy string = 'Always'
service_account string
volumes []Volume
}
@[params]
pub struct Volume {
pub mut:
name string
config_map string
secret string
empty_dir bool
}
// Deployment Specification
@[params]
pub struct DeploymentSpec {
pub mut:
metadata K8sMetadata
replicas int = 1
selector map[string]string
template PodSpec
strategy DeploymentStrategy
progress_deadline_seconds int = 600
}
@[params]
pub struct DeploymentStrategy {
pub mut:
strategy_type string = 'RollingUpdate'
rolling_update RollingUpdateStrategy
}
@[params]
pub struct RollingUpdateStrategy {
pub mut:
max_surge string = '25%'
max_unavailable string = '25%'
}
// Service Specification
@[params]
pub struct ServiceSpec {
pub mut:
metadata K8sMetadata
service_type string = 'ClusterIP' // ClusterIP, NodePort, LoadBalancer
selector map[string]string
ports []ServicePort
cluster_ip string
external_ips []string
session_affinity string
}
@[params]
pub struct ServicePort {
pub mut:
name string
protocol string = 'TCP'
port int
target_port int
node_port int
}
// ConfigMap
@[params]
pub struct ConfigMapSpec {
pub mut:
metadata K8sMetadata
data map[string]string
}
// Secret
@[params]
pub struct SecretSpec {
pub mut:
metadata K8sMetadata
secret_type string = 'Opaque'
data map[string]string // base64 encoded
}
// Kube Client Configuration
@[params]
pub struct KubeConfig {
pub mut:
kubeconfig_path string
context string = ''
namespace string = 'default'
api_server string
ca_cert_path string
client_cert_path string
client_key_path string
token string
insecure_skip_tls_verify bool
}
@[heap]
pub struct KubeClient {
pub mut:
name string = 'default'
name string = 'default'
kubeconfig_path string
config KubeConfig
@@ -177,51 +20,28 @@ pub mut:
kubectl_path string = 'kubectl'
cache_enabled bool = true
cache_ttl_seconds int = 300
}
// Validation result for YAML files
pub struct K8sValidationResult {
pub mut:
valid bool
kind string
api_version string
metadata K8sMetadata
errors []string
}
// Cluster info
pub struct ClusterInfo {
pub mut:
version string
nodes int
namespaces int
running_pods int
api_server string
}
// Initialization
fn obj_init(mut cfg KubeClient) !KubeClient {
// Resolve kubeconfig path
if cfg.kubeconfig_path.is_empty() {
home := os.home_dir()
cfg.kubeconfig_path = '${home}/.kube/config'
}
// Ensure kubeconfig exists
if !os.path_exists(cfg.kubeconfig_path) {
return error('kubeconfig not found at ${cfg.kubeconfig_path}')
}
cfg.config.kubeconfig_path = cfg.kubeconfig_path
return cfg
// your checking & initialization code if needed
fn obj_init(mycfg_ KubeClient) !KubeClient {
mut mycfg := mycfg_
return mycfg
}
// called before start if done
fn configure() ! {
// Configure any defaults or environment-specific settings
// 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) !KubeClient {
//TODO: will have to be implemented manual
mut obj := encoderhero.decode[KubeClient](heroscript)!
return obj_init(obj)!
return obj
}

View File

@@ -0,0 +1,216 @@
module kubernetes
import incubaid.herolib.data.paramsparser
import incubaid.herolib.data.encoderhero
import incubaid.herolib.data.ourjson
import os
pub const version = '1.0.0'
const singleton = false
const default = true
// K8s API Version and Kind tracking
@[params]
pub struct K8sMetadata {
pub mut:
name string
namespace string = 'default'
labels map[string]string
annotations map[string]string
owner_reference string
}
// Pod Specification
@[params]
pub struct ContainerSpec {
pub mut:
name string
image string
image_pull_policy string = 'IfNotPresent'
ports []ContainerPort
env []EnvVar
resources ResourceRequirements
volume_mounts []VolumeMount
command []string
args []string
}
@[params]
pub struct ContainerPort {
pub mut:
name string
container_port int
protocol string = 'TCP'
host_port int
}
@[params]
pub struct EnvVar {
pub mut:
name string
value string
}
@[params]
pub struct ResourceRequirements {
pub mut:
requests map[string]string // cpu, memory
limits map[string]string
}
@[params]
pub struct VolumeMount {
pub mut:
name string
mount_path string
read_only bool
}
@[params]
pub struct PodSpec {
pub mut:
metadata K8sMetadata
containers []ContainerSpec
restart_policy string = 'Always'
service_account string
volumes []Volume
}
@[params]
pub struct Volume {
pub mut:
name string
config_map string
secret string
empty_dir bool
}
// Deployment Specification
@[params]
pub struct DeploymentSpec {
pub mut:
metadata K8sMetadata
replicas int = 1
selector map[string]string
template PodSpec
strategy DeploymentStrategy
progress_deadline_seconds int = 600
}
@[params]
pub struct DeploymentStrategy {
pub mut:
strategy_type string = 'RollingUpdate'
rolling_update RollingUpdateStrategy
}
@[params]
pub struct RollingUpdateStrategy {
pub mut:
max_surge string = '25%'
max_unavailable string = '25%'
}
// Service Specification
@[params]
pub struct ServiceSpec {
pub mut:
metadata K8sMetadata
service_type string = 'ClusterIP' // ClusterIP, NodePort, LoadBalancer
selector map[string]string
ports []ServicePort
cluster_ip string
external_ips []string
session_affinity string
}
@[params]
pub struct ServicePort {
pub mut:
name string
protocol string = 'TCP'
port int
target_port int
node_port int
}
// ConfigMap
@[params]
pub struct ConfigMapSpec {
pub mut:
metadata K8sMetadata
data map[string]string
}
// Secret
@[params]
pub struct SecretSpec {
pub mut:
metadata K8sMetadata
secret_type string = 'Opaque'
data map[string]string // base64 encoded
}
// Kube Client Configuration
@[params]
pub struct KubeConfig {
pub mut:
kubeconfig_path string
context string = ''
namespace string = 'default'
api_server string
ca_cert_path string
client_cert_path string
client_key_path string
token string
insecure_skip_tls_verify bool
}
// Validation result for YAML files
pub struct K8sValidationResult {
pub mut:
valid bool
kind string
api_version string
metadata K8sMetadata
errors []string
}
// Cluster info
pub struct ClusterInfo {
pub mut:
version string
nodes int
namespaces int
running_pods int
api_server string
}
// Initialization
fn obj_init(mut cfg KubeClient) !KubeClient {
// Resolve kubeconfig path
if cfg.kubeconfig_path.is_empty() {
home := os.home_dir()
cfg.kubeconfig_path = '${home}/.kube/config'
}
// Ensure kubeconfig exists
if !os.path_exists(cfg.kubeconfig_path) {
return error('kubeconfig not found at ${cfg.kubeconfig_path}')
}
cfg.config.kubeconfig_path = cfg.kubeconfig_path
return cfg
}
fn configure() ! {
// Configure any defaults or environment-specific settings
}
pub fn heroscript_loads(heroscript string) !KubeClient {
// TODO: this will have to be redone, because its much more complicated now, need to define a nice play processors
mut obj := encoderhero.decode[KubeClient](heroscript)!
return obj_init(obj)!
}

View File

@@ -6,7 +6,7 @@ import os
fn test_model_creation() ! {
mut deployment := DeploymentSpec{
metadata: K8sMetadata{
name: 'test-app'
name: 'test-app'
namespace: 'default'
}
replicas: 3
@@ -14,21 +14,21 @@ fn test_model_creation() ! {
'app': 'test-app'
}
template: PodSpec{
metadata: K8sMetadata{
name: 'test-app-pod'
metadata: K8sMetadata{
name: 'test-app-pod'
namespace: 'default'
}
containers: [
ContainerSpec{
name: 'app'
name: 'app'
image: 'nginx:latest'
ports: [
ContainerPort{
name: 'http'
name: 'http'
container_port: 80
}
},
]
}
},
]
}
}
@@ -41,7 +41,8 @@ fn test_model_creation() ! {
fn test_yaml_validation() ! {
// Create test YAML file
test_yaml := '''
test_yaml := ''
'
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -60,7 +61,8 @@ spec:
containers:
- name: app
image: nginx:latest
'''
'
''
test_file := '/tmp/test-deployment.yaml'
os.write_file(test_file, test_yaml)!

View File

@@ -50,21 +50,21 @@ pub fn yaml_validate(yaml_path string) !K8sValidationResult {
}
// Validate kind values
valid_kinds := ['Pod', 'Deployment', 'Service', 'ConfigMap', 'Secret', 'StatefulSet',
'DaemonSet', 'Job', 'CronJob', 'Ingress', 'PersistentVolume', 'PersistentVolumeClaim']
valid_kinds := ['Pod', 'Deployment', 'Service', 'ConfigMap', 'Secret', 'StatefulSet', 'DaemonSet',
'Job', 'CronJob', 'Ingress', 'PersistentVolume', 'PersistentVolumeClaim']
if kind !in valid_kinds {
errors << 'Invalid kind: ${kind}. Valid kinds: ${valid_kinds.join(", ")}'
errors << 'Invalid kind: ${kind}. Valid kinds: ${valid_kinds.join(', ')}'
}
return K8sValidationResult{
valid: errors.len == 0
kind: kind
valid: errors.len == 0
kind: kind
api_version: api_version
metadata: K8sMetadata{
name: metadata_name
metadata: K8sMetadata{
name: metadata_name
namespace: metadata_namespace
}
errors: errors
errors: errors
}
}