From 68ac9b2e8c845c686c6eae372eae8b94372f07dd Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Wed, 25 Jun 2025 12:10:18 -0700 Subject: [PATCH] Add wild-setup-config script for wild-cloud configuration setup --- bin/wild-setup-config | 277 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 277 insertions(+) create mode 100755 bin/wild-setup-config diff --git a/bin/wild-setup-config b/bin/wild-setup-config new file mode 100755 index 0000000..bdd111e --- /dev/null +++ b/bin/wild-setup-config @@ -0,0 +1,277 @@ +#!/bin/bash + +set -e +set -o pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Helper functions +print_header() { + echo -e "\n${BLUE}=== $1 ===${NC}\n" +} + +print_info() { + echo -e "${BLUE}INFO:${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}WARNING:${NC} $1" +} + +print_success() { + echo -e "${GREEN}SUCCESS:${NC} $1" +} + +print_error() { + echo -e "${RED}ERROR:${NC} $1" +} + +# Function to prompt for input with default value +prompt_with_default() { + local prompt="$1" + local default="$2" + local current_value="$3" + local result + + if [ -n "${current_value}" ] && [ "${current_value}" != "null" ]; then + printf "%s [current: %s]: " "${prompt}" "${current_value}" >&2 + read -r result + if [ -z "${result}" ]; then + result="${current_value}" + fi + elif [ -n "${default}" ]; then + printf "%s [default: %s]: " "${prompt}" "${default}" >&2 + read -r result + if [ -z "${result}" ]; then + result="${default}" + fi + else + printf "%s: " "${prompt}" >&2 + read -r result + while [ -z "${result}" ]; do + printf "This value is required. Please enter a value: " >&2 + read -r result + done + fi + + echo "${result}" +} + +# Function to get current config value safely +get_current_config() { + local key="$1" + if [ -f "${WC_HOME}/config.yaml" ]; then + set +e + result=$(wild-config "${key}" 2>/dev/null) + set -e + echo "${result}" + else + echo "" + fi +} + +# Function to get current secret value safely +get_current_secret() { + local key="$1" + if [ -f "${WC_HOME}/secrets.yaml" ]; then + set +e + result=$(wild-secret "${key}" 2>/dev/null) + set -e + echo "${result}" + else + echo "" + fi +} + +# Check if we're in a wild-cloud directory +if [ ! -d ".wildcloud" ]; then + print_error "You must run this script from a wild-cloud directory" + exit 1 +fi + +# Set and export WC_HOME +if [ -z "${WC_HOME:-}" ]; then + WC_HOME="$(pwd)" +fi +export WC_HOME + +# Detect current network subnet and gateway for IP suggestions +CURRENT_IP=$(ip route get 8.8.8.8 | awk '{print $7; exit}' 2>/dev/null || echo "192.168.1.100") +GATEWAY_IP=$(ip route | grep default | awk '{print $3; exit}' 2>/dev/null || echo "192.168.1.1") +SUBNET_PREFIX=$(echo "${CURRENT_IP}" | cut -d. -f1-3) +print_info "Detected network: ${SUBNET_PREFIX}.x (gateway: ${GATEWAY_IP})" + +print_header "Wild-Cloud Configuration Setup" +echo "This script will help you configure your wild-cloud deployment." +echo "You can press Enter to keep current values or defaults." +echo "" + +# Basic Information +print_header "Basic Information" + +current_email=$(get_current_config "operator.email") +email=$(prompt_with_default "Your email address (for Let's Encrypt certificates)" "" "${current_email}") +wild-config-set "operator.email" "${email}" + +# Domain Configuration +print_header "Domain Configuration" + +current_base_domain=$(get_current_config "cloud.baseDomain") +base_domain=$(prompt_with_default "Your base domain name (e.g., example.com)" "" "${current_base_domain}") +wild-config-set "cloud.baseDomain" "${base_domain}" + +current_domain=$(get_current_config "cloud.domain") +domain=$(prompt_with_default "Your public cloud domain" "cloud.${base_domain}" "${current_domain}") +wild-config-set "cloud.domain" "${domain}" + +current_internal_domain=$(get_current_config "cloud.internalDomain") +internal_domain=$(prompt_with_default "Your internal cloud domain" "internal.${domain}" "${current_internal_domain}") +wild-config-set "cloud.internalDomain" "${internal_domain}" + +# Derive cluster name from domain (remove dots and make lowercase) +cluster_name=$(echo "${domain}" | tr '.' '-' | tr '[:upper:]' '[:lower:]') +wild-config-set "cluster.name" "${cluster_name}" + +# Cloudflare Configuration +print_header "Cloudflare Configuration" +echo "For automatic SSL certificates and DNS management, we use Cloudflare." +echo "" + +current_cf_domain=$(get_current_config "cluster.certManager.cloudflare.domain") +if [ -z "${current_cf_domain}" ]; then + cf_domain="${domain}" +else + cf_domain="${current_cf_domain}" +fi + +echo "Is your domain '${base_domain}' registered and managed through Cloudflare? (y/n)" +read -r use_cloudflare + +if [[ "${use_cloudflare}" =~ ^[Yy]$ ]]; then + wild-config-set "cluster.certManager.cloudflare.domain" "${cf_domain}" + + current_cf_token=$(get_current_secret "cloudflare.token") + if [ -z "${current_cf_token}" ]; then + echo "" + print_info "You'll need a Cloudflare API token with the following permissions:" + echo " - Zone:Zone:Read" + echo " - Zone:DNS:Edit" + echo " - Include:All zones" + echo "" + echo "Create one at: https://dash.cloudflare.com/profile/api-tokens" + echo "" + fi + + cf_token=$(prompt_with_default "Cloudflare API token" "" "${current_cf_token}") + wild-secret-set "cloudflare.token" "${cf_token}" +else + print_warning "You'll need to configure DNS and SSL certificates manually." + print_info "Consider transferring your domain to Cloudflare for easier management." +fi + +# Network Configuration +print_header "Network Configuration" + +current_router_ip=$(get_current_config "cloud.router.ip") +router_ip=$(prompt_with_default "Router/Gateway IP" "${GATEWAY_IP}" "${current_router_ip}") +wild-config-set "cloud.router.ip" "${router_ip}" + +current_dns_ip=$(get_current_config "cloud.dns.ip") +dns_ip=$(prompt_with_default "DNS server IP (dnsmasq machine)" "${SUBNET_PREFIX}.50" "${current_dns_ip}") +wild-config-set "cloud.dns.ip" "${dns_ip}" + +current_dhcp_range=$(get_current_config "cloud.dhcpRange") +dhcp_range=$(prompt_with_default "DHCP range for dnsmasq" "${SUBNET_PREFIX}.100,${SUBNET_PREFIX}.200" "${current_dhcp_range}") +wild-config-set "cloud.dhcpRange" "${dhcp_range}" + +current_interface=$(get_current_config "cloud.dnsmasq.interface") +interface=$(prompt_with_default "Network interface for dnsmasq" "eth0" "${current_interface}") +wild-config-set "cloud.dnsmasq.interface" "${interface}" + +current_external_resolver=$(get_current_config "cloud.dns.externalResolver") +external_resolver=$(prompt_with_default "External DNS resolver" "1.1.1.1" "${current_external_resolver}") +wild-config-set "cloud.dns.externalResolver" "${external_resolver}" + +# Cluster Configuration +print_header "Kubernetes Cluster Configuration" + +current_talos_version=$(get_current_config "cluster.nodes.talos.version") +talos_version=$(prompt_with_default "Talos version" "v1.6.1" "${current_talos_version}") +wild-config-set "cluster.nodes.talos.version" "${talos_version}" + +current_ip_pool=$(get_current_config "cluster.ipAddressPool") +ip_pool=$(prompt_with_default "MetalLB IP address pool" "${SUBNET_PREFIX}.80-${SUBNET_PREFIX}.89" "${current_ip_pool}") +wild-config-set "cluster.ipAddressPool" "${ip_pool}" + +# Automatically set load balancer IP to first address in the pool +lb_ip=$(echo "${ip_pool}" | cut -d'-' -f1) +wild-config-set "cluster.loadBalancerIp" "${lb_ip}" + +# Control plane nodes +echo "" + +current_vip=$(get_current_config "cluster.nodes.control.vip") +vip=$(prompt_with_default "Control plane virtual IP" "${SUBNET_PREFIX}.90" "${current_vip}") +wild-config-set "cluster.nodes.control.vip" "${vip}" + +for i in 1 2 3; do + current_node_ip=$(get_current_config "cluster.nodes.control.node${i}.ip") + node_ip=$(prompt_with_default "Control plane node ${i} IP address" "${SUBNET_PREFIX}.$(( 90 + i ))" "${current_node_ip}") + wild-config-set "cluster.nodes.control.node${i}.ip" "${node_ip}" +done + +# Talos Configuration +echo "" + +current_schematic_id=$(get_current_config "cluster.nodes.talos.schematicId") +echo "" +print_info "Get your Talos schematic ID from: https://factory.talos.dev/" +print_info "This customizes Talos with the drivers needed for your hardware." +schematic_id=$(prompt_with_default "Talos schematic ID" "" "${current_schematic_id}") +wild-config-set "cluster.nodes.talos.schematicId" "${schematic_id}" + +# External DNS +current_owner_id=$(get_current_config "cluster.externalDns.ownerId") +owner_id=$(prompt_with_default "External DNS owner ID" "external-dns-${cluster_name}" "${current_owner_id}") +wild-config-set "cluster.externalDns.ownerId" "${owner_id}" + +# Storage Configuration +print_header "Storage Configuration" + +current_nfs_host=$(get_current_config "cloud.nfs.host") +nfs_host=$(prompt_with_default "NFS server host" "${dns_ip}" "${current_nfs_host}") +wild-config-set "cloud.nfs.host" "${nfs_host}" + +current_media_path=$(get_current_config "cloud.nfs.mediaPath") +media_path=$(prompt_with_default "NFS media path" "/mnt/storage/media" "${current_media_path}") +wild-config-set "cloud.nfs.mediaPath" "${media_path}" + +current_storage_capacity=$(get_current_config "cloud.nfs.storageCapacity") +storage_capacity=$(prompt_with_default "Storage capacity for NFS PV" "1Ti" "${current_storage_capacity}") +wild-config-set "cloud.nfs.storageCapacity" "${storage_capacity}" + +# Docker Registry +print_header "Docker Registry Configuration" + +current_registry_host=$(get_current_config "cloud.dockerRegistryHost") +registry_host=$(prompt_with_default "Docker registry hostname" "registry.${internal_domain}" "${current_registry_host}") +wild-config-set "cloud.dockerRegistryHost" "${registry_host}" + +# Summary +print_header "Configuration Complete" +print_success "Your wild-cloud configuration has been saved!" +echo "" +print_info "Configuration files:" +echo " - ${WC_HOME}/config.yaml" +echo " - ${WC_HOME}/secrets.yaml" +echo "" +print_info "Next steps:" +echo " 1. Review your configuration files" +echo " 2. Run 'wild-setup' to generate setup files" +echo " 3. Follow the setup instructions in docs/SETUP_FULL.md" +echo "" \ No newline at end of file