#!/bin/bash # redis-setup.sh - Redis Database and User Setup for PatchMon # This script creates a dedicated Redis database and user for a PatchMon instance set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Default Redis connection details REDIS_HOST=${REDIS_HOST:-"localhost"} REDIS_PORT=${REDIS_PORT:-6379} REDIS_ADMIN_PASSWORD=${REDIS_ADMIN_PASSWORD:-"redispass1"} echo -e "${BLUE}๐Ÿ”ง PatchMon Redis Setup${NC}" echo "==================================" # Function to generate random strings generate_random_string() { local length=${1:-16} openssl rand -base64 $length | tr -d "=+/" | cut -c1-$length } # Function to check if Redis is accessible check_redis_connection() { echo -e "${YELLOW}๐Ÿ“ก Checking Redis connection...${NC}" if [ -n "$REDIS_ADMIN_PASSWORD" ]; then # With password if redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -a "$REDIS_ADMIN_PASSWORD" --no-auth-warning ping > /dev/null 2>&1; then echo -e "${GREEN}โœ… Redis connection successful${NC}" return 0 else echo -e "${RED}โŒ Cannot connect to Redis with password${NC}" echo "Please ensure Redis is running and the admin password is correct" return 1 fi else # Without password if redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" ping > /dev/null 2>&1; then echo -e "${GREEN}โœ… Redis connection successful${NC}" return 0 else echo -e "${RED}โŒ Cannot connect to Redis${NC}" echo "Please ensure Redis is running" return 1 fi fi } # Function to find next available database number find_next_db() { echo -e "${YELLOW}๐Ÿ” Finding next available database...${NC}" >&2 # Start from database 0 and keep checking until we find an empty one local db_num=0 local max_attempts=100 # Safety limit to prevent infinite loop while [ $db_num -lt $max_attempts ]; do # Test if database is empty local key_count local redis_output if [ -n "$REDIS_ADMIN_PASSWORD" ]; then # With password redis_output=$(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -a "$REDIS_ADMIN_PASSWORD" --no-auth-warning -n "$db_num" DBSIZE 2>&1) else # Without password redis_output=$(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -n "$db_num" DBSIZE 2>&1) fi # Check for authentication errors if echo "$redis_output" | grep -q "NOAUTH"; then echo -e "${RED}โŒ Authentication required but REDIS_ADMIN_PASSWORD not set${NC}" >&2 echo -e "${YELLOW}๐Ÿ’ก Please set REDIS_ADMIN_PASSWORD environment variable:${NC}" >&2 echo -e "${YELLOW} export REDIS_ADMIN_PASSWORD='your_password'${NC}" >&2 echo -e "${YELLOW} Or run: REDIS_ADMIN_PASSWORD='your_password' ./setup-redis.sh${NC}" >&2 exit 1 fi # Check for other errors if echo "$redis_output" | grep -q "ERR"; then if echo "$redis_output" | grep -q "invalid DB index"; then echo -e "${RED}โŒ Reached maximum database limit at database $db_num${NC}" >&2 echo -e "${YELLOW}๐Ÿ’ก Redis is configured with $db_num databases maximum.${NC}" >&2 echo -e "${YELLOW}๐Ÿ’ก Increase 'databases' setting in redis.conf or clean up unused databases.${NC}" >&2 exit 1 else echo -e "${RED}โŒ Error checking database $db_num: $redis_output${NC}" >&2 exit 1 fi fi key_count="$redis_output" # If database is empty, use it if [ "$key_count" = "0" ]; then echo -e "${GREEN}โœ… Found available database: $db_num (empty)${NC}" >&2 echo "$db_num" return fi echo -e "${BLUE} Database $db_num has $key_count keys, checking next...${NC}" >&2 db_num=$((db_num + 1)) done echo -e "${RED}โŒ No available databases found (checked 0-$max_attempts)${NC}" >&2 echo -e "${YELLOW}๐Ÿ’ก All checked databases are in use. Consider cleaning up unused databases.${NC}" >&2 exit 1 } # Function to create Redis user create_redis_user() { local username="$1" local password="$2" local db_num="$3" echo -e "${YELLOW}๐Ÿ‘ค Creating Redis user: $username for database $db_num${NC}" # Create user with password and permissions # Note: >password syntax is for Redis ACL, we need to properly escape it if [ -n "$REDIS_ADMIN_PASSWORD" ]; then # With password redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -a "$REDIS_ADMIN_PASSWORD" --no-auth-warning ACL SETUSER "$username" on ">${password}" ~* +@all > /dev/null else # Without password redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" ACL SETUSER "$username" on ">${password}" ~* +@all > /dev/null fi if [ $? -eq 0 ]; then echo -e "${GREEN}โœ… Redis user '$username' created successfully for database $db_num${NC}" return 0 else echo -e "${RED}โŒ Failed to create Redis user${NC}" return 1 fi } # Function to test user connection test_user_connection() { local username="$1" local password="$2" local db_num="$3" echo -e "${YELLOW}๐Ÿงช Testing user connection...${NC}" if redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" --user "$username" --pass "$password" --no-auth-warning -n "$db_num" ping > /dev/null 2>&1; then echo -e "${GREEN}โœ… User connection test successful${NC}" return 0 else echo -e "${RED}โŒ User connection test failed${NC}" return 1 fi } # Function to mark database as in-use mark_database_in_use() { local db_num="$1" echo -e "${YELLOW}๐Ÿ“ Marking database as in-use...${NC}" if [ -n "$REDIS_ADMIN_PASSWORD" ]; then redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -a "$REDIS_ADMIN_PASSWORD" --no-auth-warning -n "$db_num" SET "patchmon:initialized" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > /dev/null else redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -n "$db_num" SET "patchmon:initialized" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > /dev/null fi if [ $? -eq 0 ]; then echo -e "${GREEN}โœ… Database marked as in-use${NC}" return 0 else echo -e "${RED}โŒ Failed to mark database${NC}" return 1 fi } # Main execution main() { # Check Redis connection if ! check_redis_connection; then exit 1 fi # Generate random credentials USERNAME="patchmon_$(generate_random_string 8)" PASSWORD=$(generate_random_string 32) DB_NUM=$(find_next_db) echo "" echo -e "${BLUE}๐Ÿ“‹ Generated Configuration:${NC}" echo "Username: $USERNAME" echo "Password: $PASSWORD" echo "Database: $DB_NUM" echo "" # Create Redis user if ! create_redis_user "$USERNAME" "$PASSWORD" "$DB_NUM"; then exit 1 fi # Test user connection if ! test_user_connection "$USERNAME" "$PASSWORD" "$DB_NUM"; then exit 1 fi # Mark database as in-use to prevent reuse on next run if ! mark_database_in_use "$DB_NUM"; then exit 1 fi # Output .env configuration echo "" echo -e "${GREEN}๐ŸŽ‰ Redis setup completed successfully!${NC}" echo "" echo -e "${BLUE}๐Ÿ“„ Add these lines to your .env file:${NC}" echo "==================================" echo "REDIS_HOST=$REDIS_HOST" echo "REDIS_PORT=$REDIS_PORT" echo "REDIS_USER=$USERNAME" echo "REDIS_PASSWORD=$PASSWORD" echo "REDIS_DB=$DB_NUM" echo "==================================" echo "" echo -e "${YELLOW}๐Ÿ’ก Copy the configuration above to your .env file${NC}" } # Run main function main "$@"