diff --git a/p3/Makefile b/p3/Makefile new file mode 100644 index 0000000..242020c --- /dev/null +++ b/p3/Makefile @@ -0,0 +1,31 @@ +SHELL := /bin/bash + +CLUSTER_NAME ?= mycluster +ARGOCD_HOST_PORT ?= 8080 +APP_HOST_PORT ?= 8888 +BOOTSTRAP_SCRIPT ?= tools/bootstrap_argocd.sh + +KUBECTL ?= kubectl +K3D ?= k3d + +.PHONY: all clean fclean re + +all: + @echo "==> Running bootstrap with CLUSTER_NAME=$(CLUSTER_NAME) ARGOCD_HOST_PORT=$(ARGOCD_HOST_PORT) APP_HOST_PORT=$(APP_HOST_PORT)" + @CLUSTER_NAME="$(CLUSTER_NAME)" ARGOCD_HOST_PORT="$(ARGOCD_HOST_PORT)" APP_HOST_PORT="$(APP_HOST_PORT)" "$(BOOTSTRAP_SCRIPT)" + +## Remove app + Argo CD namespaces (cluster remains) +clean: + @echo "==> Deleting Argo CD Application (if any) and namespaces (argocd, dev)" + -@$(KUBECTL) -n argocd delete application p3-dev 2>/dev/null || true + -@$(KUBECTL) delete ns dev argocd 2>/dev/null || true + @echo "==> Clean done (cluster '$(CLUSTER_NAME)' still present)" + +## Full clean: clean + delete k3d cluster +fclean: clean + @echo "==> Deleting k3d cluster '$(CLUSTER_NAME)'" + -@$(K3D) cluster delete "$(CLUSTER_NAME)" 2>/dev/null || true + @echo "==> Full clean done" + +## Rebuild from scratch +re: fclean all diff --git a/p3/manifests/argocd/application-dev.yaml b/p3/manifests/argocd/application-dev.yaml new file mode 100644 index 0000000..e3f31a7 --- /dev/null +++ b/p3/manifests/argocd/application-dev.yaml @@ -0,0 +1,18 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: p3-dev + namespace: argocd +spec: + project: default + source: + repoURL: https://github.com/42-CC-RNCP/Inception-of-Things.git + targetRevision: lea/p3 + path: p3/manifests/dev + destination: + server: https://kubernetes.default.svc + namespace: dev + syncPolicy: + automated: + prune: true + selfHeal: true diff --git a/p3/manifests/dev/deployment.yaml b/p3/manifests/dev/deployment.yaml new file mode 100644 index 0000000..b43f0e7 --- /dev/null +++ b/p3/manifests/dev/deployment.yaml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: wil-playground + namespace: dev +spec: + replicas: 1 + selector: + matchLabels: + app: wil-playground + template: + metadata: + labels: + app: wil-playground + spec: + containers: + - name: app + image: wil42/playground:v1 + ports: + - containerPort: 8888 + imagePullPolicy: IfNotPresent diff --git a/p3/manifests/dev/kustomization.yaml b/p3/manifests/dev/kustomization.yaml new file mode 100644 index 0000000..481acde --- /dev/null +++ b/p3/manifests/dev/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - deployment.yaml + - service.yaml +images: + - name: wil42/playground + newTag: v1 diff --git a/p3/manifests/dev/service.yaml b/p3/manifests/dev/service.yaml new file mode 100644 index 0000000..9a1a0b0 --- /dev/null +++ b/p3/manifests/dev/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: playground-svc + namespace: dev +spec: + selector: + app: wil-playground + ports: + - port: 8888 + targetPort: 8888 + protocol: TCP + type: LoadBalancer diff --git a/p3/tools/bootstrap_argocd.sh b/p3/tools/bootstrap_argocd.sh new file mode 100755 index 0000000..ba872c7 --- /dev/null +++ b/p3/tools/bootstrap_argocd.sh @@ -0,0 +1,154 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ========================= +# Helpers +# ========================= +log() { echo -e "👉 \e[1m$*\e[0m"; } +ok() { echo -e "✅ $*"; } +warn() { echo -e "⚠️ $*"; } +die() { echo -e "❌ $*" >&2; exit 1; } + +# ========================= +# Config +# ========================= +CLUSTER_NAME="${CLUSTER_NAME:-mycluster}" +ARGOCD_INSTALL_URL=${ARGOCD_INSTALL_URL:-"https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml"} +ARGOCD_HOST_PORT="${ARGOCD_HOST_PORT:-8080}" # maps to cluster LB :8443 +APP_HOST_PORT="${APP_HOST_PORT:-8888}" # maps to cluster LB :8888 +ARGOCD_MANIFESTS_DIR="${ARGOCD_MANIFESTS_DIR:-manifests/argocd}" + +# ========================= +# Pre-flight +# ========================= +need() { command -v "$1" >/dev/null 2>&1 || die "Missing command: $1"; } + +ensure_docker_ready() { + need docker + if ! systemctl is-active --quiet docker; then + log "Starting Docker service..." + sudo systemctl enable --now docker + fi + if ! id -nG "$USER" | grep -qw docker; then + die "Current user is not in the 'docker' group. Run: sudo usermod -aG docker $USER && re-login (or run 'newgrp docker')." + fi + docker ps >/dev/null 2>&1 || die "Cannot connect to Docker daemon. Check /var/run/docker.sock permissions." +} + +ensure_k3d_cluster_with_ports() { + need k3d + if k3d cluster list | awk 'NR>1 {print $1}' | grep -qx "${CLUSTER_NAME}"; then + warn "Detected existing k3d cluster: ${CLUSTER_NAME}" + local lb_name="k3d-${CLUSTER_NAME}-serverlb" + local lb_id; lb_id=$(docker ps -q -f "name=^/${lb_name}$" || true) + if [[ -z "${lb_id}" ]]; then + warn "Server LB container '${lb_name}' not found; possibly old k3d or custom setup." + else + local ports; ports=$(docker port "${lb_id}" || true) + echo "${ports}" + if ! grep -q "${ARGOCD_HOST_PORT}.*->" <<<"${ports}" || ! grep -q "${APP_HOST_PORT}.*->" <<<"${ports}"; then + warn "Existing cluster lacks required host port mappings:" + warn " Need host ${ARGOCD_HOST_PORT} → LB:8443 and host ${APP_HOST_PORT} → LB:8888" + warn "Consider recreating the cluster:" + warn " k3d cluster delete ${CLUSTER_NAME} && \\" + warn " k3d cluster create ${CLUSTER_NAME} --wait \\" + warn " --port \"${ARGOCD_HOST_PORT}:8443@loadbalancer\" \\" + warn " --port \"${APP_HOST_PORT}:8888@loadbalancer\"" + else + ok "Existing cluster has required host port mappings." + fi + fi + return + fi + + log "Creating k3d cluster '${CLUSTER_NAME}' with host port mappings..." + k3d cluster create "${CLUSTER_NAME}" --wait \ + --port "${ARGOCD_HOST_PORT}:8443@loadbalancer" \ + --port "${APP_HOST_PORT}:8888@loadbalancer" + ok "k3d cluster created." +} + +# ========================= +# Waiters (ServiceLB: svclb-*) +# ========================= +wait_svclb_ready() { + local ns="$1"; local svc="$2"; local timeout="${3:-300}" + log "Waiting for ServiceLB helper pod 'svclb-${svc}-*' in namespace '${ns}' (timeout ${timeout}s)..." + local end=$((SECONDS+timeout)) + while (( SECONDS <= end )); do + local lines + lines="$(kubectl -n "${ns}" get pods --no-headers 2>/dev/null | awk '/^svclb-'"${svc}"'-/ {print $1, $2, $3}')" + if [[ -n "${lines}" ]]; then + local notready + notready="$(awk '$2!="1/1" || $3!="Running" {print $0}' <<<"${lines}" || true)" + if [[ -z "${notready}" ]]; then + ok "ServiceLB helper for '${svc}' is Running." + return 0 + fi + fi + sleep 3 + done + die "ServiceLB helper for '${svc}' not ready within ${timeout}s" +} + +# ========================= +# Argo CD +# ========================= +bootstrap_argocd() { + log "Creating namespaces (argocd, dev)..." + kubectl create ns argocd --dry-run=client -o yaml | kubectl apply -f - + kubectl create ns dev --dry-run=client -o yaml | kubectl apply -f - + ok "Namespaces ready." + + log "Installing Argo CD (in-cluster)..." + kubectl apply -n argocd -f "${ARGOCD_INSTALL_URL}" + + log "Waiting for argocd-server to be ready (up to 5 minutes)..." + kubectl rollout status deploy/argocd-server -n argocd --timeout=300s || true + + # Make argocd-server Service type=LoadBalancer and add port 8443 + log "Exposing argocd-server as LoadBalancer and adding 8443 port..." + kubectl -n argocd patch svc argocd-server -p '{"spec":{"type":"LoadBalancer"}}' >/dev/null + kubectl -n argocd patch svc argocd-server --type merge -p '{ + "spec": { + "type": "LoadBalancer", + "ports": [ + {"name":"https-alt","port":8443,"targetPort":8080} + ] + } + }' >/dev/null + + + # wait svclb_ready or it will get connection refused + wait_svclb_ready kube-system argocd-server 300 + + log "Retrieving Argo CD initial admin password..." + ARGOCD_ADMIN_PASSWORD=$(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d) + ok "Argo CD UI: https://localhost:${ARGOCD_HOST_PORT} (user: admin, password: ${ARGOCD_ADMIN_PASSWORD})" + + # apply Application + log "Applying Argo CD Application (dev/playground)..." + kubectl apply -f "${ARGOCD_MANIFESTS_DIR}/application-dev.yaml" + ok "Application applied." + + if kubectl -n dev get deploy playground >/dev/null 2>&1; then + log "Waiting for Deployment 'playground' Available..." + kubectl -n dev wait --for=condition=available deploy/playground --timeout=300s || true + else + warn "Deployment 'playground' not found yet; will continue and rely on Argo CD sync." + fi + + # wait svclb_ready or it will get connection refused + wait_svclb_ready kube-system playground-svc 300 + + ok "Playground app: http://localhost:${APP_HOST_PORT}" +} + +# ========================= +# Main +# ========================= +need kubectl +ensure_docker_ready +ensure_k3d_cluster_with_ports +bootstrap_argocd +ok "All done 🎉 Open: https://localhost:${ARGOCD_HOST_PORT} and http://localhost:${APP_HOST_PORT}" diff --git a/scripts/setup_host.sh b/scripts/setup_host.sh index 2502582..d99e84a 100755 --- a/scripts/setup_host.sh +++ b/scripts/setup_host.sh @@ -1,41 +1,231 @@ -#!/bin/bash -set -e - -VAGRANT_VERSION="2.4.7" -ARCH="amd64" -DEB_FILE="vagrant_${VAGRANT_VERSION}-1_${ARCH}.deb" -DOWNLOAD_URL="https://releases.hashicorp.com/vagrant/${VAGRANT_VERSION}/${DEB_FILE}" - -echo "Installing dependencies..." -sudo apt update -sudo apt install -y wget curl gnupg lsb-release - -# Remove old version if any -if command -v vagrant >/dev/null; then - echo "Removing existing Vagrant installation..." - sudo apt remove -y vagrant -fi +#!/usr/bin/env bash +set -euo pipefail + +# ========================= +# Config (env or args) +# ========================= +VAGRANT_VERSION="${VAGRANT_VERSION:-2.4.7}" +CLUSTER_NAME="${CLUSTER_NAME:-k3d-cluster}" + +# ========================= +# Helpers +# ========================= +log() { echo -e "👉 \e[1m$*\e[0m"; } +ok() { echo -e "✅ $*"; } +warn() { echo -e "⚠️ $*"; } +die() { echo -e "❌ $*" >&2; exit 1; } + +DISTRO_CODENAME="$(lsb_release -cs 2>/dev/null || echo bookworm)" +ARCH_DEB="$(dpkg --print-architecture)" +ARCH_UNAME="$(uname -m)" + +case "${ARCH_DEB}" in + amd64) KUBECTL_ARCH="amd64" ;; + arm64) KUBECTL_ARCH="arm64" ;; + *) die "Unsupported arch: ${ARCH_DEB}" ;; +esac + +# default: install all +DO_VAGRANT=1 +DO_PART3=1 +DO_PROVISION=1 + +usage() { + cat </dev/null 2>&1; then + echo "❌ Cannot access Docker Daemon (/var/run/docker.sock)." + echo " Check group and service status, then retry." + exit 1 + fi +} -echo "Installing Vagrant..." -sudo dpkg -i "/tmp/${DEB_FILE}" +# ========================= +# Common base +# ========================= +install_base() { + log "Installing base packages..." + sudo apt-get update -y + sudo apt-get install -y ca-certificates curl wget gnupg lsb-release apt-transport-https software-properties-common jq + ok "Base packages installed" +} -# Cleanup -rm "/tmp/${DEB_FILE}" +# ========================= +# Vagrant (Part1/2) +# ========================= +install_vagrant() { + log "Installing/updating Vagrant ${VAGRANT_VERSION}..." + local DEB_FILE="vagrant_${VAGRANT_VERSION}-1_${ARCH_DEB}.deb" + local URL="https://releases.hashicorp.com/vagrant/${VAGRANT_VERSION}/${DEB_FILE}" -# Verify installation -echo "✅ Vagrant installed successfully:" -vagrant --version + if command -v vagrant >/dev/null 2>&1; then + warn "Detected existing Vagrant: $(vagrant --version). Attempting to update/overwrite to ${VAGRANT_VERSION}" + sudo apt-get remove -y vagrant || true + fi -echo "Installing VirtualBox..." -wget -O- -q https://www.virtualbox.org/download/oracle_vbox_2016.asc | sudo gpg --dearmour -o /usr/share/keyrings/oracle_vbox_2016.gpg -echo "deb [arch=amd64 signed-by=/usr/share/keyrings/oracle_vbox_2016.gpg] http://download.virtualbox.org/virtualbox/debian bookworm contrib" | sudo tee /etc/apt/sources.list.d/virtualbox.list -sudo apt update -sudo apt install virtualbox-7.1 + wget -q "${URL}" -O "/tmp/${DEB_FILE}" || die "Failed to download Vagrant: ${URL}" + sudo dpkg -i "/tmp/${DEB_FILE}" || sudo apt-get -f install -y + rm -f "/tmp/${DEB_FILE}" + ok "Vagrant installed: $(vagrant --version)" +} + +install_virtualbox_amd64() { + log "installing VirtualBox (amd64) as Vagrant provider..." + # Oracle keyring + wget -qO- https://www.virtualbox.org/download/oracle_vbox_2016.asc \ + | sudo gpg --dearmor -o /usr/share/keyrings/oracle_vbox_2016.gpg + echo "deb [arch=amd64 signed-by=/usr/share/keyrings/oracle_vbox_2016.gpg] http://download.virtualbox.org/virtualbox/debian ${DISTRO_CODENAME} contrib" \ + | sudo tee /etc/apt/sources.list.d/virtualbox.list >/dev/null + sudo apt-get update -y + sudo apt-get install -y virtualbox-7.1 + ok "VirtualBox installed: $(vboxmanage --version || echo ok)" +} + +install_libvirt_arm64() { + log "installing libvirt + QEMU (arm64) as Vagrant provider..." + sudo apt-get update -y + sudo apt-get install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils ebtables dnsmasq-base + sudo systemctl enable --now libvirtd + sudo usermod -aG libvirt,kvm "$USER" || true + # install vagrant-libvirt plugin + vagrant plugin install vagrant-libvirt + ok "libvirt/kvm and vagrant-libvirt plugin installed. (Please re-login for group changes to take effect)" +} + +install_vagrant_with_provider() { + install_vagrant + if [[ "${ARCH_DEB}" == "amd64" ]]; then + install_virtualbox_amd64 + ok "Part1/2: Vagrant + VirtualBox ready." + else + install_libvirt_arm64 + ok "Part1/2: Vagrant + libvirt ready. (VirtualBox not supported on ARM)" + fi +} + +# ========================= +# Part3: Docker + kubectl + k3d +# ========================= +install_docker() { + if command -v docker >/dev/null 2>&1; then + ok "Docker already installed: $(docker --version)" + return + fi + log "Installing Docker (official script)..." + curl -fsSL https://get.docker.com | sh + sudo usermod -aG docker "$USER" || true + newgrp docker + ok "Docker installed." +} + +install_kubectl() { + if command -v kubectl >/dev/null 2>&1; then + ok "kubectl already installed: $(kubectl version --client --output=yaml | grep gitVersion || true)" + return + fi + log "Installing kubectl (stable)..." + tmpdir="$(mktemp -d)" + pushd "$tmpdir" >/dev/null + KVER="$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)" + curl -LO "https://storage.googleapis.com/kubernetes-release/release/${KVER}/bin/linux/${KUBECTL_ARCH}/kubectl" + chmod +x kubectl + sudo mv kubectl /usr/local/bin/ + popd >/dev/null + rm -rf "$tmpdir" + ok "kubectl installed: $(kubectl version --client --short | tr -s ' ')" +} + +install_k3d() { + if command -v k3d >/dev/null 2>&1; then + ok "k3d already installed: $(k3d version | head -n1)" + return + fi + log "Installing k3d..." + curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash + ok "k3d installed: $(k3d version | head -n1)" +} + +create_k3d_cluster() { + if k3d cluster list | grep -q "^${CLUSTER_NAME}\b"; then + ok "k3d cluster ${CLUSTER_NAME} already exists, skipping creation." + return + fi + log "Creating k3d cluster: ${CLUSTER_NAME} ..." + k3d cluster create "${CLUSTER_NAME}" --wait + ok "k3d cluster created." +} + +part3_stack() { + install_docker + install_kubectl + install_k3d + if [[ "${DO_PROVISION}" -eq 1 ]]; then + ensure_docker_ready + create_k3d_cluster + else + warn "--no-provision: Only installing tools, skipping cluster creation/Argo CD installation." + fi +} + +# ========================= +# Run +# ========================= +install_base + +if [[ "${DO_VAGRANT}" -eq 1 ]]; then + install_vagrant_with_provider +else + warn "Skipping Vagrant installation (--part3-only)" +fi + +if [[ "${DO_PART3}" -eq 1 ]]; then + part3_stack +else + warn "Skipping Part3 (Docker/k3d/kubectl) installation (--vagrant-only)" +fi -# Verify VirtualBox installation -echo "✅ VirtualBox installed successfully:" -virtualbox --help | head -n 1 +ok "All done 🎉" +warn "If you just added docker/libvirt/kvm groups, please re-login for the changes to take effect."