update
This commit is contained in:
232
Backup_Script/portainer-backup.sh
Executable file
232
Backup_Script/portainer-backup.sh
Executable file
@@ -0,0 +1,232 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Portainer Stack Backup Script
|
||||
# This script connects to a Portainer instance and exports all stacks with their configurations
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration - Update these variables
|
||||
PORTAINER_URL="http://192.168.11.12:9000" # Change this to your Portainer URL
|
||||
USERNAME="admin" # Change this to your username
|
||||
PASSWORD="JohnWayne#21" # Change this to your password or leave empty for prompt
|
||||
OUTPUT_DIR="portainer-stacks-backup"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to print colored output
|
||||
print_status() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Function to check if required tools are installed
|
||||
check_dependencies() {
|
||||
print_status "Checking dependencies..."
|
||||
|
||||
if ! command -v curl &> /dev/null; then
|
||||
print_error "curl is required but not installed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v jq &> /dev/null; then
|
||||
print_error "jq is required but not installed. Please install it with: brew install jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_status "All dependencies are available."
|
||||
}
|
||||
|
||||
# Function to prompt for configuration if not set
|
||||
get_config() {
|
||||
if [ -z "$PORTAINER_URL" ]; then
|
||||
read -p "Enter Portainer URL (e.g., http://localhost:9000): " PORTAINER_URL
|
||||
fi
|
||||
|
||||
if [ -z "$USERNAME" ]; then
|
||||
read -p "Enter Portainer username: " USERNAME
|
||||
fi
|
||||
|
||||
if [ -z "$PASSWORD" ]; then
|
||||
read -s -p "Enter Portainer password: " PASSWORD
|
||||
echo
|
||||
fi
|
||||
|
||||
# Remove trailing slash from URL if present
|
||||
PORTAINER_URL=$(echo "$PORTAINER_URL" | sed 's/\/$//g')
|
||||
}
|
||||
|
||||
# Function to authenticate with Portainer
|
||||
authenticate() {
|
||||
print_status "Authenticating with Portainer..."
|
||||
|
||||
AUTH_RESPONSE=$(curl -s -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"username\":\"$USERNAME\",\"password\":\"$PASSWORD\"}" \
|
||||
"$PORTAINER_URL/api/auth")
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
print_error "Failed to connect to Portainer at $PORTAINER_URL"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
JWT_TOKEN=$(echo "$AUTH_RESPONSE" | jq -r '.jwt // empty')
|
||||
|
||||
if [ -z "$JWT_TOKEN" ] || [ "$JWT_TOKEN" = "null" ]; then
|
||||
print_error "Authentication failed. Please check your credentials."
|
||||
print_error "Response: $AUTH_RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_status "Authentication successful."
|
||||
}
|
||||
|
||||
# Function to get all environments (endpoints)
|
||||
get_environments() {
|
||||
print_status "Getting environments..."
|
||||
|
||||
ENVIRONMENTS_RESPONSE=$(curl -s -X GET \
|
||||
-H "Authorization: Bearer $JWT_TOKEN" \
|
||||
"$PORTAINER_URL/api/endpoints")
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
print_error "Failed to get environments"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$ENVIRONMENTS_RESPONSE" | jq -r '.[].Id' 2>/dev/null || echo "1"
|
||||
}
|
||||
|
||||
# Function to get all stacks
|
||||
get_stacks() {
|
||||
print_status "Getting list of stacks..." >&2
|
||||
|
||||
STACKS_RESPONSE=$(curl -s -X GET \
|
||||
-H "Authorization: Bearer $JWT_TOKEN" \
|
||||
"$PORTAINER_URL/api/stacks")
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
print_error "Failed to get stacks" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$STACKS_RESPONSE"
|
||||
}
|
||||
|
||||
# Function to get detailed stack information
|
||||
get_stack_details() {
|
||||
local stack_id=$1
|
||||
local endpoint_id=$2
|
||||
|
||||
curl -s -X GET \
|
||||
-H "Authorization: Bearer $JWT_TOKEN" \
|
||||
"$PORTAINER_URL/api/stacks/$stack_id?endpointId=$endpoint_id"
|
||||
}
|
||||
|
||||
# Function to get stack file content
|
||||
get_stack_file() {
|
||||
local stack_id=$1
|
||||
|
||||
curl -s -X GET \
|
||||
-H "Authorization: Bearer $JWT_TOKEN" \
|
||||
"$PORTAINER_URL/api/stacks/$stack_id/file"
|
||||
}
|
||||
|
||||
# Function to save stack data
|
||||
save_stack_data() {
|
||||
local stack_info=$1
|
||||
local stack_name=$(echo "$stack_info" | jq -r '.Name')
|
||||
local stack_id=$(echo "$stack_info" | jq -r '.Id')
|
||||
local endpoint_id=$(echo "$stack_info" | jq -r '.EndpointId')
|
||||
|
||||
print_status "Processing stack: $stack_name (ID: $stack_id)"
|
||||
|
||||
# Create directory for this stack
|
||||
local stack_dir="$OUTPUT_DIR/$stack_name"
|
||||
mkdir -p "$stack_dir"
|
||||
|
||||
# Save basic stack information
|
||||
echo "$stack_info" | jq '.' > "$stack_dir/stack-info.json"
|
||||
|
||||
# Extract and save environment variables
|
||||
echo "$stack_info" | jq '.Env // []' > "$stack_dir/environment-variables.json"
|
||||
|
||||
# Save environment variables in .env format
|
||||
echo "$stack_info" | jq -r '.Env[]? | select(.name != null and .value != null) | "\(.name)=\(.value)"' > "$stack_dir/.env"
|
||||
|
||||
# Get and save stack file content (docker-compose.yml)
|
||||
print_status "Getting stack file for: $stack_name"
|
||||
STACK_FILE_RESPONSE=$(get_stack_file "$stack_id")
|
||||
|
||||
if [ $? -eq 0 ] && [ "$STACK_FILE_RESPONSE" != "null" ]; then
|
||||
echo "$STACK_FILE_RESPONSE" | jq -r '.StackFileContent // empty' > "$stack_dir/docker-compose.yml"
|
||||
else
|
||||
print_warning "Could not retrieve stack file for: $stack_name"
|
||||
fi
|
||||
|
||||
# Save additional metadata
|
||||
cat > "$stack_dir/metadata.txt" << EOF
|
||||
Stack Name: $stack_name
|
||||
Stack ID: $stack_id
|
||||
Endpoint ID: $endpoint_id
|
||||
Creation Date: $(echo "$stack_info" | jq -r '.CreationDate // "N/A"')
|
||||
Update Date: $(echo "$stack_info" | jq -r '.UpdateDate // "N/A"')
|
||||
Status: $(echo "$stack_info" | jq -r '.Status // "N/A"')
|
||||
Type: $(echo "$stack_info" | jq -r '.Type // "N/A"')
|
||||
Entry Point: $(echo "$stack_info" | jq -r '.EntryPoint // "N/A"')
|
||||
EOF
|
||||
|
||||
print_status "Stack $stack_name saved to $stack_dir"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
print_status "Starting Portainer stack backup..."
|
||||
|
||||
check_dependencies
|
||||
get_config
|
||||
authenticate
|
||||
|
||||
# Create output directory
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
# Get all stacks
|
||||
STACKS_JSON=$(get_stacks)
|
||||
|
||||
if [ -z "$STACKS_JSON" ] || [ "$STACKS_JSON" = "null" ]; then
|
||||
print_warning "No stacks found or unable to retrieve stacks."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Count stacks
|
||||
STACK_COUNT=$(echo "$STACKS_JSON" | jq '. | length')
|
||||
print_status "Found $STACK_COUNT stack(s)"
|
||||
|
||||
if [ "$STACK_COUNT" -eq 0 ]; then
|
||||
print_warning "No stacks to backup."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Process each stack
|
||||
echo "$STACKS_JSON" | jq -c '.[]' | while read -r stack; do
|
||||
save_stack_data "$stack"
|
||||
echo "---"
|
||||
done
|
||||
|
||||
print_status "Backup completed! All stacks saved to: $OUTPUT_DIR"
|
||||
print_status "Summary:"
|
||||
ls -la "$OUTPUT_DIR"
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user