Compare commits

...

12 Commits

Author SHA1 Message Date
Lukas Greve
2a529df043 add support for fedora 43 2025-11-18 16:56:44 +01:00
Lukas Greve
435ca041c0 add support for Fedora Cloud 43 2025-11-18 16:55:39 +01:00
Lukas Greve
f25c33eaca remove complex bit related to fedora rawhide 2025-11-18 16:55:24 +01:00
Lukas Greve
c99938e744 add ability to change disk size 2025-11-17 21:38:35 +01:00
Lukas Greve
e038dcef97 move back in root folder 2025-11-02 11:53:00 +01:00
Lukas Greve
0a32075220 add logic to avoid refetching fedora rawhide if already present. Otherwise, this script redownload rawhide almost every day, as there is a new image everyday 2025-11-02 11:52:39 +01:00
Lukas Greve
8266670f1d move scripts 2025-11-02 11:22:55 +01:00
Lukas Greve
7b67ff510b add aider 2025-11-02 11:22:23 +01:00
Lukas Greve
4aa7dafe26 make it a markdown 2025-11-02 11:22:13 +01:00
Lukas Greve
ebaf28040c Store VMs images in a more persistent location 2025-11-01 10:55:24 +01:00
Lukas Greve
d6e11a3e63 add logic for updating the image location for Fedora Rawhide. Does not appear to be working 2025-10-26 12:13:29 +01:00
Lukas Greve
f27930a294 Add logic to fetch latest Fedora Cloud Rawhide image 2025-10-26 12:02:16 +01:00
8 changed files with 393 additions and 46 deletions

1
.gitignore vendored
View File

@@ -10,3 +10,4 @@ terraform.tfvars.example
# Terraform plan and output files # Terraform plan and output files
*.tfplan *.tfplan
*.tfout *.tfout
.aider*

View File

View File

@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Image URLs # Image URLs with dynamic Fedora URL handling
IMAGES=( IMAGES=(
"https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.raw" "https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.raw"
"https://download.fedoraproject.org/pub/fedora/linux/releases/42/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2" "https://download.fedoraproject.org/pub/fedora/linux/releases/42/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2"
@@ -8,6 +8,7 @@ IMAGES=(
"https://dl.rockylinux.org/pub/rocky/10/images/x86_64/Rocky-10-GenericCloud-Base.latest.x86_64.qcow2" "https://dl.rockylinux.org/pub/rocky/10/images/x86_64/Rocky-10-GenericCloud-Base.latest.x86_64.qcow2"
"https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img" "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
"https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-10-latest.x86_64.qcow2" "https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-10-latest.x86_64.qcow2"
"https://download.fedoraproject.org/pub/fedora/linux/releases/43/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-43-1.6.x86_64.qcow2"
) )
# Target directory # Target directory
@@ -36,6 +37,11 @@ main() {
local failure_count=0 local failure_count=0
for url in "${IMAGES[@]}"; do for url in "${IMAGES[@]}"; do
# Skip empty URLs
if [[ -z "$url" ]]; then
continue
fi
local filename local filename
filename=$(basename "$url") filename=$(basename "$url")
local filepath="$TARGET_DIR/$filename" local filepath="$TARGET_DIR/$filename"

View File

@@ -0,0 +1,23 @@
terraform {
required_version = ">= 0.13"
required_providers {
libvirt = {
source = "dmacvicar/libvirt"
version = "0.8.3"
}
}
}
provider "libvirt" {
uri = "qemu+ssh://lukas@192.168.1.170/system"
}
module "shared_modules" {
source = "../../shared_modules"
vm_name = "f43-bios"
image_location = "https://download.fedoraproject.org/pub/fedora/linux/releases/43/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-43-1.6.x86_64.qcow2"
ssh_key = "" # please provide a SSH public key
enable_cloudinit = true
# disk_size_bytes = 101474836480
}

192
main_launcher.sh Executable file
View File

@@ -0,0 +1,192 @@
#!/bin/bash
# Main launcher script for terraform image management tools
# This script provides a menu interface to run the other scripts in proper order
# Function to display usage
usage() {
echo "Usage: $0 [options]"
echo " options:"
echo " -h, --help Display this help message"
echo " -y, --yes Automatically answer 'yes' to all prompts"
echo " -n, --no Automatically answer 'no' to all prompts"
echo ""
echo "Example:"
echo " $0 # Interactive mode with default 'yes'"
echo " $0 -y # Non-interactive mode with auto 'yes'"
echo " $0 -n # Non-interactive mode with auto 'no'"
exit 1
}
# Parse command line arguments
AUTO_YES=false
AUTO_NO=false
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
usage
;;
-y|--yes)
AUTO_YES=true
shift
;;
-n|--no)
AUTO_NO=true
shift
;;
*)
echo "Unknown option: $1"
usage
;;
esac
done
# Function to get user confirmation
confirm() {
local prompt="$1"
local default="$2" # "yes" or "no"
if [[ "$AUTO_YES" = true ]]; then
echo "$prompt [Y/n]: yes"
return 0
elif [[ "$AUTO_NO" = true ]]; then
echo "$prompt [y/N]: no"
return 1
fi
# Default behavior - yes is default
if [[ "$default" = "no" ]]; then
echo -n "$prompt [y/N]: "
else
echo -n "$prompt [Y/n]: "
fi
read -r answer
# If empty answer, use default
if [[ -z "$answer" ]]; then
answer="$default"
fi
# Convert to lowercase for comparison
answer=$(echo "$answer" | tr '[:upper:]' '[:lower:]')
if [[ "$answer" = "y" || "$answer" = "yes" ]]; then
return 0
else
return 1
fi
}
# Function to check if a script exists and is executable
check_script() {
local script="$1"
if [[ ! -f "$script" ]] || [[ ! -x "$script" ]]; then
echo "Error: Script '$script' not found or not executable"
return 1
fi
return 0
}
# Function to run a script with proper error handling
run_script() {
local script="$1"
local description="$2"
local args="$3"
echo "=== $description ==="
if check_script "$script"; then
if [[ -n "$args" ]]; then
echo "Running: $script $args"
"$script" "$args"
else
echo "Running: $script"
"$script"
fi
local exit_code=$?
if [[ $exit_code -eq 0 ]]; then
echo "$description completed successfully"
return 0
else
echo "$description failed with exit code $exit_code"
return 1
fi
else
echo "$description skipped due to missing script"
return 1
fi
}
# Function to check if libvirt images directory exists
check_images_directory() {
local image_dir="/var/lib/libvirt/images"
if [[ ! -d "$image_dir" ]]; then
echo "Warning: Directory $image_dir does not exist"
if confirm "Would you like to create it?" "yes"; then
if ! sudo mkdir -p "$image_dir"; then
echo "Error: Could not create directory $image_dir"
return 1
fi
echo "Directory $image_dir created successfully"
else
echo "Skipping image directory check"
fi
else
echo "Directory $image_dir exists"
fi
return 0
}
# Main execution logic
main() {
echo "=== Terraform Image Management Launcher ==="
echo
# Validate image directory
if ! check_images_directory; then
echo "Exiting due to image directory issues"
exit 1
fi
echo
# Ask if user wants to download images
if confirm "Do you want to download OS images?" "yes"; then
if ! run_script "./download_images.sh" "Downloading OS Images"; then
echo "Image download failed. Proceeding to update script..."
fi
fi
echo
# Ask if user wants to update image locations
if confirm "Do you want to update image locations to use local files?" "yes"; then
if ! run_script "./update_image_locations.sh" "Updating Image Locations"; then
echo "Image location update failed"
exit 1
fi
fi
echo
# Ask if user wants to update SSH keys
if confirm "Do you want to update SSH keys in terraform files?" "yes"; then
if ! run_script "./update_ssh_keys.sh" "Updating SSH Keys"; then
echo "SSH key update failed"
exit 1
fi
fi
echo
echo "=== All operations completed ==="
}
# Run main function if script is executed directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi

View File

@@ -13,7 +13,19 @@ variable "pool_name" {
variable "pool_path" { variable "pool_path" {
description = "Path for the storage pool" description = "Path for the storage pool"
type = string type = string
default = "/tmp/tf_tmp_storage" default = "/opt/tf_tmp_storage"
}
variable "disk_size_gb" {
description = "Disk size in GB"
type = number
default = 20
}
variable "disk_size_bytes" {
description = "Disk size in bytes"
type = number
default = 20 * 1024 * 1024 * 1024
} }
variable "instance_count" { variable "instance_count" {
@@ -71,7 +83,7 @@ variable "memory" {
variable "vcpu" { variable "vcpu" {
description = "Number of virtual CPUs" description = "Number of virtual CPUs"
type = number type = number
default = 2 default = 1
} }
variable "network_mode" { variable "network_mode" {

View File

@@ -1,9 +1,25 @@
resource "libvirt_volume" "vm_disk" { # Base volume (template/parent)
count = var.instance_count resource "libvirt_volume" "base_vm_image" {
name = "${var.vm_name}-${count.index}" name = "${var.vm_name}-base"
pool = "${var.vm_name}-pool" pool = "${var.vm_name}-pool"
source = var.image_location source = var.image_location
format = "qcow2" format = "qcow2"
depends_on = [libvirt_pool.tf_tmp_storage] depends_on = [
libvirt_pool.tf_tmp_storage
]
}
# Clone volume with resizable size
resource "libvirt_volume" "vm_disk" {
count = var.instance_count
name = "${var.vm_name}-${count.index}"
pool = "${var.vm_name}-pool"
format = "qcow2"
size = var.disk_size_bytes
base_volume_id = libvirt_volume.base_vm_image.id
depends_on = [
libvirt_volume.base_vm_image
]
} }

View File

@@ -53,20 +53,48 @@ if [[ ! -d "$IMAGE_DIR" ]]; then
exit 1 exit 1
fi fi
# Image URLs (hardcoded original URLs from download_images.sh) # Function to get all locally available image files (including Fedora Rawhide)
ORIGINAL_IMAGES=( get_local_images() {
"https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.raw" find "$IMAGE_DIR" -maxdepth 1 -type f \( -name "*.qcow2" -o -name "*.raw" -o -name "*.img" \) | \
"https://download.fedoraproject.org/pub/fedora/linux/releases/42/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2" while read -r image; do
"https://download.opensuse.org/tumbleweed/appliances/openSUSE-Tumbleweed-Minimal-VM.x86_64-Cloud.qcow2" basename "$image"
"https://dl.rockylinux.org/pub/rocky/10/images/x86_64/Rocky-10-GenericCloud-Base.latest.x86_64.qcow2" done | sort
"https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img" }
"https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-10-latest.x86_64.qcow2"
)
# Function to get filename from URL # Function to check if a local file matches the pattern for a Fedora Rawhide image
get_filename_from_url() { is_fedora_rawhide_image() {
local url=$1 local filename=$1
basename "$url" # Pattern matching for Fedora Rawhide images that contain "Fedora-Cloud-Base-Generic-Rawhide"
if [[ "$filename" =~ ^Fedora-Cloud-Base-Generic-Rawhide.*\.qcow2$ ]]; then
return 0
fi
return 1
}
# Function to get the latest Fedora Rawhide image path from local directory
get_latest_fedora_rawhide_path() {
local latest_file
latest_file=$(find "$IMAGE_DIR" -maxdepth 1 -name "Fedora-Cloud-Base-Generic-Rawhide*.qcow2" -type f \
| sort -r \
| head -1)
if [[ -n "$latest_file" ]]; then
echo "$latest_file"
fi
}
# Function to provide a mapping between local files and their original URLs
create_original_url_mapping() {
# Create a hash-like mapping for known images
cat << 'EOF'
noble-server-cloudimg-amd64.img=https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2=https://download.fedoraproject.org/pub/fedora/linux/releases/42/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2
Fedora-Cloud-Base-Generic-43-1.6.x86_64.qcow2=https://download.fedoraproject.org/pub/fedora/linux/releases/43/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-43-1.6.x86_64.qcow2
openSUSE-Tumbleweed-Minimal-VM.x86_64-Cloud.qcow2=https://download.opensuse.org/tumbleweed/appliances/openSUSE-Tumbleweed-Minimal-VM.x86_64-Cloud.qcow2
Rocky-10-GenericCloud-Base.latest.x86_64.qcow2=https://dl.rockylinux.org/pub/rocky/10/images/x86_64/Rocky-10-GenericCloud-Base.latest.x86_64.qcow2
debian-13-genericcloud-amd64.raw=https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.raw
CentOS-Stream-GenericCloud-x86_64-10-latest.x86_64.qcow2=https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-x86_64-10-latest.x86_64.qcow2
EOF
} }
# Find all main.tf files and process them # Find all main.tf files and process them
@@ -96,16 +124,40 @@ for file in $MAIN_TF_FILES; do
temp_file=$(mktemp) temp_file=$(mktemp)
while IFS= read -r line || [[ -n "$line" ]]; do while IFS= read -r line || [[ -n "$line" ]]; do
# Check if the line contains a file:// URL
if [[ "$line" =~ .*image_location.*=.*\"file://(.*?)\".* ]]; then if [[ "$line" =~ .*image_location.*=.*\"file://(.*?)\".* ]]; then
# Extract local path from the file:// URL # Extract local path from the file:// URL
local_file_path="${BASH_REMATCH[1]}" local_file_path="${BASH_REMATCH[1]}"
local_filename=$(basename "$local_file_path") local_filename=$(basename "$local_file_path")
# Find matching original URL for this filename # Handle Fedora Rawhide images specially
if [[ "$local_filename" =~ ^Fedora-Cloud-Base-Generic-Rawhide.*\.qcow2$ ]]; then
echo " Reverting Fedora Rawhide image: $local_filename"
# For Rawhide, we'll keep the file:// reference but note that it's a special case
if [ "$DRY_RUN" = false ]; then
echo "$line" >> "$temp_file"
else
echo " Would process Fedora Rawhide image: $local_filename (keeping file:// reference)"
echo "$line" >> "$temp_file"
fi
else
# For regular images, try to map back to original URL
# Create mapping for this specific case
mapping=$(create_original_url_mapping)
# Find matching original URL
found_match=false found_match=false
for original_url in "${ORIGINAL_IMAGES[@]}"; do while IFS= read -r mapping_line; do
if [[ "$(basename "$original_url")" == "$local_filename" ]]; then if [[ -z "$mapping_line" ]] || [[ "$mapping_line" =~ ^#.*$ ]]; then
echo " Found matching file: $local_filename" continue
fi
file_pattern=$(echo "$mapping_line" | cut -d'=' -f1)
original_url=$(echo "$mapping_line" | cut -d'=' -f2)
if [[ "$file_pattern" == "$local_filename" ]]; then
echo " Found matching original URL: $local_filename"
if [ "$DRY_RUN" = false ]; then if [ "$DRY_RUN" = false ]; then
# Use precise string replacement to avoid corrupting the file # Use precise string replacement to avoid corrupting the file
@@ -119,12 +171,13 @@ for file in $MAIN_TF_FILES; do
found_match=true found_match=true
break break
fi fi
done done <<< "$mapping"
if [ "$found_match" = false ]; then if [ "$found_match" = false ]; then
echo " Warning: No matching original URL found for $local_filename" echo " Warning: No matching original URL found for $local_filename"
echo "$line" >> "$temp_file" echo "$line" >> "$temp_file"
fi fi
fi
else else
# Not a line with image_location, just copy as is # Not a line with image_location, just copy as is
echo "$line" >> "$temp_file" echo "$line" >> "$temp_file"
@@ -146,10 +199,54 @@ for file in $MAIN_TF_FILES; do
remote_url="${BASH_REMATCH[1]}" remote_url="${BASH_REMATCH[1]}"
filename=$(basename "$remote_url") filename=$(basename "$remote_url")
# Check if the local file exists # Check if the local file exists (including Fedora Rawhide cases)
local_path="$IMAGE_DIR/$filename" local_path="$IMAGE_DIR/$filename"
if [[ -f "$local_path" ]]; then # Special handling for Fedora Rawhide - check if it's the right pattern
if [[ "$filename" =~ ^Fedora-Cloud-Base-Generic-Rawhide.*\.qcow2$ ]]; then
# For Fedora Rawhide, we need to be more flexible with matching patterns
echo " Checking Fedora Rawhide pattern for: $filename"
# Find the most recent Fedora image that matches the pattern but has different timestamp
latest_rawhide=$(find "$IMAGE_DIR" -maxdepth 1 -name "Fedora-Cloud-Base-Generic-Rawhide*.qcow2" -type f \
| sort -r \
| head -1)
if [[ -n "$latest_rawhide" ]]; then
echo " Found matching local Fedora Rawhide image: $(basename $latest_rawhide)"
if [ "$DRY_RUN" = false ]; then
new_line="${line/\"$remote_url\"/\"file://$latest_rawhide\"}"
echo "$new_line" >> "$temp_file"
echo " Updated to local file: file://$latest_rawhide"
else
echo " Would update Fedora Rawhide to: file://$latest_rawhide"
echo "$line" >> "$temp_file"
fi
else
# No matching locally - check if we can find a similar pattern
echo " Checking for any Fedora-Cloud-Base-Generic-Rawhide*.qcow2 files..."
# Look for any file with the same prefix but different timestamp
local_candidates=$(find "$IMAGE_DIR" -maxdepth 1 -name "*Fedora-Cloud-Base-Generic-Rawhide*" -type f)
if [[ -n "$local_candidates" ]]; then
most_recent=$(echo "$local_candidates" | sort -r | head -1)
echo " Found matching local Fedora Rawhide image: $(basename $most_recent)"
if [ "$DRY_RUN" = false ]; then
new_line="${line/\"$remote_url\"/\"file://$most_recent\"}"
echo "$new_line" >> "$temp_file"
echo " Updated to local file: file://$most_recent"
else
echo " Would update Fedora Rawhide to: file://$most_recent"
echo "$line" >> "$temp_file"
fi
else
echo " Local Fedora Rawhide image not found, using original URL"
echo "$line" >> "$temp_file"
fi
fi
elif [[ -f "$local_path" ]]; then
echo " Found local image: $filename" echo " Found local image: $filename"
if [ "$DRY_RUN" = false ]; then if [ "$DRY_RUN" = false ]; then