mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 11:03:59 +00:00
Add GitOps provider choice screen and cluster UI improvements
- Add _render_gitops_choice_page() to GitOpsScreenMixin for explicit Gitea / ArgoCD / None provider selection with radio buttons - Extend cluster screen with GitOps provider radio group and canvas layout - Refactor services screen layout and navigation registration - Register new gitops choice screen in screens __init__ / navigation - Expand Kong init scripts (etc/ and mock_val/) with additional logic - Update init_cnpg_backup.sh with minor fix - Refresh conf/service and conf/prod prole.cfg generated configs - Update conf/port-mapping.cfg port entries - Update Supabase Helm values.yaml - Bump modes/k3s/knoe-db/.version - Update network scan description - Add/expand tests: test_cluster_screen_layout, test_gitops_choice_screen Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
parent
43fd34ea87
commit
a1177d71bc
@ -2,10 +2,6 @@
|
||||
# Format: key: local=... remote=... ns=... svc=... address=...
|
||||
|
||||
argocd: local=8081 remote=80 ns=argocd svc=argocd-server address=0.0.0.0
|
||||
supabase-studio: local=18080 remote=3000 ns=supabase svc=studio address=0.0.0.0
|
||||
supabase-auth: local=9999 remote=9999 ns=supabase svc=auth address=127.0.0.1
|
||||
supabase-rest: local=3001 remote=3000 ns=supabase svc=rest address=0.0.0.0
|
||||
supabase-realtime: local=4000 remote=4000 ns=supabase svc=realtime address=0.0.0.0
|
||||
garage: local=3900 remote=3900 ns=knoe-system svc=garage address=0.0.0.0
|
||||
openbao: local=8200 remote=8200 ns=knoe-system svc=openbao address=0.0.0.0
|
||||
opentofu: local=8080 remote=8080 ns=knoe-system svc=opentofu address=0.0.0.0
|
||||
@ -13,4 +9,4 @@ dashboard: local=8443 remote=443 ns=kubernetes-dashboard svc=kubernetes-dashboar
|
||||
postgres: local=5432 remote=5432 ns=knoe-db svc=knoe-db-rw address=0.0.0.0
|
||||
prometheus: local=9090 remote=9090 ns=monitoring svc=kps-kube-prometheus-stack-prometheus address=127.0.0.1
|
||||
grafana: local=3000 remote=80 ns=monitoring svc=kps-grafana address=0.0.0.0
|
||||
supabase-kong: local=8000 remote=8000 ns=supabase svc=kong address=0.0.0.0
|
||||
certmgr: local=9443 remote=9443 ns=cert-manager svc=cert-manager-webhook address=127.0.0.1
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
; Prole Master Configuration File
|
||||
; Generated by install.py on 2026-03-21 23:40:10
|
||||
; Generated by install.py on 2026-03-24 18:24:09
|
||||
; This file is used as input for Ansible deployment and k8s cluster creation.
|
||||
|
||||
[User]
|
||||
@ -38,7 +38,8 @@ dependencies.verify_all = false
|
||||
disk_selection.disk_type = local
|
||||
disk_selection.local_path = /Users/chrisfu/dev/prole/prole-tools-app/dist
|
||||
disk_selection.removable_mount =
|
||||
env_setup.NAMESPACE = ${NAMESPACE}
|
||||
env_setup.CLUSTER_NAME = ${CLUSTER_NAME}
|
||||
env_setup.DATABASE_NAMESPACE = ${DATABASE_NAMESPACE}
|
||||
env_setup.PROLE_CONF = /Users/chrisfu/dev/prole/conf
|
||||
env_setup.PROLE_DATA = /Users/chrisfu/dev/prole/data
|
||||
env_setup.PROLE_HOME = /Users/chrisfu/dev/prole
|
||||
@ -50,7 +51,7 @@ init_cluster.cluster_env = prod
|
||||
init_cluster.deployment_target = prole-prod-cluster
|
||||
init_cluster.gitops_enabled = false
|
||||
init_cluster.k3s_server_url = https://myrddin.prole.org:6443
|
||||
init_cluster.k3s_token = ${PROLE_SECRET:v1:iTRfvIPRo7v-aK5j:H6zki1L-02mHJQLXIjZyFnVWByy5TfoCASeGEi08tcfZCqqybxeCatiXK_NyADR1oElbaZnvjw83fuhircDNdRRY4sQo_hEuKU0ll9s9o6QZBKZZzWpgcU4WMX7YAS4aOgc8d5pBFUH0mC-ZcJ9lSWT3JxhgBXRdbVopQQ==}
|
||||
init_cluster.k3s_token = ${PROLE_SECRET:v1:os8KqzMGFP1k3yBI:45ywbbblQIV-acyMkTt21Ff8g1H7zuZU2RXRInDQxLBsNxsqm7n18dU6CGCJ64GG7A9rblAZAaVVo9V7bMPq3JUED9z3vLXqnnDwx4JbyD5OnplIJ6KfF9PHLX-VMreioizAAcHN66gyhTc4R5Y3-z2q1aeJKtr4H4JqbQ==}
|
||||
init_cluster.kerberos_enabled = true
|
||||
init_cluster.mode = k8s
|
||||
init_cluster.start_cluster = true
|
||||
@ -58,8 +59,9 @@ init_cluster.supabase_enabled = false
|
||||
init_cnpg_deploy.force_rollout = false
|
||||
init_cnpg_deploy.run_deploy = true
|
||||
init_db_build.run_build = true
|
||||
init_password.cluster_name = ${CLUSTER_NAME}
|
||||
init_password.db_host_port = 5432
|
||||
init_password.db_namespace = ${NAMESPACE}
|
||||
init_password.db_namespace = ${DATABASE_NAMESPACE}
|
||||
init_password.db_password =
|
||||
init_password.db_password_confirm =
|
||||
init_password.db_username = root
|
||||
@ -67,7 +69,7 @@ init_password.generate_ssh_key = true
|
||||
init_scripts.run_scripts = true
|
||||
kerberos_config.enabled = true
|
||||
kerberos_config.kdc = 10.0.0.3
|
||||
kerberos_config.password = ${PROLE_SECRET:v1:rEiGEX6WGmmQ2vyE:EjwlefHMKjZwZRVIrh3x4VjqxnEddJ-EpRSaoqd3PjaZGTh5}
|
||||
kerberos_config.password = ${PROLE_SECRET:v1:Ed93pzGEE14H4z1U:2V1lCQ4-UPJcU4StFDkixNY6jvbezCI4CAfwKbJyBwnOuGH1}
|
||||
kerberos_config.realm = PROLE.ORG
|
||||
kerberos_config.test_connection = false
|
||||
kerberos_config.user = administrator
|
||||
@ -79,17 +81,17 @@ ollama_config.server_port = 11434
|
||||
[Global]
|
||||
; Variables used by name in more than one place or assumed global scope
|
||||
CLUSTER_ENV = prod
|
||||
CLUSTER_NAME = knoe-db
|
||||
DATABASE_NAMESPACE = knoe-db-17-7-043-18-140
|
||||
DB_HOST_PORT = 5432
|
||||
DB_PASSWORD =
|
||||
DEPLOYMENT_MODE = k8s
|
||||
DEPLOYMENT_TARGET = prole-prod-cluster
|
||||
DOCKER_PRELOAD = false
|
||||
NAMESPACE = knoe-db
|
||||
OPTIONAL_WORKLOADS_MIN_READY_SCHEDULABLE_NODES = 2
|
||||
KNOE_DB_USER = root
|
||||
PROLE_HOME = $HOME/dev/prole
|
||||
OPTIONAL_WORKLOADS_MIN_READY_SCHEDULABLE_NODES = 2
|
||||
PROLE_K3S_SERVER = https://myrddin.prole.org:6443
|
||||
PROLE_K3S_TOKEN = ${PROLE_SECRET:v1:cWc4c9mYxi20rxbR:wTCIMGahxg8rxxGotDtMhobeDIzf1k_9thQti2je2znzRVZVqV4TibePL21oghQvLLBbkjzd5hwIlUGGqq7sOYkpIetik4swjmaQnJ4DHGT82RWX3PZuuCrPWLGb5NOs4Hqv61TKYru5C-ImJzrPyEq7vJDgBG3aita0HQ==}
|
||||
PROLE_K3S_TOKEN = ${PROLE_SECRET:v1:TTjP4kMPgOzEndoI:YhRZHb0kebPDxVBCIY9z5OyAUV4X01LCmCxLrq6dUDI7J0WUSnI62aVXXMegfoLf04WtWAII8grOdhxuUBGbWXQ_P2qyWguNZk4J8ag9CbSPfSxUliKkbvwOFYH_qwJi-A7SA40dYzLYYWj_066MWqTgab1xFcFiwntNOQ==}
|
||||
PROLE_OPENTOFU_URL = http://127.0.0.1:8080
|
||||
SERVICE_NAMESPACE = knoe-system
|
||||
|
||||
@ -155,7 +157,7 @@ MODE = k3d
|
||||
CLUSTER_ENV = prole-service-cluster
|
||||
DISPLAY_NAME = prole-service-cluster
|
||||
K3S_SERVER_URL = https://myrddin.prole.org:6443
|
||||
K3S_TOKEN = ${PROLE_SECRET:v1:3DHF_algPRkZXK_o:hMRZr17b7GihxuRs-6NPhlcS9h-aIctsZih2SS6dPCqwZabpKbG2ziZBgLiwOAhWih-ofvR8qbaOWdmbXurTYvWAWoj5F0MzOa35klQ6ujO2A2B2Y_uHrnzHXwkwEVufl9g8mucOkSMZ6UiVkNK4jYowVZHNTXe7uhghCA==}
|
||||
K3S_TOKEN = ${PROLE_SECRET:v1:AMWPPVWetr8qzDVw:NpiGkrREpI1PJXF-W0d4Ryfe3C1FQiibBNn49sRIm5fggf8dj00_OLYdG5GUdxDZVLWbk_wSn0BK2PET7VOaCNU-B2iLyvGOuFQ41nhyPHZSwmgEPOq7YCtF8Kjv4WyENTTqXaoZaJ_3oWnrls6AalVPk85BfYuvzvybkQ==}
|
||||
MODE = k3s
|
||||
PIPELINE_URL = http://127.0.0.1:8080
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
; Prole Master Configuration File
|
||||
; Generated by install.py on 2026-03-24 14:56:35
|
||||
; Generated by install.py on 2026-03-24 21:31:16
|
||||
; This file is used as input for Ansible deployment and k8s cluster creation.
|
||||
|
||||
[User]
|
||||
@ -51,26 +51,25 @@ init_cluster.cluster_env = service
|
||||
init_cluster.deployment_target = prole-service-cluster
|
||||
init_cluster.gitops_enabled = false
|
||||
init_cluster.k3s_server_url = https://myrddin.prole.org:6443
|
||||
init_cluster.k3s_token = ${PROLE_SECRET:v1:8FFZzwnMNamN9Zl6:0ITXXU0Id4wJwpDLpxjHP7Yqi-2_W5Orzc0Imi7QB6tGUENG50fegqVvixwedBplvkBDladIb-gE2sI5MJH2p1xwRbMkb2kvBIItgYW6rBevMTkpRMV36aJshsNw8l74VoFD3LR5KUBV3f2AmLfXQTlfyGkkV64kOYgGDQ==}
|
||||
init_cluster.k3s_token = ${PROLE_SECRET:v1:CWAF-McNyYMXWLPJ:c-bbfiF4rpG4oMLHfwcCWwxaHIYEmAY7fIgCQSy4at6g6qslSSrQhCDscFmNiZam-d9JqZAxJF1xqW8EAjzzQOoB04Iv_wCMUyZovWuzN9aLnV2RHWdr4jFA963NL6OrZ37KdFAXKJ2L_FPvLH_A9SmmWHFOy0Va0JLLuA==}
|
||||
init_cluster.kerberos_enabled = true
|
||||
init_cluster.mode = k3s
|
||||
init_cluster.start_cluster = true
|
||||
init_cluster.supabase_enabled = true
|
||||
init_cluster.supabase_enabled = false
|
||||
init_cnpg_deploy.force_rollout = false
|
||||
init_cnpg_deploy.run_deploy = true
|
||||
init_db_build.run_build = true
|
||||
init_password.cluster_name = ${CLUSTER_NAME}
|
||||
init_password.db_host_port = 5432
|
||||
init_password.db_namespace = ${DATABASE_NAMESPACE}
|
||||
init_password.db_password = ${PROLE_SECRET:v1:I4c69IhpfCLlMdYM:GOPT9cox83ALUWacXGfZvEwMsEX8OMwT}
|
||||
init_password.db_password_confirm = ${PROLE_SECRET:v1:I4c69IhpfCLlMdYM:GOPT9cox83ALUWacXGfZvEwMsEX8OMwT}
|
||||
init_password.db_password = ${PROLE_SECRET:v1:ivQufWO7XUiAW8HJ:JpbStYbwhWw1VcPykbTuAe_-kKIjqmPh}
|
||||
init_password.db_password_confirm = ${PROLE_SECRET:v1:ivQufWO7XUiAW8HJ:JpbStYbwhWw1VcPykbTuAe_-kKIjqmPh}
|
||||
init_password.db_username = root
|
||||
init_password.generate_ssh_key = true
|
||||
init_scripts.run_scripts = true
|
||||
kerberos_config.enabled = true
|
||||
kerberos_config.init_authority = false
|
||||
kerberos_config.kdc = 10.0.0.3
|
||||
kerberos_config.password = ${PROLE_SECRET:v1:_m0-5CRSInOmZKpG:QfB3PmArZOX_S_pvr_vPHZMicTQ5H3yaVATDPW2D2aHGt-gF}
|
||||
kerberos_config.password = ${PROLE_SECRET:v1:i3-4lYEoA2eq03rQ:c_zSY9qIrxxeaTr1X_G2l1pdJJDDnLvx7Tgat3mr4ihPsFLT}
|
||||
kerberos_config.realm = PROLE.ORG
|
||||
kerberos_config.test_connection = false
|
||||
kerberos_config.user = administrator
|
||||
@ -81,42 +80,30 @@ ollama_config.server_port = 11434
|
||||
|
||||
[Global]
|
||||
; Variables used by name in more than one place or assumed global scope
|
||||
ARGOCD_NAMESPACE = argocd
|
||||
CLUSTER_ENV = service
|
||||
CLUSTER_NAME = knoe-db
|
||||
CNPG_ELIGIBLE_NODES = merlin.prole.org,myrddin.prole.org
|
||||
CNPG_ELIGIBLE_NODES = merlin.prole.org,myrddin.prole.org,pi.prole.org
|
||||
CNPG_STAGE1_NODE = merlin.prole.org
|
||||
DATABASE_NAMESPACE = knoe-db
|
||||
DB_HOST_PORT = 5432
|
||||
DB_PASSWORD = ${PROLE_SECRET:v1:wy6mYFXcdTTosLHd:ARnY3pxB65ii9IO5Oh_kzO4xR6e1R6R_}
|
||||
DB_PASSWORD = ${PROLE_SECRET:v1:gFx4tAqM_UUWuFeK:dT2GGXubo_bC5mHupS7PSYeRg3N5pFTG}
|
||||
DEPLOYMENT_MODE = k3s
|
||||
DEPLOYMENT_TARGET = prole-service-cluster
|
||||
DOCKER_IMPORT_DIR =
|
||||
DOCKER_PRELOAD = false
|
||||
K3S_SERVER = https://myrddin.prole.org:6443
|
||||
K3S_TOKEN = ${PROLE_SECRET:v1:-zIZOM5gyWjEhHPP:x0jUffEsPUfHkVHuvPpf2U9TCXx05CY5UKImE2MxCet6JXGxwPmnbbVXYVfWPc4NaUSIATBcxB7A7SFKmwzUdfyMWI43Ham3jQo_R5yyXIR-qPuoc7JJ85xFMPylbrfDB-kV5fVEFP6867UUKV12D8i7OLM6JUZDc0Nukw==}
|
||||
KNOE_DB_USER = root
|
||||
KUBECONTEXT = prole-k3s
|
||||
OPENTOFU_URL = http://myrddin.prole.org:8080
|
||||
OPTIONAL_WORKLOADS_MIN_READY_SCHEDULABLE_NODES = 2
|
||||
PROLE_HOME = /Users/chrisfu/dev/prole
|
||||
PROLE_K3S_SERVER = https://myrddin.prole.org:6443
|
||||
PROLE_K3S_TOKEN = K107c8c6000488eca4a067d8a73119bbae2f07b4ea1bac7d8d3dc9c500cbb8acb18::server:04572345810eae2f9619a6ed4239702b
|
||||
PROLE_K3S_TOKEN = ${PROLE_SECRET:v1:T_rh15yn36yLioXG:m_McT35zO06S4r-n6hf9iivldC6i4PUkSY1cxJW7jHC1A11kAITL1qZpyKmbMjXSjEo4KbU58eV_NrLQVjTQqy2-EUoyXhagbclA8XVnmn9ZtR6wIdDkKmqSzmygNweO_Zy68SgnsIqUCMVrIFY66h4K-kbCW3mKaQwFPw==}
|
||||
PROLE_OPENTOFU_URL = http://127.0.0.1:8080
|
||||
REGISTRY_NAMESPACE = knoe-system
|
||||
SERVICE_NAMESPACE = knoe-system
|
||||
SUPABASE_ADDITIONAL_REDIRECT_URLS = svc.prole.org
|
||||
SUPABASE_PRIMARY_NODE = merlin.prole.org
|
||||
SUPABASE_PV_BASE_DIR = /synology/d002/supabase
|
||||
SUPABASE_PV_NODE = merlin.prole.org
|
||||
SUPABASE_STORAGE_CLASS = merlin-local-iscsi-d002
|
||||
SYNOLOGY_ROOTS = /synology/d001,/synology/d002,/synology/d003,/synology/d004
|
||||
|
||||
[Welcome]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Dependencies]
|
||||
STATUS = All installed
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Network]
|
||||
AD_DC_HOST = myrddin.prole.org
|
||||
@ -131,19 +118,7 @@ KDC_AUTO_DETECTED = 10.0.0.3
|
||||
KERBEROS_AUTO_ENABLED = True
|
||||
|
||||
[Port Forwards]
|
||||
PORT_FORWARD_K3S_MAPPING_1 = id=argocd;namespace=argocd;target=svc/argocd-server;address=0.0.0.0;hostPort=8081;servicePort=80;protocol=TCP;description=ArgoCD
|
||||
PORT_FORWARD_K3S_MAPPING_10 = id=supabase-studio;namespace=supabase;target=svc/studio;address=0.0.0.0;hostPort=18080;servicePort=3000;protocol=TCP;description=Supabase Studio
|
||||
PORT_FORWARD_K3S_MAPPING_11 = id=supabase-auth;namespace=supabase;target=svc/auth;address=127.0.0.1;hostPort=9999;servicePort=9999;protocol=TCP;description=Supabase Auth (GoTrue)
|
||||
PORT_FORWARD_K3S_MAPPING_12 = id=supabase-rest;namespace=supabase;target=svc/rest;address=0.0.0.0;hostPort=3001;servicePort=3000;protocol=TCP;description=Supabase REST (PostgREST)
|
||||
PORT_FORWARD_K3S_MAPPING_13 = id=supabase-realtime;namespace=supabase;target=svc/realtime;address=0.0.0.0;hostPort=4000;servicePort=4000;protocol=TCP;description=Supabase Realtime
|
||||
PORT_FORWARD_K3S_MAPPING_2 = id=garage;namespace=knoe-system;target=svc/garage;address=0.0.0.0;hostPort=3900;servicePort=3900;protocol=TCP;description=Garage S3
|
||||
PORT_FORWARD_K3S_MAPPING_3 = id=openbao;namespace=knoe-system;target=svc/openbao;address=0.0.0.0;hostPort=8200;servicePort=8200;protocol=TCP;description=OpenBao
|
||||
PORT_FORWARD_K3S_MAPPING_4 = id=opentofu;namespace=knoe-system;target=svc/opentofu;address=0.0.0.0;hostPort=8080;servicePort=8080;protocol=TCP;description=OpenTofu
|
||||
PORT_FORWARD_K3S_MAPPING_5 = id=dashboard;namespace=kubernetes-dashboard;target=svc/kubernetes-dashboard-kong-proxy;address=127.0.0.1;hostPort=8443;servicePort=443;protocol=TCP;description=Kubernetes Dashboard
|
||||
PORT_FORWARD_K3S_MAPPING_6 = id=postgres;namespace=${DATABASE_NAMESPACE};target=svc/knoe-db-rw;address=0.0.0.0;hostPort=5432;servicePort=5432;protocol=TCP;description=PostgreSQL (primary)
|
||||
PORT_FORWARD_K3S_MAPPING_7 = id=prometheus;namespace=monitoring;target=svc/kps-kube-prometheus-stack-prometheus;address=127.0.0.1;hostPort=9090;servicePort=9090;protocol=TCP;description=Prometheus UI
|
||||
PORT_FORWARD_K3S_MAPPING_8 = id=grafana;namespace=monitoring;target=svc/kps-grafana;address=0.0.0.0;hostPort=3000;servicePort=80;protocol=TCP;description=Grafana UI
|
||||
PORT_FORWARD_K3S_MAPPING_9 = id=supabase-kong;namespace=supabase;target=svc/kong;address=0.0.0.0;hostPort=8000;servicePort=8000;protocol=TCP;description=Supabase API (Kong)
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[System Environment]
|
||||
PROLE_CONF = /Users/chrisfu/dev/prole/conf
|
||||
@ -156,7 +131,7 @@ PROLE_SERVICE = /Users/chrisfu/dev/prole/etc
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Kerberos Authentication]
|
||||
STATUS = Initialized
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Ollama]
|
||||
OLLAMA_HOST = http://fairyland.prole.org:11434
|
||||
@ -165,52 +140,52 @@ OLLAMA_SERVER_HOST = fairyland.prole.org
|
||||
OLLAMA_SERVER_PORT = 11434
|
||||
|
||||
[Optional Features]
|
||||
AT_REST_ENCRYPTION_ENABLED = true
|
||||
GITOPS_ENABLED = false
|
||||
KERBEROS_ENABLED = true
|
||||
SUPABASE_ENABLED = true
|
||||
AT_REST_ENCRYPTION_ENABLED = True
|
||||
GITOPS_ENABLED = False
|
||||
KERBEROS_ENABLED = True
|
||||
SUPABASE_ENABLED = False
|
||||
|
||||
[GitOps]
|
||||
STATUS = Skipped
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Database Creation]
|
||||
DB_USER = root
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Initialize Cluster]
|
||||
ENVIRONMENT = service
|
||||
K3S_SERVER_URL = https://myrddin.prole.org:6443
|
||||
K3S_TOKEN = ${PROLE_SECRET:v1:WjD201Yr7MHE56cs:wackF_EDDde7KmJp2SwbMlJi5mLdoHATkoyolRkPVqvnOVVScriN55ZHOO0cec-RvMIFQzhkL_yZbKhNkN9IIfkRdnAeGPDVELtM-wEDv_YlymTsrpYL_u79VR-nX3gKTCfcAha44ZyoBzObKTShzUx8eLCJMeLKYoPEKg==}
|
||||
K3S_TOKEN = ${PROLE_SECRET:v1:TiaxxeJo-nsA8u39:0m7rdp2olmPjOdoTUzLE39BRwDk9dW82BAuh1doGV6UiEt7nYpSzL7-VYS3SSIWbu4l5X5t7SR6bMCydstky7aFvS75Telo1NXraGRpUNWGuC7w7MHf48ZOjJ7Yr00EmdVuA1xfa2qqImHIcSeMCK1mcKwZtvYp_DqLqNw==}
|
||||
|
||||
[Dev Cluster (k3d)]
|
||||
CLUSTER_ENV = k3d-knoe-dev-cluster
|
||||
CLUSTER_ENV = dev
|
||||
DISPLAY_NAME = knoe-dev-cluster
|
||||
KUBECTL_CONTEXT = service
|
||||
KUBECTL_CONTEXT = prole-k3s
|
||||
MODE = k3d
|
||||
|
||||
[Service Cluster (k3s)]
|
||||
CLUSTER_ENV = prole-service-cluster
|
||||
DISPLAY_NAME = prole-service-cluster
|
||||
K3S_SERVER_URL = https://myrddin.prole.org:6443
|
||||
K3S_TOKEN = ${PROLE_SECRET:v1:ExAOsZTajCw676Sn:K29yOJp64eW0fB2usaGz8S4wPRbhD0G2wCffluAZfgHKjIkn4j1M-eT55-ExPt90mH2xBH-inHu2WDuGizV-UNV8a9ITKAPXU0zmGDmp4F-_jaHyGH3sOmgebtkaNOYA-5LUBK1pQIorjkMieGCZNet9V4i3e6PVBJtCuA==}
|
||||
K3S_TOKEN = ${PROLE_SECRET:v1:8I31Aq_l-010FTgr:EF4jOYkqBhPKTN-jKRc_SQIIfCWVMUMw6niZplo2Yz8msZ9Zd6VpCuik-cpS0PydX7fl5H9AVoZtQxQQmA7LAQHaDrlFfGfl2LaArVvXTyzRmO7MRt2UoVhQ6s-t1Aw5DPiDM8tx10CXZ1-PGJvNHNTJ76XEpepOzxoQFw==}
|
||||
MODE = k3s
|
||||
PIPELINE_URL = http://myrddin.prole.org:8080
|
||||
PIPELINE_URL = http://127.0.0.1:8080
|
||||
|
||||
[Prod Cluster (k8s)]
|
||||
ARTIFACTS_DIR =
|
||||
ARTIFACTS_DIR = /Users/chrisfu/dev/prole/data/staging
|
||||
CLUSTER_ENV = prole-prod-cluster
|
||||
DISPLAY_NAME = prole-prod-cluster
|
||||
MODE = k8s
|
||||
PIPELINE_URL = http://myrddin.prole.org:8080
|
||||
PIPELINE_URL = http://127.0.0.1:8080
|
||||
|
||||
[Docker Build]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Initialization Scripts]
|
||||
; No configuration values captured yet for this section.
|
||||
STATUS = Attempted
|
||||
|
||||
[Deployment]
|
||||
MODE = k3s
|
||||
TARGET = prole-service-cluster
|
||||
|
||||
[Install]
|
||||
STATUS = Finished
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
@ -24,7 +24,7 @@ fi
|
||||
|
||||
ACTION=${1:-start}
|
||||
|
||||
NAMESPACE="${PROLE_NAMESPACE}"
|
||||
NAMESPACE="${PROLE_NAMESPACE:-${DATABASE_NAMESPACE:-${SERVICE_NAMESPACE:-knoe-db}}}"
|
||||
CNPG_CLUSTER_NAME=${CNPG_CLUSTER_NAME:-knoe-db}
|
||||
CNPG_OPERATOR_NAMESPACE=${CNPG_OPERATOR_NAMESPACE:-cnpg-system}
|
||||
GARAGE_NAME=${GARAGE_NAME:-garage}
|
||||
|
||||
@ -138,6 +138,12 @@ kubectl_apply_retry() {
|
||||
done
|
||||
}
|
||||
|
||||
# Sets KONG_CONFIG_CHANGED=1 in the caller's scope when the ConfigMap was
|
||||
# created or updated; leaves it 0 when kubectl reported "unchanged".
|
||||
# A temp file is used to communicate the result out of the subshell.
|
||||
KONG_CONFIG_CHANGED=0
|
||||
_KONG_CONFIG_CHANGED_FILE=""
|
||||
|
||||
create_kong_config() {
|
||||
echo "Creating/updating Kong declarative config '$KONG_CONFIG_NAME' in namespace '$NAMESPACE' ..."
|
||||
|
||||
@ -194,6 +200,8 @@ KONGEOF
|
||||
)
|
||||
|
||||
# Use a subshell to ensure the cleanup trap doesn't leak globally (and trip `set -u` later).
|
||||
# A sentinel file is used to communicate a config change back to the parent shell.
|
||||
_KONG_CONFIG_CHANGED_FILE="$(mktemp)"
|
||||
(
|
||||
tmp="$(mktemp)"
|
||||
trap 'rm -f "${tmp:-}"' EXIT
|
||||
@ -203,8 +211,18 @@ KONGEOF
|
||||
--from-literal=kong.yml="$kong_yml" \
|
||||
--dry-run=client -o yaml >"$tmp"
|
||||
|
||||
kubectl_apply_retry -f "$tmp"
|
||||
local apply_out
|
||||
apply_out=$(kubectl_apply_retry -f "$tmp" 2>&1)
|
||||
echo "$apply_out"
|
||||
if ! echo "$apply_out" | grep -q 'unchanged'; then
|
||||
echo "1" >"$_KONG_CONFIG_CHANGED_FILE"
|
||||
fi
|
||||
)
|
||||
if [[ -f "$_KONG_CONFIG_CHANGED_FILE" ]] && [[ "$(cat "$_KONG_CONFIG_CHANGED_FILE")" == "1" ]]; then
|
||||
KONG_CONFIG_CHANGED=1
|
||||
fi
|
||||
rm -f "$_KONG_CONFIG_CHANGED_FILE"
|
||||
_KONG_CONFIG_CHANGED_FILE=""
|
||||
|
||||
echo "ConfigMap '$KONG_CONFIG_NAME' ready."
|
||||
}
|
||||
@ -286,17 +304,36 @@ deploy() {
|
||||
|
||||
local manifests_dir="$PROLE_HOME/deploy/opentofu/k3s/manifests/prole"
|
||||
|
||||
kubectl_apply_retry -f "$manifests_dir/kong-deployment.yaml" -n "$NAMESPACE"
|
||||
kubectl_apply_retry -f "$manifests_dir/kong-service.yaml" -n "$NAMESPACE"
|
||||
# Determine whether the Deployment already exists before applying manifests.
|
||||
local deployment_existed=0
|
||||
kubectl_rt get deployment "$KONG_NAME" -n "$NAMESPACE" >/dev/null 2>&1 && deployment_existed=1
|
||||
|
||||
local deploy_out
|
||||
deploy_out=$(kubectl_apply_retry -f "$manifests_dir/kong-deployment.yaml" -n "$NAMESPACE" 2>&1)
|
||||
echo "$deploy_out"
|
||||
local svc_out
|
||||
svc_out=$(kubectl_apply_retry -f "$manifests_dir/kong-service.yaml" -n "$NAMESPACE" 2>&1)
|
||||
echo "$svc_out"
|
||||
|
||||
echo "Waiting for $KONG_NAME rollout ..."
|
||||
kubectl rollout status deployment/"$KONG_NAME" -n "$NAMESPACE" --timeout=120s
|
||||
|
||||
# ConfigMaps do not trigger a Deployment rollout by default; always restart
|
||||
# Kong on update/start so it reloads the declarative config.
|
||||
echo "Restarting $KONG_NAME to reload declarative config ..."
|
||||
kubectl rollout restart deployment/"$KONG_NAME" -n "$NAMESPACE" >/dev/null 2>&1 || true
|
||||
kubectl rollout status deployment/"$KONG_NAME" -n "$NAMESPACE" --timeout=120s >/dev/null 2>&1 || true
|
||||
# ConfigMaps do not trigger a Deployment rollout by default. Only restart
|
||||
# Kong when something actually changed: either this is a fresh deployment or
|
||||
# the declarative config ConfigMap was modified. Skipping the restart when
|
||||
# nothing changed prevents a new ReplicaSet from being created every run.
|
||||
local need_restart=0
|
||||
[[ "$deployment_existed" -eq 0 ]] && need_restart=1
|
||||
[[ "${KONG_CONFIG_CHANGED:-0}" -eq 1 ]] && need_restart=1
|
||||
|
||||
if [[ "$need_restart" -eq 1 ]]; then
|
||||
echo "Restarting $KONG_NAME to reload declarative config ..."
|
||||
kubectl rollout restart deployment/"$KONG_NAME" -n "$NAMESPACE" >/dev/null 2>&1 || true
|
||||
kubectl rollout status deployment/"$KONG_NAME" -n "$NAMESPACE" --timeout=120s >/dev/null 2>&1 || true
|
||||
else
|
||||
echo "$KONG_NAME config unchanged; skipping rollout restart."
|
||||
fi
|
||||
|
||||
echo "$KONG_NAME deployed successfully."
|
||||
}
|
||||
|
||||
|
||||
@ -357,8 +357,9 @@ class ProleInstaller(
|
||||
("Database Creation", "init_password"),
|
||||
("Initialization Scripts", "init_scripts"),
|
||||
("Kerberos Authentication", "kerberos_config"),
|
||||
("GitOps", "gitops_config"),
|
||||
("GitOps Provider", "gitops_choice"),
|
||||
("ArgoCD", "argocd_config"),
|
||||
("GitOps / Gitea", "gitops_config"),
|
||||
("Supabase", "supabase_config"),
|
||||
("Deployment", "init_cnpg_deploy"),
|
||||
("Post Install", "create_installer"),
|
||||
@ -665,6 +666,16 @@ class ProleInstaller(
|
||||
self.prod_artifacts_path = tk.StringVar(
|
||||
value=str(PROJECT_ROOT / "data" / "staging")
|
||||
)
|
||||
# GitOps provider choice (gitea / argocd / none)
|
||||
self.gitops_provider = tk.StringVar(value="gitea")
|
||||
# Google Workspace
|
||||
self.gworkspace_domain = tk.StringVar()
|
||||
self.gworkspace_customer_id = tk.StringVar()
|
||||
self.gworkspace_admin_email = tk.StringVar()
|
||||
# Google Cloud
|
||||
self.gcloud_project_id = tk.StringVar()
|
||||
self.gcloud_region = tk.StringVar(value="us-central1")
|
||||
self.gcloud_sa_key_path = tk.StringVar()
|
||||
self.k3s_server_url = tk.StringVar()
|
||||
self.k3s_token = tk.StringVar()
|
||||
self.k3s_services_status = {
|
||||
@ -767,6 +778,7 @@ class ProleInstaller(
|
||||
self._register_canvas_renderer(
|
||||
"supabase_config", self._render_supabase_config_page
|
||||
)
|
||||
self._register_canvas_renderer("gitops_choice", self._render_gitops_choice_page)
|
||||
self._register_canvas_renderer("argocd_config", self._render_argocd_config_page)
|
||||
self._register_canvas_renderer("gitops_config", self._render_gitops_config_page)
|
||||
self._register_canvas_renderer("init_cluster", self._render_init_cluster_page)
|
||||
@ -801,6 +813,7 @@ class ProleInstaller(
|
||||
self._register_page("init_db_build", None)
|
||||
self._register_page("init_scripts", None)
|
||||
self._register_page("kerberos_config", None)
|
||||
self._register_page("gitops_choice", None)
|
||||
self._register_page("argocd_config", None)
|
||||
self._register_page("gitops_config", None)
|
||||
self._register_page("supabase_config", None)
|
||||
|
||||
@ -329,6 +329,180 @@ class ClusterScreenMixin:
|
||||
fill="#6e6e73",
|
||||
font=("SF Pro Text", 10),
|
||||
)
|
||||
y += 40
|
||||
|
||||
# ── GitOps Provider ────────────────────────────────────
|
||||
self._canvas_items.append(
|
||||
ui.canvas_text(
|
||||
self,
|
||||
x_label,
|
||||
y,
|
||||
"GitOps Provider:",
|
||||
fill="black",
|
||||
font=("SF Pro Text", 12, "bold"),
|
||||
)
|
||||
)
|
||||
y += 4
|
||||
for label, value in [
|
||||
("Gitea", "gitea"),
|
||||
("ArgoCD", "argocd"),
|
||||
("None", "none"),
|
||||
]:
|
||||
rb = tk.Radiobutton(
|
||||
self.bg_canvas,
|
||||
text=label,
|
||||
variable=self.gitops_provider,
|
||||
value=value,
|
||||
bg="white",
|
||||
fg="black",
|
||||
activebackground="white",
|
||||
selectcolor="white",
|
||||
font=("SF Pro Text", 11),
|
||||
)
|
||||
rb_win = self.bg_canvas.create_window(
|
||||
x_label + 160 + ["gitea", "argocd", "none"].index(value) * 110,
|
||||
y - 2,
|
||||
window=rb,
|
||||
anchor="nw",
|
||||
)
|
||||
self._canvas_items.append(rb_win)
|
||||
self._overlay_widgets.append(rb)
|
||||
y += 34
|
||||
|
||||
# ── Google Workspace ───────────────────────────────────
|
||||
self._canvas_items.append(
|
||||
ui.canvas_text(
|
||||
self,
|
||||
x_label,
|
||||
y,
|
||||
"Google Workspace",
|
||||
fill="black",
|
||||
font=("SF Pro Text", 12, "bold"),
|
||||
)
|
||||
)
|
||||
y += 28
|
||||
for field_label, var, placeholder in [
|
||||
("Domain:", self.gworkspace_domain, "example.com"),
|
||||
("Customer ID:", self.gworkspace_customer_id, "C0xxxxxxx"),
|
||||
("Admin Email:", self.gworkspace_admin_email, "admin@example.com"),
|
||||
]:
|
||||
self._canvas_items.append(
|
||||
ui.canvas_text(
|
||||
self,
|
||||
x_label + 20,
|
||||
y,
|
||||
field_label,
|
||||
fill="black",
|
||||
font=("SF Pro Text", 11),
|
||||
)
|
||||
)
|
||||
gw_entry = tk.Entry(
|
||||
self.bg_canvas,
|
||||
textvariable=var,
|
||||
width=36,
|
||||
bg="white",
|
||||
fg="black",
|
||||
insertbackground="black",
|
||||
highlightbackground="#CCCCCC",
|
||||
highlightthickness=1,
|
||||
relief="flat",
|
||||
font=("SF Pro Text", 11),
|
||||
)
|
||||
gw_win = self.bg_canvas.create_window(
|
||||
x_label + 160, y - 6, window=gw_entry, anchor="nw"
|
||||
)
|
||||
self._canvas_items.append(gw_win)
|
||||
self._overlay_widgets.append(gw_entry)
|
||||
y += 30
|
||||
|
||||
y += 6
|
||||
# ── Google Cloud ───────────────────────────────────────
|
||||
self._canvas_items.append(
|
||||
ui.canvas_text(
|
||||
self,
|
||||
x_label,
|
||||
y,
|
||||
"Google Cloud",
|
||||
fill="black",
|
||||
font=("SF Pro Text", 12, "bold"),
|
||||
)
|
||||
)
|
||||
y += 28
|
||||
for field_label, var in [
|
||||
("Project ID:", self.gcloud_project_id),
|
||||
("Region:", self.gcloud_region),
|
||||
]:
|
||||
self._canvas_items.append(
|
||||
ui.canvas_text(
|
||||
self,
|
||||
x_label + 20,
|
||||
y,
|
||||
field_label,
|
||||
fill="black",
|
||||
font=("SF Pro Text", 11),
|
||||
)
|
||||
)
|
||||
gc_entry = tk.Entry(
|
||||
self.bg_canvas,
|
||||
textvariable=var,
|
||||
width=36,
|
||||
bg="white",
|
||||
fg="black",
|
||||
insertbackground="black",
|
||||
highlightbackground="#CCCCCC",
|
||||
highlightthickness=1,
|
||||
relief="flat",
|
||||
font=("SF Pro Text", 11),
|
||||
)
|
||||
gc_win = self.bg_canvas.create_window(
|
||||
x_label + 160, y - 6, window=gc_entry, anchor="nw"
|
||||
)
|
||||
self._canvas_items.append(gc_win)
|
||||
self._overlay_widgets.append(gc_entry)
|
||||
y += 30
|
||||
# Service Account Key
|
||||
self._canvas_items.append(
|
||||
ui.canvas_text(
|
||||
self,
|
||||
x_label + 20,
|
||||
y,
|
||||
"SA Key Path:",
|
||||
fill="black",
|
||||
font=("SF Pro Text", 11),
|
||||
)
|
||||
)
|
||||
sa_entry = tk.Entry(
|
||||
self.bg_canvas,
|
||||
textvariable=self.gcloud_sa_key_path,
|
||||
width=36,
|
||||
bg="white",
|
||||
fg="black",
|
||||
insertbackground="black",
|
||||
highlightbackground="#CCCCCC",
|
||||
highlightthickness=1,
|
||||
relief="flat",
|
||||
font=("SF Pro Text", 11),
|
||||
)
|
||||
sa_win = self.bg_canvas.create_window(
|
||||
x_label + 160, y - 6, window=sa_entry, anchor="nw"
|
||||
)
|
||||
self._canvas_items.append(sa_win)
|
||||
self._overlay_widgets.append(sa_entry)
|
||||
sa_browse = tk.Button(
|
||||
self.bg_canvas,
|
||||
text="Browse...",
|
||||
command=lambda: self.gcloud_sa_key_path.set(
|
||||
filedialog.askopenfilename(
|
||||
filetypes=[("JSON", "*.json"), ("All", "*")]
|
||||
)
|
||||
or self.gcloud_sa_key_path.get()
|
||||
),
|
||||
)
|
||||
sa_browse_win = self.bg_canvas.create_window(
|
||||
x_label + 580, y - 8, window=sa_browse, anchor="nw"
|
||||
)
|
||||
self._canvas_items.append(sa_browse_win)
|
||||
self._overlay_widgets.append(sa_browse)
|
||||
y += 34
|
||||
|
||||
# Common Services Status Check (Notebook)
|
||||
|
||||
@ -15,6 +15,88 @@ from knoe.core.env import PROJECT_ROOT, _normalize_cluster_env, _parse_bool
|
||||
class GitOpsScreenMixin:
|
||||
"""GitOps / Gitea deployment screen."""
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# GitOps provider choice screen
|
||||
# ------------------------------------------------------------------
|
||||
def _render_gitops_choice_page(self):
|
||||
"""Explicit GitOps provider selection: Gitea, ArgoCD, or None."""
|
||||
content_width = self.bg_canvas.winfo_width() or 975
|
||||
right_margin = content_width - 48
|
||||
ui.canvas_text(
|
||||
self,
|
||||
right_margin,
|
||||
40,
|
||||
"Prole",
|
||||
fill="#6e6e73",
|
||||
font=("SF Pro Text", 32, "bold"),
|
||||
anchor="ne",
|
||||
)
|
||||
ui.canvas_text(
|
||||
self,
|
||||
right_margin,
|
||||
85,
|
||||
"Infrastructure Automated.",
|
||||
fill="#6e6e73",
|
||||
font=("SF Pro Text", 18),
|
||||
anchor="ne",
|
||||
)
|
||||
self._render_title("GitOps Provider", y=150)
|
||||
description = (
|
||||
"Choose your GitOps provider for this deployment.\n"
|
||||
"Gitea deploys a self-hosted Git server; ArgoCD adds continuous delivery.\n"
|
||||
"Select None to skip GitOps tooling entirely."
|
||||
)
|
||||
self._render_paragraph(description, y=210)
|
||||
|
||||
x_label = 48
|
||||
y = 310
|
||||
|
||||
for label, value in [
|
||||
("Gitea — self-hosted Git + CI (recommended)", "gitea"),
|
||||
("ArgoCD — continuous delivery / GitOps sync", "argocd"),
|
||||
("None — skip GitOps tooling", "none"),
|
||||
]:
|
||||
rb = tk.Radiobutton(
|
||||
self.bg_canvas,
|
||||
text=label,
|
||||
variable=self.gitops_provider,
|
||||
value=value,
|
||||
command=self._on_gitops_provider_change,
|
||||
bg="white",
|
||||
fg="black",
|
||||
activebackground="white",
|
||||
selectcolor="white",
|
||||
font=("SF Pro Text", 12),
|
||||
)
|
||||
win = self.bg_canvas.create_window(x_label, y, window=rb, anchor="nw")
|
||||
self._canvas_items.append(win)
|
||||
self._overlay_widgets.append(rb)
|
||||
y += 36
|
||||
|
||||
def _on_gitops_provider_change(self):
|
||||
"""Persist the chosen GitOps provider to prole_cfg."""
|
||||
provider = self.gitops_provider.get()
|
||||
try:
|
||||
if "Optional Features" not in self.prole_cfg_data:
|
||||
self.prole_cfg_data["Optional Features"] = {}
|
||||
self.prole_cfg_data["Optional Features"]["GITOPS_PROVIDER"] = provider
|
||||
# Keep legacy flags in sync so downstream steps remain consistent.
|
||||
self.prole_cfg_data["Optional Features"]["GITOPS_ENABLED"] = str(
|
||||
provider == "gitea"
|
||||
)
|
||||
self.prole_cfg_data["Optional Features"]["ARGOCD_ENABLED"] = str(
|
||||
provider == "argocd"
|
||||
)
|
||||
self._save_prole_cfg()
|
||||
except Exception:
|
||||
pass
|
||||
# Sync boolean vars used by the individual feature screens.
|
||||
self.gitops_enabled.set(provider == "gitea")
|
||||
self.argocd_enabled.set(provider == "argocd")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Gitea deployment screen
|
||||
# ------------------------------------------------------------------
|
||||
def _render_gitops_config_page(self):
|
||||
content_width = self.bg_canvas.winfo_width() or 975
|
||||
right_margin = content_width - 48
|
||||
|
||||
@ -345,9 +345,12 @@ class NavigationMixin:
|
||||
if current_id == "kerberos_config":
|
||||
self.show_page("init_scripts")
|
||||
return
|
||||
if current_id == "argocd_config":
|
||||
if current_id == "gitops_choice":
|
||||
self.show_page("kerberos_config")
|
||||
return
|
||||
if current_id == "argocd_config":
|
||||
self.show_page("gitops_choice")
|
||||
return
|
||||
if current_id == "gitops_config":
|
||||
self.show_page("argocd_config")
|
||||
return
|
||||
@ -592,7 +595,7 @@ class NavigationMixin:
|
||||
if self.kerberos_enabled.get():
|
||||
self.show_page("kerberos_config")
|
||||
else:
|
||||
self.show_page("argocd_config")
|
||||
self.show_page("gitops_choice")
|
||||
return
|
||||
|
||||
if current_id == "kerberos_config":
|
||||
@ -634,9 +637,17 @@ class NavigationMixin:
|
||||
os.environ.get("KRB5_AD_SERVICE_NAME", "prole-kerberos-ad-dc")
|
||||
)
|
||||
self._save_prole_cfg()
|
||||
self.show_page("gitops_choice")
|
||||
return
|
||||
if current_id == "gitops_choice":
|
||||
if "Optional Features" not in self.prole_cfg_data:
|
||||
self.prole_cfg_data["Optional Features"] = {}
|
||||
self.prole_cfg_data["Optional Features"]["GITOPS_PROVIDER"] = (
|
||||
self.gitops_provider.get()
|
||||
)
|
||||
self._save_prole_cfg()
|
||||
self.show_page("argocd_config")
|
||||
return
|
||||
|
||||
if current_id == "argocd_config":
|
||||
self.prole_cfg_data["Optional Features"]["ARGOCD_ENABLED"] = str(
|
||||
self.argocd_enabled.get()
|
||||
@ -787,6 +798,8 @@ class NavigationMixin:
|
||||
self.next_button.configure(state="disabled")
|
||||
else:
|
||||
self.next_button.configure(state="normal")
|
||||
elif pid == "gitops_choice":
|
||||
self.next_button.configure(state="normal")
|
||||
elif pid == "argocd_config":
|
||||
if self.argocd_enabled.get():
|
||||
if getattr(self, "_argocd_success", False):
|
||||
|
||||
@ -166,11 +166,11 @@ class ServicesScreenMixin:
|
||||
("Kubectl Status", self.KUBECTL_STATUS_TAB),
|
||||
("Common Services", "init_common_services.sh"),
|
||||
("Common Services Log", "common_services_log"),
|
||||
("Cert-Manager", "init_certmgr.sh"),
|
||||
("CloudNative-PG", "init_cloudnative_pg.sh"),
|
||||
]
|
||||
scripts.append(("Prole DB Backup", "init_cnpg_backup.sh"))
|
||||
scripts.append(("Kong API Gateway", "init_kong.sh"))
|
||||
scripts.append(("DB Manager", "init_db_manager.sh"))
|
||||
scripts.append(("Monitoring", "init_monitoring.sh"))
|
||||
mode = self._deployment_mode()
|
||||
if mode != "k3d":
|
||||
@ -224,6 +224,7 @@ class ServicesScreenMixin:
|
||||
env["DB_PASSWORD"] = password
|
||||
env["GRAFANA_ADMIN_PASSWORD"] = password
|
||||
env["NAMESPACE"] = (self.db_namespace.get() or "").strip()
|
||||
env["PROLE_NAMESPACE"] = env["NAMESPACE"]
|
||||
env["SERVICE_NAMESPACE"] = self._get_service_namespace()
|
||||
if self.kerberos_realm.get().strip():
|
||||
env["KRB5_REALM"] = self.kerberos_realm.get().strip()
|
||||
@ -284,13 +285,13 @@ class ServicesScreenMixin:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 1. init_common_services.sh update
|
||||
# 1. init_common_services.sh start
|
||||
overall_success = True
|
||||
if overall_success:
|
||||
script = "init_common_services.sh"
|
||||
_select_tab(script)
|
||||
self.script_consoles[script].clear()
|
||||
self.script_consoles[script].write(f"Running {script} update...\n")
|
||||
self.script_consoles[script].write(f"Running {script} start...\n")
|
||||
|
||||
svc_log_path = _log_path_for(script)
|
||||
self._last_common_services_log_path = svc_log_path
|
||||
@ -319,9 +320,10 @@ class ServicesScreenMixin:
|
||||
pass
|
||||
|
||||
svc_args = list(mode_args)
|
||||
svc_args += ["-n", env.get("NAMESPACE") or env.get("SERVICE_NAMESPACE") or "default"]
|
||||
if self.kerberos_enabled.get():
|
||||
svc_args.append("-k")
|
||||
svc_args.append("update")
|
||||
svc_args.append("start")
|
||||
rc_svc = self.controller.run_script(
|
||||
script, args=svc_args, env=env, on_line=_svc_line
|
||||
)
|
||||
@ -333,7 +335,7 @@ class ServicesScreenMixin:
|
||||
|
||||
if rc_svc != 0:
|
||||
self.script_consoles[script].write(
|
||||
f"\nERROR: {script} update failed with code {rc_svc}\n"
|
||||
f"\nERROR: {script} start failed with code {rc_svc}\n"
|
||||
)
|
||||
overall_success = False
|
||||
else:
|
||||
@ -345,60 +347,7 @@ class ServicesScreenMixin:
|
||||
"Skipping common services initialization because previous steps failed.\n"
|
||||
)
|
||||
|
||||
# 2. init_certmgr.sh initialize
|
||||
if overall_success:
|
||||
script = "init_certmgr.sh"
|
||||
_select_tab(script)
|
||||
self.script_consoles[script].clear()
|
||||
self.script_consoles[script].write(f"Running {script} initialize...\n")
|
||||
self.script_consoles[script].write(
|
||||
"> bash etc/init_certmgr.sh initialize\n"
|
||||
)
|
||||
|
||||
log_path = _log_path_for(script)
|
||||
self._record_install_log(log_path)
|
||||
try:
|
||||
log_fp = log_path.open("a", encoding="utf-8")
|
||||
except Exception:
|
||||
log_fp = None
|
||||
|
||||
def _certmgr_line(line):
|
||||
self.script_consoles[script].write(line)
|
||||
self._process_script_output_line(line)
|
||||
if log_fp:
|
||||
try:
|
||||
log_fp.write(line)
|
||||
log_fp.flush()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
rc_cm = self.controller.run_script(
|
||||
script,
|
||||
args=mode_args + ["initialize"],
|
||||
env=env,
|
||||
on_line=_certmgr_line,
|
||||
)
|
||||
if log_fp:
|
||||
try:
|
||||
log_fp.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if rc_cm != 0:
|
||||
self.script_consoles[script].write(
|
||||
f"\nERROR: {script} initialize failed with code {rc_cm}\n"
|
||||
)
|
||||
overall_success = False
|
||||
else:
|
||||
self.script_consoles[script].write(
|
||||
f"\n{script} completed successfully.\n"
|
||||
)
|
||||
else:
|
||||
self.script_consoles["init_certmgr.sh"].write(
|
||||
"Skipping cert-manager initialization because previous steps failed.\n"
|
||||
)
|
||||
|
||||
# 3. CloudNative-PG initialization (Python)
|
||||
# 2. CloudNative-PG initialization (Python)
|
||||
cnpg_tab = "init_cloudnative_pg.sh"
|
||||
if overall_success:
|
||||
_select_tab(cnpg_tab)
|
||||
@ -527,8 +476,9 @@ class ServicesScreenMixin:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
kong_ns = env.get("NAMESPACE") or "knoe-db"
|
||||
rc_kong = self.controller.run_script(
|
||||
script, args=mode_args + ["start"], env=env, on_line=_kong_line
|
||||
script, args=mode_args + ["-n", kong_ns, "start"], env=env, on_line=_kong_line
|
||||
)
|
||||
if log_fp:
|
||||
try:
|
||||
@ -551,6 +501,55 @@ class ServicesScreenMixin:
|
||||
"Skipping Kong because previous steps failed.\n"
|
||||
)
|
||||
|
||||
# 6. init_db_manager.sh start
|
||||
if overall_success:
|
||||
script = "init_db_manager.sh"
|
||||
if script in self.script_consoles:
|
||||
_select_tab(script)
|
||||
self.script_consoles[script].clear()
|
||||
self.script_consoles[script].write(f"Running {script} start...\n")
|
||||
|
||||
log_path = _log_path_for(script)
|
||||
self._record_install_log(log_path)
|
||||
try:
|
||||
log_fp = log_path.open("a", encoding="utf-8")
|
||||
except Exception:
|
||||
log_fp = None
|
||||
|
||||
def _dbmgr_line(line):
|
||||
self.script_consoles[script].write(line)
|
||||
self._process_script_output_line(line)
|
||||
if log_fp:
|
||||
try:
|
||||
log_fp.write(line)
|
||||
log_fp.flush()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
rc_dbmgr = self.controller.run_script(
|
||||
script, args=mode_args + ["start"], env=env, on_line=_dbmgr_line
|
||||
)
|
||||
if log_fp:
|
||||
try:
|
||||
log_fp.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if rc_dbmgr != 0:
|
||||
self.script_consoles[script].write(
|
||||
f"\nERROR: {script} start failed with code {rc_dbmgr}\n"
|
||||
)
|
||||
overall_success = False
|
||||
else:
|
||||
self.script_consoles[script].write(
|
||||
f"\n{script} completed successfully.\n"
|
||||
)
|
||||
else:
|
||||
if "init_db_manager.sh" in self.script_consoles:
|
||||
self.script_consoles["init_db_manager.sh"].write(
|
||||
"Skipping DB Manager because previous steps failed.\n"
|
||||
)
|
||||
|
||||
# 7. init_monitoring.sh initialize
|
||||
if overall_success and opt_allowed:
|
||||
script = "init_monitoring.sh"
|
||||
|
||||
@ -130,6 +130,12 @@ kubectl_apply_retry() {
|
||||
done
|
||||
}
|
||||
|
||||
# Sets KONG_CONFIG_CHANGED=1 in the caller's scope when the ConfigMap was
|
||||
# created or updated; leaves it 0 when kubectl reported "unchanged".
|
||||
# A temp file is used to communicate the result out of the subshell.
|
||||
KONG_CONFIG_CHANGED=0
|
||||
_KONG_CONFIG_CHANGED_FILE=""
|
||||
|
||||
create_kong_config() {
|
||||
echo "Creating/updating Kong declarative config '$KONG_CONFIG_NAME' in namespace '$NAMESPACE' ..."
|
||||
|
||||
@ -168,6 +174,8 @@ KONGEOF
|
||||
)
|
||||
|
||||
# Use a subshell to ensure the cleanup trap doesn't leak globally (and trip `set -u` later).
|
||||
# A sentinel file is used to communicate a config change back to the parent shell.
|
||||
_KONG_CONFIG_CHANGED_FILE="$(mktemp)"
|
||||
(
|
||||
tmp="$(mktemp)"
|
||||
trap 'rm -f "${tmp:-}"' EXIT
|
||||
@ -177,8 +185,18 @@ KONGEOF
|
||||
--from-literal=kong.yml="$kong_yml" \
|
||||
--dry-run=client -o yaml >"$tmp"
|
||||
|
||||
kubectl_apply_retry -f "$tmp"
|
||||
local apply_out
|
||||
apply_out=$(kubectl_apply_retry -f "$tmp" 2>&1)
|
||||
echo "$apply_out"
|
||||
if ! echo "$apply_out" | grep -q 'unchanged'; then
|
||||
echo "1" >"$_KONG_CONFIG_CHANGED_FILE"
|
||||
fi
|
||||
)
|
||||
if [[ -f "$_KONG_CONFIG_CHANGED_FILE" ]] && [[ "$(cat "$_KONG_CONFIG_CHANGED_FILE")" == "1" ]]; then
|
||||
KONG_CONFIG_CHANGED=1
|
||||
fi
|
||||
rm -f "$_KONG_CONFIG_CHANGED_FILE"
|
||||
_KONG_CONFIG_CHANGED_FILE=""
|
||||
|
||||
echo "ConfigMap '$KONG_CONFIG_NAME' ready."
|
||||
}
|
||||
@ -238,17 +256,36 @@ deploy() {
|
||||
|
||||
local manifests_dir="$PROLE_HOME/deploy/opentofu/k3s/manifests/prole"
|
||||
|
||||
kubectl_apply_retry -f "$manifests_dir/kong-deployment.yaml" -n "$NAMESPACE"
|
||||
kubectl_apply_retry -f "$manifests_dir/kong-service.yaml" -n "$NAMESPACE"
|
||||
# Determine whether the Deployment already exists before applying manifests.
|
||||
local deployment_existed=0
|
||||
kubectl_rt get deployment "$KONG_NAME" -n "$NAMESPACE" >/dev/null 2>&1 && deployment_existed=1
|
||||
|
||||
local deploy_out
|
||||
deploy_out=$(kubectl_apply_retry -f "$manifests_dir/kong-deployment.yaml" -n "$NAMESPACE" 2>&1)
|
||||
echo "$deploy_out"
|
||||
local svc_out
|
||||
svc_out=$(kubectl_apply_retry -f "$manifests_dir/kong-service.yaml" -n "$NAMESPACE" 2>&1)
|
||||
echo "$svc_out"
|
||||
|
||||
echo "Waiting for $KONG_NAME rollout ..."
|
||||
kubectl rollout status deployment/"$KONG_NAME" -n "$NAMESPACE" --timeout=120s
|
||||
|
||||
# ConfigMaps do not trigger a Deployment rollout by default; always restart
|
||||
# Kong on update/start so it reloads the declarative config.
|
||||
echo "Restarting $KONG_NAME to reload declarative config ..."
|
||||
kubectl rollout restart deployment/"$KONG_NAME" -n "$NAMESPACE" >/dev/null 2>&1 || true
|
||||
kubectl rollout status deployment/"$KONG_NAME" -n "$NAMESPACE" --timeout=120s >/dev/null 2>&1 || true
|
||||
# ConfigMaps do not trigger a Deployment rollout by default. Only restart
|
||||
# Kong when something actually changed: either this is a fresh deployment or
|
||||
# the declarative config ConfigMap was modified. Skipping the restart when
|
||||
# nothing changed prevents a new ReplicaSet from being created every run.
|
||||
local need_restart=0
|
||||
[[ "$deployment_existed" -eq 0 ]] && need_restart=1
|
||||
[[ "${KONG_CONFIG_CHANGED:-0}" -eq 1 ]] && need_restart=1
|
||||
|
||||
if [[ "$need_restart" -eq 1 ]]; then
|
||||
echo "Restarting $KONG_NAME to reload declarative config ..."
|
||||
kubectl rollout restart deployment/"$KONG_NAME" -n "$NAMESPACE" >/dev/null 2>&1 || true
|
||||
kubectl rollout status deployment/"$KONG_NAME" -n "$NAMESPACE" --timeout=120s >/dev/null 2>&1 || true
|
||||
else
|
||||
echo "$KONG_NAME config unchanged; skipping rollout restart."
|
||||
fi
|
||||
|
||||
echo "$KONG_NAME deployed successfully."
|
||||
}
|
||||
|
||||
|
||||
@ -1 +1 @@
|
||||
3
|
||||
4
|
||||
@ -1,47 +1,51 @@
|
||||
Network Discovery Summary:
|
||||
Primary Router: 10.0.0.1 (eero_5d:50:f2)
|
||||
DNS Servers: 10.0.0.5, 10.0.0.4, 100.100.100.100
|
||||
DNS Servers: 10.0.0.5, 100.100.100.100, 10.0.0.4
|
||||
Detected Devices:
|
||||
- 10.0.0.38 [7e:19:9a:fe:9f:ed] (7e:19:9a:fe:9f:ed): Ports [22, 445, 5900, 11434, 88], Services: ['SSH', 'VNC', 'SMB/CIFS (Possible Windows/AD)', 'Ollama', 'Active Directory Related']
|
||||
- 10.0.0.1 [9c:57:bc:5d:50:f2] (eero_5d:50:f2): Ports [], Services: []
|
||||
- 10.0.0.33 [ec:b5:fa:b0:76:e4] (PhilipsLight_b0:76:e4): Ports [80, 443], Services: ['Web Server']
|
||||
- 10.0.0.206 [00:a0:de:a2:0b:ef] (Yamaha_a2:0b:ef): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.189 [00:17:88:a3:2f:cc] (PhilipsLight_a3:2f:cc): Ports [80, 443], Services: ['Web Server']
|
||||
- 10.0.0.179 [48:a6:b8:a4:8e:cc] (Sonos_a4:8e:cc): Ports [], Services: []
|
||||
- 10.0.0.38\ [7e:19:9a:fe:9f:ed] (7e:19:9a:fe:9f:ed): Ports [], Services: []
|
||||
- 10.0.0.188 [00:16:6c:c5:1f:54] (SamsungElect_c5:1f:54): Ports [80, 443], Services: ['Web Server']
|
||||
- 10.0.0.4 [b8:27:eb:b3:6f:2b] (RaspberryPiF_b3:6f:2b): Ports [22, 53, 2049], Services: ['DNS', 'SSH', 'NFS']
|
||||
- 10.0.0.3 [2c:cf:67:8c:2b:47] (RaspberryPi_8c:2b:47): Ports [22, 53, 80, 443, 445, 5900, 88, 389, 636], Services: ['DNS', 'SSH', 'VNC', 'Web Server', 'SMB/CIFS (Possible Windows/AD)', 'Active Directory Related']
|
||||
- 10.0.0.5 [b8:27:eb:88:3a:41] (RaspberryPiF_88:3a:41): Ports [22, 53, 2049, 5900], Services: ['DNS', 'SSH', 'NFS', 'VNC']
|
||||
- 10.0.0.205 [a8:20:66:28:12:e7] (Apple_28:12:e7): Ports [22, 445, 5900, 88], Services: ['SSH', 'VNC', 'SMB/CIFS (Possible Windows/AD)', 'Active Directory Related']
|
||||
- 10.0.0.170 [b0:ee:7b:ca:73:99] (Roku_ca:73:99): Ports [], Services: []
|
||||
- 10.0.0.203 [00:11:32:3b:2f:08] (Synology_3b:2f:08): Ports [22, 80, 443, 2049, 445], Services: ['SSH', 'NFS', 'Web Server', 'SMB/CIFS (Possible Windows/AD)']
|
||||
- 10.0.0.1 [9c:57:bc:5d:50:f2] (eero_5d:50:f2): Ports [53], Services: ['DNS']
|
||||
- 10.0.0.3 [2c:cf:67:8c:2b:47] (RaspberryPi_8c:2b:47): Ports [22, 53, 80, 443, 2049, 445, 5900, 88, 389, 636], Services: ['DNS', 'SSH', 'NFS', 'VNC', 'Web Server', 'SMB/CIFS (Possible Windows/AD)', 'Active Directory Related']
|
||||
- 10.0.0.4 [b8:27:eb:b3:6f:2b] (RaspberryPiF_b3:6f:2b): Ports [22, 53, 443, 2049], Services: ['DNS', 'SSH', 'NFS', 'Web Server']
|
||||
- 10.0.0.5 [b8:27:eb:88:3a:41] (RaspberryPiF_88:3a:41): Ports [22, 53, 443, 2049, 5900], Services: ['DNS', 'SSH', 'NFS', 'VNC', 'Web Server']
|
||||
- 10.0.0.6 [2c:cf:67:45:8d:97] (RaspberryPi_45:8d:97): Ports [22, 80, 443], Services: ['SSH', 'Web Server']
|
||||
- 10.0.0.2 [dc:a4:ca:ea:1a:2f] (Apple_ea:1a:2f): Ports [], Services: []
|
||||
- 10.0.0.6 [2c:cf:67:45:8d:97] (RaspberryPi_45:8d:97): Ports [22, 443], Services: ['SSH', 'Web Server']
|
||||
- 10.0.0.22 [2c:cf:67:45:8d:97] (RaspberryPi_45:8d:97): Ports [22, 443], Services: ['SSH', 'Web Server']
|
||||
- 10.0.0.22 [2c:cf:67:45:8d:97] (RaspberryPi_45:8d:97): Ports [22, 80, 443], Services: ['SSH', 'Web Server']
|
||||
- 10.0.0.26 [c8:db:26:08:52:f8] (Logitech_08:52:f8): Ports [], Services: []
|
||||
- 10.0.0.205 [a8:20:66:28:12:e7] (Apple_28:12:e7): Ports [22, 445, 5900, 88], Services: ['SSH', 'VNC', 'SMB/CIFS (Possible Windows/AD)', 'Active Directory Related']
|
||||
- 10.0.0.33 [ec:b5:fa:b0:76:e4] (PhilipsLight_b0:76:e4): Ports [80, 443], Services: ['Web Server']
|
||||
- 10.0.0.48 [0c:fe:45:53:f4:3c] (SonyInteract_53:f4:3c): Ports [], Services: []
|
||||
- 10.0.0.37 [54:07:7d:22:c0:b2] (Netgear_22:c0:b2): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.55 [48:a6:b8:a7:50:60] (Sonos_a7:50:60): Ports [], Services: []
|
||||
- 10.0.0.45 [f8:b4:6a:30:a4:1f] (HewlettPacka_30:a4:1f): Ports [80, 443], Services: ['Web Server']
|
||||
- 10.0.0.46 [d4:f7:d5:40:ab:17] (SonyInteract_40:ab:17): Ports [], Services: []
|
||||
- 10.0.0.41 [b8:27:eb:57:10:d9] (RaspberryPiF_57:10:d9): Ports [22], Services: ['SSH']
|
||||
- 10.0.0.206 [00:a0:de:a2:0b:ef] (Yamaha_a2:0b:ef): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.73 [4c:a9:19:b3:12:f8] (TuyaSmart_b3:12:f8): Ports [], Services: []
|
||||
- 10.0.0.1\ [9c:57:bc:5d:50:f2] (eero_5d:50:f2): Ports [], Services: []
|
||||
- 10.0.0.95 [b8:27:eb:88:3a:41] (RaspberryPiF_88:3a:41): Ports [22, 53, 443, 2049, 5900], Services: ['DNS', 'SSH', 'NFS', 'VNC', 'Web Server']
|
||||
- 10.0.0.107 [b8:06:0d:b7:7c:56] (TuyaSmart_b7:7c:56): Ports [], Services: []
|
||||
- 10.0.0.113 [60:81:10:92:02:4e] (Apple_92:02:4e): Ports [], Services: []
|
||||
- 10.0.0.94 [f0:20:ff:bf:9a:19] (Intel_bf:9a:19): Ports [], Services: []
|
||||
Note: Potential host for NVIDIA cards (PC Hardware vendor)
|
||||
- 10.0.0.175 [28:80:88:e4:10:1a] (Netgear_e4:10:1a): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.123 [3c:ef:8c:96:e3:3c] (ZhejiangDahu_96:e3:3c): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.124 [9c:8e:cd:02:73:c4] (AmcrestTechn_02:73:c4): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.130 [f8:bb:bf:a3:84:eb] (eero_a3:84:eb): Ports [53], Services: ['DNS']
|
||||
- 10.0.0.111 [ca:0b:6c:5d:0a:e5] (ca:0b:6c:5d:0a:e5): Ports [], Services: []
|
||||
- 10.0.0.127 [58:55:ca:4a:60:6e] (Apple_4a:60:6e): Ports [22], Services: ['SSH']
|
||||
- 10.0.0.125 [a0:60:32:04:73:ba] (AmcrestTechn_04:73:ba): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.117 [40:f5:20:1e:5e:91] (Espressif_1e:5e:91): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.130 [f8:bb:bf:a3:84:eb] (eero_a3:84:eb): Ports [53], Services: ['DNS']
|
||||
- 10.0.0.107 [b8:06:0d:b7:7c:56] (TuyaSmart_b7:7c:56): Ports [], Services: []
|
||||
- 10.0.0.143 [60:5f:8d:7a:aa:32] (eero_7a:aa:32): Ports [53], Services: ['DNS']
|
||||
- 10.0.0.145 [7c:a6:b0:04:db:1c] (7c:a6:b0:04:db:1c): Ports [], Services: []
|
||||
- 10.0.0.155 [62:17:97:b3:06:a1] (62:17:97:b3:06:a1): Ports [], Services: []
|
||||
- 10.0.0.175 [28:80:88:e4:10:1a] (Netgear_e4:10:1a): Ports [80], Services: ['Web Server']
|
||||
- 10.0.0.208 [a0:ad:9f:30:84:5f] (ASUSTekCOMPU_30:84:5f): Ports [], Services: []
|
||||
- 10.0.0.170 [b0:ee:7b:ca:73:99] (Roku_ca:73:99): Ports [], Services: []
|
||||
- 10.0.0.179 [48:a6:b8:a4:8e:cc] (Sonos_a4:8e:cc): Ports [], Services: []
|
||||
- 10.0.0.189 [00:17:88:a3:2f:cc] (PhilipsLight_a3:2f:cc): Ports [80, 443], Services: ['Web Server']
|
||||
- 10.0.0.188 [00:16:6c:c5:1f:54] (SamsungElect_c5:1f:54): Ports [80, 443], Services: ['Web Server']
|
||||
- 10.0.0.196 [60:5f:8d:88:08:f2] (eero_88:08:f2): Ports [53], Services: ['DNS']
|
||||
- 10.0.0.203 [00:11:32:3b:2f:08] (Synology_3b:2f:08): Ports [22, 80, 443, 2049, 445], Services: ['SSH', 'NFS', 'Web Server', 'SMB/CIFS (Possible Windows/AD)']
|
||||
- 10.0.0.199 [7c:a6:b0:01:a7:33] (7c:a6:b0:01:a7:33): Ports [], Services: []
|
||||
- 10.0.0.204 [50:eb:f6:56:f3:26] (ASUSTekCOMPU_56:f3:26): Ports [22, 3389, 445, 5900, 11434], Services: ['SSH', 'VNC', 'SMB/CIFS (Possible Windows/AD)', 'RDP (Windows)', 'Ollama']
|
||||
- 10.0.0.180 [4c:e1:73:42:1a:be] (HuizhouDehon_2:1a:be): Ports [445], Services: ['SMB/CIFS (Possible Windows/AD)']
|
||||
- 10.0.0.208 [a0:ad:9f:30:84:5f] (ASUSTekCOMPU_30:84:5f): Ports [], Services: []
|
||||
- 10.0.0.113 [60:81:10:92:02:4e] (Apple_92:02:4e): Ports [], Services: []
|
||||
Ollama Instances found at: 10.0.0.38, 10.0.0.204
|
||||
|
||||
Ansible Inventory Summary:
|
||||
|
||||
@ -210,7 +210,7 @@ deployment:
|
||||
resources: {}
|
||||
|
||||
db:
|
||||
enabled: true
|
||||
enabled: false
|
||||
replicaCount: 1
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
@ -225,7 +225,6 @@ deployment:
|
||||
volumeMounts: {}
|
||||
volumes: {}
|
||||
resources: {}
|
||||
|
||||
functions:
|
||||
enabled: true
|
||||
replicaCount: 1
|
||||
@ -261,7 +260,7 @@ deployment:
|
||||
resources: {}
|
||||
|
||||
kong:
|
||||
enabled: true
|
||||
enabled: false
|
||||
replicaCount: 1
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
@ -276,7 +275,6 @@ deployment:
|
||||
volumeMounts: {}
|
||||
volumes: {}
|
||||
resources: {}
|
||||
|
||||
meta:
|
||||
enabled: true
|
||||
replicaCount: 1
|
||||
@ -346,7 +344,7 @@ deployment:
|
||||
resources: {}
|
||||
|
||||
storage:
|
||||
enabled: true
|
||||
enabled: false
|
||||
replicaCount: 1
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
@ -361,9 +359,8 @@ deployment:
|
||||
volumeMounts: {}
|
||||
volumes: {}
|
||||
resources: {}
|
||||
|
||||
studio:
|
||||
enabled: true
|
||||
enabled: false
|
||||
replicaCount: 1
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
@ -378,7 +375,6 @@ deployment:
|
||||
volumeMounts: {}
|
||||
volumes: {}
|
||||
resources: {}
|
||||
|
||||
vector:
|
||||
enabled: true
|
||||
replicaCount: 1
|
||||
@ -396,6 +392,12 @@ deployment:
|
||||
volumes: {}
|
||||
resources: {}
|
||||
|
||||
## External Kong — shared Kong gateway in kube-system (local kong deployment is disabled)
|
||||
externalKong:
|
||||
enabled: true
|
||||
host: kong-proxy.kube-system.svc.cluster.local
|
||||
port: 80
|
||||
|
||||
externalDatabase:
|
||||
enabled: false
|
||||
host: ""
|
||||
@ -627,10 +629,14 @@ environment:
|
||||
DB_SSL: disable
|
||||
REQUEST_ALLOW_X_FORWARDED_PATH: "true"
|
||||
FILE_SIZE_LIMIT: "52428800"
|
||||
FILE_STORAGE_BACKEND_PATH: /var/lib/storage
|
||||
## Storage backend: rewired to shared Garage S3 (knoe-system)
|
||||
STORAGE_BACKEND: s3
|
||||
TENANT_ID: stub
|
||||
REGION: stub
|
||||
GLOBAL_S3_BUCKET: stub
|
||||
REGION: garage
|
||||
GLOBAL_S3_BUCKET: supabase-storage
|
||||
GLOBAL_S3_ENDPOINT: http://garage.knoe-system.svc.cluster.local:3900
|
||||
GLOBAL_S3_PROTOCOL: http
|
||||
GLOBAL_S3_FORCE_PATH_STYLE: "true"
|
||||
ENABLE_IMAGE_TRANSFORMATION: "true"
|
||||
|
||||
studio:
|
||||
|
||||
@ -29,6 +29,14 @@ class _DummyClusterApp(ScreenBaseMixin, ClusterScreenMixin):
|
||||
self.selected_kubectx = tk.StringVar(master=root, value="")
|
||||
self.service_namespace = tk.StringVar(master=root, value="knoe-system")
|
||||
self.prod_artifacts_path = tk.StringVar(master=root, value="/tmp")
|
||||
# GitOps / GWorkspace / GCloud variables added to prod screen
|
||||
self.gitops_provider = tk.StringVar(master=root, value="gitea")
|
||||
self.gworkspace_domain = tk.StringVar(master=root, value="")
|
||||
self.gworkspace_customer_id = tk.StringVar(master=root, value="")
|
||||
self.gworkspace_admin_email = tk.StringVar(master=root, value="")
|
||||
self.gcloud_project_id = tk.StringVar(master=root, value="")
|
||||
self.gcloud_region = tk.StringVar(master=root, value="us-central1")
|
||||
self.gcloud_sa_key_path = tk.StringVar(master=root, value="")
|
||||
|
||||
# Legacy variables still referenced by non-UI logic elsewhere
|
||||
self.k3s_server_url = tk.StringVar(master=root, value="")
|
||||
@ -176,9 +184,15 @@ def test_kubectx_selection_requires_apply():
|
||||
self.selected_kubectx = tk.StringVar(master=root, value="ctx-000")
|
||||
self.service_namespace = tk.StringVar(master=root, value="knoe-system")
|
||||
self.prod_artifacts_path = tk.StringVar(master=root, value="/tmp")
|
||||
self.gitops_provider = tk.StringVar(master=root, value="gitea")
|
||||
self.gworkspace_domain = tk.StringVar(master=root, value="")
|
||||
self.gworkspace_customer_id = tk.StringVar(master=root, value="")
|
||||
self.gworkspace_admin_email = tk.StringVar(master=root, value="")
|
||||
self.gcloud_project_id = tk.StringVar(master=root, value="")
|
||||
self.gcloud_region = tk.StringVar(master=root, value="us-central1")
|
||||
self.gcloud_sa_key_path = tk.StringVar(master=root, value="")
|
||||
self.k3s_server_url = tk.StringVar(master=root, value="")
|
||||
self.k3s_token = tk.StringVar(master=root, value="")
|
||||
|
||||
self._kubectx_applied = "ctx-000"
|
||||
self._switch_calls: list[str] = []
|
||||
|
||||
@ -231,3 +245,29 @@ def test_kubectx_selection_requires_apply():
|
||||
assert app._switch_calls == ["ctx-001"]
|
||||
finally:
|
||||
root.destroy()
|
||||
|
||||
|
||||
def test_prod_cluster_screen_renders_google_and_gitops_fields():
|
||||
"""Prod env must show GitOps Provider, Google Workspace, and Google Cloud fields."""
|
||||
root = tk.Tk()
|
||||
root.withdraw()
|
||||
try:
|
||||
canvas = tk.Canvas(root, width=975, height=900, bg="white")
|
||||
canvas.pack(fill="both", expand=False)
|
||||
root.update()
|
||||
app = _DummyClusterApp(root, canvas, kubectx_values=["ctx-prod"])
|
||||
app.cluster_env.set("prod")
|
||||
app._render_init_cluster_page()
|
||||
root.update()
|
||||
texts = _canvas_texts(canvas)
|
||||
assert "GitOps Provider:" in texts
|
||||
assert "Google Workspace" in texts
|
||||
assert "Google Cloud" in texts
|
||||
assert "Domain:" in texts
|
||||
assert "Customer ID:" in texts
|
||||
assert "Admin Email:" in texts
|
||||
assert "Project ID:" in texts
|
||||
assert "Region:" in texts
|
||||
assert "SA Key Path:" in texts
|
||||
finally:
|
||||
root.destroy()
|
||||
|
||||
91
tests/installer/test_gitops_choice_screen.py
Normal file
91
tests/installer/test_gitops_choice_screen.py
Normal file
@ -0,0 +1,91 @@
|
||||
"""Tests for the GitOps provider choice screen (_render_gitops_choice_page)."""
|
||||
from __future__ import annotations
|
||||
import tkinter as tk
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
||||
if str(PROJECT_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from knoe.ui.screens.base import ScreenBaseMixin
|
||||
from knoe.ui.screens.gitops import GitOpsScreenMixin
|
||||
|
||||
|
||||
class _DummyGitOpsApp(ScreenBaseMixin, GitOpsScreenMixin):
|
||||
"""Minimal surface to render the GitOps choice screen."""
|
||||
|
||||
def __init__(self, root: tk.Tk, canvas: tk.Canvas):
|
||||
self.root = root
|
||||
self.bg_canvas = canvas
|
||||
self._canvas_items: list[int] = []
|
||||
self._overlay_widgets: list[tk.Widget] = []
|
||||
self.gitops_provider = tk.StringVar(master=root, value="gitea")
|
||||
self.gitops_enabled = tk.BooleanVar(master=root, value=False)
|
||||
self.argocd_enabled = tk.BooleanVar(master=root, value=False)
|
||||
self.prole_cfg_data: dict = {}
|
||||
|
||||
def _save_prole_cfg(self):
|
||||
pass
|
||||
|
||||
|
||||
def _canvas_texts(cnv: tk.Canvas) -> list[str]:
|
||||
return [
|
||||
cnv.itemcget(item, "text")
|
||||
for item in cnv.find_all()
|
||||
if cnv.type(item) == "text"
|
||||
]
|
||||
|
||||
|
||||
def test_gitops_choice_page_renders_title_and_options():
|
||||
"""The choice screen must render a title and all three provider options."""
|
||||
root = tk.Tk()
|
||||
root.withdraw()
|
||||
try:
|
||||
canvas = tk.Canvas(root, width=975, height=600, bg="white")
|
||||
canvas.pack(fill="both", expand=False)
|
||||
root.update()
|
||||
app = _DummyGitOpsApp(root, canvas)
|
||||
app._render_gitops_choice_page()
|
||||
root.update()
|
||||
texts = _canvas_texts(canvas)
|
||||
assert "GitOps Provider" in texts
|
||||
# All three provider labels must appear as Radiobutton text (widget titles).
|
||||
widget_texts = [w.cget("text") for w in app._overlay_widgets if isinstance(w, tk.Radiobutton)]
|
||||
assert any("Gitea" in t for t in widget_texts)
|
||||
assert any("ArgoCD" in t for t in widget_texts)
|
||||
assert any("None" in t for t in widget_texts)
|
||||
finally:
|
||||
root.destroy()
|
||||
|
||||
|
||||
def test_on_gitops_provider_change_syncs_boolean_vars():
|
||||
"""Selecting a provider must update gitops_enabled and argocd_enabled accordingly."""
|
||||
root = tk.Tk()
|
||||
root.withdraw()
|
||||
try:
|
||||
canvas = tk.Canvas(root, width=975, height=600, bg="white")
|
||||
canvas.pack()
|
||||
root.update()
|
||||
app = _DummyGitOpsApp(root, canvas)
|
||||
|
||||
app.gitops_provider.set("gitea")
|
||||
app._on_gitops_provider_change()
|
||||
assert app.gitops_enabled.get() is True
|
||||
assert app.argocd_enabled.get() is False
|
||||
assert app.prole_cfg_data["Optional Features"]["GITOPS_PROVIDER"] == "gitea"
|
||||
|
||||
app.gitops_provider.set("argocd")
|
||||
app._on_gitops_provider_change()
|
||||
assert app.gitops_enabled.get() is False
|
||||
assert app.argocd_enabled.get() is True
|
||||
assert app.prole_cfg_data["Optional Features"]["ARGOCD_ENABLED"] == "True"
|
||||
|
||||
app.gitops_provider.set("none")
|
||||
app._on_gitops_provider_change()
|
||||
assert app.gitops_enabled.get() is False
|
||||
assert app.argocd_enabled.get() is False
|
||||
assert app.prole_cfg_data["Optional Features"]["GITOPS_PROVIDER"] == "none"
|
||||
finally:
|
||||
root.destroy()
|
||||
Loading…
Reference in New Issue
Block a user