├── LICENSE.md
├── README.md
├── assets
├── README.md
├── banner.png
├── example-1.2.png
├── example-2.0.2.png
└── example-2.0.jpg
├── pvekclean.sh
└── version.txt
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Jordan Hillis - jordan@hillis.email - https://jordanhillis.com
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | Easily remove old/unused PVE kernels on your Proxmox VE system
4 |
5 | [](https://github.com/jordanhillis/pvekclean)
6 | [](https://opensource.org/licenses/MIT)
7 | 
8 | 
9 | 
10 |
11 | ### What is PVE Kernel Cleaner?
12 |
13 | PVE Kernel Cleaner is a program to compliment Proxmox Virtual Environment which is an open-source server virtualization environment. PVE Kernel Cleaner allows you to purge old/unused kernels filling the /boot directory. As new kernels are released the older ones have to be manually removed frequently to make room for newer ones. This can become quite tedious and require extensive time spent monitoring the system when new kernels are released and when older ones need to be cleared out to make room. With this issue existing, PVE Kernel Cleaner was created to solve it.
14 |
15 | ## Example Usage
16 |
17 | 
18 |
19 | ## Features
20 |
21 | * Removes old PVE kernels from your system
22 | * Ability to schedule PVE kernels to automatically be removed on a daily/weekly/monthly basis
23 | * Run a simple pvekclean command for ease of access
24 | * Checks health of boot disk based on space available
25 | * Debug mode for non-destructive testing
26 | * Update function to easily update the program to the latest version
27 | * Allows you to specify the minimum number of most recent PVE kernels to retain
28 | * Support for the latest Proxmox versions and PVE kernels
29 |
30 | ## Latest Version
31 |
32 | * v2.0.2
33 |
34 | ## Prerequisites
35 |
36 | Before using this program you will need to have the following packages installed.
37 | * cron
38 | * curl
39 | * git
40 |
41 | To install all required packages enter the following command.
42 |
43 | ##### Debian:
44 |
45 | ```
46 | sudo apt-get install cron curl git
47 | ```
48 |
49 | ## Installing
50 |
51 | You can install PVE Kernel Cleaner using either Git or Curl. Choose the method that suits you best:
52 |
53 | ### Installation via Git
54 |
55 | 1. Open your terminal.
56 |
57 | 2. Enter the following commands one by one to install PVE Kernel Cleaner:
58 |
59 | ```bash
60 | git clone https://github.com/jordanhillis/pvekclean.git
61 | cd pvekclean
62 | chmod +x pvekclean.sh
63 | ./pvekclean.sh
64 | ```
65 | ### Installation via Curl
66 |
67 | 1. Open your terminal.
68 |
69 | 2. Use the following command to install PVE Kernel Cleaner:
70 |
71 | ```bash
72 | curl -o pvekclean.sh https://raw.githubusercontent.com/jordanhillis/pvekclean/master/pvekclean.sh
73 | chmod +x pvekclean.sh
74 | ./pvekclean.sh
75 | ```
76 |
77 | ## Updating
78 |
79 | PVE Kernel Cleaner checks for updates automatically when you run it. If an update is available, you'll be notified within the program. Simply follow the on-screen instructions to install the update, and you're all set with the latest version!
80 |
81 | ## Usage
82 |
83 | Example of usage:
84 | ```
85 | pvekclean [OPTION1] [OPTION2]...
86 |
87 | -k, --keep [number] Keep the specified number of most recent PVE kernels on the system
88 | Can be used with -f or --force for non-interactive removal
89 | -f, --force Force the removal of old PVE kernels without confirm prompts
90 | -rn, --remove-newer Remove kernels that are newer than the currently running kernel
91 | -s, --scheduler Have old PVE kernels removed on a scheduled basis
92 | -v, --version Shows current version of pvekclean
93 | -r, --remove Uninstall pvekclean from the system
94 | -i, --install Install pvekclean to the system
95 | -d, --dry-run Run the program in dry run mode for testing without making system changes
96 |
97 | ```
98 |
99 | ## Usage Examples:
100 | Here are some common ways to use PVE Kernel Cleaner:
101 |
102 | * **Remove Old Kernels Non-Interactively:**
103 | ```bash
104 | pvekclean -f
105 | ```
106 | This command removes old PVE kernels without requiring user confirmation.
107 |
108 | * **Set Number of Kernels to Keep:**
109 | ```bash
110 | pvekclean -k 3
111 | ```
112 | This command specifies the number of most recent PVE kernels to keep on the system.
113 |
114 | * **Force Remove Old Kernels While Keeping a Certain Number:**
115 | ```bash
116 | pvekclean -f -k 3
117 | ```
118 | This command forces the removal of old PVE kernels while retaining a specific number of the most recent ones.
119 |
120 | * **Remove Newer Kernels and Keep a Specific Number:**
121 | ```bash
122 | pvekclean -rn -k 2
123 | ```
124 | This command removes newer PVE kernels and keeps a specified number of the most recent ones.
125 |
126 | * **Schedule Regular Kernel Removal:**
127 | ```bash
128 | pvekclean -s
129 | ```
130 | This command sets up PVE Kernel Cleaner to remove old PVE kernels on a scheduled basis. You can configure the schedule according to your needs.
131 |
132 | * **Perform a Dry Run without Making Changes:**
133 | ```bash
134 | pvekclean -d
135 | ```
136 | This command runs PVE Kernel Cleaner in dry run mode, simulating actions without actually removing any kernels or making changes to your system. It's useful for testing and understanding what the script would do.
137 |
138 | ## Developers
139 |
140 | * **Jordan Hillis** - *Lead Developer*
141 |
142 | ## License
143 |
144 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details
145 |
146 | ## Acknowledgments
147 |
148 | * This program is not an official program by Proxmox Server Solutions GmbH
149 |
--------------------------------------------------------------------------------
/assets/README.md:
--------------------------------------------------------------------------------
1 | Asset files here only. Not intended for program use.
2 |
--------------------------------------------------------------------------------
/assets/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jordanhillis/pvekclean/5739796801762520bcf4d66ad1b2b09638ad373b/assets/banner.png
--------------------------------------------------------------------------------
/assets/example-1.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jordanhillis/pvekclean/5739796801762520bcf4d66ad1b2b09638ad373b/assets/example-1.2.png
--------------------------------------------------------------------------------
/assets/example-2.0.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jordanhillis/pvekclean/5739796801762520bcf4d66ad1b2b09638ad373b/assets/example-2.0.2.png
--------------------------------------------------------------------------------
/assets/example-2.0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jordanhillis/pvekclean/5739796801762520bcf4d66ad1b2b09638ad373b/assets/example-2.0.jpg
--------------------------------------------------------------------------------
/pvekclean.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | : '
3 | ______________________________________________
4 |
5 | PVE Kernel Cleaner
6 | By Jordan Hillis
7 | jordan@hillis.email
8 | https://jordanhillis.com
9 | ______________________________________________
10 |
11 | MIT License
12 |
13 | Copyright (c) 2023 Jordan Hillis - jordan@hillis.email - https://jordanhillis.com
14 |
15 | Permission is hereby granted, free of charge, to any person obtaining a copy
16 | of this software and associated documentation files (the "Software"), to deal
17 | in the Software without restriction, including without limitation the rights
18 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19 | copies of the Software, and to permit persons to whom the Software is
20 | furnished to do so, subject to the following conditions:
21 | The above copyright notice and this permission notice shall be included in all
22 | copies or substantial portions of the Software.
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 | SOFTWARE.
30 | ______________________________________________
31 | '
32 |
33 | # Percentage of used space in the /boot which would consider it critically full
34 | boot_critical_percent="80"
35 |
36 | # To check for updates or not
37 | check_for_updates=true
38 |
39 | # Dry run mode is for testing without actually removing anything
40 | dry_run=false
41 |
42 | # Current kernel
43 | current_kernel=$(uname -r)
44 |
45 | # Name of the program
46 | program_name="pvekclean"
47 |
48 | # Version
49 | version="2.0.2"
50 |
51 | # Text Colors
52 | black="\e[38;2;0;0;0m"
53 | gray="\e[30m"
54 | red="\e[31m"
55 | green="\e[32m"
56 | yellow="\e[33m"
57 | blue="\e[34m"
58 | magenta="\e[35m"
59 | cyan="\e[36m"
60 | white="\e[37m"
61 | orange="\e[38;5;202m"
62 |
63 | # Background Colors
64 | bg_black="\e[40m"
65 | bg_red="\e[41m"
66 | bg_green="\e[42m"
67 | bg_yellow="\e[43m"
68 | bg_blue="\e[44m"
69 | bg_magenta="\e[45m"
70 | bg_cyan="\e[46m"
71 | bg_white="\e[47m"
72 | bg_orange="\e[48;5;202m"
73 |
74 | # Text Styles
75 | bold="\e[1m"
76 |
77 | # Reset formatting
78 | reset="\e[0m"
79 |
80 | # Force purging without dialog confirms
81 | force_purge=false
82 |
83 | # Allow removing kernels newer than current
84 | remove_newer=false
85 |
86 | # Check if script is ran as root, if not exit
87 | check_root() {
88 | if [[ $EUID -ne 0 ]]; then
89 | printf "${bold}[!] Error:${reset} this script must be ran as the root user.\n"
90 | exit 1
91 | fi
92 | }
93 |
94 | # Shown current version
95 | version() {
96 | printf $version"\n"
97 | exit 0
98 | }
99 |
100 | # Header for PVE Kernel Cleaner
101 | header_info() {
102 | echo -e " ${bg_black}${orange} ${reset}
103 | ${bg_black}${orange} █▀▀█ ▀█ █▀ █▀▀ █ █ █▀▀ █▀▀█ █▀▀▄ █▀▀ █ ${reset}
104 | ${bg_black}${orange} █ █ █▄█ █▀▀ █▀▄ █▀▀ █▄▄▀ █ █ █▀▀ █ ${reset}
105 | ${bg_black}${orange} █▀▀▀ ▀ ▀▀▀ ▀ ▀ ▀▀▀ ▀ ▀▀ ▀ ▀ ▀▀▀ ▀▀▀ ${reset}
106 | ${bg_black}${orange} ${reset}
107 | ${bg_black}${white} █▀▀ █ █▀▀ █▀▀█ █▀▀▄ █▀▀ █▀▀█ ${reset}
108 | ${bg_black}${white} █ █ █▀▀ █▄▄█ █ █ █▀▀ █▄▄▀ ${white}${bold}⎦˚◡˚⎣ v$version ${reset}
109 | ${bg_black}${white} ▀▀▀ ▀▀▀ ▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀ ▀ ▀▀ ${reset}
110 | ${bg_orange}${black} ${bold}By Jordan Hillis [jordan@hillis.email] ${reset}
111 | ___________________________________________
112 | "
113 | if [ "$dry_run" == "true" ]; then
114 | printf " ${bg_yellow}${black}${bold} DRY RUN MODE IS: ${red}ON ${reset}\n"
115 | printf "${bg_green}${bold}${black} This is what the script would do in regular mode ${reset}\n${bg_green}${bold}${black} (but without making actual changes) ${reset}\n\n"
116 | fi
117 | }
118 |
119 | # Function to get drive status based on usage percentage
120 | get_drive_status() {
121 | local usage=$1
122 | # Check if the input is a number
123 | if ! [[ $usage =~ ^[0-9]+$ ]]; then
124 | echo "${bold}N/A${reset}"
125 | else
126 | if (( usage <= 50 )); then
127 | echo "${bold}${green}Healthy${reset}"
128 | elif (( usage > 50 && usage <= 75 )); then
129 | echo "${bold}${orange}Moderate Capacity${reset}"
130 | else
131 | echo "${bold}${red}Critically Full${reset}"
132 | fi
133 | fi
134 | }
135 |
136 | # Show current system information
137 | kernel_info() {
138 | # Lastest kernel installed
139 | latest_kernel=$(dpkg --list | awk '/proxmox-kernel-.*-pve/{print $2}' | sed -n 's/proxmox-kernel-//p' | sort -V | tail -n 1 | tr -d '[:space:]')
140 | [ -z "$latest_kernel" ] && latest_kernel="N/A"
141 | # Show operating system used
142 | printf " ${bold}OS:${reset} $(cat /etc/os-release | grep "PRETTY_NAME" | sed 's/PRETTY_NAME=//g' | sed 's/["]//g' | awk '{print $0}')\n"
143 | # Get information about the /boot folder
144 | boot_info=($(echo $(df -Ph | grep /boot | tail -1) | sed 's/%//g'))
145 | # Show information about the /boot
146 | printf " ${bold}Boot Disk:${reset} ${boot_info[4]}%% full [${boot_info[2]}/${boot_info[1]} used, ${boot_info[3]} free] \n"
147 | # Show current kernel in use
148 | printf " ${bold}Current Kernel:${reset} $current_kernel\n"
149 | # Check if they are running a PVE kernel
150 | if [[ "$current_kernel" == *"pve"* ]]; then
151 | # Check if we are running the latest kernel, if not warn
152 | if [[ "$latest_kernel" != *"$current_kernel"* ]]; then
153 | printf " ${bold}Latest Kernel:${reset} ${latest_kernel}\n"
154 | fi
155 | # Warn them that they aren't on a PVE kernel
156 | else
157 | printf "___________________________________________\n\n"
158 | printf "${bold}[!]${reset} Warning, you're not running a PVE kernel\n"
159 | # Ask them if they want to continue
160 | printf "${bold}[*]${reset} Would you like to continue [y/N] "
161 | read -n 1 -r
162 | printf "\n"
163 | if [[ $REPLY =~ ^[Yy]$ ]]; then
164 | # Continue on if they wish
165 | printf "${bold}[-]${reset} Alright, we will continue on\n"
166 | else
167 | # Exit script
168 | printf "\nGood bye!\n"
169 | exit 0
170 | fi
171 | fi
172 | printf "___________________________________________\n\n"
173 | }
174 |
175 | # Usage information on how to use PVE Kernel Clean
176 | show_usage() {
177 | # Skip showing usage when force_purge is enabled
178 | if [ $force_purge == false ]; then
179 | printf "${bold}Usage:${reset} $(basename $0) [OPTION1] [OPTION2]...\n\n"
180 | printf " -k, --keep [number] Keep the specified number of most recent PVE kernels on the system\n"
181 | printf " Can be used with -f or --force for non-interactive removal\n"
182 | printf " -f, --force Force the removal of old PVE kernels without confirm prompts\n"
183 | printf " -rn, --remove-newer Remove kernels that are newer than the currently running kernel\n"
184 | printf " -s, --scheduler Have old PVE kernels removed on a scheduled basis\n"
185 | printf " -v, --version Shows current version of $program_name\n"
186 | printf " -r, --remove Uninstall $program_name from the system\n"
187 | printf " -i, --install Install $program_name to the system\n"
188 | printf " -d, --dry-run Run the program in dry run mode for testing without making system changes\n"
189 | printf "___________________________________________\n\n"
190 | fi
191 | }
192 |
193 | # Schedule PVE Kernel Cleaner at a time desired
194 | scheduler() {
195 | # Check if pvekclean is on the system, if not exit
196 | if [ ! -f /usr/local/sbin/$program_name ]; then
197 | printf "${bold}[!]${reset} Sorry $program_name is required to be installed on the system for this functionality.\n"
198 | exit 1
199 | fi
200 | # Check if cron is installed
201 | if ! [ -x "$(command -v crontab)" ]; then
202 | printf "${bold}[*]${reset} Error, cron does not appear to be installed.\n"
203 | printf " Please install cron with the command 'sudo apt-get install cron'\n\n"
204 | exit 1
205 | fi
206 | # Check if the cronjob exists on the system
207 | check_cron_exists=$(crontab -l | grep "$program_name")
208 | # Cronjob exists
209 | if [ -n "$check_cron_exists" ]; then
210 | # Get the current cronjob scheduling
211 | cron_current=$(crontab -l | grep "$program_name" | sed "s/[^a-zA-Z']/ /g" | sed -e "s/\b\(.\)/\u\1/g" | awk '{print $1;}')
212 | # Ask the user if they would like to remove the scheduling
213 | printf "${bold}[-]${reset} Would you like to remove the currently scheduled PVE Kernel Cleaner? (Current: $cron_current) [y/N] "
214 | read -n 1 -r
215 | if [[ $REPLY =~ ^[Yy]$ ]]; then
216 | # Remove the cronjob
217 | (crontab -l | grep -v "$program_name")| crontab -
218 | printf "\n[*] Successfully removed the ${cron_current,,} scheduled PVE Kernel Cleaner!\n"
219 | else
220 | # Keep it
221 | printf "\n\nAlright we will keep your current settings then.\n"
222 | fi
223 | # Cronjob does not exist
224 | else
225 | # Ask how often the would like to check for old PVE kernels
226 | printf "${bold}[-]${reset} How often would you like to check for old PVE kernels?\n 1) Daily\n 2) Weekly\n 3) Monthly\n\n - Enter a number option above? "
227 | read -r -p "" response
228 | case "$response" in
229 | 1)
230 | cron_time="daily"
231 | ;;
232 | 2)
233 | cron_time="weekly"
234 | ;;
235 | 3)
236 | cron_time="monthly"
237 | ;;
238 | *)
239 | printf "\nThat is not a valid option!\n"
240 | exit 1
241 | ;;
242 | esac
243 | # Ask if they want to set a specific number of kernels to keep
244 | printf "${bold}[-]${reset} Enter the number of latest kernels to keep (or press Enter to skip): "
245 | read number_of_kernels
246 | if [[ "$number_of_kernels" =~ ^[0-9]+$ ]]; then
247 | kernel_option=" -k $number_of_kernels"
248 | printf "${bold}[-]${reset} Okay, we will keep at least $number_of_kernels kernels on the system."
249 | else
250 | kernel_option=""
251 | fi
252 | # Add the cronjob
253 | (crontab -l ; echo "@$cron_time /usr/local/sbin/$program_name -f$kernel_option")| crontab -
254 | printf "\n[-] Scheduled $cron_time PVE Kernel Cleaner successfully!\n"
255 | fi
256 | exit 0
257 | }
258 |
259 | # Installs PVE Kernel Cleaner for easier access
260 | install_program() {
261 | force_pvekclean_update=false
262 | local tmp_file="/tmp/.pvekclean_install_lock"
263 | local install=false
264 | local ask_interval=3600 # 1 hour in seconds
265 | # If pvekclean exists on the system
266 | if [ -e /usr/local/sbin/$program_name ]; then
267 | # Get current version of pvekclean
268 | pvekclean_installed_version=$(/usr/local/sbin/$program_name -v | awk '{printf $0}')
269 | # If the version differs, update it to the latest from the script
270 | if [ $version != $pvekclean_installed_version ] && [ $force_purge == false ]; then
271 | printf "${bold}[!]${reset} A new version of PVE Kernel Cleaner has been detected (Installed: $pvekclean_installed_version | New: $version).\n"
272 | printf "${bold}[*]${reset} Installing update...\n"
273 | force_pvekclean_update=true
274 | fi
275 | fi
276 | # Check if the file doesn't exist or it's been over an hour since the last ask
277 | if [ ! -e "$tmp_file" ] || [ ! -f "$tmp_file" ] || [ $(( $(date +%s) - $(cat "$tmp_file") )) -gt $ask_interval ] || [ $force_pvekclean_update == true ] || [ -n "$force_pvekclean_install" ]; then
278 | # If pvekclean does not exist on the system or force_purge is enabled
279 | if [ ! -f /usr/local/sbin/$program_name ] || [ $force_pvekclean_update == true ] || [ -n "$force_pvekclean_install" ]; then
280 | # Ask user if we can install it to their system
281 | if [ $force_purge == true ]; then
282 | REPLY="n"
283 | else
284 | # Update the timestamp in the file to record the time of the last ask
285 | echo $(date +%s) > "$tmp_file"
286 | # Ask if we can install it
287 | printf "${bold}[-]${reset} Can we install PVE Kernel Cleaner to your /usr/local/sbin for easier access [y/N] "
288 | read -n 1 -r
289 | printf "\n"
290 | fi
291 | # User agrees to have it installed
292 | if [[ $REPLY =~ ^[Yy]$ ]]; then
293 | # Copy the script to /usr/local/sbin and set execution permissions
294 | cp $0 /usr/local/sbin/$program_name
295 | chmod +x /usr/local/sbin/$program_name
296 | # Tell user how to use it
297 | printf "${bold}[*]${reset} Installed PVE Kernel Cleaner to /usr/local/sbin/$program_name\n"
298 | printf "${bold}[*]${reset} Run the command \"$program_name\" to begin using this program.\n"
299 | printf "${bold}[-]${reset} Run the command \"$program_name -r\" to remove this program at any time.\n"
300 | exit 0
301 | fi
302 | fi
303 | fi
304 | if [ -n "$force_pvekclean_install" ]; then
305 | exit 0
306 | fi
307 | }
308 |
309 | # Uninstall pvekclean from the system
310 | uninstall_program() {
311 | # If pvekclean exists on the system
312 | if [ -e /usr/local/sbin/$program_name ]; then
313 | # Confirm that they wish to remove it
314 | printf "${bold}[-]${reset} Are you sure that you would like to remove $program_name? [y/N] "
315 | read -n 1 -r
316 | printf "\n"
317 | if [[ $REPLY =~ ^[Yy]$ ]]; then
318 | # Remove the program
319 | rm -f /usr/local/sbin/$program_name
320 | printf "${bold}[*]${reset} Successfully removed PVE Kernel Cleaner from the system!\n"
321 | printf "${bold}[-]${reset} Sorry to see you go :(\n"
322 | else
323 | printf "\nExiting...\nThat was a close one ⎦˚◡˚⎣\n"
324 | fi
325 | exit 0
326 | else
327 | # Tell the user that it is not installed
328 | printf "${bold}[!]${reset} This program is not installed on the system.\n"
329 | exit 1
330 | fi
331 | }
332 |
333 | # PVE Kernel Clean main function
334 | pve_kernel_clean() {
335 | # Find all the PVE kernels on the system
336 | kernels=$(dpkg --list | grep -E "(pve-kernel|proxmox-kernel)-[0-9].*" | grep -E "Kernel Image" | grep -vE "${latest_kernel%-pve}|series|transitional" | awk '{print $2}' | sed -n 's/\(pve\|proxmox\)-kernel-\(.*\)/\2/p' | sort -V)
337 | # List of kernels that will be removed (adds them as the script goes on)
338 | kernels_to_remove=()
339 | # Boot drive status
340 | boot_drive_status=$(get_drive_status ${boot_info[4]})
341 | # Show space used, status and free space available
342 | printf "${bold}[*]${reset} Boot disk space used is ${bold}${boot_drive_status}${reset} at ${boot_info[4]}%% capacity (${boot_info[3]} free)\n"
343 | # For each kernel that was found via dpkg
344 | current_kernel_passed=false
345 | for kernel in $kernels
346 | do
347 | # Check if the kernel is already in the array
348 | if [[ " ${kernels_to_remove[@]} " =~ " $kernel " ]]; then
349 | continue # Skip adding it again
350 | fi
351 | # Only if not removing newer kernels and kernel matches the current kernel
352 | if [ "$(echo $kernel | grep "$current_kernel")" ]; then
353 | if [ "$remove_newer" == "false" ]; then
354 | break
355 | else
356 | current_kernel_passed=true
357 | continue
358 | fi
359 | # Add kernel to the list of removal since it is old
360 | else
361 | kernels_to_remove+=("$kernel") # Add the kernel to the array
362 | fi
363 | done
364 | # If remove_newer is set keep the last kernel installed as its newest
365 | # if [ "$remove_newer" == "true" ] && [ "$current_kernel_passed" == "true" ] && [ ${#kernels_to_remove[@]} -gt 0 ]; then
366 | # unset kernels_to_remove[-1]
367 | # fi
368 | # If keep_kernels is set we remove this number from the array to remove
369 | if [[ -n "$keep_kernels" ]] && [[ "$keep_kernels" =~ ^[0-9]+$ ]]; then
370 | if [ $keep_kernels -gt 0 ]; then
371 | printf "${bold}[*]${reset} The last ${bold}$keep_kernels${reset} kernel$([ "$keep_kernels" -eq 1 ] || echo 's') will be held back from being removed.\n"
372 | # Check if the number of kernels to keep is greater than or equal to the number of kernels in the array
373 | if [ "$keep_kernels" -ge "${#kernels_to_remove[@]}" ]; then
374 | # Set keep_kernels to the number of kernels in the array
375 | keep_kernels="${#kernels_to_remove[@]}"
376 | fi
377 | kernels_to_keep=("${kernels_to_remove[@]:${#kernels_to_remove[@]}-$keep_kernels:$keep_kernels}")
378 | kernels_to_remove=("${kernels_to_remove[@]::${#kernels_to_remove[@]}-$keep_kernels}")
379 | fi
380 | fi
381 | # Show kernels to be removed
382 | printf "${bold}[-]${reset} Searching for old PVE kernels on your system...\n"
383 | for kernel in "${kernels_to_remove[@]}"
384 | do
385 | printf " ${bold}${green}+${reset} \"$kernel\" added to the kernel remove list\n"
386 | done
387 | for kernel in "${kernels_to_keep[@]}"
388 | do
389 | printf " ${bold}${red}-${reset} \"$kernel\" is being held back from removal\n"
390 | done
391 | printf "${bold}[-]${reset} PVE kernel search complete!\n"
392 | # If there are no kernels to be removed then exit
393 | if [ ${#kernels_to_remove[@]} -eq 0 ]; then
394 | printf "${bold}[!]${reset} It appears there are no old PVE kernels on your system ⎦˚◡˚⎣\n"
395 | printf "${bold}[-]${reset} Good bye!\n"
396 | # Kernels found in removal list
397 | else
398 | num_to_remove=${#kernels_to_remove[@]}
399 | # Check if force removal was passed
400 | if [ $force_purge == true ]; then
401 | REPLY="y"
402 | # Ask the user if they want to remove the selected kernels found
403 | else
404 | printf "${bold}[!]${reset} Would you like to remove the ${bold}$num_to_remove${reset} selected PVE kernel$([ "$num_to_remove" -eq 1 ] || echo 's') listed above? [y/N]: "
405 | read -n 1 -r
406 | printf "\n"
407 | fi
408 | # User wishes to remove the kernels
409 | if [[ $REPLY =~ ^[Yy]$ ]]; then
410 | printf "${bold}[*]${reset} Removing $num_to_remove old PVE kernel$([ "$num_to_remove" -eq 1 ] || echo 's')...\n"
411 | for kernel in "${kernels_to_remove[@]}"
412 | do
413 | printf "${bold}[-]${reset} Removing kernel: $kernel..."
414 | # Purge the old kernels via apt and suppress output
415 | if [ "$dry_run" != "true" ]; then
416 | /usr/bin/apt purge -y pve-kernel-$kernel > /dev/null 2>&1
417 | /usr/bin/apt purge -y proxmox-kernel-$kernel > /dev/null 2>&1
418 | /usr/bin/apt purge -y pve-kernel-${kernel%-pve} > /dev/null 2>&1
419 | /usr/bin/apt purge -y proxmox-kernel-${kernel%-pve} > /dev/null 2>&1
420 | /usr/bin/apt purge -y pve-headers-${kernel%-pve} > /dev/null 2>&1
421 | /usr/bin/apt purge -y proxmox-headers-${kernel%-pve} > /dev/null 2>&1
422 | fi
423 | sleep 1
424 | printf "${bold}${green}DONE!${reset}\n"
425 | done
426 | printf "${bold}[*]${reset} Updating GRUB..."
427 | # Update grub after kernels are removed, suppress output
428 | if [ "$dry_run" != "true" ]; then
429 | /usr/sbin/update-grub > /dev/null 2>&1
430 | fi
431 | printf "${bold}${green}DONE!${reset}\n"
432 | # Get information about the /boot folder
433 | boot_info=($(echo $(df -Ph | grep /boot | tail -1) | sed 's/%//g'))
434 | # Show information about the /boot
435 | printf "${bold}[-]${reset} ${bold}Boot Disk:${reset} ${boot_info[4]}%% full [${boot_info[2]}/${boot_info[1]} used, ${boot_info[3]} free] \n"
436 | # Script finished successfully
437 | printf "${bold}[-]${reset} Have a nice $(timeGreeting) ⎦˚◡˚⎣\n"
438 | # User wishes to not remove the kernels above, exit
439 | else
440 | printf "\nExiting...\n"
441 | printf "See you later ⎦˚◡˚⎣\n"
442 | fi
443 | fi
444 | exit 0
445 | }
446 |
447 | # Function to check for updates
448 | check_for_update() {
449 | if [ "$check_for_updates" == "true" ] && [ "$force_purge" == "false" ]; then
450 | # Get latest version number
451 | local remote_version=$(curl -s -m 10 https://raw.githubusercontent.com/jordanhillis/pvekclean/master/version.txt | tr -d '\n' || echo "")
452 | # Unable to fetch remote version, so just skip the update check
453 | if [ -z "$remote_version" ]; then
454 | printf "${bold}[*]${reset} Failed to check for updates. Skipping update check.\n"
455 | return
456 | fi
457 | # Validate the remote_version format using a regex
458 | if [[ ! "$remote_version" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
459 | printf "${bold}[*]${reset} Invalid remote version format: ${bold}${orange}$remote_version${reset}. Skipping update check.\n"
460 | return
461 | fi
462 | # If version isn't the same
463 | if [ "$remote_version" != "$version" ]; then
464 | printf "*** A new version $remote_version is available! ***\n"
465 | printf "${bold}[*]${reset} Do you want to update? [y/N] "
466 | read -n 1 -r
467 | printf "\n"
468 | if [[ $REPLY =~ ^[Yy]$ ]]; then
469 | local updated_script=$(curl -s -m 10 https://raw.githubusercontent.com/jordanhillis/pvekclean/master/pvekclean.sh)
470 | # Check if the updated script contains the shebang line
471 | if [[ "$updated_script" == "#!/bin/bash"* ]]; then
472 | echo "$updated_script" > "$0" # Overwrite the current script
473 | printf "${bold}[*]${reset} Successfully updated to version $remote_version\n"
474 | exec "$0" "$@"
475 | else
476 | printf "${bold}[*]${reset} The updated script does not contain the expected shebang line.\n"
477 | printf "${bold}[*]${reset} Update aborted!\n"
478 | fi
479 | fi
480 | fi
481 | fi
482 | }
483 |
484 | timeGreeting() {
485 | h=$(date +%k) # Use %k to get the hour as a decimal number (no leading zero)
486 | ((h >= 5 && h < 12)) && echo "morning" && return
487 | ((h >= 12 && h < 17)) && echo "afternoon" && return
488 | ((h >= 17 && h < 21)) && echo "evening" && return
489 | echo "night"
490 | }
491 |
492 | main() {
493 | # Check for root
494 | check_root
495 | # Show header information
496 | header_info
497 | # Script usage
498 | show_usage
499 | # Show kernel information
500 | kernel_info
501 | # Check for updates
502 | check_for_update
503 | # Install program to /usr/local/sbin/
504 | install_program
505 | }
506 |
507 | while [[ $# -gt 0 ]]; do
508 | case "$1" in
509 | -i|--install )
510 | force_pvekclean_install=true
511 | main
512 | install_program
513 | ;;
514 | -r|--remove )
515 | main
516 | uninstall_program
517 | ;;
518 | -s|--scheduler)
519 | main
520 | scheduler
521 | ;;
522 | -v|--version)
523 | version
524 | ;;
525 | -h|--help)
526 | main
527 | exit 0
528 | ;;
529 | -k|--keep)
530 | if [[ $# -gt 1 && "$2" =~ ^[0-9]+$ ]]; then
531 | keep_kernels="$2"
532 | shift 2
533 | continue
534 | else
535 | echo -e "${bold}Error:${reset} --keep/-k requires a number argument."
536 | exit 1
537 | fi
538 | ;;
539 | -f|--force)
540 | force_purge=true
541 | shift
542 | continue
543 | ;;
544 | -rn|--remove-newer)
545 | remove_newer=true
546 | shift
547 | continue
548 | ;;
549 | -d|--dry-run)
550 | dry_run=true
551 | shift
552 | continue
553 | ;;
554 | *)
555 | echo -e "${bold}Unknown option:${reset} $1"
556 | exit 1
557 | ;;
558 | esac
559 | shift
560 | done
561 |
562 | main
563 | pve_kernel_clean
564 |
--------------------------------------------------------------------------------
/version.txt:
--------------------------------------------------------------------------------
1 | 2.0.2
2 |
--------------------------------------------------------------------------------