# Proxmox LXC update automation

Tags: Proxmox Homelab Linux Selfhosting

Reading time: 3 minutes

Description: A simple script to update all LXC's on Proxmox






The following is a little script i use to update my LXC’s on Proxmox, it takes the current state, lock and operating system of the container into account.


Container are only updated if they are:


# Detecting the OS

Almost every linux distribution has a little file in their /etc directory, containing basic system information.

The name of this file changed a few times but is currently os-release


This file contains information about the distribution, in the case of my Gentoo system:

1
2
3
4
5
6
7
8
NAME=Gentoo
ID=gentoo
PRETTY_NAME="Gentoo Linux"
ANSI_COLOR="1;32"
HOME_URL="https://www.gentoo.org/"
SUPPORT_URL="https://www.gentoo.org/support/"
BUG_REPORT_URL="https://bugs.gentoo.org/"
VERSION_ID="2.13"

We can ignore almost everything since we only need the NAME field (you could also use the ID instead) which can be extracted with:

1
cat /etc/os-release | grep "^NAME=" | cut -f2 -d"="

# Executing commands from the host in a container

Since we want this information about the container, not the host, we need to execute it in the target lxc.

This can be done via the pct exec command (lxcid would be the numeric id of the container):

1
pct exec <lxcid> -- bash -c "cat /etc/os-release" | grep "^NAME=" | cut -f2 -d"="

# The actual update part

Knowing the distribution, we can use a case statement in combination with pct exec to execute the update command.

To provide some readabiliyt, the distribution name is definted as a constant at the beginning of the script.


Now we only need to iterate over the running, not locked LXC’s and update them.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/bin/bash

DEBIAN="Debian GNU/Linux"
FEDORA="Fedora Linux"

mapfile containers < <( pct list | tail -n +2 | cut -f1 -d' ' )
ct_lock=$(pct list | tail -n +2 | cut -f13 -d' ')

function update_container() {
  container=$1
  distro=$(pct exec $container -- bash -c "cat /etc/os-release" | grep "^NAME=" | cut -f2 -d"=")
  distro=${distro//\"}

  case $distro in
    $DEBIAN)
      echo "Updating $container with $distro"
      pct exec $container -- bash -c "apt update && apt upgrade -y"
      ;;
    $FEDORA)
      echo "Updating $container with $distro"
      pct exec $container -- bash -c "dnf update -y"
      ;;
    *)
      echo "Unknown distro: $distro"
      ;;
  esac
}

i=0
while [ $i -lt ${#containers[@]} ]
do
  status=`pct status ${containers[$i]}`
  locked=${ct_lock[$i]}

  if [ "$status" == "status: running" ] && [ -z $locked ]; then
    update_container ${containers[$i]}
  fi
  i=$((i+1))
done

# Extending the script with more distributions

Create another constant at the beginning of the file with the information obtained from /etc/os-release and expand the case statement.