Add scripts for managing common services and enhance service namespace handling

- Introduced scripts `init_common_services.sh` and `status_common_services.sh` for deploying and checking common services (OpenBao, OpenTofu, registry) within Kubernetes namespaces.
- Improved service namespace configuration in `install.py` and updated initialization logic.
- Updated `prole.cfg` and `kerberos-configmap.yaml` with necessary changes to integrate the new features.
This commit is contained in:
chrisfu 2026-02-07 23:20:08 -08:00
parent f47c18fef7
commit d88f5b6424
5 changed files with 417 additions and 169 deletions

View File

@ -1,4 +1,9 @@
; Prole Master Configuration File
; Generated by install.py on 2026-02-07 22:54:03
; This file is used as input for Ansible deployment and k8s cluster creation.
[Inputs]
; Screen-scoped inputs used for unattended replays (-S)
build.deploy_env = Dev
build.run_build = false
dependencies.auto_install_missing = true
@ -9,17 +14,19 @@ 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 = prole-chrisfu-abracadabra
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
env_setup.prole_logs = /Users/chrisfu/dev/prole/logs
env_setup.prole_service = /Users/chrisfu/dev/prole/etc
env_setup.NAMESPACE = prole-chrisfu-abracadabra
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
env_setup.PROLE_LOGS = /Users/chrisfu/dev/prole/logs
env_setup.PROLE_SERVICE = /Users/chrisfu/dev/prole/etc
init_cluster.at_rest_encryption_enabled = true
init_cluster.cluster_env = prole-service-cluster
init_cluster.cluster_env = k3d-prole-dev-cluster
init_cluster.deployment_target = prole-dev-cluster
init_cluster.k3s_server_url = https://myrddin.prole.org:6443
init_cluster.k3s_token = ${PROLE_SECRET:v1:T5sfnR62PYD8mB6x:9rlfh08fyPnsItAHzpY_qSSgTTIaYQed4kYuzJIRVF25mRcqmmxX0ccZpXpDP-0YqfJETY0XmfVhCx8kuq4AAfd2bCqfcArXETJPDjo-4FUE3iPYeLkpNEzXrGGp1Jp4t7gaYQZd0p-_J6UUCh6xjwl_w0AU2Rs45l-3A6WkwFVqNS_fIqapboH6md_3yRcjFU0p3N9IuQTT6ea7BGuAzM9d_swR3DzUHN0ZVMOlQ5AsiKCh_q3G6lTEy2n8l3utDdLoKht0wWc9kaE9XxRPMWT9cZlJUjLP64uglQ30t6Qp-jEXH9Ecv8J1GY4CfIoMrE1pY5XttelMqWXTCn_CQHtI6yapXeJvQvCSAPRBNvNZqAH7cLlcQ4THNGcm55EtNjSA-d4P0anPk26PAkyheplDtB6fJCv2zlHJGS89jr_Y40PBvojeGO3K3mtKXEu_pArZJK6g4ilCXnQPt8cN_Woq4JRNIYzim47L6c0inp3R_L60KiRQF8DH9CGZAQtjueB343_4-aNlrDTWTfIZqf6hBNjIo_5cRjcAuESSq2DaVEWL0Ucsfj922WjjQAQvlc1E-YItisEAzjsNcOpawVFrlNBEJ0oGooPOw-nfvcdh5MicW-IStqV67uK7y1jsQUbEgr2-Jj5L5Q7njrzQZymyAYlzc1Ra6LgTUbZzVC9DtNZOpFLrfV_SHBnBBZBrt7T6xGqd_-P5x0P4S9T7-KnaKtGk15VRlL86G-oxOF3ubfJjiMsOtYAOyh8-gATu9wWL692kq2VwYIAsB5qGXcG6jwzcBZiT-iOl01yHGFAQCd6Rno3Y56a_HdXUxZ9LIKXjtRGjxjVplIlAt0VWgUQ1xB0hCEWM8SRcIRkRUpR00cj28J_9gp2I29s2RKnlXY67YsdlXZAl28IqbZP9TqlJEFVohhCGu6moBGbaCaEb2stUamp_lUEfGEPB74p9WxvpSuCZT0jQMtqMTsCokI0N6xXMu8O4i9Pe-md4f2z3xWfooKGZWPAufSX1Eb1Q5jGBJ1YNz_b_q8CzFqAyGYtm_EMKTBXe2i2YEBZnFMjxlmFp5kRqb4Y-GPCoHTLMKjZ-jV9DAcGO3hQcO-cmDpF9e4zWUFt0olkRjgR7xaoJB8Mc9tfhWSAC0IQcD8DZ54YFVhqwd0bByVw_jt-Qxd67aydobdyinevj-qgEuVtwkzNmIWiaxnJfSNV0bjk3Re9G8m3-Dypeo4TB2dkw9o_TY4JL7pKYFvZ-ZfiJW1mJAqmiPUk=}
init_cluster.kerberos_enabled = false
init_cluster.k3s_token = ${PROLE_SECRET:v1:HXX9yZVJsqlB7U44:CgPv2ktXimi3P5d3KH1wotkrH-cRF-fiFXQDoe2kdoz4cAxl3JdqlKTcCKIG6i2-PWQEr0emK9k3LJTPCA6tj-rZYyWuDyAUCsylwmU-YPAWJbbQ-Weicu9e-0QgHALAVcV2d4N0BmvarxefTGYHYOA8wEhsVdty-EnirQ==}
init_cluster.kerberos_enabled = true
init_cluster.mode = k3d
init_cluster.start_cluster = true
init_cluster.supabase_enabled = false
init_cnpg_deploy.force_rollout = false
@ -29,10 +36,10 @@ init_password.db_host_port = 5432
init_password.db_namespace = prole-chrisfu-abracadabra
init_password.db_password = ${OPENBAO:kv/prole/prole-chrisfu-abracadabra/db#password}
init_password.db_password_confirm = ${OPENBAO:kv/prole/prole-chrisfu-abracadabra/db#password}
init_password.db_username = chrisfu
init_password.db_username = root
init_password.generate_ssh_key = true
init_scripts.run_scripts = true
kerberos_config.enabled = false
kerberos_config.enabled = true
kerberos_config.init_authority = false
kerberos_config.kdc = 10.0.0.3
kerberos_config.password = ${OPENBAO:kv/prole/prole-chrisfu-abracadabra/kerberos#password}
@ -42,115 +49,93 @@ kerberos_config.user =
network_scan.run = true
[Global]
cluster_env = prole-service-cluster
db_host_port = 5432
db_password = ${OPENBAO:kv/prole/prole-chrisfu-abracadabra/db#password}
deployment_mode = k3s
deployment_target = prole-service-cluster
docker_import_dir =
namespace = prole-chrisfu-abracadabra
prole_db_user = chrisfu
prole_home = /Users/chrisfu/dev/prole
prole_k3s_server = https://myrddin.prole.org:6443
prole_k3s_token = ${PROLE_SECRET:v1:T5sfnR62PYD8mB6x:9rlfh08fyPnsItAHzpY_qSSgTTIaYQed4kYuzJIRVF25mRcqmmxX0ccZpXpDP-0YqfJETY0XmfVhCx8kuq4AAfd2bCqfcArXETJPDjo-4FUE3iPYeLkpNEzXrGGp1Jp4t7gaYQZd0p-_J6UUCh6xjwl_w0AU2Rs45l-3A6WkwFVqNS_fIqapboH6md_3yRcjFU0p3N9IuQTT6ea7BGuAzM9d_swR3DzUHN0ZVMOlQ5AsiKCh_q3G6lTEy2n8l3utDdLoKht0wWc9kaE9XxRPMWT9cZlJUjLP64uglQ30t6Qp-jEXH9Ecv8J1GY4CfIoMrE1pY5XttelMqWXTCn_CQHtI6yapXeJvQvCSAPRBNvNZqAH7cLlcQ4THNGcm55EtNjSA-d4P0anPk26PAkyheplDtB6fJCv2zlHJGS89jr_Y40PBvojeGO3K3mtKXEu_pArZJK6g4ilCXnQPt8cN_Woq4JRNIYzim47L6c0inp3R_L60KiRQF8DH9CGZAQtjueB343_4-aNlrDTWTfIZqf6hBNjIo_5cRjcAuESSq2DaVEWL0Ucsfj922WjjQAQvlc1E-YItisEAzjsNcOpawVFrlNBEJ0oGooPOw-nfvcdh5MicW-IStqV67uK7y1jsQUbEgr2-Jj5L5Q7njrzQZymyAYlzc1Ra6LgTUbZzVC9DtNZOpFLrfV_SHBnBBZBrt7T6xGqd_-P5x0P4S9T7-KnaKtGk15VRlL86G-oxOF3ubfJjiMsOtYAOyh8-gATu9wWL692kq2VwYIAsB5qGXcG6jwzcBZiT-iOl01yHGFAQCd6Rno3Y56a_HdXUxZ9LIKXjtRGjxjVplIlAt0VWgUQ1xB0hCEWM8SRcIRkRUpR00cj28J_9gp2I29s2RKnlXY67YsdlXZAl28IqbZP9TqlJEFVohhCGu6moBGbaCaEb2stUamp_lUEfGEPB74p9WxvpSuCZT0jQMtqMTsCokI0N6xXMu8O4i9Pe-md4f2z3xWfooKGZWPAufSX1Eb1Q5jGBJ1YNz_b_q8CzFqAyGYtm_EMKTBXe2i2YEBZnFMjxlmFp5kRqb4Y-GPCoHTLMKjZ-jV9DAcGO3hQcO-cmDpF9e4zWUFt0olkRjgR7xaoJB8Mc9tfhWSAC0IQcD8DZ54YFVhqwd0bByVw_jt-Qxd67aydobdyinevj-qgEuVtwkzNmIWiaxnJfSNV0bjk3Re9G8m3-Dypeo4TB2dkw9o_TY4JL7pKYFvZ-ZfiJW1mJAqmiPUk=}
prole_opentofu_url = http://127.0.0.1:8080
; Variables used by name in more than one place or assumed global scope
CLUSTER_ENV = k3d-prole-dev-cluster
DB_HOST_PORT = 5432
DB_PASSWORD = ${OPENBAO:kv/prole/prole-chrisfu-abracadabra/db#password}
DEPLOYMENT_MODE = k3d
DEPLOYMENT_TARGET = prole-dev-cluster
NAMESPACE = prole-chrisfu-abracadabra
SERVICE_NAMESPACE = default
PROLE_DB_USER = root
PROLE_HOME = /Users/chrisfu/dev/prole
PROLE_K3S_SERVER = https://myrddin.prole.org:6443
PROLE_K3S_TOKEN = ${PROLE_SECRET:v1:LytIXLCWuapSbR1I:ahBM0OeRZy5AYarqjIve9tpyYfgHEjUAo28d_YC8cCs4WHMvZX3OeIcbHBHynuhSzvV5K7oILRhQThUo11mfzspt4M6GPO3C6NO9gVNN08z2ZI1XiZ5UJDD4Yew8zVcKshA6_Hq4DLLF71oA7edNgCDkzxXZZEFzO8cbFw==}
PROLE_OPENTOFU_URL = http://127.0.0.1:8080
[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
ad_dc_ip = 10.0.0.3
ansible_domain = prole.org
ansible_infrastructure = /Users/chrisfu/dev/prole/infrastructure
ansible_inventory = /Users/chrisfu/dev/prole/infrastructure/inventory
ansible_realm = PROLE.ORG
ansible_topology = {"domain":"prole.org","realm":"PROLE.ORG","internal_records":{"aventage.prole.org":"10.0.0.206","fairyland.prole.org":"10.0.0.208","loghost.prole.org":"10.0.0.3","morana.prole.org":"10.0.0.66","morgoth.prole.org":"10.0.0.204","myrddin.prole.org":"10.0.0.3","pi.prole.org":"10.0.0.5","raspberry.prole.org":"10.0.0.4","retropie.prole.org":"10.0.0.207","synology.prole.org":"10.0.0.203","zinfandel.prole.org":"10.0.0.205"},"ad_dc":{"host":"myrddin.prole.org","ip":"10.0.0.3"},"k3s":{"server_url":"https://myrddin.prole.org:6443","server_host":"myrddin.prole.org","token_present":true},"groups":{"iscsi":["pi.prole.org","raspberry.prole.org","myrddin.prole.org","retropie.prole.org"],"pihole":["pi.prole.org","raspberry.prole.org"],"ad_dc":["myrddin.prole.org"],"k3s_hosts":["pi.prole.org","myrddin.prole.org","retropie.prole.org"],"linux_hosts":["pi.prole.org","raspberry.prole.org","myrddin.prole.org","retropie.prole.org"]},"hosts":{"myrddin.prole.org":"10.0.0.3","pi.prole.org":"10.0.0.5","raspberry.prole.org":"10.0.0.4","retropie.prole.org":"10.0.0.207"},"unmapped_hosts":[]}
kdc_ansible_detected = 10.0.0.3
AD_DC_HOST = myrddin.prole.org
AD_DC_IP = 10.0.0.3
ANSIBLE_DOMAIN = prole.org
ANSIBLE_INFRASTRUCTURE = /Users/chrisfu/dev/prole/infrastructure
ANSIBLE_INVENTORY = /Users/chrisfu/dev/prole/infrastructure/inventory
ANSIBLE_REALM = PROLE.ORG
ANSIBLE_TOPOLOGY = {"domain":"prole.org","realm":"PROLE.ORG","internal_records":{"aventage.prole.org":"10.0.0.206","fairyland.prole.org":"10.0.0.208","loghost.prole.org":"10.0.0.3","morana.prole.org":"10.0.0.66","morgoth.prole.org":"10.0.0.204","myrddin.prole.org":"10.0.0.3","pi.prole.org":"10.0.0.5","raspberry.prole.org":"10.0.0.4","retropie.prole.org":"10.0.0.207","synology.prole.org":"10.0.0.203","zinfandel.prole.org":"10.0.0.205"},"ad_dc":{"host":"myrddin.prole.org","ip":"10.0.0.3"},"k3s":{"server_url":"https://myrddin.prole.org:6443","server_host":"myrddin.prole.org","token_present":true},"groups":{"iscsi":["pi.prole.org","raspberry.prole.org","myrddin.prole.org","retropie.prole.org"],"pihole":["pi.prole.org","raspberry.prole.org"],"ad_dc":["myrddin.prole.org"],"k3s_hosts":["pi.prole.org","myrddin.prole.org","retropie.prole.org"],"linux_hosts":["pi.prole.org","raspberry.prole.org","myrddin.prole.org","retropie.prole.org"]},"hosts":{"myrddin.prole.org":"10.0.0.3","pi.prole.org":"10.0.0.5","raspberry.prole.org":"10.0.0.4","retropie.prole.org":"10.0.0.207"},"unmapped_hosts":[]}
KDC_ANSIBLE_DETECTED = 10.0.0.3
KDC_AUTO_DETECTED = 10.0.0.3
KERBEROS_AUTO_ENABLED = True
[Port Forwards]
PORT_FORWARD_EXTERNAL_DB_HOST = myrddin.prole.org
PORT_FORWARD_EXTERNAL_DB_IP = 10.0.0.3
PORT_FORWARD_EXTERNAL_DB_PORT = 5432
PORT_FORWARD_EXTERNAL_DB_SERVICE = prole-db-rw
PORT_FORWARD_K3D_ENABLED = true
PORT_FORWARD_K3D_MAPPING_1 = 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 (https://127.0.0.1:8443)
PORT_FORWARD_K3D_MAPPING_2 = id=prometheus;namespace=default;target=svc/prometheus-community-kube-prometheus;address=127.0.0.1;hostPort=9090;servicePort=9090;protocol=TCP;description=Prometheus UI (http://127.0.0.1:9090)
PORT_FORWARD_K3D_MAPPING_3 = id=grafana;namespace=${NAMESPACE};target=svc/grafana;address=0.0.0.0;hostPort=3000;servicePort=3000;protocol=TCP;description=Grafana UI (0.0.0.0:3000)
PORT_FORWARD_K3D_MAPPING_4 = id=postgres;namespace=${NAMESPACE};target=svc/prole-db-rw;address=0.0.0.0;hostPort=5432;servicePort=5432;protocol=TCP;description=PostgreSQL (primary) (0.0.0.0:5432)
PORT_FORWARD_K3D_MAPPING_5 = id=openbao;namespace=${NAMESPACE};target=svc/openbao;address=127.0.0.1;hostPort=8200;servicePort=8200;protocol=TCP;description=OpenBao UI (http://127.0.0.1:8200)
PORT_FORWARD_K3S_ENABLED = true
PORT_FORWARD_K3S_HOSTS = myrddin.prole.org
PORT_FORWARD_K3S_MAPPING_1 = id=grafana;namespace=${NAMESPACE};target=svc/grafana;address=0.0.0.0;hostPort=3000;servicePort=3000;protocol=TCP;description=Grafana UI (0.0.0.0:3000)
PORT_FORWARD_K3S_MAPPING_2 = id=opentofu;namespace=${NAMESPACE};target=svc/opentofu;address=0.0.0.0;hostPort=8080;servicePort=8080;protocol=TCP;description=OpenTofu UI/API (0.0.0.0:8080)
PORT_FORWARD_K3S_MAPPING_3 = id=openbao;namespace=${NAMESPACE};target=svc/openbao;address=0.0.0.0;hostPort=8200;servicePort=8200;protocol=TCP;description=OpenVault/OpenBao UI/API (0.0.0.0:8200)
PORT_FORWARD_K3S_MAPPING_4 = id=postgres;namespace=${NAMESPACE};target=svc/prole-db-rw;address=0.0.0.0;hostPort=5432;servicePort=5432;protocol=TCP;description=PostgreSQL external (0.0.0.0:5432)
PORT_FORWARD_K3S_MAPPING_5 = id=registry;namespace=${NAMESPACE};target=svc/registry;address=0.0.0.0;hostPort=5000;servicePort=5000;protocol=TCP;description=Docker registry (0.0.0.0:5000)
; No configuration values captured yet for this section.
[System Environment]
prole_conf = /Users/chrisfu/dev/prole/conf
prole_data = /Users/chrisfu/dev/prole/data
prole_home = /Users/chrisfu/dev/prole
prole_logs = /Users/chrisfu/dev/prole/logs
prole_opentofu_url = http://127.0.0.1:8080
prole_service = /Users/chrisfu/dev/prole/etc
PROLE_CONF = /Users/chrisfu/dev/prole/conf
PROLE_DATA = /Users/chrisfu/dev/prole/data
PROLE_HOME = /Users/chrisfu/dev/prole
PROLE_LOGS = /Users/chrisfu/dev/prole/logs
PROLE_SERVICE = /Users/chrisfu/dev/prole/etc
[Monitoring]
; No configuration values captured yet for this section.
[Kerberos Authentication]
; No configuration values captured yet for this section.
[Optional Features]
at_rest_encryption_enabled = true
kerberos_enabled = false
supabase_enabled = false
; No configuration values captured yet for this section.
[Database Creation]
db_name = prole-chrisfu-abracadabra
db_password_set = true
db_user = chrisfu
namespace = prole-chrisfu-abracadabra
; No configuration values captured yet for this section.
[Initialize Cluster]
environment = prole-service-cluster
k3s_server_url = https://myrddin.prole.org:6443
k3s_token = ${PROLE_SECRET:v1:T5sfnR62PYD8mB6x:9rlfh08fyPnsItAHzpY_qSSgTTIaYQed4kYuzJIRVF25mRcqmmxX0ccZpXpDP-0YqfJETY0XmfVhCx8kuq4AAfd2bCqfcArXETJPDjo-4FUE3iPYeLkpNEzXrGGp1Jp4t7gaYQZd0p-_J6UUCh6xjwl_w0AU2Rs45l-3A6WkwFVqNS_fIqapboH6md_3yRcjFU0p3N9IuQTT6ea7BGuAzM9d_swR3DzUHN0ZVMOlQ5AsiKCh_q3G6lTEy2n8l3utDdLoKht0wWc9kaE9XxRPMWT9cZlJUjLP64uglQ30t6Qp-jEXH9Ecv8J1GY4CfIoMrE1pY5XttelMqWXTCn_CQHtI6yapXeJvQvCSAPRBNvNZqAH7cLlcQ4THNGcm55EtNjSA-d4P0anPk26PAkyheplDtB6fJCv2zlHJGS89jr_Y40PBvojeGO3K3mtKXEu_pArZJK6g4ilCXnQPt8cN_Woq4JRNIYzim47L6c0inp3R_L60KiRQF8DH9CGZAQtjueB343_4-aNlrDTWTfIZqf6hBNjIo_5cRjcAuESSq2DaVEWL0Ucsfj922WjjQAQvlc1E-YItisEAzjsNcOpawVFrlNBEJ0oGooPOw-nfvcdh5MicW-IStqV67uK7y1jsQUbEgr2-Jj5L5Q7njrzQZymyAYlzc1Ra6LgTUbZzVC9DtNZOpFLrfV_SHBnBBZBrt7T6xGqd_-P5x0P4S9T7-KnaKtGk15VRlL86G-oxOF3ubfJjiMsOtYAOyh8-gATu9wWL692kq2VwYIAsB5qGXcG6jwzcBZiT-iOl01yHGFAQCd6Rno3Y56a_HdXUxZ9LIKXjtRGjxjVplIlAt0VWgUQ1xB0hCEWM8SRcIRkRUpR00cj28J_9gp2I29s2RKnlXY67YsdlXZAl28IqbZP9TqlJEFVohhCGu6moBGbaCaEb2stUamp_lUEfGEPB74p9WxvpSuCZT0jQMtqMTsCokI0N6xXMu8O4i9Pe-md4f2z3xWfooKGZWPAufSX1Eb1Q5jGBJ1YNz_b_q8CzFqAyGYtm_EMKTBXe2i2YEBZnFMjxlmFp5kRqb4Y-GPCoHTLMKjZ-jV9DAcGO3hQcO-cmDpF9e4zWUFt0olkRjgR7xaoJB8Mc9tfhWSAC0IQcD8DZ54YFVhqwd0bByVw_jt-Qxd67aydobdyinevj-qgEuVtwkzNmIWiaxnJfSNV0bjk3Re9G8m3-Dypeo4TB2dkw9o_TY4JL7pKYFvZ-ZfiJW1mJAqmiPUk=}
; No configuration values captured yet for this section.
[Dev Cluster (k3d)]
cluster_env = k3d-prole-dev-cluster
display_name = prole-dev-cluster
kubectl_context = prole-service-cluster
mode = k3d
CLUSTER_ENV = k3d-prole-dev-cluster
DISPLAY_NAME = prole-dev-cluster
KUBECTL_CONTEXT =
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:T5sfnR62PYD8mB6x:9rlfh08fyPnsItAHzpY_qSSgTTIaYQed4kYuzJIRVF25mRcqmmxX0ccZpXpDP-0YqfJETY0XmfVhCx8kuq4AAfd2bCqfcArXETJPDjo-4FUE3iPYeLkpNEzXrGGp1Jp4t7gaYQZd0p-_J6UUCh6xjwl_w0AU2Rs45l-3A6WkwFVqNS_fIqapboH6md_3yRcjFU0p3N9IuQTT6ea7BGuAzM9d_swR3DzUHN0ZVMOlQ5AsiKCh_q3G6lTEy2n8l3utDdLoKht0wWc9kaE9XxRPMWT9cZlJUjLP64uglQ30t6Qp-jEXH9Ecv8J1GY4CfIoMrE1pY5XttelMqWXTCn_CQHtI6yapXeJvQvCSAPRBNvNZqAH7cLlcQ4THNGcm55EtNjSA-d4P0anPk26PAkyheplDtB6fJCv2zlHJGS89jr_Y40PBvojeGO3K3mtKXEu_pArZJK6g4ilCXnQPt8cN_Woq4JRNIYzim47L6c0inp3R_L60KiRQF8DH9CGZAQtjueB343_4-aNlrDTWTfIZqf6hBNjIo_5cRjcAuESSq2DaVEWL0Ucsfj922WjjQAQvlc1E-YItisEAzjsNcOpawVFrlNBEJ0oGooPOw-nfvcdh5MicW-IStqV67uK7y1jsQUbEgr2-Jj5L5Q7njrzQZymyAYlzc1Ra6LgTUbZzVC9DtNZOpFLrfV_SHBnBBZBrt7T6xGqd_-P5x0P4S9T7-KnaKtGk15VRlL86G-oxOF3ubfJjiMsOtYAOyh8-gATu9wWL692kq2VwYIAsB5qGXcG6jwzcBZiT-iOl01yHGFAQCd6Rno3Y56a_HdXUxZ9LIKXjtRGjxjVplIlAt0VWgUQ1xB0hCEWM8SRcIRkRUpR00cj28J_9gp2I29s2RKnlXY67YsdlXZAl28IqbZP9TqlJEFVohhCGu6moBGbaCaEb2stUamp_lUEfGEPB74p9WxvpSuCZT0jQMtqMTsCokI0N6xXMu8O4i9Pe-md4f2z3xWfooKGZWPAufSX1Eb1Q5jGBJ1YNz_b_q8CzFqAyGYtm_EMKTBXe2i2YEBZnFMjxlmFp5kRqb4Y-GPCoHTLMKjZ-jV9DAcGO3hQcO-cmDpF9e4zWUFt0olkRjgR7xaoJB8Mc9tfhWSAC0IQcD8DZ54YFVhqwd0bByVw_jt-Qxd67aydobdyinevj-qgEuVtwkzNmIWiaxnJfSNV0bjk3Re9G8m3-Dypeo4TB2dkw9o_TY4JL7pKYFvZ-ZfiJW1mJAqmiPUk=}
mode = k3s
pipeline_url = http://127.0.0.1:8080
CLUSTER_ENV = prole-service-cluster
DISPLAY_NAME = prole-service-cluster
K3S_SERVER_URL = https://myrddin.prole.org:6443
K3S_TOKEN = ${PROLE_SECRET:v1:Wdqp1yRSbGarX4QV:LpTinWtd3tTRgs0Xao6ghMpb3kr9kJ4hU_e1e3S1e7NWf33lFcZpR2sR3CFWMvvWFJY9rBHnxsD5QtBB_6uk6KPFSCabc01RAsiToqsdvuiw3zCPLqviVODJiZqp3pOFNrogJg7TE8WcuCMPMqBqtNXFzQkT01HVib94sA==}
MODE = k3s
PIPELINE_URL = http://127.0.0.1:8080
[Prod Cluster (k8s)]
artifacts_dir =
cluster_env = prole-prod-cluster
display_name = prole-prod-cluster
mode = k8s
pipeline_url = http://127.0.0.1:8080
ARTIFACTS_DIR = /Users/chrisfu/dev/prole/data/staging
CLUSTER_ENV = prole-prod-cluster
DISPLAY_NAME = prole-prod-cluster
MODE = k8s
PIPELINE_URL = http://127.0.0.1:8080
[Docker Build]
local_registry = localhost:5000
local_registry_internal = k3d-prole-registry.localhost:5000
status = Built
; No configuration values captured yet for this section.
[Initialization Scripts]
status = Attempted
; No configuration values captured yet for this section.
[Deployment]
mode = k3s
opentofu_pipeline_dir = /Users/chrisfu/dev/prole/deploy/opentofu/k3s
status = Attempted
target = prole-service-cluster
MODE = k3d
TARGET = prole-dev-cluster
[Install]
status = Finished
; No configuration values captured yet for this section.

View File

@ -0,0 +1,75 @@
#!/usr/bin/env bash
set -u
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck disable=SC1090
source "$SCRIPT_DIR/prole_cfg.sh"
usage() {
cat <<EOF
Usage: init_common_services.sh [-n|--namespace NS] <update|start|status>
Deploys common infrastructure services (OpenBao, OpenTofu, registry if available)
into the given Kubernetes namespace.
EOF
}
NS=""
ACTION="update"
while [ $# -gt 0 ]; do
case "$1" in
-n|--namespace)
shift
NS="${1:-}"
shift
;;
-n=*|--namespace=*)
NS="${1#*=}"
shift
;;
update|start|status)
ACTION="$1"
shift
;;
-h|--help)
usage
exit 0
;;
*)
usage
exit 2
;;
esac
done
if [ -z "$NS" ]; then
NS="${SERVICE_NAMESPACE:-${NAMESPACE:-}}"
fi
if [ -z "$NS" ]; then
NS="default"
fi
echo "Deploying common services (namespace=$NS, action=$ACTION)"
rc=0
if [ -x "$SCRIPT_DIR/init_openbao.sh" ]; then
"$SCRIPT_DIR/init_openbao.sh" -n "$NS" "$ACTION" || rc=$?
else
echo "WARN: init_openbao.sh not found; skipping OpenBao."
fi
if [ -x "$SCRIPT_DIR/init_opentofu.sh" ]; then
"$SCRIPT_DIR/init_opentofu.sh" -n "$NS" "$ACTION" || rc=$?
else
echo "WARN: init_opentofu.sh not found; skipping OpenTofu."
fi
if [ -x "$SCRIPT_DIR/init_registry.sh" ]; then
"$SCRIPT_DIR/init_registry.sh" -n "$NS" "$ACTION" || rc=$?
else
echo "WARN: init_registry.sh not found; registry deploy skipped."
fi
exit "$rc"

View File

@ -0,0 +1,75 @@
#!/usr/bin/env bash
set -u
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck disable=SC1090
source "$SCRIPT_DIR/prole_cfg.sh"
usage() {
cat <<EOF
Usage: status_common_services.sh [-n|--namespace NS]
Checks common infrastructure services (Docker registry, OpenBao, OpenTofu)
inside the given Kubernetes namespace.
EOF
}
NS=""
while [ $# -gt 0 ]; do
case "$1" in
-n|--namespace)
shift
NS="${1:-}"
shift
;;
-n=*|--namespace=*)
NS="${1#*=}"
shift
;;
-h|--help)
usage
exit 0
;;
*)
usage
exit 2
;;
esac
done
if [ -z "$NS" ]; then
NS="${SERVICE_NAMESPACE:-${NAMESPACE:-}}"
fi
if [ -z "$NS" ]; then
NS="default"
fi
if ! command -v kubectl >/dev/null 2>&1; then
echo "ERROR: kubectl not found in PATH"
exit 1
fi
timestamp=$(date "+%Y-%m-%d %H:%M:%S")
ctx=$(kubectl config current-context 2>/dev/null || true)
echo "Common service status"
echo "Time: $timestamp"
echo "Context: ${ctx:-<unknown>}"
echo "Namespace: $NS"
echo ""
run_cmd() {
echo "\$ $*"
"$@" 2>&1 || true
echo ""
}
echo "== Services =="
run_cmd kubectl -n "$NS" get svc registry openbao opentofu
echo "== Workloads =="
run_cmd kubectl -n "$NS" get deploy registry opentofu
run_cmd kubectl -n "$NS" get statefulset openbao
echo "== Pods =="
run_cmd kubectl -n "$NS" get pods | grep -Ei "registry|openbao|opentofu" || true

View File

@ -1184,6 +1184,14 @@ class ProleInstaller:
# Cursor blink timer id for command preview
self._cursor_blink_after_id = None
self._cursor_blink_visible = False
self._k3s_status_after_id = None
self._k3s_status_active = False
self._k3s_status_inflight = False
self._k3s_service_status_console = None
self._k3s_service_deploy_console = None
self._k3s_service_notebook = None
self._k3s_service_status_tab = None
self._k3s_service_deploy_tab = None
# Shared dependency catalog from installer.config
self.dependencies = list(inst_config.DEPENDENCIES)
@ -1213,6 +1221,7 @@ class ProleInstaller:
}
self._cfg_secret_cache = {}
self._secrets_finalized = False
self.service_namespace = tk.StringVar(value='default')
# Try to load existing docker_import_dir from prole.cfg
try:
@ -1232,6 +1241,7 @@ class ProleInstaller:
# Preload saved cluster env and namespace if available
saved_cluster = cfg['Global'].get('CLUSTER_ENV', '').strip()
saved_ns = cfg['Global'].get('NAMESPACE', '').strip()
saved_service_ns = cfg['Global'].get('SERVICE_NAMESPACE', '').strip()
if saved_cluster:
try:
self.cluster_env.set(saved_cluster)
@ -1242,8 +1252,15 @@ class ProleInstaller:
self.db_namespace.set(saved_ns)
except Exception:
pass
if saved_service_ns:
try:
self.service_namespace.set(saved_service_ns)
except Exception:
pass
self.prole_cfg_data['Global']['SERVICE_NAMESPACE'] = saved_service_ns
except Exception:
pass
self.prole_cfg_data['Global'].setdefault('SERVICE_NAMESPACE', self.service_namespace.get())
# Disk selection variables
self.selected_disk_type = tk.StringVar(value='local') # 'removable' or 'local'
@ -1781,6 +1798,11 @@ class ProleInstaller:
except Exception:
pass
try:
self._stop_k3s_service_status_updates()
except Exception:
pass
# Reset slide_area background to white for safety
try:
self.slide_area.configure(bg='white')
@ -2341,6 +2363,7 @@ class ProleInstaller:
env["DB_PASSWORD"] = self.db_password.get().strip()
env["OPENTOFU_ADMIN_PASSWORD"] = self.db_password.get().strip()
env["NAMESPACE"] = namespace
env["SERVICE_NAMESPACE"] = self._get_service_namespace()
mode = self._deployment_mode()
if mode:
env["PROLE_MODE"] = mode
@ -2365,6 +2388,15 @@ class ProleInstaller:
env["PROLE_K3S_TOKEN"] = k3s_token
return env
def _get_service_namespace(self) -> str:
ns = (self.prole_cfg_data.get('Global', {}) or {}).get('SERVICE_NAMESPACE', '').strip()
if not ns:
try:
ns = (self.service_namespace.get() or '').strip()
except Exception:
ns = ''
return ns or 'default'
def _cluster_env_key(self, env: str | None = None) -> str:
try:
current = env if env is not None else self.cluster_env.get()
@ -4373,33 +4405,58 @@ class ProleInstaller:
self._overlay_widgets.append(token_entry)
y += 34
# Service Status
self._canvas_items.append(ui.canvas_text(self, x_label, y, 'Remote K3s Service Status:', fill='black', font=('SF Pro Text', 12, 'bold')))
service_ns = self._get_service_namespace()
self._canvas_items.append(ui.canvas_text(
self, x_label, y,
f"Common Services (namespace: {service_ns})",
fill='black', font=('SF Pro Text', 12, 'bold')
))
y += 30
for service, var in self.k3s_services_status.items():
ui.canvas_text(self, x_label + 20, y, f"{service}:", fill='black', font=('SF Pro Text', 11))
# Dynamic status label
status_val = var.get()
color = '#34c759' if status_val == "Good" else '#ff3b30' if status_val == "Failing" else '#6e6e73'
status_label = tk.Label(self.bg_canvas, textvariable=var, fg=color, bg='white', font=('SF Pro Text', 11, 'bold'))
status_win = self.bg_canvas.create_window(x_label + 120, y, window=status_label, anchor='nw')
self._canvas_items.append(status_win)
self._overlay_widgets.append(status_label)
y += 25
y += 10
deploy_btn = tk.Button(self.bg_canvas, text='Deploy Missing Services', command=self._deploy_k3s_services,
bg='#F5F5DC', fg='black', activebackground='#E5E5D5',
highlightbackground='#F5F5DC', highlightthickness=0,
relief='flat', font=('SF Pro Text', 10), padx=10, pady=5)
notebook = ttk.Notebook(self.bg_canvas)
status_frame = tk.Frame(notebook, bg='white')
deploy_frame = tk.Frame(notebook, bg='white')
status_console = ui.TerminalConsole(status_frame)
deploy_console = ui.TerminalConsole(deploy_frame)
status_console.pack(fill='both', expand=True)
deploy_console.pack(fill='both', expand=True)
notebook.add(status_frame, text='Status')
notebook.add(deploy_frame, text='Deploy Output')
self._k3s_service_notebook = notebook
self._k3s_service_status_console = status_console
self._k3s_service_deploy_console = deploy_console
self._k3s_service_status_tab = status_frame
self._k3s_service_deploy_tab = deploy_frame
console_width = 900
console_height = 230
console_window = self.bg_canvas.create_window(
x_label, y, window=notebook, anchor='nw',
width=console_width, height=console_height
)
self._canvas_items.append(console_window)
self._overlay_widgets.extend([notebook, status_frame, deploy_frame, status_console, deploy_console])
y += console_height + 16
deploy_btn = tk.Button(
self.bg_canvas,
text='Deploy Missing Services',
command=self._deploy_k3s_services,
bg='#F5F5DC',
fg='black',
activebackground='#E5E5D5',
highlightbackground='#F5F5DC',
highlightthickness=0,
relief='flat',
font=('SF Pro Text', 10),
padx=10,
pady=5,
)
deploy_win = self.bg_canvas.create_window(x_label + 20, y, window=deploy_btn, anchor='nw')
self._canvas_items.append(deploy_win)
self._overlay_widgets.append(deploy_btn)
y += 40
# Async service status check
y += 30
self._verify_k3s_services()
elif selected_env_key == 'prod':
@ -4551,74 +4608,130 @@ class ProleInstaller:
return ["default"]
def _verify_k3s_services(self):
"""Verify registry:2 and openbao on remote k3s cluster."""
def _verify():
self.k3s_services_status["registry"].set("Checking...")
self.k3s_services_status["openbao"].set("Checking...")
self.k3s_services_status["opentofu"].set("Checking...")
# Connection details for remote k3s (same as in ncurses version)
k3s_server, k3s_token = self._k3s_connection_info()
if not k3s_server:
self.k3s_services_status["registry"].set("Missing server")
self.k3s_services_status["openbao"].set("Missing server")
self.k3s_services_status["opentofu"].set("Missing server")
return
if not k3s_token:
self.k3s_services_status["registry"].set("Missing token")
self.k3s_services_status["openbao"].set("Missing token")
self.k3s_services_status["opentofu"].set("Missing token")
return
if self._cluster_env_key() != 'service':
self._stop_k3s_service_status_updates()
return
self._start_k3s_service_status_updates()
base_cmd = self._k3s_kubectl_base_cmd()
def _start_k3s_service_status_updates(self):
if not self._k3s_status_active:
self._k3s_status_active = True
if self._k3s_status_after_id:
try:
# Check registry
res = subprocess.run(base_cmd + ["get", "service", "-A"], capture_output=True, text=True)
if "registry" in res.stdout.lower():
self.k3s_services_status["registry"].set("Good")
else:
self.k3s_services_status["registry"].set("Failing")
# Check openbao
if "openbao" in res.stdout.lower() or "bao" in res.stdout.lower():
self.k3s_services_status["openbao"].set("Good")
else:
self.k3s_services_status["openbao"].set("Failing")
self.root.after_cancel(self._k3s_status_after_id)
except Exception:
pass
self._k3s_status_after_id = None
self._schedule_k3s_service_status_update(0)
# Check opentofu
if "opentofu" in res.stdout.lower():
self.k3s_services_status["opentofu"].set("Good")
else:
self.k3s_services_status["opentofu"].set("Failing")
except Exception as e:
self.k3s_services_status["registry"].set("Error")
self.k3s_services_status["openbao"].set("Error")
self.k3s_services_status["opentofu"].set("Error")
print(f"K3s connection error: {str(e)}")
def _stop_k3s_service_status_updates(self):
self._k3s_status_active = False
self._k3s_status_inflight = False
if self._k3s_status_after_id:
try:
self.root.after_cancel(self._k3s_status_after_id)
except Exception:
pass
self._k3s_status_after_id = None
threading.Thread(target=_verify, daemon=True).start()
def _schedule_k3s_service_status_update(self, delay_ms: int):
if not self._k3s_status_active:
return
if not self.root or not self.root.winfo_exists():
return
try:
self._k3s_status_after_id = self.root.after(delay_ms, self._run_k3s_service_status_once)
except Exception:
self._k3s_status_after_id = None
def _run_k3s_service_status_once(self):
if self._k3s_status_inflight:
return
if not self._k3s_service_status_console:
self._k3s_status_inflight = False
self.safe_after(lambda: self._schedule_k3s_service_status_update(30000))
return
self._k3s_status_inflight = True
console = self._k3s_service_status_console
console.clear()
console.write(f"Service status refresh @ {time.strftime('%Y-%m-%d %H:%M:%S')}\n\n")
def worker():
try:
k3s_server, k3s_token = self._k3s_connection_info()
if not k3s_server:
console.write("Missing K3s server URL.\n")
return
if not k3s_token:
console.write("Missing K3s token.\n")
return
ns = self._get_service_namespace()
env = self._script_env_for_namespace(ns)
env["PROLE_MODE"] = "k3s"
kubeconfig_path = None
try:
kubeconfig_path = _write_k3s_kubeconfig(k3s_server, k3s_token)
env["KUBECONFIG"] = str(kubeconfig_path)
rc = self.controller.run_script(
"status_common_services.sh",
args=["-n", ns],
env=env,
on_line=lambda l: console.write(l)
)
console.write(f"\nExit status: {rc}\n")
finally:
if kubeconfig_path:
try:
os.unlink(kubeconfig_path)
except Exception:
pass
finally:
self._k3s_status_inflight = False
self.safe_after(lambda: self._schedule_k3s_service_status_update(30000))
threading.Thread(target=worker, daemon=True).start()
def _deploy_k3s_services(self):
"""Deploy registry, OpenBao, and OpenTofu to remote k3s cluster."""
"""Deploy common services (registry/OpenBao/OpenTofu) to remote k3s cluster."""
def _deploy():
console = self._k3s_service_deploy_console
if console:
console.clear()
console.write(f"Deploying common services @ {time.strftime('%Y-%m-%d %H:%M:%S')}\n\n")
try:
if self._k3s_service_notebook and self._k3s_service_deploy_tab:
self._k3s_service_notebook.select(self._k3s_service_deploy_tab)
except Exception:
pass
k3s_server, k3s_token = self._k3s_connection_info()
if not k3s_server or not k3s_token:
if console:
if not k3s_server:
console.write("Missing K3s server URL.\n")
if not k3s_token:
console.write("Missing K3s token.\n")
self._verify_k3s_services()
return
env = self._script_env_for_namespace((self.db_namespace.get() or '').strip() or 'default')
env["DB_PASSWORD"] = (self.db_password.get() or '').strip()
if env["DB_PASSWORD"]:
env["OPENTOFU_ADMIN_PASSWORD"] = env["DB_PASSWORD"]
service_ns = self._get_service_namespace()
env = self._script_env_for_namespace(service_ns)
env["PROLE_MODE"] = "k3s"
kubeconfig_path = None
try:
kubeconfig_path = _write_k3s_kubeconfig(k3s_server, k3s_token)
env["KUBECONFIG"] = str(kubeconfig_path)
self.controller.run_script("init_openbao.sh", args=["-n", env["NAMESPACE"], "update"], env=env)
self.controller.run_script("init_opentofu.sh", args=["-n", env["NAMESPACE"], "update"], env=env)
rc = self.controller.run_script(
"init_common_services.sh",
args=["-n", env["NAMESPACE"], "update"],
env=env,
on_line=lambda l: console.write(l) if console else None
)
if console:
console.write(f"\nExit status: {rc}\n")
finally:
if kubeconfig_path:
try:
@ -4672,18 +4785,18 @@ class ProleInstaller:
self.prole_cfg_data['Initialize Cluster']['ENVIRONMENT'] = self.cluster_env.get()
self.prole_cfg_data['Initialize Cluster']['K3S_SERVER_URL'] = (self.k3s_server_url.get() or '').strip()
self.prole_cfg_data['Initialize Cluster']['K3S_TOKEN'] = _encrypt_cfg_secret(self.k3s_token.get() or '')
self.prole_cfg_data['Global']['SERVICE_NAMESPACE'] = self._get_service_namespace()
# Save config
self._save_prole_cfg()
# Apply OpenBao configuration for current namespace, then refresh statuses
ns = (self.db_namespace.get() or '').strip() or 'default'
# Apply common services configuration for service namespace, then refresh statuses
ns = self._get_service_namespace()
def worker():
try:
env_vars = self._script_env_for_namespace(ns)
# Use 'update' to (re)apply manifests and config in the selected namespace
self.controller.run_script("init_openbao.sh", args=["-n", ns, "update"], env=env_vars)
self.controller.run_script("init_opentofu.sh", args=["-n", ns, "update"], env=env_vars)
self.controller.run_script("init_common_services.sh", args=["-n", ns, "update"], env=env_vars)
except Exception as e:
print(f"Cluster service update failed: {e}")
finally:
@ -4692,7 +4805,7 @@ class ProleInstaller:
threading.Thread(target=worker, daemon=True).start()
messagebox.showinfo("Success", "Cluster configuration saved and OpenBao applied.")
messagebox.showinfo("Success", "Cluster configuration saved and common services applied.")
def _cluster_status_snapshot(self) -> dict:
env = self._cluster_env_key()

View File

@ -12,8 +12,8 @@ data:
[realms]
PROLE.ORG = {
kdc = kdc.prole.org
admin_server = kdc.prole.org
kdc = 10.0.0.3
admin_server = 10.0.0.3
}
[domain_realm]