diff --git a/proxmox_converter.sh b/proxmox_converter.sh new file mode 100644 index 0000000..7635a23 --- /dev/null +++ b/proxmox_converter.sh @@ -0,0 +1,225 @@ +#!/bin/bash + +# Proxmox Image Converter +# This script converts various virtual machine image formats to Proxmox-compatible format +# Supported formats: VMDK, VHD, VHDX, QED, QCOW2, RAW + +set -euo pipefail + +# Color codes for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Required tools +REQUIRED_TOOLS=("qemu-img" "md5sum" "awk" "grep" "basename" "dirname") + +# Log file +LOG_FILE="/var/log/proxmox_converter.log" +TEMP_DIR="/tmp/proxmox_convert" + +# Function to log messages +log_message() { + local level=$1 + local message=$2 + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + echo -e "${timestamp} [${level}] ${message}" >> "${LOG_FILE}" + + case ${level} in + "ERROR") + echo -e "${RED}ERROR: ${message}${NC}" >&2 + ;; + "WARNING") + echo -e "${YELLOW}WARNING: ${message}${NC}" + ;; + "INFO") + echo -e "${GREEN}INFO: ${message}${NC}" + ;; + esac +} + +# Function to check required tools +check_requirements() { + local missing_tools=() + + for tool in "${REQUIRED_TOOLS[@]}"; do + if ! command -v "$tool" >/dev/null 2>&1; then + missing_tools+=("$tool") + fi + done + + if [ ${#missing_tools[@]} -ne 0 ]; then + log_message "ERROR" "Missing required tools: ${missing_tools[*]}" + log_message "ERROR" "Please install them using: apt-get install qemu-utils coreutils grep" + exit 1 + fi +} + +# Function to verify disk image integrity +verify_image() { + local image_path=$1 + local checksum_before=$2 + + if [ ! -f "$image_path" ]; then + log_message "ERROR" "Image file not found: $image_path" + return 1 + } + + local checksum_after=$(md5sum "$image_path" | awk '{print $1}') + + if [ "$checksum_before" != "$checksum_after" ]; then + log_message "ERROR" "Image verification failed! Checksums don't match" + return 1 + fi + + log_message "INFO" "Image verification successful" + return 0 +} + +# Function to detect image format +detect_format() { + local image_path=$1 + + if [ ! -f "$image_path" ]; then + log_message "ERROR" "Image file not found: $image_path" + return 1 + } + + local format=$(qemu-img info "$image_path" | grep "file format" | awk '{print $3}') + + if [ -z "$format" ]; then + log_message "ERROR" "Unable to detect image format" + return 1 + fi + + echo "$format" + return 0 +} + +# Function to convert image to QCOW2 +convert_to_qcow2() { + local input_path=$1 + local output_path=$2 + local format=$3 + + # Calculate checksum before conversion + local checksum_before=$(md5sum "$input_path" | awk '{print $1}') + + # Create temp directory if it doesn't exist + mkdir -p "$TEMP_DIR" + + # Convert image + log_message "INFO" "Converting $input_path to QCOW2 format..." + if ! qemu-img convert -f "$format" -O qcow2 "$input_path" "${TEMP_DIR}/temp.qcow2"; then + log_message "ERROR" "Conversion failed" + rm -f "${TEMP_DIR}/temp.qcow2" + return 1 + fi + + # Verify source image hasn't been modified + if ! verify_image "$input_path" "$checksum_before"; then + log_message "ERROR" "Source image was modified during conversion" + rm -f "${TEMP_DIR}/temp.qcow2" + return 1 + fi + + # Move converted image to final destination + mv "${TEMP_DIR}/temp.qcow2" "$output_path" + + log_message "INFO" "Conversion completed successfully" + return 0 +} + +# Function to import image to Proxmox +import_to_proxmox() { + local image_path=$1 + local vm_id=$2 + local storage=$3 + + # Verify VM ID is valid + if ! [[ "$vm_id" =~ ^[0-9]+$ ]]; then + log_message "ERROR" "Invalid VM ID: $vm_id" + return 1 + fi + + # Check if VM ID already exists + if qm status "$vm_id" >/dev/null 2>&1; then + log_message "ERROR" "VM ID $vm_id already exists" + return 1 + } + + # Check if storage exists + if ! pvesm status | grep -q "^$storage"; then + log_message "ERROR" "Storage $storage not found" + return 1 + } + + # Import disk + log_message "INFO" "Importing disk to Proxmox..." + if ! qm importdisk "$vm_id" "$image_path" "$storage"; then + log_message "ERROR" "Failed to import disk" + return 1 + } + + log_message "INFO" "Disk imported successfully" + return 0 +} + +# Main function +main() { + local input_path=$1 + local vm_id=$2 + local storage=$3 + + # Check requirements + check_requirements + + # Create log directory if it doesn't exist + mkdir -p "$(dirname "$LOG_FILE")" + + # Detect input format + local format + format=$(detect_format "$input_path") + if [ $? -ne 0 ]; then + exit 1 + fi + + # Generate output path + local filename=$(basename "$input_path") + local output_path="${TEMP_DIR}/${filename%.*}.qcow2" + + # Convert image if not already in QCOW2 format + if [ "$format" != "qcow2" ]; then + if ! convert_to_qcow2 "$input_path" "$output_path" "$format"; then + exit 1 + fi + else + cp "$input_path" "$output_path" + fi + + # Import to Proxmox + if ! import_to_proxmox "$output_path" "$vm_id" "$storage"; then + rm -f "$output_path" + exit 1 + fi + + # Cleanup + rm -f "$output_path" + log_message "INFO" "Image conversion and import completed successfully" +} + +# Script usage +usage() { + echo "Usage: $0 " + echo "Example: $0 /path/to/windows.vmdk 100 local-lvm" + exit 1 +} + +# Check arguments +if [ $# -ne 3 ]; then + usage +fi + +# Run main function +main "$1" "$2" "$3" \ No newline at end of file