|
| 1 | +#!/usr/bin/env bash |
| 2 | + |
| 3 | +# The path to the directory that holds this script |
| 4 | +CURRENT_SCRIPT_DIR="$(dirname -- "$(readlink -f "${BASH_SOURCE[0]}")")" |
| 5 | + |
| 6 | +# This ceates a minimal set up in /tmp/debug-initramfs directory for |
| 7 | +# comparing built ipa initramfs the master ipa initramfs. |
| 8 | +set_up_debug_dirs() { |
| 9 | + # Export DISABLE_UPLOAD, ENABLE_BOOTSTRAP_TEST, TEST_IN_CI to allow local |
| 10 | + # test run. |
| 11 | + export DISABLE_UPLOAD="true" |
| 12 | + export ENABLE_BOOTSTRAP_TEST="false" |
| 13 | + export TEST_IN_CI="false" |
| 14 | + |
| 15 | + # Build ipa with build_ipa.sh |
| 16 | + cd "$CURRENT_SCRIPT_DIR/../jenkins/scripts/dynamic_worker_workflow" || exit |
| 17 | + if [[ ! -x ./build_ipa.sh ]]; then |
| 18 | + echo "Error: build_ipa.sh not found or not executable in $(pwd)" |
| 19 | + exit 1 |
| 20 | + fi |
| 21 | + ./build_ipa.sh |
| 22 | + |
| 23 | + # Even if build_ipa.sh exits with error this script can continue as long as |
| 24 | + # /tmp/dib/ironic-python-agent.initramfs has been created |
| 25 | + if [[ ! -f /tmp/dib/ironic-python-agent.initramfs ]]; then |
| 26 | + exit 1 |
| 27 | + fi |
| 28 | + |
| 29 | + # Unzip ironic-python-agent.initramfs |
| 30 | + sudo mkdir -p /tmp/debug-initramfs/build-ipa-initramfs |
| 31 | + sudo cp /tmp/dib/ironic-python-agent.initramfs /tmp/debug-initramfs/ |
| 32 | + cd /tmp/debug-initramfs/build-ipa-initramfs || exit |
| 33 | + gunzip -c ../ironic-python-agent.initramfs | sudo cpio -id |
| 34 | + |
| 35 | + # Get master ironic-python-agent.initramfs and unzip |
| 36 | + sudo mkdir -p /tmp/debug-initramfs/master-ipa-initramfs |
| 37 | + cd /tmp/debug-initramfs || exit |
| 38 | + sudo wget https://tarballs.opendev.org/openstack/ironic-python-agent/dib/ipa-centos9-master.tar.gz |
| 39 | + sudo tar -xzf ipa-centos9-master.tar.gz |
| 40 | + cd master-ipa-initramfs || exit |
| 41 | + gunzip -c ../ipa-centos9-master.initramfs | sudo cpio -id |
| 42 | +} |
| 43 | + |
| 44 | +# ----------------------------------------------------------------------------- |
| 45 | +# compare_dir_sizes <relative_path> [base_dir1] [base_dir2] |
| 46 | +# |
| 47 | +# Compares the sizes of files and directories at the given <relative_path> |
| 48 | +# inside two extracted initramfs directories (or any two directories). |
| 49 | +# |
| 50 | +# Usage examples: |
| 51 | +# ./ipa_debug_tools.sh compare_dir_sizes |
| 52 | +# ./ipa_debug_tools.sh compare_dir_sizes usr |
| 53 | +# ./ipa_debug_tools.sh compare_dir_sizes usr/lib ~/ipa-build-initramfs ~/ipa-initramfs |
| 54 | +# ./ipa_debug_tools.sh compare_dir_sizes . ~/ipa-build-initramfs ~/ipa-initramfs |
| 55 | +# |
| 56 | +# - <relative_path>: Path inside the compared directories (e.g., usr, usr/lib) |
| 57 | +# - [base_dir1]: First base directory (default: /tmp/debug-initramfs/build-ipa-initramfs) |
| 58 | +# - [base_dir2]: Second base directory (default: /tmp/debug-initramfs/master-ipa-initramfs) |
| 59 | +# |
| 60 | +# The function prints a table of entries, their sizes in both directories, |
| 61 | +# and the size difference. It also lists files only present in one directory. |
| 62 | +# ----------------------------------------------------------------------------- |
| 63 | +compare_dir_sizes() { |
| 64 | + path="${1:-}" |
| 65 | + basedir1="${2:-/tmp/debug-initramfs/build-ipa-initramfs}" |
| 66 | + basedir2="${3:-/tmp/debug-initramfs/master-ipa-initramfs}" |
| 67 | + |
| 68 | + dir1="${basedir1}/${path}" |
| 69 | + dir2="${basedir2}/${path}" |
| 70 | + |
| 71 | + # Color codes |
| 72 | + RED='\033[0;31m' |
| 73 | + GREEN='\033[0;32m' |
| 74 | + YELLOW='\033[1;33m' |
| 75 | + BLUE='\033[0;34m' |
| 76 | + PURPLE='\033[0;35m' |
| 77 | + CYAN='\033[0;36m' |
| 78 | + NC='\033[0m' # No Color |
| 79 | + BOLD='\033[1m' |
| 80 | + |
| 81 | + echo -e "${CYAN}📊 Comparing directories:${NC}" |
| 82 | + echo -e " ${BLUE}🏗️ Build IPA:${NC} ${dir1}" |
| 83 | + echo -e " ${GREEN}🎯 Master IPA:${NC} ${dir2}" |
| 84 | + echo "" |
| 85 | + |
| 86 | + # Print table header |
| 87 | + printf "${BOLD}%-40s %-22s %-22s %-22s${NC}\n" "Directory/File" "🏗️ Build" "🎯 Master" "📏 Diff" |
| 88 | + echo "=======================================================================================================" |
| 89 | + |
| 90 | + tmpfile=$(mktemp) |
| 91 | + checked=0 |
| 92 | + skipped=0 |
| 93 | + |
| 94 | + # Compare entries present in both directories |
| 95 | + find "${dir1}" -mindepth 1 -maxdepth 1 -printf '%f\n' | sort > /tmp/dir1_list |
| 96 | + find "${dir2}" -mindepth 1 -maxdepth 1 -printf '%f\n' | sort > /tmp/dir2_list |
| 97 | + comm -12 /tmp/dir1_list /tmp/dir2_list | while IFS= read -r name; do |
| 98 | + # Get size in bytes for each entry |
| 99 | + bsize=$(du -sb "${dir1}/${name}" 2>/dev/null | cut -f1) |
| 100 | + isize=$(du -sb "${dir2}/${name}" 2>/dev/null | cut -f1) |
| 101 | + # Calculate absolute difference |
| 102 | + diff=$(( bsize > isize ? bsize - isize : isize - bsize )) |
| 103 | + echo -e "${name}\t${bsize}\t${isize}\t${diff}" |
| 104 | + done | sort -k4,4nr > "${tmpfile}" |
| 105 | + |
| 106 | + # Print entries with size differences |
| 107 | + while IFS=$'\t' read -r name bsize isize diff; do |
| 108 | + checked=$((checked+1)) |
| 109 | + if [[ "${diff}" -eq 0 ]]; then |
| 110 | + skipped=$((skipped+1)) |
| 111 | + continue |
| 112 | + fi |
| 113 | + |
| 114 | + # Color code based on size difference magnitude |
| 115 | + if [[ "${diff}" -gt 10485760 ]]; then # > 10MB |
| 116 | + diff_color="${RED}" |
| 117 | + icon="🔴" |
| 118 | + elif [[ "${diff}" -gt 1048576 ]]; then # > 1MB |
| 119 | + diff_color="${YELLOW}" |
| 120 | + icon="🟡" |
| 121 | + else |
| 122 | + diff_color="${GREEN}" |
| 123 | + icon="🟢" |
| 124 | + fi |
| 125 | + |
| 126 | + printf "%-40s ${BLUE}%-22s${NC} ${GREEN}%-22s${NC} ${diff_color}%s %-21s${NC}\n" \ |
| 127 | + "${name}" \ |
| 128 | + "$(numfmt --to=iec "${bsize}")" \ |
| 129 | + "$(numfmt --to=iec "${isize}")" \ |
| 130 | + "${icon}" \ |
| 131 | + "$(numfmt --to=iec "${diff}")" |
| 132 | + done < "$tmpfile" |
| 133 | + |
| 134 | + echo -e "\n${PURPLE}📈 Summary:${NC} Checked ${BOLD}${checked}${NC} common entries, skipped ${BOLD}${skipped}${NC} identical sizes." |
| 135 | + echo "=======================================================================================================" |
| 136 | + |
| 137 | + rm -f "${tmpfile}" |
| 138 | + |
| 139 | + # List files only in dir1 |
| 140 | + echo -e "\n${BLUE}🏗️ Only in Build IPA (${dir1}):${NC}" |
| 141 | + echo "-------------------------------------------------------------------------------------------------------" |
| 142 | + comm -23 /tmp/dir1_list /tmp/dir2_list | while IFS= read -r name; do |
| 143 | + bsize=$(du -sb "${dir1}/${name}" 2>/dev/null | cut -f1) |
| 144 | + echo -e "${bsize}\t${name}" |
| 145 | + done | sort -k1,1nr | while IFS=$'\t' read -r bsize name; do |
| 146 | + printf "${BLUE}%-40s %-22s${NC}\n" "➕ ${name}" "$(numfmt --to=iec ${bsize})" |
| 147 | + done |
| 148 | + |
| 149 | + echo "=======================================================================================================" |
| 150 | + |
| 151 | + # List files only in dir2 |
| 152 | + echo -e "\n${GREEN}🎯 Only in Master IPA (${dir2}):${NC}" |
| 153 | + echo "-------------------------------------------------------------------------------------------------------" |
| 154 | + comm -13 /tmp/dir1_list /tmp/dir2_list | while IFS= read -r name; do |
| 155 | + isize=$(du -sb "${dir2}/${name}" 2>/dev/null | cut -f1) |
| 156 | + echo -e "${isize}\t${name}" |
| 157 | + done | sort -k1,1nr | while IFS=$'\t' read -r isize name; do |
| 158 | + printf "${GREEN}%-40s %-22s${NC}\n" "➕ ${name}" "$(numfmt --to=iec ${isize})" |
| 159 | + done |
| 160 | + |
| 161 | + # Print some empty lines for clarity |
| 162 | + echo "" |
| 163 | + echo "" |
| 164 | + echo "" |
| 165 | + |
| 166 | + # Remove temporary dir lists |
| 167 | + rm /tmp/dir1_list /tmp/dir2_list |
| 168 | +} |
| 169 | + |
| 170 | +# Print a rpm package list. The print omits packages that are identical in both |
| 171 | +#the built ipa and master. |
| 172 | +# Check if packages are a part of CentOS Stream in https://pkgs.org |
| 173 | +compare_rpm_packages() { |
| 174 | + basedir1="${1:-/tmp/debug-initramfs/build-ipa-initramfs}" |
| 175 | + basedir2="${2:-/tmp/debug-initramfs/master-ipa-initramfs}" |
| 176 | + compfile1="/tmp/build-ipa-rpm.txt" |
| 177 | + compfile2="/tmp/master-ipa-rpm.txt" |
| 178 | + |
| 179 | + sudo chroot "${basedir1}" rpm -qa | sort > "${compfile1}" |
| 180 | + sudo chroot "${basedir2}" rpm -qa | sort > "${compfile2}" |
| 181 | + |
| 182 | + common_count=$(comm -12 "${compfile1}" "${compfile2}" | wc -l) |
| 183 | + echo -e "\nNumber of common packages: ${common_count}\n" |
| 184 | + # Extract base package names and join for fuzzy matching |
| 185 | + awk -F'-[0-9]' '{print $1}' "${compfile1}" | sort > /tmp/build-ipa-base.txt |
| 186 | + awk -F'-[0-9]' '{print $1}' "${compfile2}" | sort > /tmp/master-ipa-base.txt |
| 187 | + |
| 188 | + printf "%-65s | %-65s\n" "In ${basedir1}" "In ${basedir2}" |
| 189 | + printf -- "----------------------------------------------------------------------------------------------------------------------------------\n" |
| 190 | + |
| 191 | + join -a1 -a2 -e '' -o 1.1,2.1 /tmp/build-ipa-base.txt /tmp/master-ipa-base.txt | \ |
| 192 | + while IFS=' ' read -r left right; do |
| 193 | + # Find the full package lines for each base name |
| 194 | + lfull=$(grep -m1 "^${left}-" "${compfile1}" || echo "") |
| 195 | + rfull=$(grep -m1 "^${right}-" "${compfile2}" || echo "") |
| 196 | + # Skip printing if both lines are non-empty and exactly the same |
| 197 | + if [[ -n "${lfull}" && "${lfull}" == "${rfull}" ]]; then |
| 198 | + continue |
| 199 | + fi |
| 200 | + printf "%-65s | %-65s\n" "${lfull}" "${rfull}" |
| 201 | + done |
| 202 | + |
| 203 | + sudo rm -f "${compfile1}" "${compfile2}" /tmp/build-ipa-base.txt /tmp/master-ipa-base.txt |
| 204 | +} |
| 205 | + |
| 206 | +# After debugging and comparison operations, temporary directories can be cleaned up. |
| 207 | +# Usage: |
| 208 | +# ./ipa_debug_tools.sh clean_up_debug_dirs |
| 209 | +# ----------------------------------------------------------------------------- |
| 210 | +clean_up_debug_dirs() { |
| 211 | + # Clean up debug directories |
| 212 | + sudo rm -rf /tmp/debug-initramfs |
| 213 | +} |
| 214 | + |
| 215 | +# Allow calling functions |
| 216 | +# ----------------------------------------------------------------------------- |
| 217 | +function_name="$1" |
| 218 | +shift |
| 219 | + |
| 220 | +# Check if function exists and call it |
| 221 | +if declare -f "$function_name" > /dev/null; then |
| 222 | + "$function_name" "$@" |
| 223 | +else |
| 224 | + echo "Error: Function '$function_name' not found" |
| 225 | + echo "Available functions: set_up_debug_dirs, compare_dir_sizes, compare_rpm_packages, clean_up_debug_dirs" |
| 226 | + exit 1 |
| 227 | +fi |
0 commit comments