#!/bin/bash

rm ~/.kube/config # comment this out if you have more than one cluster

# ____________________ EDIT VARIABLES __________________________
export NODES=(
  "sandy"   # "192.168.1.14"
  "gary"    # "192.168.1.13"
  "sheldon" # "192.168.1.16"
  "pearl"   # "192.168.1.19"
) # In this script you can replace --host and --server-host with --ip and --server-ip if you don't have DNS names
export USER="pleb"
export SSH_KEY="/home/pleb/.ssh/bikiniBottom"
export CLUSTER_NAME="bikinibottom"
export K3SVer="0.13.11"
export VIPIP="192.168.1.21" # Virtual IP address that the master nodes will share
export VIPHostname="bikinibotton"
export NETWORKSuffix="lan"
export EXTRAArgs="--disable traefik --disable servicelb"
export MetalLB_IPRange="192.168.1.21" # Range for MetalLB to use
# _______________________ END OF VARIABLES ______________________

GREEN='\033[32m'
RED='\033[0;31m'
ENDCOLOR='\033[0m'

for index in "${!NODES[@]}"; do
  echo -e "${GREEN}------- Installing on ${NODES[$index]} -------${ENDCOLOR}"

  # The first server starts the cluster
  if [[ $index -eq 0 ]]; then
    k3sup install \
      --cluster \
      --user $USER \
      --host ${NODES[$index]} \
      --ssh-key $SSH_KEY \
      --k3s-version $K3SVer \
      --local-path $HOME/.kube/config \
      --context $CLUSTER_NAME \
      --merge \
      --tls-san $VIPIP --tls-san $VIPHostname --tls-san $VIPHostname.$NETWORKSuffix \
      --k3s-extra-args "${EXTRAArgs}"
  elif [[ $index -eq 1 || $index -eq 2 ]]; then
    # The second and third nodes join as master nodes
    k3sup join \
      --server \
      --host ${NODES[$index]} \
      --user $USER \
      --server-user $USER \
      --server-host ${NODES[0]} \
      --ssh-key $SSH_KEY \
      --k3s-version $K3SVer \
      --k3s-extra-args "${EXTRAArgs}"
  else
    # The rest of the nodes join as worker nodes
    k3sup join \
      --host ${NODES[$index]} \
      --server-user $USER \
      --server-host ${NODES[0]} \
      --user $USER \
      --ssh-key $SSH_KEY \
      --k3s-version $K3SVer
  fi
done

echo -e "${GREEN}------- k3s installed, moving to backend apps  -------${ENDCOLOR}"

# MetalLB Installation
echo -e "${GREEN}------- Installing MetalLB Load Balancer -------${ENDCOLOR}"
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.10.3/manifests/namespace.yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.10.3/manifests/metallb.yaml
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - $MetalLB_IPRange
EOF

# Traefik Installation
echo -e "${GREEN}------- Installing Traefik Ingress Controller -------${ENDCOLOR}"
helm repo add traefik https://traefik.github.io/charts
helm repo update
# create values.yaml for traefik. Need this to be "local" so that X-Forwarded-For headers are transmitted
echo "\
additionalArguments:
  - '--serversTransport.insecureSkipVerify=true'
service:
  spec:
    externalTrafficPolicy: Local
    " > /tmp/traefik-values.yaml
helm upgrade --install traefik traefik/traefik --create-namespace --namespace traefik --values /tmp/traefik-values.yaml
cat <<EOF | kubectl apply -f -
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: dashboard
  namespace: traefik
spec:
  entryPoints:
    - web
  routes:
    - match: Host('traefik.localhost') && (PathPrefix('/dashboard') || PathPrefix('/api'))
      kind: Rule
      services:
        - name: api@internal
          kind: TraefikService
EOF

# Cert-Manager Installation
echo -e "${GREEN}------- Installing Cert Manager -------${ENDCOLOR}"
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm upgrade --install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set installCRDs=true

# Test out external IP address assignment with MetalLB
sleep 10
echo -e "${GREEN}------- Testing out MetalLB Load Balancer -------${ENDCOLOR}"
kubens default
kubectl create deploy nginx --image=nginx
sleep 5
kubectl expose deploy nginx --port=80 --target-port=80 --type=LoadBalancer
sleep 20
external_ip=$(kubectl get service nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
if [[ -n "$external_ip" ]]; then
    echo -e "External IP: $external_ip"
    if command -v open &> /dev/null; then
      open "http://${external_ip}:80"
    elif command -v xdg-open &> /dev/null; then
      xdg-open "http://${external_ip}:80"
    elif command -v google-chrome &> /dev/null; then
      google-chrome "http://${external_ip}:80"
    else
      echo -e "${RED}Failed to open web browser. Please manually open a web browser and navigate to http://${external_ip}:80.${ENDCOLOR}"
    fi
else
    echo -e "${RED}LoadBalancer is still pending, may not be functional yet${ENDCOLOR}"
fi

# Print Traefik External IP
echo -e "${GREEN}------- Print Traefik Ingress Point -------${ENDCOLOR}"
kubectl get svc -n traefik
external_ip=$(kubectl get service traefik -n traefik -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo -e "\nOn your router, ${GREEN}Port forward${ENDCOLOR} ports 80 and 443 to ${GREEN}$external_ip${ENDCOLOR}"


echo -e "\n${GREEN}------- Setup Complete -------${ENDCOLOR}\n"
