#!/usr/bin/env bash set -euo pipefail project_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) namespace=elastic operator_version=3.5.0 for command in helm kubectl; do if ! command -v "${command}" >/dev/null 2>&1; then echo "Required command not found: ${command}" >&2 exit 1 fi done for dependency in storageclass/rook-ceph-block-ec; do if ! kubectl get "${dependency}" >/dev/null 2>&1; then echo "Required Kubernetes object not found: ${dependency}" >&2 exit 1 fi done helm repo add elastic https://helm.elastic.co --force-update helm repo update elastic helm upgrade --install elastic-operator elastic/eck-operator \ --namespace "${namespace}" \ --create-namespace \ --version "${operator_version}" \ --values "${project_dir}/operator-values.yaml" \ --wait \ --timeout 10m for crd in \ elasticsearches.elasticsearch.k8s.elastic.co \ kibanas.kibana.k8s.elastic.co \ beats.beat.k8s.elastic.co \ agents.agent.k8s.elastic.co; do kubectl wait --for=condition=Established "crd/${crd}" --timeout=2m done kubectl apply --dry-run=server --validate=false \ --filename "${project_dir}/stack.yaml" \ --filename "${project_dir}/netflow.yaml" \ --filename "${project_dir}/ingress.yaml" kubectl apply --validate=false \ --filename "${project_dir}/stack.yaml" \ --filename "${project_dir}/netflow.yaml" \ --filename "${project_dir}/ingress.yaml" for attempt in {1..360}; do es_health=$(kubectl --namespace "${namespace}" get elasticsearch/elasticsearch \ --output=jsonpath='{.status.health}') es_nodes=$(kubectl --namespace "${namespace}" get elasticsearch/elasticsearch \ --output=jsonpath='{.status.availableNodes}') kb_health=$(kubectl --namespace "${namespace}" get kibana/kibana \ --output=jsonpath='{.status.health}') kb_nodes=$(kubectl --namespace "${namespace}" get kibana/kibana \ --output=jsonpath='{.status.availableNodes}') beat_health=$(kubectl --namespace "${namespace}" get beat/netflow \ --output=jsonpath='{.status.health}') beat_nodes=$(kubectl --namespace "${namespace}" get beat/netflow \ --output=jsonpath='{.status.availableNodes}') load_balancer_ip=$(kubectl --namespace "${namespace}" get service/netflow \ --output=jsonpath='{.status.loadBalancer.ingress[0].ip}') echo "Check ${attempt}/360: Elasticsearch ${es_health:-unknown} (${es_nodes:-0}/3), Kibana ${kb_health:-unknown} (${kb_nodes:-0}/2), Filebeat ${beat_health:-unknown} (${beat_nodes:-0}/1), LB=${load_balancer_ip:-pending}" if [[ "${es_health}" == "green" \ && "${es_nodes}" == "3" \ && "${kb_health}" == "green" \ && "${kb_nodes}" == "2" \ && "${beat_health}" == "green" \ && "${beat_nodes}" == "1" \ && "${load_balancer_ip}" == "192.168.0.20" ]]; then break fi if [[ "${attempt}" == "360" ]]; then echo "Timed out waiting for the complete Elastic Stack rollout" >&2 exit 1 fi sleep 5 done "${project_dir}/install-traefik-assets.sh" kubectl apply --dry-run=server --validate=false \ --filename "${project_dir}/traefik-access.yaml" kubectl apply --validate=false \ --filename "${project_dir}/traefik-access.yaml" for attempt in {1..240}; do agent_health=$(kubectl --namespace "${namespace}" get agent/traefik-access \ --output=jsonpath='{.status.health}') agent_nodes=$(kubectl --namespace "${namespace}" get agent/traefik-access \ --output=jsonpath='{.status.availableNodes}') agent_expected=$(kubectl --namespace "${namespace}" get agent/traefik-access \ --output=jsonpath='{.status.expectedNodes}') echo "Agent check ${attempt}/240: ${agent_health:-unknown} (${agent_nodes:-0}/${agent_expected:-0})" if [[ "${agent_health}" == "green" \ && -n "${agent_expected}" \ && "${agent_expected}" != "0" \ && "${agent_nodes}" == "${agent_expected}" ]]; then break fi if [[ "${attempt}" == "240" ]]; then echo "Timed out waiting for the Traefik access-log agents" >&2 exit 1 fi sleep 5 done echo echo "Elastic Stack is ready in namespace ${namespace}." echo "Kibana: https://kibana.brunner.ninja" echo "NetFlow collector: ${load_balancer_ip}:2055/UDP" echo "Traefik access logs: logs-traefik.access-default" echo "Retrieve the Kibana 'elastic' password with:" echo "kubectl get secret elasticsearch-es-elastic-user -n ${namespace} -o go-template='{{.data.elastic | base64decode}}{{\"\\n\"}}'"