200 lines
4.9 KiB
CUE
200 lines
4.9 KiB
CUE
package templates
|
|
|
|
import (
|
|
timoniv1 "timoni.sh/core/v1alpha1"
|
|
)
|
|
|
|
#NodeGroup: {
|
|
role: string
|
|
replicas: int | *1
|
|
repository: string | *"quay.io/radicle_garden/radicle-node"
|
|
pullPolicy: string | *"IfNotPresent"
|
|
version: string | *"latest"
|
|
nodeIdSeed: string | *""
|
|
|
|
storage: {
|
|
className: string | *"local-path"
|
|
size: string | *"1Gi"
|
|
}
|
|
|
|
resources: {...}
|
|
|
|
sidecars: {
|
|
events: bool | *true
|
|
}
|
|
|
|
scripts: {
|
|
init: string | *"""
|
|
#!/bin/sh
|
|
set -e
|
|
|
|
KUBE_CONFIG_DIR=/tmp/config-source
|
|
RAD_HOME=/home/radicle/.radicle
|
|
RAD_CONFIG=${RAD_HOME}/config.json
|
|
|
|
echo "[INIT] Hostname: $(hostname)"
|
|
# --- STANDARD INIT LOGIC (User 11011) ---
|
|
mkdir -p "${RAD_HOME}"
|
|
|
|
if [ -f "${KUBE_CONFIG_DIR}/config.json" ]; then
|
|
cp "${KUBE_CONFIG_DIR}/config.json" "${RAD_CONFIG}"
|
|
echo "[INIT] Config copied successfully."
|
|
else
|
|
echo "[INIT] ERROR: Source config not found."
|
|
exit 1
|
|
fi
|
|
"""
|
|
start: string | *"""
|
|
#!/bin/sh
|
|
set -e
|
|
|
|
RAD_HOME=/home/radicle/.radicle
|
|
RAD_ALIAS=$(hostname)
|
|
RAD_KEY=${RAD_HOME}/keys/radicle
|
|
RAD_CONFIG=${RAD_HOME}/config.json
|
|
|
|
#
|
|
# Generate keys
|
|
#
|
|
if [ ! -f "${RAD_KEY}" ]; then
|
|
echo "[START] Generating identity for: ${RAD_ALIAS}..."
|
|
# We move the config out of the way so 'rad auth' doesn't complain
|
|
if [ -f "${RAD_CONFIG}" ]; then
|
|
mv "${RAD_CONFIG}" "${RAD_CONFIG}.bak"
|
|
fi
|
|
|
|
# RAD_KEYGEN_SEED requires a 32-byte hex string.
|
|
# We hash either the injected NODE_ID_SEED or the hostname to generate it.
|
|
if [ -n "${NODE_ID_SEED}" ]; then
|
|
export RAD_KEYGEN_SEED=$(echo "${NODE_ID_SEED}" | sha256sum | tr -d "\\n *-")
|
|
else
|
|
export RAD_KEYGEN_SEED=$(hostname | sha256sum | tr -d "\\n *-")
|
|
fi
|
|
|
|
rad auth --alias "${RAD_ALIAS}"
|
|
|
|
if [ -f "${RAD_CONFIG}.bak" ]; then
|
|
mv "${RAD_CONFIG}.bak" "${RAD_CONFIG}"
|
|
fi
|
|
echo "[START] Identity generated"
|
|
fi
|
|
|
|
#
|
|
# Update config settings
|
|
#
|
|
echo "[START] Node's alias set to: $(rad config set node.alias "${RAD_ALIAS}")"
|
|
|
|
# Extract the first external address, stripping JSON formatting
|
|
EXT_ADDRESS=$(rad config get node.externalAddresses | tr -d '[]" \\n' | cut -d',' -f1)
|
|
|
|
if [ -n "$EXT_ADDRESS" ]; then
|
|
# Check if it already starts with the pod's hostname to prevent stuttering
|
|
case "$EXT_ADDRESS" in
|
|
${RAD_ALIAS}.*)
|
|
echo "[START] External address already correct: ${EXT_ADDRESS}"
|
|
;;
|
|
*)
|
|
rad config remove node.externalAddresses "${EXT_ADDRESS}"
|
|
NEW_ADDRESS="${RAD_ALIAS}.${EXT_ADDRESS}"
|
|
rad config push node.externalAddresses "${NEW_ADDRESS}"
|
|
echo "[START] Node's external address updated to: ${NEW_ADDRESS}"
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
#
|
|
# Start node
|
|
#
|
|
echo "[START] Starting Radicle node..."
|
|
exec rad node start --foreground
|
|
"""
|
|
events: string | *"""
|
|
#!/bin/sh
|
|
|
|
RAD_HOME=/home/radicle/.radicle
|
|
RAD_NODE_SOCKET=${RAD_HOME}/node/control.sock
|
|
|
|
echo "[EVENTS] Waiting for node socket..."
|
|
while [ ! -S ${RAD_NODE_SOCKET} ]; do
|
|
sleep 1
|
|
done
|
|
echo "[EVENTS] Socket found. Streaming events..."
|
|
exec rad node events
|
|
"""
|
|
}
|
|
|
|
radicleConfig: {
|
|
node: {
|
|
// Automatically generate the base external address using the role.
|
|
// The start.sh script will dynamically prepend the pod's hostname to this at boot.
|
|
externalAddresses: [...string] | *["\(role).default.svc.cluster.local:8776"]
|
|
// Set network to "test" by default.
|
|
network: "test"
|
|
...
|
|
}
|
|
...
|
|
}
|
|
}
|
|
|
|
// Config defines the schema and defaults for the Instance values.
|
|
#Config: {
|
|
kubeVersion!: string
|
|
clusterVersion: timoniv1.#SemVer & {#Version: kubeVersion, #Minimum: "1.20.0"}
|
|
moduleVersion!: string
|
|
metadata: timoniv1.#Metadata & {#Version: moduleVersion}
|
|
metadata: labels: timoniv1.#Labels
|
|
metadata: annotations?: timoniv1.#Annotations
|
|
|
|
// The topology map is merged with the #NodeGroup schema
|
|
topology: [string]: #NodeGroup
|
|
|
|
// Helper to generate metadata with a specific name
|
|
#Meta: {
|
|
name: string
|
|
out: {
|
|
"name": name
|
|
namespace: metadata.namespace
|
|
if metadata.annotations != _|_ {
|
|
annotations: metadata.annotations
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Instance takes the config values and outputs the Kubernetes objects.
|
|
#Instance: {
|
|
config: #Config
|
|
|
|
// Extract unique roles to create headless services
|
|
let _roles = {
|
|
for name, group in config.topology {
|
|
"\(group.role)": true
|
|
}
|
|
}
|
|
|
|
objects: {
|
|
// Generate one Headless Service per role (e.g. seed, peer, bootstrap)
|
|
for roleName, _ in _roles {
|
|
"svc-\(roleName)": #Service & {
|
|
#config: config
|
|
#role: roleName
|
|
}
|
|
}
|
|
|
|
// Generate a StatefulSet and ConfigMap for each group in the topology
|
|
for name, group in config.topology {
|
|
"cm-\(name)": #ConfigMap & {
|
|
#config: config
|
|
#name: name
|
|
#group: group
|
|
}
|
|
"sts-\(name)": #StatefulSet & {
|
|
#config: config
|
|
#name: name
|
|
#group: group
|
|
#cmName: name + "-config"
|
|
}
|
|
}
|
|
}
|
|
}
|