forked from wazuh/wazuh-docker
665 lines
28 KiB
YAML
665 lines
28 KiB
YAML
name: (5.x) Docker PR check
|
|
permissions:
|
|
contents: read
|
|
id-token: write
|
|
on:
|
|
pull_request:
|
|
types: [opened, synchronize, reopened, ready_for_review]
|
|
branches:
|
|
- 5.*
|
|
- main
|
|
paths:
|
|
- 'build-docker-images/**'
|
|
- 'multi-node/**'
|
|
- 'single-node/**'
|
|
- 'wazuh-agent/**'
|
|
- '.github/**'
|
|
workflow_dispatch:
|
|
inputs:
|
|
docker_reference:
|
|
description: 'Branch or tag to build from'
|
|
required: true
|
|
type: string
|
|
|
|
jobs:
|
|
|
|
prepare-variables:
|
|
if: ${{ !github.event.pull_request.draft }}
|
|
runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}
|
|
outputs:
|
|
WAZUH_VERSION: ${{ steps.dotenv.outputs.WAZUH_VERSION }}
|
|
WAZUH_IMAGE_VERSION: ${{ steps.dotenv.outputs.WAZUH_IMAGE_VERSION }}
|
|
WAZUH_REGISTRY: ${{ vars.IMAGE_REGISTRY_DEV }}
|
|
IMAGE_TAG: ${{ steps.dotenv.outputs.IMAGE_TAG }}
|
|
WAZUH_MINOR_VERSION: ${{ steps.dotenv.outputs.WAZUH_MINOR_VERSION }}
|
|
steps:
|
|
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Export .env variables
|
|
id: dotenv
|
|
shell: bash
|
|
run: |
|
|
if [ ! -f .env ]; then echo "::error::.env missing"; exit 1; fi
|
|
grep -v '^#' .env | grep -v '^\s*$' >> "$GITHUB_OUTPUT"
|
|
FULL_VERSION=$(grep "^WAZUH_VERSION=" .env | cut -d'=' -f2)
|
|
MINOR_VERSION=$(echo "$FULL_VERSION" | cut -d'.' -f1,2)
|
|
echo "WAZUH_MINOR_VERSION=$MINOR_VERSION" >> "$GITHUB_OUTPUT"
|
|
|
|
|
|
build-images:
|
|
needs: prepare-variables
|
|
uses: ./.github/workflows/5_build_and_push_images.yml
|
|
secrets: inherit
|
|
with:
|
|
image_tag: ${{ needs.prepare-variables.outputs.WAZUH_IMAGE_VERSION }}
|
|
docker_reference: ${{ github.head_ref || inputs.docker_reference }}
|
|
wazuh_automation_reference: '5.0.0'
|
|
commit_list: '["latest", "latest", "latest", "latest"]'
|
|
assistant_revision: 'latest'
|
|
id: ${{ github.run_id }}
|
|
dev: true
|
|
|
|
Execute-Goss-tests:
|
|
needs: [prepare-variables, build-images]
|
|
runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}
|
|
env:
|
|
WAZUH_IMAGE_VERSION: ${{ needs.prepare-variables.outputs.WAZUH_IMAGE_VERSION }}
|
|
WAZUH_REGISTRY: ${{ needs.prepare-variables.outputs.WAZUH_REGISTRY }}
|
|
steps:
|
|
|
|
- name: Check out code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Install Goss
|
|
uses: e1himself/goss-installation-action@v1.0.3
|
|
with:
|
|
version: 'v0.4.4'
|
|
|
|
- name: Configure aws credentials
|
|
uses: aws-actions/configure-aws-credentials@v4
|
|
with:
|
|
role-to-assume: ${{ secrets.AWS_IAM_DOCKER_ROLE }}
|
|
aws-region: "${{ secrets.AWS_REGION }}"
|
|
|
|
- name: Log in to Amazon ECR
|
|
uses: aws-actions/amazon-ecr-login@v2
|
|
|
|
- name: Execute Goss tests (wazuh-manager)
|
|
run: dgoss run ${{ env.WAZUH_REGISTRY }}/wazuh/wazuh-manager:${{ env.WAZUH_IMAGE_VERSION }}-latest
|
|
env:
|
|
GOSS_SLEEP: 30
|
|
GOSS_FILE: .github/.goss.yaml
|
|
|
|
check-single-node:
|
|
name: Check single node on ${{ matrix.os }}
|
|
runs-on: ${{ matrix.os }}
|
|
strategy:
|
|
matrix:
|
|
os: ["codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}", "codebuild-github-actions-codebuild-runner-devops-arm-${{ github.run_id }}-${{ github.run_attempt }}"]
|
|
fail-fast: false
|
|
needs: [prepare-variables, Execute-Goss-tests]
|
|
env:
|
|
WAZUH_IMAGE_VERSION: ${{ needs.prepare-variables.outputs.WAZUH_IMAGE_VERSION }}
|
|
WAZUH_MINOR_VERSION: ${{ needs.prepare-variables.outputs.WAZUH_MINOR_VERSION }}
|
|
WAZUH_REGISTRY: ${{ needs.prepare-variables.outputs.WAZUH_REGISTRY }}
|
|
INDEXER_USERNAME: admin
|
|
INDEXER_PASSWORD: admin
|
|
MANAGER_NODES: "manager"
|
|
API_USERNAME: wazuh-wui
|
|
API_PASSWORD: wazuh-wui
|
|
steps:
|
|
|
|
- name: Check out code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Configure aws credentials
|
|
uses: aws-actions/configure-aws-credentials@v4
|
|
with:
|
|
role-to-assume: ${{ secrets.AWS_IAM_DOCKER_ROLE }}
|
|
aws-region: "${{ secrets.AWS_REGION }}"
|
|
|
|
- name: Log in to Amazon ECR
|
|
uses: aws-actions/amazon-ecr-login@v2
|
|
|
|
- name: Download artifact_urls.yaml
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: presigned-artifact-urls-${{ github.run_id }}
|
|
path: ./single-node/
|
|
|
|
- name: Log in to Docker Hub
|
|
uses: docker/login-action@v4
|
|
with:
|
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
|
|
|
- name: Add environment variables into GITHUB_ENV
|
|
run: |
|
|
# Export variables to the environment
|
|
awk -F':' '!/^#/ && NF>1 {name=$1; val=substr($0,length(name)+3); gsub(/[-.]/,"_",name); print name "=" val}' ${{ vars.ARTIFACT_URL_FILE_NAME }} >> "$GITHUB_ENV"
|
|
working-directory: ./single-node/
|
|
|
|
- name: Create single node certficates
|
|
run: |
|
|
curl --output ./wazuh-certs-tool.sh "${{ env.wazuh_certs_tool }}"
|
|
cat > config.yml <<EOF
|
|
nodes:
|
|
# Wazuh indexer server nodes
|
|
indexer:
|
|
- name: wazuh.indexer
|
|
dns: "wazuh.indexer"
|
|
|
|
# Wazuh manager nodes
|
|
# Use node_type only with more than one Wazuh manager
|
|
manager:
|
|
- name: wazuh.manager
|
|
dns: "wazuh.manager"
|
|
|
|
# Wazuh dashboard node
|
|
dashboard:
|
|
- name: wazuh.dashboard
|
|
dns: "wazuh.dashboard"
|
|
EOF
|
|
cat config.yml
|
|
sudo bash ../tools/utils/deployment/certificates-conf.sh --cert --copy --priv
|
|
sudo sysctl -w vm.max_map_count=262144
|
|
working-directory: ./single-node
|
|
|
|
- name: Edit single node docker-compose file
|
|
shell: bash
|
|
env:
|
|
WAZUH_REGISTRY: ${{ env.WAZUH_REGISTRY }}
|
|
run: |
|
|
TARGET_FILE="single-node/docker-compose.yml"
|
|
if [ -f "$TARGET_FILE" ]; then
|
|
echo "Updating registry in $TARGET_FILE to: ${{ env.WAZUH_REGISTRY }}"
|
|
sed -i "s|wazuh/wazuh-|${{ env.WAZUH_REGISTRY }}/wazuh/wazuh-|g" "$TARGET_FILE"
|
|
sed -i "s/\(.*wazuh\/wazuh-.*:\)${{ env.WAZUH_IMAGE_VERSION }}/\1${{ env.WAZUH_IMAGE_VERSION }}-latest/g" "$TARGET_FILE"
|
|
else
|
|
echo "File $TARGET_FILE not found"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Start single node stack
|
|
id: start_single_node_stack
|
|
run: docker compose up -d
|
|
working-directory: ./single-node
|
|
|
|
- name: Check Wazuh indexer start
|
|
if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }}
|
|
run: |
|
|
for i in {1..20}; do
|
|
echo "Checking Wazuh indexer health (Attempt $i/20)"
|
|
RESPONSE=$(curl -XGET "https://127.0.0.1:9200/_cluster/health?pretty" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s --retry 2 || true)
|
|
INDEXER_CONTAINERS=$(docker ps --format '{{.Names}}' | grep "indexer")
|
|
if echo "$RESPONSE" | grep -qE "green|yellow"; then
|
|
echo "Cluster Online"
|
|
echo "$RESPONSE"
|
|
exit 0
|
|
fi
|
|
echo "Waiting for cluster to be online"
|
|
for CONTAINER_NAME in $INDEXER_CONTAINERS; do
|
|
echo ""
|
|
echo "========================================================="
|
|
echo "Container logs for $CONTAINER_NAME"
|
|
echo "========================================================="
|
|
docker logs --tail 30 "$CONTAINER_NAME"
|
|
echo "---------------------------------------------------------"
|
|
done
|
|
[ $i -lt 20 ] && sleep 60
|
|
done
|
|
status_index="`curl -XGET "https://127.0.0.1:9200/_cat/indices" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s | wc -l`"
|
|
status_index_green="`curl -XGET "https://127.0.0.1:9200/_cat/indices" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s | grep -E "green|yellow" | wc -l`"
|
|
if [[ $status_index_green -eq $status_index ]]; then
|
|
curl -XGET "https://127.0.0.1:9200/_cat/indices" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s
|
|
else
|
|
curl -XGET "https://127.0.0.1:9200/_cat/indices" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s
|
|
exit 1
|
|
fi
|
|
|
|
|
|
- name: Check Wazuh indexer nodes
|
|
if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }}
|
|
run: |
|
|
nodes="`curl -XGET "https://127.0.0.1:9200/_cat/nodes" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s | grep -E "indexer" | wc -l`"
|
|
echo "Wazuh indexer nodes: ${nodes}"
|
|
|
|
- name: Check Wazuh templates
|
|
if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }}
|
|
run: |
|
|
qty_templates="`curl -XGET "https://127.0.0.1:9200/_cat/templates" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s | grep -P "wazuh|wazuh-agent|wazuh-statistics" | wc -l`"
|
|
templates="`curl -XGET "https://127.0.0.1:9200/_cat/templates" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s | grep -P "wazuh|wazuh-agent|wazuh-statistics"`"
|
|
if [[ $qty_templates -gt 3 ]]; then
|
|
echo "wazuh templates:"
|
|
echo "${templates}"
|
|
else
|
|
echo "wazuh templates:"
|
|
echo "${templates}"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Check Wazuh manager start
|
|
if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }}
|
|
run: |
|
|
for NODE in "${{ env.MANAGER_NODES }}"; do
|
|
ok=false
|
|
for i in {1..20}; do
|
|
TOKEN=$(curl -s -u ${{ env.API_USERNAME }}:${{ env.API_PASSWORD }} -k -X POST "https://127.0.0.1:55000/security/user/authenticate?raw=true")
|
|
services="`curl -k -s -X GET "https://127.0.0.1:55000/cluster/$NODE/status?pretty=true" -H "Authorization: Bearer ${TOKEN}" | jq -r .data.affected_items | grep running | wc -l`"
|
|
if [[ $services -gt 7 ]]; then
|
|
echo "Wazuh Manager $NODE Services: ${services}"
|
|
echo "OK"
|
|
ok=true
|
|
break
|
|
else
|
|
curl -k -X GET "https://127.0.0.1:55000/cluster/$NODE/status?pretty=true" -H "Authorization: Bearer ${TOKEN}" | jq -r .data.affected_items
|
|
echo "Wazuh Manager $NODE Services: ${services}. Retrying in 30s"
|
|
[ $i -lt 20 ] && sleep 30
|
|
fi
|
|
done
|
|
if [[ "$ok" != "true" ]]; then
|
|
echo "Error: Wazuh Manager $NODE did not reach expected running services threshold"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
- name: Check Wazuh dashboard service URL
|
|
if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }}
|
|
run: |
|
|
for i in {1..20}; do
|
|
echo "Checking Wazuh dashboard (Attempt $i/20)"
|
|
STATUS=$(curl -k -s -o /dev/null -w "%{http_code}" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} "https://127.0.0.1:443/app/status" || true)
|
|
echo "Current status: $STATUS"
|
|
if [[ "$STATUS" == "200" ]]; then
|
|
echo "Wazuh dashboard is UP"
|
|
exit 0
|
|
elif [[ "$STATUS" == "429" || "$STATUS" == "503" ]]; then
|
|
echo "Dashboard is busy or initializing (Status $STATUS). Retrying in 30s"
|
|
else
|
|
echo "Unexpected status $STATUS. Retrying in 30s"
|
|
fi
|
|
sleep 30
|
|
done
|
|
echo "Error: Dashboard did not reach 200 status in time."
|
|
exit 1
|
|
|
|
- name: Modify Docker endpoint into Wazuh agent docker-compose.yml file
|
|
if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }}
|
|
run: sed -i "s/<WAZUH_MANAGER_IP>/$(ip addr show docker0 | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1)/g" wazuh-agent/docker-compose.yml
|
|
|
|
- name: Edit Wazuh agent docker-compose file
|
|
if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }}
|
|
shell: bash
|
|
env:
|
|
WAZUH_REGISTRY: ${{ env.WAZUH_REGISTRY }}
|
|
run: |
|
|
TARGET_FILE="wazuh-agent/docker-compose.yml"
|
|
if [ -f "$TARGET_FILE" ]; then
|
|
echo "Updating registry in $TARGET_FILE to: ${{ env.WAZUH_REGISTRY }}"
|
|
sed -i "s|wazuh/wazuh-|${{ env.WAZUH_REGISTRY }}/wazuh/wazuh-|g" "$TARGET_FILE"
|
|
sed -i "s/\(.*wazuh\/wazuh-.*:\)${{ env.WAZUH_IMAGE_VERSION }}/\1${{ env.WAZUH_IMAGE_VERSION }}-latest/g" "$TARGET_FILE"
|
|
else
|
|
echo "File $TARGET_FILE not found"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Start Wazuh agent
|
|
if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }}
|
|
run: docker compose up -d
|
|
working-directory: ./wazuh-agent
|
|
|
|
- name: Check Wazuh agent enrollment
|
|
if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }}
|
|
run: |
|
|
enrolled=false
|
|
for i in {1..5}; do
|
|
TOKEN=$(curl -s -u ${{ env.API_USERNAME }}:${{ env.API_PASSWORD }} -k -X POST "https://127.0.0.1:55000/security/user/authenticate?raw=true")
|
|
agents="`curl -k -s -X GET "https://127.0.0.1:55000/agents?pretty=true" -H "Authorization: Bearer ${TOKEN}" | jq -r .data.affected_items | grep active | wc -l`"
|
|
if [[ $agents -gt 0 ]]; then
|
|
echo "Wazuh agents: ${agents}"
|
|
echo "OK"
|
|
enrolled=true
|
|
break
|
|
else
|
|
curl -k -s -X GET "https://127.0.0.1:55000/agents?pretty=true" -H "Authorization: Bearer ${TOKEN}"
|
|
echo "Wazuh agents: ${agents}. Retrying in 10s"
|
|
[ $i -lt 5 ] && sleep 10
|
|
fi
|
|
done
|
|
if [[ "$enrolled" != "true" ]]; then
|
|
echo "Error: Wazuh agent enrollment did not reach expected active agents threshold"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Check errors in wazuh-manager.log for Wazuh manager
|
|
if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }}
|
|
run: ./.github/single-node-log-check.sh
|
|
|
|
- name: Check documents into wazuh-states index
|
|
if: ${{ always() && steps.start_single_node_stack.outcome == 'success' }}
|
|
run: |
|
|
for i in {1..20}; do
|
|
echo "Checking documents in wazuh-states (Attempt $i/20)..."
|
|
RESPONSE=$(curl -XGET "https://127.0.0.1:9200/wazuh-states*/_count" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s || echo "{}")
|
|
DOCS=$(echo "$RESPONSE" | jq -r '.count // 0')
|
|
if [[ "$DOCS" -gt 0 ]]; then
|
|
echo "wazuh-states index has documents: ${DOCS}"
|
|
exit 0
|
|
fi
|
|
echo "The index is empty or does not exist yet (Count: $DOCS). Waiting 60s"
|
|
[ $i -lt 20 ] && sleep 60
|
|
done
|
|
echo "Error: No documents found in wazuh-states after 20 attempts."
|
|
echo "Last response: $RESPONSE"
|
|
exit 1
|
|
|
|
- name: Docker logs
|
|
if: always()
|
|
continue-on-error: true
|
|
run: |
|
|
INDEXER_CONTAINERS=$(docker ps --format '{{.Names}}')
|
|
for CONTAINER_NAME in $INDEXER_CONTAINERS; do
|
|
echo ""
|
|
echo "========================================================="
|
|
echo "Container logs for $CONTAINER_NAME"
|
|
echo "========================================================="
|
|
docker logs "$CONTAINER_NAME"
|
|
echo "---------------------------------------------------------"
|
|
done
|
|
working-directory: ./single-node
|
|
|
|
check-multi-node:
|
|
name: Check multi node on ${{ matrix.os }}
|
|
runs-on: ${{ matrix.os }}
|
|
strategy:
|
|
matrix:
|
|
os: ["codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}", "codebuild-github-actions-codebuild-runner-devops-arm-${{ github.run_id }}-${{ github.run_attempt }}"]
|
|
fail-fast: false
|
|
needs: [prepare-variables, Execute-Goss-tests]
|
|
env:
|
|
WAZUH_IMAGE_VERSION: ${{ needs.prepare-variables.outputs.WAZUH_IMAGE_VERSION }}
|
|
WAZUH_MINOR_VERSION: ${{ needs.prepare-variables.outputs.WAZUH_MINOR_VERSION }}
|
|
WAZUH_REGISTRY: ${{ needs.prepare-variables.outputs.WAZUH_REGISTRY }}
|
|
INDEXER_USERNAME: admin
|
|
INDEXER_PASSWORD: admin
|
|
MANAGER_NODES: "master,worker01"
|
|
API_USERNAME: wazuh-wui
|
|
API_PASSWORD: wazuh-wui
|
|
steps:
|
|
|
|
- name: Check out code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Configure aws credentials
|
|
uses: aws-actions/configure-aws-credentials@v4
|
|
with:
|
|
role-to-assume: ${{ secrets.AWS_IAM_DOCKER_ROLE }}
|
|
aws-region: "${{ secrets.AWS_REGION }}"
|
|
|
|
- name: Log in to Amazon ECR
|
|
uses: aws-actions/amazon-ecr-login@v2
|
|
|
|
- name: Download artifact_urls.yaml
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: presigned-artifact-urls-${{ github.run_id }}
|
|
path: ./multi-node/
|
|
|
|
- name: Log in to Docker Hub
|
|
uses: docker/login-action@v4
|
|
with:
|
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
|
|
|
- name: Add environment variables into GITHUB_ENV
|
|
run: |
|
|
# Export variables to the environment
|
|
awk -F':' '!/^#/ && NF>1 {name=$1; val=substr($0,length(name)+3); gsub(/[-.]/,"_",name); print name "=" val}' ${{ vars.ARTIFACT_URL_FILE_NAME }} >> "$GITHUB_ENV"
|
|
working-directory: ./multi-node/
|
|
|
|
- name: Create multi node certficates
|
|
run: |
|
|
curl --output ./wazuh-certs-tool.sh "${{ env.wazuh_certs_tool }}"
|
|
cat > config.yml <<EOF
|
|
nodes:
|
|
# Wazuh indexer server nodes
|
|
indexer:
|
|
- name: wazuh1.indexer
|
|
dns: "wazuh1.indexer"
|
|
- name: wazuh2.indexer
|
|
dns: "wazuh2.indexer"
|
|
- name: wazuh3.indexer
|
|
dns: "wazuh3.indexer"
|
|
|
|
# Wazuh manager nodes
|
|
# Use node_type only with more than one Wazuh manager
|
|
manager:
|
|
- name: wazuh.master
|
|
dns: "wazuh.master"
|
|
node_type: master
|
|
- name: wazuh.worker
|
|
dns: "wazuh.worker"
|
|
node_type: worker
|
|
|
|
# Wazuh dashboard node
|
|
dashboard:
|
|
- name: wazuh.dashboard
|
|
dns: "wazuh.dashboard"
|
|
EOF
|
|
cat config.yml
|
|
sudo bash ../tools/utils/deployment/certificates-conf.sh --cert --copy --priv
|
|
sudo sysctl -w vm.max_map_count=262144
|
|
working-directory: ./multi-node
|
|
|
|
- name: Edit multi node docker-compose file
|
|
shell: bash
|
|
run: |
|
|
TARGET_FILE="multi-node/docker-compose.yml"
|
|
if [ -f "$TARGET_FILE" ]; then
|
|
echo "Updating registry in $TARGET_FILE to: ${{ env.WAZUH_REGISTRY }}"
|
|
sed -i "s|wazuh/wazuh-|${{ env.WAZUH_REGISTRY }}/wazuh/wazuh-|g" "$TARGET_FILE"
|
|
sed -i "s/\(.*wazuh\/wazuh-.*:\)${{ env.WAZUH_IMAGE_VERSION }}/\1${{ env.WAZUH_IMAGE_VERSION }}-latest/g" "$TARGET_FILE"
|
|
else
|
|
echo "File $TARGET_FILE not found"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Start multi node stack
|
|
id: start_multi_node_stack
|
|
run: docker compose up -d
|
|
working-directory: ./multi-node
|
|
|
|
- name: Check Wazuh indexer start
|
|
if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }}
|
|
run: |
|
|
for i in {1..20}; do
|
|
echo "Checking Wazuh indexer health (Attempt $i/20)"
|
|
RESPONSE=$(curl -XGET "https://127.0.0.1:9200/_cluster/health?pretty" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s --retry 2 || true)
|
|
INDEXER_CONTAINERS=$(docker ps --format '{{.Names}}' | grep "indexer")
|
|
if echo "$RESPONSE" | grep -qE "green|yellow"; then
|
|
echo "Cluster Online"
|
|
echo "$RESPONSE"
|
|
exit 0
|
|
fi
|
|
echo "Waiting for cluster to be online"
|
|
for CONTAINER_NAME in $INDEXER_CONTAINERS; do
|
|
echo ""
|
|
echo "========================================================="
|
|
echo "Container logs for $CONTAINER_NAME"
|
|
echo "========================================================="
|
|
docker logs --tail 30 "$CONTAINER_NAME"
|
|
echo "---------------------------------------------------------"
|
|
done
|
|
[ $i -lt 20 ] && sleep 60
|
|
done
|
|
status_index="`curl -XGET "https://127.0.0.1:9200/_cat/indices" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s | wc -l`"
|
|
status_index_green="`curl -XGET "https://127.0.0.1:9200/_cat/indices" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s | grep -E "green" | wc -l`"
|
|
if [[ $status_index_green -eq $status_index ]]; then
|
|
curl -XGET "https://127.0.0.1:9200/_cat/indices" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s
|
|
else
|
|
curl -XGET "https://127.0.0.1:9200/_cat/indices" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s
|
|
exit 1
|
|
fi
|
|
|
|
- name: Check Wazuh indexer nodes
|
|
if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }}
|
|
run: |
|
|
nodes="`curl -XGET "https://127.0.0.1:9200/_cat/nodes" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s | grep -E "indexer" | wc -l`"
|
|
if [[ $nodes -eq 3 ]]; then
|
|
echo "Wazuh indexer nodes: ${nodes}"
|
|
else
|
|
echo "Wazuh indexer nodes: ${nodes}"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Check Wazuh templates
|
|
if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }}
|
|
run: |
|
|
qty_templates="`curl -XGET "https://127.0.0.1:9200/_cat/templates" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s | grep "wazuh" | wc -l`"
|
|
templates="`curl -XGET "https://127.0.0.1:9200/_cat/templates" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s | grep "wazuh"`"
|
|
if [[ $qty_templates -gt 3 ]]; then
|
|
echo "wazuh templates:"
|
|
echo "${templates}"
|
|
else
|
|
echo "wazuh templates:"
|
|
echo "${templates}"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Check Wazuh manager start
|
|
if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }}
|
|
run: |
|
|
IFS=',' read -r -a NODES <<< "${{ env.MANAGER_NODES }}"
|
|
for NODE in "${NODES[@]}"; do
|
|
if [[ "$NODE" == "master" ]]; then
|
|
THRESHOLD=8
|
|
else
|
|
THRESHOLD=7
|
|
fi
|
|
ok=false
|
|
for i in {1..20}; do
|
|
TOKEN=$(curl -s -u ${{ env.API_USERNAME }}:${{ env.API_PASSWORD }} -k -X POST "https://127.0.0.1:55000/security/user/authenticate?raw=true")
|
|
services="`curl -k -s -X GET "https://127.0.0.1:55000/cluster/$NODE/status?pretty=true" -H "Authorization: Bearer ${TOKEN}" | jq -r .data.affected_items | grep running | wc -l`"
|
|
if [[ $services -ge $THRESHOLD ]]; then
|
|
echo "Wazuh Manager $NODE Services: ${services}"
|
|
echo "OK"
|
|
ok=true
|
|
break
|
|
else
|
|
curl -k -X GET "https://127.0.0.1:55000/cluster/$NODE/status?pretty=true" -H "Authorization: Bearer ${TOKEN}" | jq -r .data.affected_items
|
|
echo "Wazuh Manager $NODE Services: ${services}. Retrying in 30s"
|
|
[ $i -lt 20 ] && sleep 30
|
|
fi
|
|
done
|
|
if [[ "$ok" != "true" ]]; then
|
|
echo "Error: Wazuh Manager $NODE did not reach expected running services threshold"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
- name: Check Wazuh dashboard service URL
|
|
if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }}
|
|
run: |
|
|
for i in {1..20}; do
|
|
echo "Checking Wazuh dashboard (Attempt $i/20)"
|
|
STATUS=$(curl -k -s -o /dev/null -w "%{http_code}" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} "https://127.0.0.1:443/app/status" || true)
|
|
echo "Current status: $STATUS"
|
|
if [[ "$STATUS" == "200" ]]; then
|
|
echo "Wazuh dashboard is UP"
|
|
exit 0
|
|
elif [[ "$STATUS" == "429" || "$STATUS" == "503" ]]; then
|
|
echo "Dashboard is busy or initializing (Status $STATUS). Retrying in 30s"
|
|
else
|
|
echo "Unexpected status $STATUS. Retrying in 30s"
|
|
fi
|
|
sleep 30
|
|
done
|
|
echo "Error: Dashboard did not reach 200 status in time."
|
|
exit 1
|
|
|
|
- name: Modify Docker endpoint into Wazuh agent docker-compose.yml file
|
|
if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }}
|
|
run: sed -i "s/<WAZUH_MANAGER_IP>/$(ip addr show docker0 | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1)/g" wazuh-agent/docker-compose.yml
|
|
|
|
- name: Edit Wazuh agent docker-compose file
|
|
if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }}
|
|
shell: bash
|
|
env:
|
|
WAZUH_REGISTRY: ${{ env.WAZUH_REGISTRY }}
|
|
run: |
|
|
TARGET_FILE="wazuh-agent/docker-compose.yml"
|
|
if [ -f "$TARGET_FILE" ]; then
|
|
echo "Updating registry in $TARGET_FILE to: ${{ env.WAZUH_REGISTRY }}"
|
|
sed -i "s|wazuh/wazuh-|${{ env.WAZUH_REGISTRY }}/wazuh/wazuh-|g" "$TARGET_FILE"
|
|
sed -i "s/\(.*wazuh\/wazuh-.*:\)${{ env.WAZUH_IMAGE_VERSION }}/\1${{ env.WAZUH_IMAGE_VERSION }}-latest/g" "$TARGET_FILE"
|
|
else
|
|
echo "File $TARGET_FILE not found"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Start Wazuh agent
|
|
if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }}
|
|
run: docker compose -f wazuh-agent/docker-compose.yml up -d
|
|
|
|
- name: Check Wazuh agent enrollment
|
|
if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }}
|
|
run: |
|
|
enrolled=false
|
|
for i in {1..5}; do
|
|
TOKEN=$(curl -s -u ${{ env.API_USERNAME }}:${{ env.API_PASSWORD }} -k -X POST "https://127.0.0.1:55000/security/user/authenticate?raw=true")
|
|
agents="`curl -k -s -X GET "https://127.0.0.1:55000/agents?pretty=true" -H "Authorization: Bearer ${TOKEN}" | jq -r .data.affected_items | grep active | wc -l`"
|
|
if [[ $agents -gt 0 ]]; then
|
|
echo "Wazuh agents: ${agents}"
|
|
echo "OK"
|
|
enrolled=true
|
|
break
|
|
else
|
|
curl -k -s -X GET "https://127.0.0.1:55000/agents?pretty=true" -H "Authorization: Bearer ${TOKEN}"
|
|
echo "Wazuh agents: ${agents}. Retrying in 10s"
|
|
[ $i -lt 5 ] && sleep 10
|
|
fi
|
|
done
|
|
if [[ "$enrolled" != "true" ]]; then
|
|
echo "Error: Wazuh agent enrollment did not reach expected active agents threshold"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Check errors in wazuh-manager.log for Wazuh manager
|
|
if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }}
|
|
run: ./.github/multi-node-log-check.sh
|
|
|
|
- name: Check documents into wazuh-states index
|
|
if: ${{ always() && steps.start_multi_node_stack.outcome == 'success' }}
|
|
run: |
|
|
for i in {1..20}; do
|
|
echo "Checking documents in wazuh-states (Attempt $i/20)..."
|
|
RESPONSE=$(curl -XGET "https://127.0.0.1:9200/wazuh-states*/_count" -u ${{ env.INDEXER_USERNAME }}:${{ env.INDEXER_PASSWORD }} -k -s || echo "{}")
|
|
DOCS=$(echo "$RESPONSE" | jq -r '.count // 0')
|
|
if [[ "$DOCS" -gt 0 ]]; then
|
|
echo "wazuh-states index has documents: ${DOCS}"
|
|
exit 0
|
|
fi
|
|
echo "The index is empty or does not exist yet (Count: $DOCS). Waiting 60s"
|
|
[ $i -lt 20 ] && sleep 60
|
|
done
|
|
echo "Error: No documents found in wazuh-states after 20 attempts."
|
|
echo "Last response: $RESPONSE"
|
|
exit 1
|
|
|
|
- name: Docker logs
|
|
if: always()
|
|
continue-on-error: true
|
|
run: |
|
|
INDEXER_CONTAINERS=$(docker ps --format '{{.Names}}')
|
|
for CONTAINER_NAME in $INDEXER_CONTAINERS; do
|
|
echo ""
|
|
echo "========================================================="
|
|
echo "Container logs for $CONTAINER_NAME"
|
|
echo "========================================================="
|
|
docker logs "$CONTAINER_NAME"
|
|
echo "---------------------------------------------------------"
|
|
done
|
|
working-directory: ./multi-node
|