Red Green Repeat Adventures of a Spec Driven Junkie

Using lsb_release for better install scripts

Did you know there’s a command to find out the “codename” of a Debian or Ubuntu distribution? I dig into this command more and use it to help create a bootstrapped postgres installation script usable across different Ubuntu or Debian distributions.

I hope this will inspire you to use lsb_release more in your installation scripts for automatic installation and setup.

This article will take you about four minutes to read.

John Singleton Copley - Daniel Crommelin Verplanck source and more information

Introduction

I was setting up an automated installation of postgres in my vagrant/virtualbox setup and need to configure the correct repository.

The repository needed for postgres depends on the version of the linux distribution, configured on the top level of the Vagrant file:

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/xenial64"
  config.vm.provider 'virtualbox' do |v|
    v.memory = 512
    v.cpus = 2
  end
end

postgres complication??

As a database, postgres has specific builds for each operating system. When installing on Debian-based system like Ubuntu, postgres uses the codename of the distribution to organize their builds.

The debian repository entry is in the form:

echo "deb http://apt.postgresql.org/pub/repos/apt/ <distribution codename>-pgdg main" > /etc/apt/sources.list.d/pgdg.list

Where distribution codename would be the codename of the distribution.

Distribution Codename?!

Where does the distribution codename come from?? Isn’t a number enough?

Yes, a number would be enough (i.e. Ubuntu 16.04) there can be multiple releases of a version of a distribution: betas, release candidates, security fixes, etc.

Also, a “codename” can be easier to remember than just a number and harder to fat-finger. :-)

Examples of recent Ubuntu codenames:

  • Ubuntu 16.04 - Xenial Xerus
  • Ubuntu 18.04 - Bionic Beaver
  • Ubuntu 20.04 - Focal Fossa

source

and recent Debian codenames:

  • Debian 8 - Jessie
  • Debian 9 - Stretch
  • Debian 10 - Buster

source

How to combine this information with postgres’ archive requirement?

Solution 1: Hardcode

I can just write the version into the postgres script:

echo "deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main" > /etc/apt/sources.list.d/pgdg.list
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -

That would work, it did for me the first time and if I always use the same distribution, this will work perfectly. I will have to remember what the distribution’s codename is in the script.

Solution 2: Argument

What if I change distributions? Ubuntu 16.04 did come out in 2016… almost five years ago! It’s Long Term Support will end soon and I don’t want to be using gasp an unsupported operating system!

When I update the distribution used for the vagrantbox, I would need to remember to update this entry too. I don’t want to always remember that, (as easy as it is to grep or sed.)

Another solution: I can set up the vagrant file to pass in a parameter of the distribution name, like for which version of ruby to install:

config.vm.provision :shell, path: "vagrant_scripts/install-ruby.sh", args: "2.5", privileged: false

and in the script, access it:

rvm use --default --install $1

The postgres example would be:

From the Vagrantfile:

config.vm.provision :shell, path: "vagrant_scripts/install-postgres.sh", args: "xenial"

The corresponding install-postgres.sh file contents:

echo "deb http://apt.postgresql.org/pub/repos/apt/ $1-pgdg main" > /etc/apt/sources.list.d/pgdg.list
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -

That’s getting better. The Vagrantfile calling the install-postgres script will manage the version the script uses.

Solution 3: lsb_release

What if I don’t want to remember to update the install-postgres.sh file each time I change distributions, like when I want to experiment with the newer versions and not commit to it for production systems?

What if I want to have the postgres install script to be portable, using it in vagrant setup as well as straight up command-line installs?

The argument approach would still work, as long as we pass the parameter into the script.

Can we do better?

Can the script be “bootstrapped” itself? Meaning, one can run it anywhere and just do the right thing?

Yes, by using lsb_release, the script can retrieve the distribution’s codename consistently and without human intervention:

The install-postgres.sh file:

echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -

Nice - now the install-postgres.sh file will be usable without passing information in:

The Vagrantfile would call it as:

config.vm.provision :shell, path: "vagrant_scripts/install-postgres.sh"

Less is definitely more here. ;-)

lsb_release

If you want to find out more about lsb_release, the manpage has further details and additional options for the command:

$ man lsb_release
lsb_release(1)                  General Commands Manual                 lsb_release(1)

NAME
       lsb_release - print distribution-specific information

SYNOPSIS
       lsb_release [options]

Additional option, -a shows more information:

vagrant@ubuntu-xenial:~/rgr$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.6 LTS
Release:        16.04
Codename:       xenial

Conclusion

What started as a way to automate installation of postgres more turned into a dive into a linux utility: lsb_release, that returns details of the distribution, such as it’s codename, release, and description.

I will be using this information more to help automate installation scripts wherever I can.