Files
VPS_Management/vps_management.sh
T
2026-08-04 22:43:35 +01:00

533 lines
17 KiB
Bash
Executable File

#!/bin/bash
################################################################################
# Multi-Hosting Provider Management Script
# Supports: Hetzner, Vultr, DigitalOcean
################################################################################
export TERM=tmux-256color
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
API_KEYS_DIR="$HOME/.apikeys"
LOG_FILE="$HOME/.hosting_manager.log"
check_dependencies() {
local missing_tools=()
for tool in curl jq bc; do
if ! command -v "$tool" &> /dev/null; then
missing_tools+=("$tool")
fi
done
if [[ ${#missing_tools[@]} -gt 0 ]]; then
echo -e "${RED}Error: Missing required tools: ${missing_tools[*]}${NC}"
echo -e "${YELLOW}Install them with: sudo apt-get install ${missing_tools[*]}${NC}"
exit 1
fi
}
log_action() {
local level=$1
local message=$2
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $message" >> "$LOG_FILE"
}
clear_screen() {
clear
}
print_header() {
echo -e "${CYAN}╔════════════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}${NC} Multi-Hosting Provider Management Tool ${CYAN}${NC}"
echo -e "${CYAN}╚════════════════════════════════════════════════════════════╝${NC}"
}
pause_menu() {
echo -e "\n${YELLOW}Press Enter to continue...${NC}"
read -r
}
# ============================================================================
# VULTR FUNCTIONS
# ============================================================================
vultr_get_api_key() {
if [[ ! -f "$API_KEYS_DIR/vultr.txt" ]]; then
echo -e "${RED}Error: Vultr API key not found${NC}"
return 1
fi
cat "$API_KEYS_DIR/vultr.txt" | tr -d '\n' | tr -d ' '
}
vultr_list_instances() {
local api_key=$(vultr_get_api_key)
[[ -z "$api_key" ]] && echo '{"instances":[]}' && return 1
local response=$(curl -s -w "\n%{http_code}" -X GET "https://api.vultr.com/v2/instances" \
-H "Authorization: Bearer $api_key" -H "Content-Type: application/json")
local http_code=$(echo "$response" | tail -n1)
local body=$(echo "$response" | sed '$d')
if [[ "$http_code" != "200" ]]; then
echo -e "${RED}Vultr API Error (HTTP $http_code)${NC}" >&2
log_action "ERROR" "Vultr API returned HTTP $http_code"
echo '{"instances":[]}'
return 1
fi
echo "$body"
}
vultr_display_instances() {
clear_screen
print_header
echo -e "\n${BLUE}Vultr Instances:${NC}\n"
local instances=$(vultr_list_instances)
if ! echo "$instances" | jq empty 2>/dev/null; then
echo -e "${RED}Failed to retrieve instances${NC}"
log_action "ERROR" "Invalid Vultr API response"
pause_menu
return
fi
local instance_count=$(echo "$instances" | jq '.instances | length' 2>/dev/null || echo 0)
[[ $instance_count -eq 0 ]] && echo -e "${YELLOW}No instances found${NC}" && pause_menu && return
echo "$instances" | jq -r '.instances[] | "\(if .label != null then .label else "N/A" end)\t|\t\(.id)\t|\t\(.region)\t|\t\(.status)"' | \
column -t -s $'\t' -N "NAME,INSTANCE_ID,REGION,STATUS"
log_action "INFO" "Displayed Vultr instances ($instance_count found)"
pause_menu
}
vultr_instance_bandwidth() {
clear_screen
print_header
echo -e "\n${BLUE}Vultr Bandwidth Usage (Today):${NC}\n"
local api_key=$(vultr_get_api_key)
[[ -z "$api_key" ]] && echo -e "${RED}API key not found${NC}" && pause_menu && return 1
local instances=$(vultr_list_instances)
if ! echo "$instances" | jq empty 2>/dev/null; then
echo -e "${RED}Failed to retrieve instances${NC}"
pause_menu
return
fi
local instance_count=$(echo "$instances" | jq '.instances | length' 2>/dev/null || echo 0)
[[ $instance_count -eq 0 ]] && echo -e "${YELLOW}No instances found${NC}" && pause_menu && return
local today=$(date '+%Y-%m-%d')
echo "$instances" | jq -r '.instances[] | .id' | while read -r instance_id; do
local label=$(echo "$instances" | jq -r ".instances[] | select(.id == \"$instance_id\") | .label")
local bandwidth=$(curl -s -X GET "https://api.vultr.com/v2/instances/$instance_id/bandwidth" \
-H "Authorization: Bearer $api_key" -H "Content-Type: application/json")
local incoming=$(echo "$bandwidth" | jq -r ".bandwidth.\"$today\"[0]" 2>/dev/null || echo "0")
local outgoing=$(echo "$bandwidth" | jq -r ".bandwidth.\"$today\"[1]" 2>/dev/null || echo "0")
local incoming_mb=$(echo "scale=2; $incoming / 1024 / 1024" | bc -l 2>/dev/null || echo "0")
local outgoing_mb=$(echo "scale=2; $outgoing / 1024 / 1024" | bc -l 2>/dev/null || echo "0")
echo -e "${CYAN}$label:${NC}"
echo -e " Incoming: ${GREEN}${incoming_mb} MB${NC}"
echo -e " Outgoing: ${GREEN}${outgoing_mb} MB${NC}\n"
done
log_action "INFO" "Viewed Vultr bandwidth usage"
pause_menu
}
# ============================================================================
# DIGITALOCEAN FUNCTIONS
# ============================================================================
digitalocean_get_api_key() {
if [[ ! -f "$API_KEYS_DIR/digitalocean.txt" ]]; then
echo -e "${RED}Error: DigitalOcean API key not found${NC}"
return 1
fi
cat "$API_KEYS_DIR/digitalocean.txt" | tr -d '\n' | tr -d ' '
}
digitalocean_list_droplets() {
local api_key=$(digitalocean_get_api_key)
[[ -z "$api_key" ]] && echo '{"droplets":[]}' && return 1
local response=$(curl -s -w "\n%{http_code}" -X GET "https://api.digitalocean.com/v2/droplets" \
-H "Authorization: Bearer $api_key" -H "Content-Type: application/json")
local http_code=$(echo "$response" | tail -n1)
local body=$(echo "$response" | sed '$d')
if [[ "$http_code" != "200" ]]; then
echo -e "${RED}DigitalOcean API Error (HTTP $http_code)${NC}" >&2
log_action "ERROR" "DigitalOcean API returned HTTP $http_code"
echo '{"droplets":[]}'
return 1
fi
echo "$body"
}
digitalocean_display_droplets() {
clear_screen
print_header
echo -e "\n${BLUE}DigitalOcean Droplets:${NC}\n"
local droplets=$(digitalocean_list_droplets)
if ! echo "$droplets" | jq empty 2>/dev/null; then
echo -e "${RED}Failed to retrieve droplets${NC}"
log_action "ERROR" "Invalid DigitalOcean API response"
pause_menu
return
fi
local droplet_count=$(echo "$droplets" | jq '.droplets | length' 2>/dev/null || echo 0)
[[ $droplet_count -eq 0 ]] && echo -e "${YELLOW}No droplets found${NC}" && pause_menu && return
echo "$droplets" | jq -r '.droplets[] | "\(.name)\t|\t\(.id)\t|\t\(.region.slug)\t|\t\(.status)"' | \
column -t -s $'\t' -N "NAME,DROPLET_ID,REGION,STATUS"
log_action "INFO" "Displayed DigitalOcean droplets ($droplet_count found)"
pause_menu
}
digitalocean_display_droplet_info() {
clear_screen
print_header
echo -e "\n${BLUE}DigitalOcean Droplet Detailed Info:${NC}\n"
local droplets=$(digitalocean_list_droplets)
if ! echo "$droplets" | jq empty 2>/dev/null; then
echo -e "${RED}Failed to retrieve droplets${NC}"
pause_menu
return
fi
local droplet_count=$(echo "$droplets" | jq '.droplets | length' 2>/dev/null || echo 0)
[[ $droplet_count -eq 0 ]] && echo -e "${YELLOW}No droplets found${NC}" && pause_menu && return
echo "$droplets" | jq -r '.droplets[] | "\(.name)\t|\t\(.memory)MB\t|\t\(.vcpus) vCPU\t|\t\(.disk)GB\t|\t\(.region.name)\t|\t\(.networks.v4[] | select(.type == \"public\") | .ip_address // \"N/A\")"' | \
column -t -s $'\t' -N "NAME,MEMORY,VCPUS,DISK,REGION,PUBLIC_IP"
log_action "INFO" "Viewed DigitalOcean droplet details"
pause_menu
}
# ============================================================================
# HETZNER FUNCTIONS
# ============================================================================
hetzner_find_api_keys() {
local keys=()
if [[ ! -d "$API_KEYS_DIR" ]]; then
return 1
fi
while IFS= read -r -d '' file; do
keys+=("$file")
done < <(find "$API_KEYS_DIR" -maxdepth 1 -name "hetzner*.txt" -type f -print0 2>/dev/null)
if [[ ${#keys[@]} -eq 0 ]]; then
return 1
fi
IFS=$'\n' sorted_keys=($(sort <<<"${keys[*]}"))
unset IFS
printf '%s\n' "${sorted_keys[@]}"
}
hetzner_select_project() {
local api_key=""
local selected_file=""
local keys_array=()
while IFS= read -r key; do
keys_array+=("$key")
done < <(hetzner_find_api_keys)
if [[ ${#keys_array[@]} -eq 0 ]]; then
echo -e "${RED}Error: No Hetzner API keys found in $API_KEYS_DIR${NC}"
log_action "ERROR" "No Hetzner API keys found"
return 1
fi
if [[ ${#keys_array[@]} -eq 1 ]]; then
selected_file="${keys_array[0]}"
else
clear_screen
print_header
echo -e "\n${BLUE}Select Hetzner Project:${NC}\n"
for i in "${!keys_array[@]}"; do
local filename=$(basename "${keys_array[$i]}")
local project_name="${filename#hetzner-}"
project_name="${project_name%.txt}"
echo -e "$((i+1)). ${YELLOW}$project_name${NC}"
done
echo ""
read -p "Choose a project (1-${#keys_array[@]}): " choice
if ! [[ "$choice" =~ ^[0-9]+$ ]] || ((choice < 1 || choice > ${#keys_array[@]})); then
echo -e "${RED}Invalid selection${NC}"
log_action "ERROR" "Invalid Hetzner project selection"
return 1
fi
selected_file="${keys_array[$((choice-1))]}"
fi
api_key=$(cat "$selected_file" | tr -d '\n' | tr -d ' ')
echo "$api_key"
}
hetzner_list_servers() {
local api_key="$1"
[[ -z "$api_key" ]] && return 1
local response
response=$(curl -s -w "\n%{http_code}" \
-H "Authorization: Bearer $api_key" \
-H "Content-Type: application/json" \
https://api.hetzner.cloud/v1/servers)
local http_code
http_code=$(echo "$response" | tail -n1)
local body
body=$(echo "$response" | sed '$d')
if [[ "$http_code" != "200" ]]; then
echo '{"servers":[]}'
log_action "ERROR" "Hetzner API HTTP $http_code"
return 1
fi
echo "$body"
}
hetzner_display_servers() {
clear_screen
print_header
echo -e "\n${BLUE}Hetzner Cloud Servers:${NC}\n"
local api_key=$(hetzner_select_project)
[[ -z "$api_key" ]] && pause_menu && return
local servers=$(hetzner_list_servers "$api_key")
if ! echo "$servers" | jq empty 2>/dev/null; then
echo -e "${RED}Failed to retrieve servers${NC}"
log_action "ERROR" "Invalid Hetzner API response"
pause_menu
return
fi
local server_count=$(echo "$servers" | jq '.servers | length' 2>/dev/null || echo 0)
[[ $server_count -eq 0 ]] && echo -e "${YELLOW}No servers found${NC}" && pause_menu && return
echo "$servers" | jq -r '.servers[] | "\(.name)\t|\t\(.id)\t|\t\(.datacenter.name)\t|\t\(.status)"' | \
column -t -s $'\t' -N "NAME,SERVER_ID,DATACENTER,STATUS"
log_action "INFO" "Displayed Hetzner servers ($server_count found)"
pause_menu
}
hetzner_display_server_info() {
clear_screen
print_header
echo -e "\n${BLUE}Hetzner Cloud Server Detailed Info:${NC}\n"
local api_key=$(hetzner_select_project)
[[ -z "$api_key" ]] && pause_menu && return
local servers=$(hetzner_list_servers "$api_key")
if ! echo "$servers" | jq empty 2>/dev/null; then
echo -e "${RED}Failed to retrieve servers${NC}"
pause_menu
return
fi
local server_count=$(echo "$servers" | jq '.servers | length' 2>/dev/null || echo 0)
[[ $server_count -eq 0 ]] && echo -e "${YELLOW}No servers found${NC}" && pause_menu && return
echo "$servers" | jq -r '.servers[] | "\(.name)\t|\t\(.server_type.name)\t|\t\(.server_type.cores) cores\t|\t\(.server_type.memory)GB\t|\t\(.server_type.disk)GB\t|\t\(.datacenter.description)\t|\t\(.public_net.ipv4.ip // \"N/A\")"' | \
column -t -s $'\t' -N "NAME,SERVER_TYPE,CORES,MEMORY,DISK,DATACENTER,PUBLIC_IP"
log_action "INFO" "Viewed Hetzner server details"
pause_menu
}
# ============================================================================
# API KEY MANAGEMENT
# ============================================================================
setup_api_keys() {
clear_screen
print_header
echo -e "\n${BLUE}API Key Setup:${NC}\n"
if [[ ! -d "$API_KEYS_DIR" ]]; then
mkdir -p "$API_KEYS_DIR"
chmod 700 "$API_KEYS_DIR"
echo -e "${GREEN}Created $API_KEYS_DIR${NC}"
fi
echo -e "${YELLOW}1.${NC} Setup Vultr API Key"
echo -e "${YELLOW}2.${NC} Setup DigitalOcean API Key"
echo -e "${YELLOW}3.${NC} Setup Hetzner API Key (Single Project)"
echo -e "${YELLOW}4.${NC} Setup Hetzner API Key (Multiple Projects)"
echo -e "${YELLOW}5.${NC} Back to Main Menu"
echo ""
read -p "Choose an option: " choice
case $choice in
1)
read -sp "Enter Vultr API Key: " vultr_key
echo ""
echo "$vultr_key" > "$API_KEYS_DIR/vultr.txt"
chmod 600 "$API_KEYS_DIR/vultr.txt"
echo -e "${GREEN}Vultr API key saved${NC}"
log_action "INFO" "Vultr API key configured"
;;
2)
read -sp "Enter DigitalOcean API Key: " do_key
echo ""
echo "$do_key" > "$API_KEYS_DIR/digitalocean.txt"
chmod 600 "$API_KEYS_DIR/digitalocean.txt"
echo -e "${GREEN}DigitalOcean API key saved${NC}"
log_action "INFO" "DigitalOcean API key configured"
;;
3)
read -sp "Enter Hetzner API Key: " hz_key
echo ""
echo "$hz_key" > "$API_KEYS_DIR/hetzner.txt"
chmod 600 "$API_KEYS_DIR/hetzner.txt"
echo -e "${GREEN}Hetzner API key saved${NC}"
log_action "INFO" "Hetzner API key configured"
;;
4)
read -p "Enter project name (e.g., production, staging): " project_name
read -sp "Enter Hetzner API Key for $project_name: " hz_key
echo ""
echo "$hz_key" > "$API_KEYS_DIR/hetzner-${project_name}.txt"
chmod 600 "$API_KEYS_DIR/hetzner-${project_name}.txt"
echo -e "${GREEN}Hetzner API key for '$project_name' saved${NC}"
log_action "INFO" "Hetzner API key for project '$project_name' configured"
;;
5)
return
;;
*)
echo -e "${RED}Invalid option${NC}"
;;
esac
pause_menu
setup_api_keys
}
# ============================================================================
# LOGGING
# ============================================================================
view_logs() {
clear_screen
print_header
echo -e "\n${BLUE}Recent Activity Log (Last 50 entries):${NC}\n"
if [[ ! -f "$LOG_FILE" ]]; then
echo -e "${YELLOW}No log file found${NC}"
pause_menu
return
fi
tail -n 50 "$LOG_FILE" | while IFS= read -r line; do
if [[ "$line" == *"ERROR"* ]]; then
echo -e "${RED}$line${NC}"
elif [[ "$line" == *"WARNING"* ]]; then
echo -e "${YELLOW}$line${NC}"
else
echo -e "${GREEN}$line${NC}"
fi
done
pause_menu
}
# ============================================================================
# MAIN MENU
# ============================================================================
show_main_menu() {
clear_screen
print_header
echo -e "\n${BLUE}Main Menu:${NC}\n"
echo -e "${YELLOW}1.${NC} List Vultr Instances"
echo -e "${YELLOW}2.${NC} Vultr Instance Bandwidth Usage (Today)"
echo -e "${YELLOW}3.${NC} List DigitalOcean Droplets"
echo -e "${YELLOW}4.${NC} DigitalOcean Droplet Detailed Info"
echo -e "${YELLOW}5.${NC} List Hetzner Servers"
echo -e "${YELLOW}6.${NC} Hetzner Server Detailed Info"
echo -e "${YELLOW}7.${NC} Setup/Update API Keys"
echo -e "${YELLOW}8.${NC} View Activity Logs"
echo -e "${YELLOW}9.${NC} Exit"
echo ""
read -p "Choose an option (1-9): " choice
case $choice in
1) vultr_display_instances ;;
2) vultr_instance_bandwidth ;;
3) digitalocean_display_droplets ;;
4) digitalocean_display_droplet_info ;;
5) hetzner_display_servers ;;
6) hetzner_display_server_info ;;
7) setup_api_keys ;;
8) view_logs ;;
9)
clear_screen
echo -e "${CYAN}Goodbye!${NC}"
log_action "INFO" "Script terminated"
exit 0
;;
*)
echo -e "${RED}Invalid option${NC}"
pause_menu
;;
esac
show_main_menu
}
# ============================================================================
# MAIN EXECUTION
# ============================================================================
check_dependencies
log_action "INFO" "Script started"
show_main_menu