diff --git a/test-tools/README.md b/test-tools/README.md index 64dc8c453dba5..3db416533fbba 100644 --- a/test-tools/README.md +++ b/test-tools/README.md @@ -1,6 +1,6 @@ # Basic cluster environment -This is a environment definition with the required configuration to be prepared to freshly install a Wazuh Indexer +This is an environment definition with the required configuration to be prepared to freshly install a Wazuh Indexer cluster with two nodes using Vagrant and Libvirt to provision the Virtual Machines. It also generates the node's required certificates using the `wazuh-certs-tool` and copy them to each node's `home` diff --git a/test-tools/Vagrantfile b/test-tools/Vagrantfile index 54cafae781ed1..b922ddc66cf21 100644 --- a/test-tools/Vagrantfile +++ b/test-tools/Vagrantfile @@ -7,7 +7,7 @@ system(" Vagrant.configure("2") do |config| config.vm.define "indexer_1" do |indexer_1| - indexer_1.vm.box = "generic/rhel9" + indexer_1.vm.box = "generic/alma9" indexer_1.vm.synced_folder ".", "/vagrant" indexer_1.vm.network "private_network", ip: "192.168.56.10" indexer_1.vm.hostname = "node-1" @@ -16,13 +16,17 @@ Vagrant.configure("2") do |config| vb.cpus = "4" end indexer_1.vm.provision "shell", inline: <<-SHELL - sudo systemctl stop firewalld - sudo systemctl disable firewalld - sudo yum clean all + systemctl stop firewalld + systemctl disable firewalld + yum clean all + yum install curl jq unzip tar -y # Add node-2 to /etc/hosts - sudo echo "192.168.56.11 node-2" >> /etc/hosts + echo "192.168.56.11 node-2" >> /etc/hosts # Copy generated certificates cp /vagrant/wazuh-certificates.tar /home/vagrant/wazuh-certificates.tar + # Copy test scripts + cp -r /vagrant/scripts /home/vagrant/scripts + chown -R vagrant:vagrant /home/vagrant/scripts SHELL end config.vm.define "indexer_2" do |indexer_2| @@ -35,12 +39,16 @@ Vagrant.configure("2") do |config| vb.cpus = "4" end indexer_2.vm.provision "shell", inline: <<-SHELL - sudo systemctl stop ufw - sudo systemctl disable ufw + systemctl stop ufw + systemctl disable ufw + apt-get install curl jq unzip tar -y # Add node-1 to /etc/hosts echo "192.168.56.10 node-1" >> /etc/hosts # Copy generated certificates cp /vagrant/wazuh-certificates.tar /home/vagrant/wazuh-certificates.tar + # Copy test scripts + cp -r /vagrant/scripts /home/vagrant/scripts + chown -R vagrant:vagrant /home/vagrant/scripts SHELL end end diff --git a/test-tools/scripts/00_run.sh b/test-tools/scripts/00_run.sh new file mode 100644 index 0000000000000..085cd85b9e86c --- /dev/null +++ b/test-tools/scripts/00_run.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +# Prompt the user for GitHub Token and artifact details securely +if [ -z "$GITHUB_TOKEN" ]; then + read -rsp 'Enter GitHub Token: ' GITHUB_TOKEN + echo "" +fi +export GITHUB_TOKEN + +if [ -z "$RUN_ID" ]; then + read -rp 'Enter Action Run ID: ' RUN_ID +fi +export RUN_ID + +if [ -z "$ARTIFACT_NAME" ]; then + read -rp 'Enter Artifact Name: ' ARTIFACT_NAME +fi +export ARTIFACT_NAME + +# Define environment variables with default values if not provided +read -rp "Enter current node name (default: 'node-1'): " NODE_NAME +export NODE_NAME=${NODE_NAME:-"node-1"} + +IP_ADDRESS=$(ip addr show eth1 2>/dev/null | grep 'inet ' | awk '{print $2}' | cut -d/ -f1) +if [ -z "$IP_ADDRESS" ]; then + IP_ADDRESS="127.0.0.1" +fi +read -rp "Enter IP of current node (default: '$IP_ADDRESS'): " NODE_IP +export NODE_IP=${NODE_IP:-$IP_ADDRESS} + +export CERTS_PATH=${CERTS_PATH:-"/home/vagrant/wazuh-certificates.tar"} + +# Optional variables for Node 2 +read -rp 'Enter secondary Node name (optional): ' NODE_2 +read -rp 'Enter IP of secondary Node (optional): ' IP_NODE_2 + +# Logging function with timestamps +log() { + echo "$(date +'%Y-%m-%d %H:%M:%S') - $1" +} + +# Function to run a command and check for errors +run_command() { + local cmd=$1 + log "Executing: $cmd" + if ! eval "$cmd"; then + log "Error executing: $cmd" + exit 1 + else + log "Successfully executed: $cmd" + fi +} + +# Main execution +log "Starting the script execution" + +run_command "bash 01_download_and_install_package.sh -id $RUN_ID -n $ARTIFACT_NAME" + +# Apply certificates +if [ -n "$NODE_2" ] && [ -n "$IP_NODE_2" ]; then + run_command "sudo bash 02_apply_certificates.sh -p $CERTS_PATH -n $NODE_NAME -nip $NODE_IP -s $NODE_2 -sip $IP_NODE_2" +else + run_command "sudo bash 02_apply_certificates.sh -p $CERTS_PATH -n $NODE_NAME -nip $NODE_IP" +fi + +# Start indexer service +run_command "sudo bash 03_manage_indexer_service.sh -a start" + +# Initialize cluster (assumes this step doesn't depend on Node 2 presence) +run_command "sudo bash 04_initialize_cluster.sh" +sleep 10 + +# Validate installed plugins +if [ -n "$NODE_2" ]; then + run_command "bash 05_validate_installed_plugins.sh -n $NODE_NAME -n $NODE_2" +else + run_command "bash 05_validate_installed_plugins.sh -n $NODE_NAME" +fi + +# Validate setup and command manager +run_command "bash 06_validate_setup.sh" +run_command "bash 07_validate_command_manager.sh" + +# Uninstall indexer +log "Running 08_uninstall_indexer.sh" +run_command "sudo bash 08_uninstall_indexer.sh" + +log "All tasks completed successfully." diff --git a/test-tools/scripts/01_download_and_install_package.sh b/test-tools/scripts/01_download_and_install_package.sh new file mode 100644 index 0000000000000..b57f916ddefda --- /dev/null +++ b/test-tools/scripts/01_download_and_install_package.sh @@ -0,0 +1,173 @@ +#!/bin/bash + +# SPDX-License-Identifier: Apache-2.0 +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. + +# Tool dependencies +DEPENDENCIES=(curl jq unzip) +# Default package revision +PKG_REVISION="0" +# Wazuh indexer repository +REPO="wazuh/wazuh-indexer" + +# Function to display usage help +usage() { + echo "Usage: $0 --run-id [-v ] [-r ] [-n ]" + echo + echo "Parameters:" + echo " -id, --run-id The GHA workflow execution ID." + echo " -v, --version (Optional) The version of the wazuh-indexer package." + echo " -r, --revision (Optional) The revision of the package. Defaults to '0' if not provided." + echo " -n, --name (Optional) The package name. If not provided, it will be configured based on version and revision." + echo + echo "Please ensure you have the GITHUB_TOKEN environment variable set to access the GitHub repository, and all the dependencies installed: " "${DEPENDENCIES[@]}" + exit 1 +} + +# Parse named parameters +while [[ "$#" -gt 0 ]]; do + case $1 in + --artifact-id|-id) RUN_ID="$2"; shift ;; + --version|-v) PKG_VERSION="$2"; shift ;; + --revision|-r) PKG_REVISION="$2"; shift ;; + --name|-n) PKG_NAME="$2"; shift ;; + -h|--help) usage ;; + *) echo "Unknown parameter passed: $1"; usage ;; + esac + shift +done + +# Validate all dependencies are installed +for dep in "${DEPENDENCIES[@]}" +do + if ! command -v "${dep}" &> /dev/null + then + echo "Error: Dependency '$dep' is not installed. Please install $dep and try again." >&2 + exit 1 + fi +done + +# Check if RUN_ID is provided +if [ -z "$RUN_ID" ]; then + echo "Error: RUN_ID is required." + usage +fi + +# Validate GITHUB_TOKEN environment variable +if [ -z "$GITHUB_TOKEN" ]; then + echo "Please ensure you have the GITHUB_TOKEN environment variable set to access the GitHub repository." + exit 1 +fi + +# Ensure either PKG_NAME or both PKG_VERSION and PKG_REVISION are provided +if [ -z "$PKG_NAME" ] && { [ -z "$PKG_VERSION" ] || [ -z "$PKG_REVISION" ]; }; then + echo "Error: Either a package name (--name) or both a version (--version) and revision (--revision) must be provided." + usage +fi + +# Detect OS and architecture +if [ -f /etc/os-release ]; then + . /etc/os-release + OS=$(echo "$NAME" | tr '[:upper:]' '[:lower:]') +else + echo "Unsupported OS." + exit 1 +fi + +# Determine package type if PKG_NAME is not provided +ARCH=$(uname -m) +case "$OS" in + *ubuntu* | *debian*) + PKG_FORMAT="deb" + if [ -z "$PKG_NAME" ]; then + [ "$ARCH" == "x86_64" ] && ARCH="amd64" + [ "$ARCH" == "aarch64" ] && ARCH="arm64" + PKG_NAME="wazuh-indexer_${PKG_VERSION}-${PKG_REVISION}_${ARCH}.${PKG_FORMAT}" + fi + ;; + *centos* | *fedora* | *rhel* | *"red hat"* | *alma*) + PKG_FORMAT="rpm" + if [ -z "$PKG_NAME" ]; then + PKG_NAME="wazuh-indexer-${PKG_VERSION}-${PKG_REVISION}.${ARCH}.${PKG_FORMAT}" + fi + ;; + *) + echo "Unsupported OS." + exit 1 + ;; +esac + +# Check if the package is already present +if [ -f "$PKG_NAME" ]; then + echo "Package $PKG_NAME found locally. Reusing existing package." +else + # Fetch the list of artifacts + echo "Fetching artifacts list..." + RUN_URL="https://api.github.com/repos/${REPO}/actions/artifacts" + RESPONSE=$(curl -s -L -H "Accept: application/vnd.github+json" -H "Authorization: Bearer $GITHUB_TOKEN" -H "X-GitHub-Api-Version: 2022-11-28" "$RUN_URL?name=$PKG_NAME") + + # Check if the curl command was successful + if [ $? -ne 0 ]; then + echo "Error: Failed to fetch artifacts." + exit 1 + fi + + # Check if the artifact from the specified workflow run ID exists + echo "Checking ${PKG_NAME} package is generated for workflow run ${RUN_ID}" + ARTIFACT=$(echo "$RESPONSE" | jq -e ".artifacts[] | select(.workflow_run.id == $RUN_ID)") + + if [ -z "$ARTIFACT" ]; then + echo "Error: Wazuh indexer package not found." + exit 1 + fi + + ARTIFACT_ID=$(echo "$ARTIFACT" | jq -r '.id') + echo "Wazuh indexer artifact detected. Artifact ID: $ARTIFACT_ID" + + # Download the package + ARTIFACT_URL="https://api.github.com/repos/${REPO}/actions/artifacts/${ARTIFACT_ID}/zip" + echo "Downloading wazuh-indexer package from GitHub artifactory..." + echo "(It could take a couple of minutes)" + + if ! curl -L -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "$ARTIFACT_URL" -o package.zip > /dev/null 2>&1; then + echo "Error downloading package." + exit 1 + fi + echo "Package downloaded successfully" + + # Unzip the package + echo "Decompressing wazuh-indexer package..." + unzip ./package.zip + rm package.zip + + # shellcheck disable=SC2181 + if [ $? -ne 0 ]; then + echo "Error unzipping package." + exit 1 + fi + echo "Package decompressed" +fi + +# Install the package +echo "Installing wazuh-indexer package..." +case "$PKG_FORMAT" in + "deb") + sudo dpkg -i "$PKG_NAME" > /dev/null 2>&1 + ;; + "rpm") + sudo rpm -i "$PKG_NAME" > /dev/null 2>&1 + ;; +esac + +# shellcheck disable=SC2181 +if [ $? -ne 0 ]; then + echo "Error installing package." + exit 1 +fi + +echo "Package installed successfully." diff --git a/test-tools/scripts/02_apply_certificates.sh b/test-tools/scripts/02_apply_certificates.sh new file mode 100644 index 0000000000000..c754eebf4b10e --- /dev/null +++ b/test-tools/scripts/02_apply_certificates.sh @@ -0,0 +1,117 @@ +#!/bin/bash + +# SPDX-License-Identifier: Apache-2.0 +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. + +# Tool dependencies +DEPENDENCIES=(tar) + +# Function to display usage help +usage() { + echo "Usage: $0 --path-to-certs --current-node [--second-node ] [--current-node-ip ] [--second-node-ip ]" + echo + echo "Parameters:" + echo " -p, --path-to-certs Path to the generated Wazuh certificates tar" + echo " -n, --current-node Name of the current node" + echo " -s, --second-node (Optional) Name of the second node" + echo " -nip, --current-node-ip (Optional) IP address of the current node. Default: CURRENT_NODE" + echo " -sip, --second-node-ip (Optional) IP address of the second node. Default: SECOND_NODE" + echo + echo "Please ensure you have all the dependencies installed: " "${DEPENDENCIES[@]}" + exit 1 +} + +# Parse named arguments +while [[ "$#" -gt 0 ]]; do + case $1 in + --path-to-certs|-p) PATH_TO_CERTS="$2"; shift ;; + --current-node|-n) CURRENT_NODE="$2"; shift ;; + --second-node|-s) SECOND_NODE="$2"; shift ;; + --current-node-ip|-nip) CURRENT_NODE_IP="$2"; shift ;; + --second-node-ip|-sip) SECOND_NODE_IP="$2"; shift ;; + -h|--help) usage ;; + *) echo "Unknown parameter passed: $1"; usage ;; + esac + shift +done + +# Validate all dependencies are installed +for dep in "${DEPENDENCIES[@]}" +do + if ! command -v ${dep} &> /dev/null + then + echo "Error: Dependency '$dep' is not installed. Please install $dep and try again." >&2 + exit 1 + fi +done + +# Validate mandatory arguments +if [ -z "$PATH_TO_CERTS" ] || [ -z "$CURRENT_NODE" ]; then + echo "Error: Missing mandatory parameter." + usage +fi + +# Set default values if optional arguments are not provided +CURRENT_NODE_IP=${CURRENT_NODE_IP:-$CURRENT_NODE} +SECOND_NODE_IP=${SECOND_NODE_IP:-$SECOND_NODE} +CONFIG_FILE="/etc/wazuh-indexer/opensearch.yml" +BACKUP_FILE="./opensearch.yml.bak" + +# Backup the original config file +echo "Creating a backup of the original config file..." +cp $CONFIG_FILE $BACKUP_FILE + +# Replace values in the config file +echo "Updating configuration..." +sed -i "s/node\.name: \"node-1\"/node.name: \"${CURRENT_NODE}\"/" $CONFIG_FILE + +if [ -n "$SECOND_NODE" ]; then + sed -i "s/#discovery\.seed_hosts:/discovery.seed_hosts:\n - \"${CURRENT_NODE_IP}\"\n - \"${SECOND_NODE_IP}\"/" $CONFIG_FILE + sed -i "/cluster\.initial_master_nodes:/!b;n;c- ${CURRENT_NODE}\n- ${SECOND_NODE}" $CONFIG_FILE + sed -i ':a;N;$!ba;s/plugins\.security\.nodes_dn:\n- "CN=node-1,OU=Wazuh,O=Wazuh,L=California,C=US"/plugins.security.nodes_dn:\n- "CN='"${CURRENT_NODE}"',OU=Wazuh,O=Wazuh,L=California,C=US"\n- "CN='"${SECOND_NODE}"',OU=Wazuh,O=Wazuh,L=California,C=US"/' $CONFIG_FILE +else + sed -i "s/#discovery\.seed_hosts:/discovery.seed_hosts:\n - \"${CURRENT_NODE_IP}\"/" $CONFIG_FILE + sed -i "/cluster\.initial_master_nodes:/!b;n;c- ${CURRENT_NODE}" $CONFIG_FILE + sed -i ':a;N;$!ba;s/plugins\.security\.nodes_dn:\n- "CN=node-1,OU=Wazuh,O=Wazuh,L=California,C=US"/plugins.security.nodes_dn:\n- "CN='"${CURRENT_NODE}"',OU=Wazuh,O=Wazuh,L=California,C=US"/' $CONFIG_FILE +fi + +# shellcheck disable=SC2181 +if [ $? -eq 0 ]; then + echo "Configuration updated successfully. Backup created at ${BACKUP_FILE}" +else + echo "Error updating configuration." + exit 1 +fi + +# Directory for certificates +CERT_DIR="/etc/wazuh-indexer/certs" +if [ -d "$CERT_DIR" ]; then + echo "Certificates directory already exists. Removing it..." + rm -rf +fi +# Extract certificates +echo "Creating certificates directory and extracting certificates..." +mkdir -p $CERT_DIR + +if ! tar -xf "$PATH_TO_CERTS" -C "$CERT_DIR" "./$CURRENT_NODE.pem" "./$CURRENT_NODE-key.pem" "./admin.pem" "./admin-key.pem" "./root-ca.pem" ; then + echo "Error extracting certificates." + exit 1 +fi + +# Move and set permissions for certificates +echo "Moving and setting permissions for certificates..." +mv -n "$CERT_DIR/$CURRENT_NODE.pem" "$CERT_DIR/indexer.pem" +mv -n "$CERT_DIR/$CURRENT_NODE-key.pem" "$CERT_DIR/indexer-key.pem" +chmod 500 "$CERT_DIR" +chmod 400 "$CERT_DIR"/* +chown -R wazuh-indexer:wazuh-indexer "$CERT_DIR" + +# shellcheck disable=SC2181 +if [ $? -eq 0 ]; then + echo "Certificates configured successfully." +else + echo "Error configuring certificates." + exit 1 +fi diff --git a/test-tools/scripts/03_manage_indexer_service.sh b/test-tools/scripts/03_manage_indexer_service.sh new file mode 100644 index 0000000000000..d9100b270c2b1 --- /dev/null +++ b/test-tools/scripts/03_manage_indexer_service.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +# SPDX-License-Identifier: Apache-2.0 +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. + +# Function to check the status of the wazuh-indexer service +check_service_is_running() { + if systemctl is-active --quiet wazuh-indexer ; then + echo "wazuh-indexer service is running." + else + echo "Error: wazuh-indexer service is not running." >&2 + exit 1 + fi +} + +# Function to display usage help +usage() { + echo "Usage: $0 --action " + echo + echo "This script manages the wazuh-indexer service." + echo + echo "Options:" + echo " -a, --action Specify the action to perform: start, stop, or restart." + echo " -h, --help Show this help message and exit." + echo + exit 1 +} + +# Parse named arguments +while [[ "$#" -gt 0 ]]; do + case $1 in + --action|-a) ACTION="$2"; shift ;; + -h|--help) usage ;; + *) echo "Unknown parameter passed: $1"; usage ;; + esac + shift +done + +# Check if ACTION is provided +if [ -z "$ACTION" ]; then + echo "Error: Action is required." + usage +fi + +# Execute the action +case $ACTION in + start) + echo "Starting wazuh-indexer service..." + systemctl daemon-reload > /dev/null 2>&1 + systemctl enable wazuh-indexer > /dev/null 2>&1 + systemctl start wazuh-indexer > /dev/null 2>&1 + check_service_is_running + ;; + stop) + echo "Stopping wazuh-indexer service..." + systemctl stop wazuh-indexer + systemctl is-active --quiet wazuh-indexer + if [ $? -ne 0 ]; then + echo "wazuh-indexer service stopped successfully." + else + echo "Error: Failed to stop wazuh-indexer service." >&2 + exit 1 + fi + ;; + restart) + echo "Restarting wazuh-indexer service..." + systemctl restart wazuh-indexer + check_service_is_running + ;; + *) + echo "Error: Invalid action specified. Use start, stop, or restart." + usage + ;; +esac diff --git a/test-tools/scripts/04_initialize_cluster.sh b/test-tools/scripts/04_initialize_cluster.sh new file mode 100644 index 0000000000000..a7121b7c09d94 --- /dev/null +++ b/test-tools/scripts/04_initialize_cluster.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +# SPDX-License-Identifier: Apache-2.0 +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. + +# Tool dependencies +DEPENDENCIES=(curl jq) + +# Function to display usage help +usage() { + echo "Usage: $0 [-ip ] [-u ] [-p ]" + echo + echo "Parameters:" + echo " -ip, --cluster-ip (Optional) IP address of the cluster. Default: localhost" + echo " -u, --user (Optional) Username for authentication. Default: admin" + echo " -p, --password (Optional) Password for authentication. Default: admin" + echo + echo "Please ensure you have all the dependencies installed: " "${DEPENDENCIES[@]}" + exit 1 +} + +# Validate all dependencies are installed +for dep in "${DEPENDENCIES[@]}" +do + if ! command -v "${dep}" &> /dev/null + then + echo "Error: Dependency '$dep' is not installed. Please install $dep and try again." >&2 + exit 1 + fi +done + +# Default values +CLUSTER_IP="localhost" +USER="admin" +PASSWORD="admin" + +# Parse named arguments +while [[ "$#" -gt 0 ]]; do + case $1 in + -ip|--cluster-ip) CLUSTER_IP="$2"; shift ;; + -u|--user) USER="$2"; shift ;; + -p|--password) PASSWORD="$2"; shift ;; + -h|--help) usage ;; + *) echo "Unknown parameter passed: $1"; usage ;; + esac + shift +done + +# Initialize cluster +echo "Initializing wazuh-indexer cluster..." +bash /usr/share/wazuh-indexer/bin/indexer-security-init.sh > /dev/null 2>&1 + +# Check if the initialization was successful +# shellcheck disable=SC2181 +if [ $? -ne 0 ]; then + echo "Error: Failed to initialize cluster." + exit 1 +fi + +# Check the Wazuh indexer status +echo "Checking cluster status..." +sleep 2 +RESPONSE=$(curl -s -k -u "$USER:$PASSWORD" "https://$CLUSTER_IP:9200") + +# Check if the request was successful +# shellcheck disable=SC2181 +if [ $? -ne 0 ]; then + echo "Error: Failed to connect to cluster." + exit 1 +fi + +# Parse and print the response +INDEXER_NAME=$(echo "$RESPONSE" | jq -r '.name') +CLUSTER_NAME=$(echo "$RESPONSE" | jq -r '.cluster_name') +VERSION_NUMBER=$(echo "$RESPONSE" | jq -r '.version.number') +echo "Indexer Status:" +echo " Node Name: $INDEXER_NAME" +echo " Cluster Name: $CLUSTER_NAME" +echo " Version Number: $VERSION_NUMBER" + +# Verify the Wazuh indexer nodes +echo "Verifying the Wazuh indexer nodes..." +NODES_RESPONSE=$(curl -s -k -u "$USER:$PASSWORD" "https://$CLUSTER_IP:9200/_cat/nodes?v") + +# shellcheck disable=SC2181 +if [ $? -ne 0 ]; then + echo "Error: Failed to retrieve Wazuh indexer nodes." + exit 1 +fi + +echo "Nodes:" +echo "$NODES_RESPONSE" +echo "Initialization completed successfully." diff --git a/test-tools/scripts/05_validate_installed_plugins.sh b/test-tools/scripts/05_validate_installed_plugins.sh new file mode 100644 index 0000000000000..2801598394f25 --- /dev/null +++ b/test-tools/scripts/05_validate_installed_plugins.sh @@ -0,0 +1,95 @@ +#!/bin/bash +# SPDX-License-Identifier: Apache-2.0 +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. + +# Tool dependencies +DEPENDENCIES=(curl jq) + +# Function to display usage help +usage() { + echo "Usage: $0 [-ip -u -p ] -n -n [...]" + echo + echo "Parameters:" + echo " -ip, --cluster-ip (Optional) IP address of the cluster (default: localhost)" + echo " -u, --user (Optional) Username for authentication (default: admin)" + echo " -p, --password (Optional) Password for authentication (default: admin)" + echo " -n, --node Name of the nodes (add as many as needed)" + echo + echo "Please ensure you have all the dependencies installed: " "${DEPENDENCIES[@]}" + exit 1 +} + +# Validate all dependencies are installed +for dep in "${DEPENDENCIES[@]}" +do + if ! command -v "${dep}" &> /dev/null + then + echo "Error: Dependency '$dep' is not installed. Please install $dep and try again." >&2 + exit 1 + fi +done + +# Default values +CLUSTER_IP="localhost" +USER="admin" +PASSWORD="admin" +NODES=() + +# Parse named arguments +while [[ "$#" -gt 0 ]]; do + case $1 in + -ip|--cluster-ip) CLUSTER_IP="$2"; shift ;; + -u|--user) USER="$2"; shift ;; + -p|--password) PASSWORD="$2"; shift ;; + -n|--node) NODES+=("$2"); shift ;; + -h|--help) usage ;; + *) echo "Unknown parameter passed: $1"; usage ;; + esac + shift +done + +# Check if mandatory arguments are provided +if [ -z "$CLUSTER_IP" ] || [ -z "$USER" ] || [ -z "$PASSWORD" ] || [ ${#NODES[@]} -eq 0 ]; then + echo "Error: Missing mandatory parameter." + usage +fi + +# Check the installed plugins on each node +REQUIRED_PLUGINS=("wazuh-indexer-command-manager" "wazuh-indexer-setup") +ALL_MISSING_PLUGINS=() + +echo "Checking installed plugins on Wazuh indexer nodes..." +for NODE in "${NODES[@]}"; do + echo "Checking node $NODE..." + RESPONSE=$(curl -s -k -u "$USER:$PASSWORD" "https://$CLUSTER_IP:9200/_cat/plugins?v" | grep "$NODE") + # Check if the request was successful + # shellcheck disable=SC2181 + if [ $? -ne 0 ]; then + echo "Error: Failed to connect to Wazuh indexer." + exit 1 + fi + MISSING_PLUGINS=() + for PLUGIN in "${REQUIRED_PLUGINS[@]}"; do + if echo "$RESPONSE" | grep -q "$PLUGIN"; then + echo " $PLUGIN is installed on $NODE." + else + MISSING_PLUGINS+=("$PLUGIN") + fi + done + if [ ${#MISSING_PLUGINS[@]} -ne 0 ]; then + echo "Error: The following required plugins are missing on $NODE:" + for PLUGIN in "${MISSING_PLUGINS[@]}"; do + echo " $PLUGIN" + done + ALL_MISSING_PLUGINS+=("${MISSING_PLUGINS[@]}") + fi +done + +if [ ${#ALL_MISSING_PLUGINS[@]} -ne 0 ]; then + echo "Error: Some nodes are missing required plugins." + exit 1 +fi + +echo "All required plugins are installed on all nodes." diff --git a/test-tools/scripts/06_validate_setup.sh b/test-tools/scripts/06_validate_setup.sh new file mode 100644 index 0000000000000..dc9e90688f180 --- /dev/null +++ b/test-tools/scripts/06_validate_setup.sh @@ -0,0 +1,153 @@ +#!/bin/bash + +# SPDX-License-Identifier: Apache-2.0 +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. + +# Tool dependencies +DEPENDENCIES=(curl jq) + +# Function to display usage help +usage() { + echo "Usage: $0 [-ip ] [-u ] [-p ]" + echo + echo "Parameters:" + echo " -ip, --cluster-ip (Optional) IP address of the cluster. Default: localhost" + echo " -u, --user (Optional) Username for authentication. Default: admin" + echo " -p, --password (Optional) Password for authentication. Default: admin" + echo + echo "Please ensure you have all the dependencies installed: " "${DEPENDENCIES[@]}" + exit 1 +} + +# Validate all dependencies are installed +for dep in "${DEPENDENCIES[@]}" +do + if ! command -v "${dep}" &> /dev/null + then + echo "Error: Dependency '$dep' is not installed. Please install $dep and try again." >&2 + exit 1 + fi +done + +# Default values +CLUSTER_IP="localhost" +USER="admin" +PASSWORD="admin" + +# Parse named arguments +while [[ "$#" -gt 0 ]]; do + case $1 in + -ip|--cluster-ip) CLUSTER_IP="$2"; shift ;; + -u|--user) USER="$2"; shift ;; + -p|--password) PASSWORD="$2"; shift ;; + -h|--help) usage ;; + *) echo "Unknown parameter passed: $1"; usage ;; + esac + shift +done + +# List of expected items +EXPECTED_TEMPLATES=("index-template-agent" "index-template-alerts" "index-template-fim" "index-template-packages" + "index-template-processes" "index-template-system" "index-template-vulnerabilities") + +# Fetch the templates +echo "Fetching templates from Wazuh indexer cluster..." +TEMPLATES_RESPONSE=$(curl -s -k -u "$USER:$PASSWORD" "https://$CLUSTER_IP:9200/_cat/templates?v") +# Check if the request was successful +if [ $? -ne 0 ]; then + echo "Error: Failed to fetch templates." + exit 1 +fi + +# Validate the templates +MISSING_TEMPLATES=() +echo "Validating templates..." +for TEMPLATE in "${EXPECTED_TEMPLATES[@]}"; do + if echo "$TEMPLATES_RESPONSE" | grep -q "$TEMPLATE"; then + # Fetch the template info to check for required fields + TEMPLATE_INFO=$(curl -s -k -u "$USER:$PASSWORD" "https://$CLUSTER_IP:9200/_template/$TEMPLATE") + if ! echo "$TEMPLATE_INFO" | jq -e '.[] | .mappings.properties.agent.properties.id' > /dev/null; then + echo " Error: Template $TEMPLATE is missing required field 'agent.id'." + MISSING_TEMPLATES+=("$TEMPLATE") + elif ! echo "$TEMPLATE_INFO" | jq -e '.[] | .mappings.properties.agent.properties.groups' > /dev/null; then + echo " Error: Template $TEMPLATE is missing required field 'agent.groups'." + MISSING_TEMPLATES+=("$TEMPLATE") + else + echo " Template $TEMPLATE is created correctly." + fi + else + MISSING_TEMPLATES+=("$TEMPLATE") + echo " Error: Template $TEMPLATE is missing." + fi +done + +if [ ${#MISSING_TEMPLATES[@]} -ne 0 ]; then + echo "Some templates were not created correctly:" + for TEMPLATE in "${MISSING_TEMPLATES[@]}"; do + echo " $TEMPLATE" + done + echo +else + echo "All templates are correctly created." + echo +fi + +# Fetch the indices +echo "Fetching indices from Wazuh indexer cluster..." +INDICES_RESPONSE=$(curl -s -k -u "$USER:$PASSWORD" "https://$CLUSTER_IP:9200/_cat/indices?v") +# Check if the request was successful +# shellcheck disable=SC2181 +if [ $? -ne 0 ]; then + echo "Error: Failed to fetch indices." + exit 1 +fi + +# Fetch the protected indices +echo "Fetching protected indices from Wazuh indexer cluster..." +PROTECTED_RESPONSE=$(curl -s -k -u "$USER:$PASSWORD" "https://$CLUSTER_IP:9200/_cat/indices/.*?v") +# Check if the request was successful +# shellcheck disable=SC2181 +if [ $? -ne 0 ]; then + echo "Error: Failed to fetch indices." + exit 1 +fi + +# Validate index patterns +echo "Validating index patterns..." +INVALID_PATTERNS=() +while read -r line; do + TEMPLATE_NAME=$(echo "$line" | awk '{print $1}') + INDEX_PATTERN=$(echo "$line" | awk '{print $2}' | tr -d '[]') + + if [[ $INDEX_PATTERN == .* ]]; then + TO_MATCH=$PROTECTED_RESPONSE + else + TO_MATCH=$INDICES_RESPONSE + fi + + # Check if index pattern ends with '*' + if [[ $INDEX_PATTERN != *\* ]]; then + echo " Error: Index pattern $INDEX_PATTERN does not end with '*'." + INVALID_PATTERNS+=("$INDEX_PATTERN") + continue + fi + + if echo "$TO_MATCH" | grep -q "$INDEX_PATTERN"; then + echo " Index pattern $INDEX_PATTERN is valid." + else + INVALID_PATTERNS+=("$INDEX_PATTERN") + echo " Error: Index pattern $INDEX_PATTERN not found in indices for template $TEMPLATE_NAME." + fi +done <<< "$(echo "$TEMPLATES_RESPONSE" | tail -n +2)" # Skip header line + +if [ ${#INVALID_PATTERNS[@]} -ne 0 ]; then + echo "Errors on index-patterns detected:" + for PATTERN in "${INVALID_PATTERNS[@]}"; do + echo " $PATTERN" + done + echo +else + echo "Index-patterns validated successfully." +fi diff --git a/test-tools/scripts/07_validate_command_manager.sh b/test-tools/scripts/07_validate_command_manager.sh new file mode 100644 index 0000000000000..e96209bd4c8f6 --- /dev/null +++ b/test-tools/scripts/07_validate_command_manager.sh @@ -0,0 +1,115 @@ +#!/bin/bash + +# SPDX-License-Identifier: Apache-2.0 +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. + +# Tool dependencies +DEPENDENCIES=(curl jq) + +# Function to display usage help +usage() { + echo "Usage: $0 [-ip ] [-u ] [-p ]" + echo + echo "Parameters:" + echo " -ip, --cluster-ip (Optional) IP address of the cluster. Default: localhost" + echo " -u, --user (Optional) Username for authentication. Default: admin" + echo " -p, --password (Optional) Password for authentication. Default: admin" + echo + echo "Please ensure you have all the dependencies installed: " "${DEPENDENCIES[@]}" + exit 1 +} + +# Validate all dependencies are installed +for dep in "${DEPENDENCIES[@]}" +do + if ! command -v "${dep}" &> /dev/null + then + echo "Error: Dependency '$dep' is not installed. Please install $dep and try again." >&2 + exit 1 + fi +done + +# Default values +CLUSTER_IP="localhost" +USERNAME="admin" +PASSWORD="admin" + +# Parse named arguments +while [[ "$#" -gt 0 ]]; do + case $1 in + -ip|--cluster-ip) CLUSTER_IP="$2"; shift ;; + -u|--user) USERNAME="$2"; shift ;; + -p|--password) PASSWORD="$2"; shift ;; + -h|--help) usage ;; + *) echo "Unknown parameter passed: $1"; usage ;; + esac + shift +done + +COMMANDS_INDEX=".commands" +SRC="Engine" +USR="TestUser" +TRG_ID="TestTarget" +ARG="/test/path/fake/args" +BODY="{ + \"source\": \"$SRC\", + \"user\": \"$USR\", + \"target\": { + \"id\": \"$TRG_ID\", + \"type\": \"agent\" + }, + \"action\": { + \"name\": \"restart\", + \"args\": [ + \"$ARG\" + ], + \"version\": \"v4\" + }, + \"timeout\": 30 +}" + +# Send the POST request and check it is successful +if ! curl -s -k -u "$USERNAME:$PASSWORD" -X POST "https://$CLUSTER_IP:9200/_plugins/_command_manager/commands" -H 'accept: */*' -H 'Content-Type: application/json' -d "$BODY" > /dev/null 2>&1; then + echo "Error: Failed to create command." + exit 1 +fi +echo "Command created successfully." +# Sleep to avoid the next request to be sent before index is created +curl -s -k -u "$USERNAME:$PASSWORD" -X POST "https://$CLUSTER_IP:9200/_forcemerge" -H 'accept: */*' +sleep 2 + +# Fetch the indices +echo "Validating .commands index is created..." +INDICES_RESPONSE=$(curl -s -k -u "$USERNAME:$PASSWORD" "https://$CLUSTER_IP:9200/_cat/indices/.*?v") +# shellcheck disable=SC2181 +if [ $? -ne 0 ]; then + echo "Error: Failed to fetch indices." + exit 1 +fi +if echo "$INDICES_RESPONSE" | grep -q "$COMMANDS_INDEX"; then + echo "Index created correctly." +else + echo "Error: Index is not created." + exit 1 +fi + +sleep 5 +echo "Validate the command is created" +# Validate the command was created +SEARCH_RESPONSE=$(curl -s -k -u "$USERNAME:$PASSWORD" "https://$CLUSTER_IP:9200/.commands/_search") +# Check if the request was successful +# shellcheck disable=SC2181 +if [ $? -ne 0 ]; then + echo "Error: Failed to search for the command." + exit 1 +fi + +# Check if the command is found in the search results +if echo "$SEARCH_RESPONSE" | grep -q "\"$USR\"" && echo "$SEARCH_RESPONSE" | grep -q "\"$TRG_ID\""; then + echo "Validation successful: The command was created and found in the search results." +else + echo "Error: The command was not found in the search results." + exit 1 +fi diff --git a/test-tools/scripts/08_uninstall_indexer.sh b/test-tools/scripts/08_uninstall_indexer.sh new file mode 100644 index 0000000000000..094c7ca8781b1 --- /dev/null +++ b/test-tools/scripts/08_uninstall_indexer.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +# SPDX-License-Identifier: Apache-2.0 +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. + +# Function to display usage help +usage() { + echo "Usage: $0 [-h]" + echo + echo "This script uninstalls Wazuh Indexer and validates its removal." + echo + echo "Options:" + echo " -h, --help Show this help message and exit." + echo + exit 1 +} + +# Check for help flag +if [[ "$1" == "-h" || "$1" == "--help" ]]; then + usage +fi + +# Detect package manager +if command -v apt-get &> /dev/null; then + PKG_MANAGER="apt-get" +elif command -v yum &> /dev/null; then + PKG_MANAGER="yum" +else + echo "Unsupported package manager. Please use a system with apt-get or yum." + exit 1 +fi + +# Uninstall Wazuh Indexer +echo "Uninstalling Wazuh Indexer..." +sudo systemctl stop wazuh-indexer > /dev/null 2>&1 +sudo systemctl disable wazuh-indexer > /dev/null 2>&1 + +if [ "$PKG_MANAGER" == "apt-get" ]; then + sudo apt-get remove --purge wazuh-indexer -y > /dev/null 2>&1 +elif [ "$PKG_MANAGER" == "yum" ]; then + sudo yum remove wazuh-indexer -y > /dev/null 2>&1 +fi +rm -rf /etc/wazuh-indexer + +# Validate removal +echo "Validating Wazuh Indexer removal..." + +# Check for remaining files and directories +if [ "$PKG_MANAGER" == "apt-get" ]; then + if dpkg -l | grep wazuh-indexer > /dev/null 2>&1; then + echo "Error: Wazuh Indexer packages still present." + exit 1 + else + echo "Wazuh Indexer packages removed." + fi +elif [ "$PKG_MANAGER" == "yum" ]; then + if rpm -qa | grep wazuh-indexer > /dev/null 2>&1; then + echo "Error: Wazuh Indexer packages still present." + exit 1 + else + echo "Wazuh Indexer packages removed." + fi +fi + +# Check for remaining services +if systemctl list-units --full -all | grep wazuh-indexer.service > /dev/null 2>&1; then + echo "Error: Wazuh Indexer service still present." + exit 1 +else + echo "Wazuh Indexer service removed." +fi + +echo "Wazuh Indexer uninstallation and validation completed successfully." diff --git a/test-tools/scripts/README.md b/test-tools/scripts/README.md new file mode 100644 index 0000000000000..06d84a44f50d5 --- /dev/null +++ b/test-tools/scripts/README.md @@ -0,0 +1,79 @@ +# Test utils scripts + +This is a collection of scripts aimed to facilitate the validation of the wazuh-indexer packages generated on the GitHub Action Workflow. + +Even if these scripts can be executed in almost any Linux environment, we expect it to be used alongside the +Vagrant environment defined in the `test-tools`, using the scripts inside the VMs to facilitate the validation steps. + +### GitHub token requirements + +Create a personal access token for GitHub with at least `read:packages` permissions. + +## Validation flow + +The scripts can be used to prepare and validate a single node or multi-node cluster, as required. + +### All-at-once + +#### Single node + +Use the `00_run.sh` utility to execute all the scripts automatically +```bash +sudo bash 00_run.sh +``` + +#### Multi node cluster + +> This section assumes you are using the `node-1` and `node-2` Vagrant VMs + +1. On the `node-2` VM install and prepare the `wazuh-indexer` component + ```bash + GITHUB_TOKEN= bash 01_download_and_install_package.sh -id -n + ``` + ```bash + sudo bash 02_apply_certificates.sh -p ../wazuh-certificates.tar -n node-2 -nip 192.168.56.11 -s node-1 -sip 192.168.56.10 + ``` + ```bash + sudo bash 03_manage_indexer_service.sh -a start + ``` +2. On the `node-1` VM execute the _all-at-once_ utility + ```bash + sudo bash 00_run.sh + ``` + +### Manual execution + +If you prefer, you can run each script individually. + +1. Download and install the `wazuh-indexer` package _(mandatory on each node)_ + ```bash + GITHUB_TOKEN= bash 01_download_and_install_package.sh -id -n + ``` +2. Configure and start the service _(mandatory on each node)_ + ```bash + sudo bash 02_apply_certificates.sh -p -n -nip + ``` + ```bash + sudo bash 03_manage_indexer_service.sh -a start + ``` + > With this script you can also `restart` and `stop` the service +3. Initialize the cluster + ```bash + sudo bash 04_initialize_cluster.sh + ``` +4. Check all the plugins are installed + ```bash + bash 05_validate_installed_plugins.sh -n + ``` +5. Check the setup plugin configured the index-patterns correctly + ```bash + bash 06_validate_setup.sh + ``` +6. Check the command manager plugin works correctly + ```bash + bash 07_validate_command_manager.sh + ``` +7. Uninstall Wazuh indexer + ```bash + sudo bash 08_uninstall_indexer.sh + ```