Files
Tips-Tricks/rhel8-iso-update.sh
2026-01-29 14:57:12 -08:00

666 lines
19 KiB
Bash

#!/bin/bash
#===============================================================================
# RHEL 8.10 Offline Update Script
#
# This interactive script guides administrators through applying updates
# from a locally-mounted ISO file.
#
# ISO: Full_Latest_RHEL8_x86_64_patches_2026-01-13.iso
# Mount Point: /media/JanPatch
# Repo File: /etc/yum.repos.d/JanPatch.repo
#===============================================================================
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
ISO_NAME="Full_Latest_RHEL8_x86_64_patches_2026-01-13.iso"
ISO_PATH="/var/isos/${ISO_NAME}"
MOUNT_POINT="/media/JanPatch"
REPO_FILE="/etc/yum.repos.d/JanPatch.repo"
# Global variables for tracking
FOUND_ISO_LOCATIONS=()
UNMOUNTED_USB_DEVICES=()
USB_MOUNT_DIR="" # Track if we mounted a USB drive
#-------------------------------------------------------------------------------
# Helper Functions
#-------------------------------------------------------------------------------
print_header() {
echo ""
echo -e "${BLUE}===============================================================================${NC}"
echo -e "${BLUE} $1${NC}"
echo -e "${BLUE}===============================================================================${NC}"
echo ""
}
print_step() {
echo -e "${GREEN}[STEP $1]${NC} $2"
echo ""
}
print_info() {
echo -e "${YELLOW}[INFO]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
pause_continue() {
echo ""
read -p "Press Enter to continue..."
echo ""
}
confirm_action() {
local prompt="$1"
local response
echo ""
read -p "${prompt} (y/n): " response
case "$response" in
[yY]|[yY][eE][sS]) return 0 ;;
*) return 1 ;;
esac
}
check_root() {
if [[ $EUID -ne 0 ]]; then
print_error "This script must be run as root or with sudo."
echo "Please run: sudo $0"
exit 1
fi
}
#-------------------------------------------------------------------------------
# ISO Detection Functions
#-------------------------------------------------------------------------------
detect_external_media() {
# Find mounted external media (USB drives, external disks)
# Looks in common mount locations for removable media
local found_locations=()
local search_paths=(
"/run/media"
"/media"
"/mnt"
)
print_info "Scanning for external media..."
echo ""
for base_path in "${search_paths[@]}"; do
if [[ -d "$base_path" ]]; then
# Find the ISO file recursively in media locations
while IFS= read -r -d '' file; do
found_locations+=("$file")
done < <(find "$base_path" -maxdepth 3 -name "$ISO_NAME" -type f -print0 2>/dev/null)
fi
done
# Return results via global variable
FOUND_ISO_LOCATIONS=("${found_locations[@]}")
}
detect_unmounted_usb() {
# Detect USB drives that might not be mounted yet
# Returns list of unmounted USB block devices
local unmounted_usb=()
# Get list of USB block devices
for device in /sys/block/sd*; do
if [[ -d "$device" ]]; then
local devname=$(basename "$device")
local removable=$(cat "$device/removable" 2>/dev/null)
# Check if it's removable (USB)
if [[ "$removable" == "1" ]]; then
# Check each partition
for part in /dev/${devname}*; do
if [[ -b "$part" && "$part" != "/dev/$devname" ]]; then
# Check if partition is mounted
if ! mountpoint -q "$part" 2>/dev/null && ! grep -q "^$part " /proc/mounts; then
unmounted_usb+=("$part")
fi
fi
done
fi
fi
done
UNMOUNTED_USB_DEVICES=("${unmounted_usb[@]}")
}
show_iso_search_menu() {
# Display menu for ISO location options
local options=()
local option_paths=()
local count=1
echo "Where would you like to load the ISO from?"
echo ""
# Option: Default location if exists
if [[ -f "$ISO_PATH" ]]; then
echo " ${count}) Default location: ${ISO_PATH}"
options+=("default")
option_paths+=("$ISO_PATH")
((count++))
fi
# Options: Found on external media
for location in "${FOUND_ISO_LOCATIONS[@]}"; do
echo " ${count}) External media: ${location}"
options+=("external")
option_paths+=("$location")
((count++))
done
# Option: Mount unmounted USB
if [[ ${#UNMOUNTED_USB_DEVICES[@]} -gt 0 ]]; then
echo ""
echo " Unmounted USB devices detected:"
for usb in "${UNMOUNTED_USB_DEVICES[@]}"; do
echo " ${count}) Mount and scan: ${usb}"
options+=("mount_usb")
option_paths+=("$usb")
((count++))
done
fi
# Option: Manual path entry
echo ""
echo " ${count}) Enter path manually"
options+=("manual")
option_paths+=("")
((count++))
# Option: Exit
echo " ${count}) Exit"
options+=("exit")
option_paths+=("")
echo ""
read -p "Select option [1-${count}]: " selection
# Validate selection
if [[ ! "$selection" =~ ^[0-9]+$ ]] || [[ "$selection" -lt 1 ]] || [[ "$selection" -gt ${#options[@]} ]]; then
print_error "Invalid selection."
return 1
fi
local idx=$((selection - 1))
local chosen_option="${options[$idx]}"
local chosen_path="${option_paths[$idx]}"
case "$chosen_option" in
"default"|"external")
ISO_PATH="$chosen_path"
return 0
;;
"mount_usb")
mount_usb_device "$chosen_path"
return $?
;;
"manual")
read -p "Enter full path to ISO file: " custom_path
if [[ -f "$custom_path" ]]; then
ISO_PATH="$custom_path"
return 0
else
print_error "File not found: ${custom_path}"
return 1
fi
;;
"exit")
echo "Exiting."
exit 0
;;
esac
}
mount_usb_device() {
local device="$1"
local mount_dir="/mnt/usb_temp_$$"
print_info "Mounting ${device}..."
mkdir -p "$mount_dir"
if mount "$device" "$mount_dir"; then
print_success "Mounted ${device} to ${mount_dir}"
# Search for ISO on mounted device
local found_iso=$(find "$mount_dir" -maxdepth 2 -name "$ISO_NAME" -type f 2>/dev/null | head -1)
if [[ -n "$found_iso" ]]; then
print_success "Found ISO: ${found_iso}"
if confirm_action "Copy ISO to ${ISO_PATH}? (This will take several minutes for 30GB)"; then
print_info "Copying ISO... This may take a while."
# Ensure target directory exists
mkdir -p "$(dirname "$ISO_PATH")"
# Copy with progress using rsync if available, otherwise cp
if command -v rsync &>/dev/null; then
rsync -ah --progress "$found_iso" "$ISO_PATH"
else
cp -v "$found_iso" "$ISO_PATH"
fi
if [[ -f "$ISO_PATH" ]]; then
print_success "ISO copied successfully."
umount "$mount_dir"
rmdir "$mount_dir"
return 0
else
print_error "Failed to copy ISO."
fi
else
# Use directly from USB
ISO_PATH="$found_iso"
USB_MOUNT_DIR="$mount_dir" # Remember to cleanup later
print_info "Using ISO directly from USB (slower but no copy needed)"
return 0
fi
else
print_error "ISO file not found on ${device}"
echo "Files on device:"
ls -la "$mount_dir" | head -10
fi
umount "$mount_dir"
rmdir "$mount_dir"
return 1
else
print_error "Failed to mount ${device}"
rmdir "$mount_dir" 2>/dev/null
return 1
fi
}
#-------------------------------------------------------------------------------
# Main Script Functions
#-------------------------------------------------------------------------------
show_welcome() {
clear
print_header "RHEL 8.10 Offline Update Script"
echo "This script will guide you through applying updates from the ISO file:"
echo ""
echo " ISO File: ${ISO_NAME}"
echo " Mount Point: ${MOUNT_POINT}"
echo " Repo File: ${REPO_FILE}"
echo ""
echo "Steps this script will perform:"
echo " 1. Verify the ISO file exists"
echo " 2. Create mount point and mount the ISO"
echo " 3. Create the local repository configuration"
echo " 4. Refresh the package cache"
echo " 5. Show available updates"
echo " 6. Apply updates"
echo " 7. Check if reboot is required"
echo " 8. Cleanup (optional)"
echo ""
if ! confirm_action "Ready to begin?"; then
echo "Exiting."
exit 0
fi
}
step1_verify_iso() {
print_header "Step 1: Locate ISO File"
print_step "1" "Searching for ISO file..."
# Detect external media with ISO
detect_external_media
detect_unmounted_usb
# Check if ISO exists in default location
local iso_found=false
if [[ -f "$ISO_PATH" ]]; then
iso_found=true
fi
# Check if found on external media
if [[ ${#FOUND_ISO_LOCATIONS[@]} -gt 0 ]]; then
iso_found=true
fi
# Show what we found
if [[ "$iso_found" == true ]] || [[ ${#UNMOUNTED_USB_DEVICES[@]} -gt 0 ]]; then
# If only one option (default location) and no USB, use it directly
if [[ -f "$ISO_PATH" ]] && [[ ${#FOUND_ISO_LOCATIONS[@]} -eq 0 ]] && [[ ${#UNMOUNTED_USB_DEVICES[@]} -eq 0 ]]; then
print_success "ISO file found: ${ISO_PATH}"
local size=$(du -h "$ISO_PATH" | cut -f1)
print_info "File size: ${size}"
else
# Multiple options available - show menu
if ! show_iso_search_menu; then
print_error "Failed to locate ISO file."
exit 1
fi
print_success "Using ISO: ${ISO_PATH}"
fi
else
# Nothing found anywhere
print_error "ISO file not found."
echo ""
echo "The script searched for: ${ISO_NAME}"
echo ""
echo "Locations checked:"
echo " - ${ISO_PATH}"
echo " - /run/media/*/ (mounted USB drives)"
echo " - /media/*/"
echo " - /mnt/*/"
echo ""
if confirm_action "Would you like to enter the path manually?"; then
read -p "Enter full path to ISO file: " custom_path
if [[ -f "$custom_path" ]]; then
ISO_PATH="$custom_path"
print_success "Using ISO: ${ISO_PATH}"
else
print_error "File not found: ${custom_path}"
exit 1
fi
else
echo ""
echo "Please copy the ISO to /var/isos/ and run this script again."
echo ""
echo "Example from USB drive:"
echo " cp /run/media/\$(whoami)/USBDRIVE/${ISO_NAME} /var/isos/"
exit 1
fi
fi
# Verify the file is readable
if [[ ! -r "$ISO_PATH" ]]; then
print_error "ISO file exists but is not readable. Check permissions."
exit 1
fi
pause_continue
}
step2_mount_iso() {
print_header "Step 2: Mount the ISO"
print_step "2" "Creating mount point and mounting ISO..."
# Check if already mounted
if mountpoint -q "$MOUNT_POINT" 2>/dev/null; then
print_info "Mount point ${MOUNT_POINT} is already mounted."
if confirm_action "Would you like to unmount and remount?"; then
umount "$MOUNT_POINT"
else
print_info "Using existing mount."
pause_continue
return
fi
fi
# Create mount point if it doesn't exist
if [[ ! -d "$MOUNT_POINT" ]]; then
print_info "Creating mount point: ${MOUNT_POINT}"
mkdir -p "$MOUNT_POINT"
fi
# Mount the ISO
print_info "Mounting ISO..."
if mount -o loop "$ISO_PATH" "$MOUNT_POINT"; then
print_success "ISO mounted successfully to ${MOUNT_POINT}"
# Show contents
echo ""
print_info "ISO contents:"
ls -la "$MOUNT_POINT" | head -15
else
print_error "Failed to mount ISO."
exit 1
fi
pause_continue
}
step3_create_repo() {
print_header "Step 3: Create Repository Configuration"
print_step "3" "Creating local repository file..."
# Check if repo file already exists
if [[ -f "$REPO_FILE" ]]; then
print_info "Repo file already exists: ${REPO_FILE}"
echo ""
echo "Current contents:"
cat "$REPO_FILE"
echo ""
if ! confirm_action "Would you like to overwrite it?"; then
print_info "Keeping existing repo file."
pause_continue
return
fi
fi
# Create the repo file
cat > "$REPO_FILE" << 'EOF'
[dvd-rhel-patches]
name=DVD for RHEL Patches
baseurl=file:///media/JanPatch
enabled=1
gpgcheck=0
EOF
print_success "Repository file created: ${REPO_FILE}"
echo ""
echo "Contents:"
cat "$REPO_FILE"
pause_continue
}
step4_refresh_cache() {
print_header "Step 4: Refresh Package Cache"
print_step "4" "Cleaning and rebuilding DNF cache..."
print_info "Running: dnf clean all"
dnf clean all
echo ""
print_info "Running: dnf makecache"
dnf makecache
echo ""
print_info "Verifying repository is available..."
dnf repolist | grep -E "dvd-rhel-patches|repo id"
if dnf repolist | grep -q "dvd-rhel-patches"; then
print_success "Repository is available and ready."
else
print_error "Repository not found in repolist. Please check configuration."
fi
pause_continue
}
step5_check_updates() {
print_header "Step 5: Check Available Updates"
print_step "5" "Checking for available updates..."
print_info "Running: dnf check-update"
echo ""
# dnf check-update returns exit code 100 if updates are available
dnf check-update
local exit_code=$?
echo ""
if [[ $exit_code -eq 100 ]]; then
print_success "Updates are available (see list above)."
elif [[ $exit_code -eq 0 ]]; then
print_info "No updates available. System may already be up to date."
else
print_error "Error checking for updates."
fi
pause_continue
}
step6_apply_updates() {
print_header "Step 6: Apply Updates"
print_step "6" "Ready to apply updates..."
echo "This will install all available updates from the ISO."
echo ""
if ! confirm_action "Do you want to proceed with installing updates?"; then
print_info "Skipping update installation."
pause_continue
return
fi
echo ""
print_info "Running: dnf update -y"
echo ""
if dnf update -y; then
print_success "Updates installed successfully."
else
print_error "Some updates may have failed. Please review the output above."
fi
pause_continue
}
step7_check_reboot() {
print_header "Step 7: Check Reboot Status"
print_step "7" "Checking if a reboot is required..."
print_info "Running: needs-restarting -r"
echo ""
if needs-restarting -r; then
print_success "No reboot required."
else
print_info "A reboot is recommended to complete the update."
echo ""
if confirm_action "Would you like to reboot now?"; then
print_info "System will reboot in 10 seconds. Press Ctrl+C to cancel."
sleep 10
systemctl reboot
else
print_info "Please remember to reboot the system later."
fi
fi
pause_continue
}
step8_cleanup() {
print_header "Step 8: Cleanup (Optional)"
print_step "8" "Cleanup options..."
echo "You can now clean up the update configuration."
echo ""
# Disable repo
if confirm_action "Disable the dvd-rhel-patches repository?"; then
dnf config-manager --set-disabled dvd-rhel-patches
print_success "Repository disabled."
fi
# Remove repo file
if confirm_action "Remove the repo file (${REPO_FILE})?"; then
rm -f "$REPO_FILE"
print_success "Repo file removed."
fi
# Unmount ISO
if mountpoint -q "$MOUNT_POINT" 2>/dev/null; then
if confirm_action "Unmount the ISO from ${MOUNT_POINT}?"; then
umount "$MOUNT_POINT"
rmdir "$MOUNT_POINT" 2>/dev/null
print_success "ISO unmounted."
fi
fi
# Unmount USB if we mounted one
if [[ -n "$USB_MOUNT_DIR" ]] && mountpoint -q "$USB_MOUNT_DIR" 2>/dev/null; then
if confirm_action "Unmount the USB drive from ${USB_MOUNT_DIR}?"; then
umount "$USB_MOUNT_DIR"
rmdir "$USB_MOUNT_DIR" 2>/dev/null
print_success "USB drive unmounted. Safe to remove."
fi
fi
# Delete ISO (only if it's in /var/isos, not on USB)
if [[ -f "/var/isos/$ISO_NAME" ]]; then
if confirm_action "Delete the ISO file (/var/isos/${ISO_NAME})? This will free up ~30GB."; then
rm -f "/var/isos/$ISO_NAME"
print_success "ISO file deleted."
fi
fi
echo ""
print_success "Cleanup complete."
}
show_complete() {
print_header "Update Process Complete"
echo "The RHEL 8.10 update process has finished."
echo ""
echo "Summary:"
echo " - Updates were applied from: ${ISO_NAME}"
echo " - Check the output above for any errors"
echo ""
if needs-restarting -r 2>/dev/null; then
echo -e " - Reboot status: ${GREEN}Not required${NC}"
else
echo -e " - Reboot status: ${YELLOW}Reboot recommended${NC}"
fi
echo ""
echo "If you encounter any issues, contact the Cybersecurity Team."
echo ""
}
#-------------------------------------------------------------------------------
# Main Execution
#-------------------------------------------------------------------------------
main() {
check_root
show_welcome
step1_verify_iso
step2_mount_iso
step3_create_repo
step4_refresh_cache
step5_check_updates
step6_apply_updates
step7_check_reboot
step8_cleanup
show_complete
}
# Run main function
main