The original words of Phanes, tirelessly carved into a slab of "No'".

Documenting Changes on your Linux System: etckeeper

[highlighter line=0]
I’ll go ahead and cover what I did to set up etckeeper and how I’ll be using it for the most part.

Install, Configure, Initialize

First, install. This is on a stock Fedora 23 system with the XFCE install selected and i3wm installed as a window manager.

Installation

sudo dnf install etckeeper etckeeper-dnf

Configuration:

Then, edit /etc/etckeeper/etckeeper.conf

vim /etc/etckeeper/etckeeper.conf

Here’s the configuration I’m using to start out:

# The VCS to use.
#VCS="hg"
VCS="git"
#VCS="bzr"
#VCS="darcs"

# Options passed to git commit when run by etckeeper.
GIT_COMMIT_OPTIONS=""

# Options passed to hg commit when run by etckeeper.
HG_COMMIT_OPTIONS=""

# Options passed to bzr commit when run by etckeeper.
BZR_COMMIT_OPTIONS=""

# Options passed to darcs record when run by etckeeper.
DARCS_COMMIT_OPTIONS="-a"

# Uncomment to avoid etckeeper committing existing changes
# to /etc automatically once per day.
#AVOID_DAILY_AUTOCOMMITS=1

# Uncomment the following to avoid special file warning
# (the option is enabled automatically by cronjob regardless).
#AVOID_SPECIAL_FILE_WARNING=1

# Uncomment to avoid etckeeper committing existing changes to 
# /etc before installation. It will cancel the installation,
# so you can commit the changes by hand.
AVOID_COMMIT_BEFORE_INSTALL=1

# The high-level package manager that's being used.
# (apt, pacman-g2, yum, dnf, zypper etc)
HIGHLEVEL_PACKAGE_MANAGER=dnf

# The low-level package manager that's being used.
# (dpkg, rpm, pacman, pacman-g2, etc)
LOWLEVEL_PACKAGE_MANAGER=rpm

# To push each commit to a remote, put the name of the remote here.
# (eg, "origin" for git). Space-separated lists of multiple remotes
# also work (eg, "origin gitlab github" for git).
PUSH_REMOTE=""

From there, I need to (as root) initialize etckeeper’s repository. We’re using a git backend for this setup.

[root@localhost ~]# etckeeper init -d /etc
Initialized empty Git repository in /etc/.git/
[root@localhost etc]# 

Ignoring Files

Eesy, peezey, breezey. If you want to stop tracking changes to a file or names matching a pattern, you can edit .gitignore:

vim /etc/.gitignore 

But don’t go nuts with it. etckeeper also maintains this file for the most part. You’ll want to keep your additions inside the file with the block that is indicated to be handled by etckeeper. Once you do this you’ll need to use etckeeper to update its cache for each file:

etckeeper vsc rm --cached $filename

Initializing

Now here’s where the cool part happens. You use etckeeper to make the commit.  If you need to troubleshoot, since etckeeper is a generic wrapper for most version control systems, you can handle any complex version management using the VCS as a subsystem of etckeeper.

etckeeper commit "Initial commit.  Allows restore to a sane state in case of a SHTF scenario."

And then prepare your eyeballs because etckeeper will take any change that it tracks from the previous state and display it while it commits to version control, which in this first instance of committing is a change from nothing, so everything is getting captured that first time. The default buffer size in most terminals can’t even scrollback through all of it (mine couldn’t) so you may want to pipe the command into less or another paginator of choice if you actually care to read through it (I don’t).

Administration:

If you make a change in /etc perform the commit.  It’s that easy.

So, now that you’ve committed you will be able to check to see any changes that have been made along with the descriptions that you’ve provided:

git -C /etc log --pretty=oneline

or:

etckeeper vcs log --pretty=oneline

On the left you’ll see a highlighted checksum of the commit which you should think of as a unique identifier for the version of the change set committed. One the right, the description you supplied. Almost a sane change control setup, no?

So, let’s say you bring in a new sysadmin and they go changing stuff.

In my case I had a joker named Tom Brady who liked to put his name on everything. So, he added “Tom Brady” as the last line to /etc/hosts.

At this point I have no idea what was changed.

Since etckeeper ensures a path context of /etc, I just ran:

etckeeper vcs diff

And here’s my result:

[root@localhost ~]# etckeeper vcs diff
diff --git a/hosts b/hosts
index 849c10d..72f1e04 100644
--- a/hosts
+++ b/hosts
@@ -1,2 +1,3 @@
 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
+tom brady

And I was immediately able to see that Tom is mismanaging the hosts file (Dammit. Tom).

So here’s what’s happening with these commands. Because etckeeper supports multiple version control systems, it will relay the command you supply to it via the “vcs” command as a subcommand. In our case we just used git diff to see what’s different from our last committed change. Neat stuff if you have a busy environment where many changes occur and you need to keep your stuff clean and accounted for. I fully intend to introduce this tool for this reason to an enterprise environment and see it as invaluable — I don’t know how I survived this long without it.

So, obviously we need to roll back the file, in some cases several files with complex arrangements. So, let’s backtrack a bit here and cover this process from the beginning:

  1. Check to see what’s changed:
  2. [root@localhost ~]# etckeeper vcs status -s
     M hosts
    [root@localhost ~]# etckeeper vcs diff 
    diff --git a/hosts b/hosts
    index 849c10d..72f1e04 100644
    --- a/hosts
    +++ b/hosts
    @@ -1,2 +1,3 @@
     127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
     ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    +tom brady
    
  3. Check your commit history and find a revision you can live with restoring to, noting the revision hash:
  4. [root@localhost ~]# etckeeper vcs log --pretty=oneline
    75ee94d6250089cda0893773a4e2eabae5c46d33 Initial commit.  Allows restore to a sane state in case of a SHTF scenario.
    
  5. Use the vcs subcommand, the case of git to check out that revision of the file, in this case /etc/hosts:
  6. [root@localhost ~]# etckeeper vcs checkout 75ee94d6250089cda0893773a4e2eabae5c46d33 /etc/hosts
    [root@localhost ~]# cat /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    
  7. Compare current working set in /etc to whats in the most recent commit to be sure there isn’t anything else you should look at:
  8. [root@localhost ~]# etckeeper vcs diff
    [root@localhost ~]# etckeeper vcs status
    On branch master
    nothing to commit, working directory clean
    

And done. Bam. I can think of few break-fix situations that would not have hours saved by this, and it’s a solid enough system that writing wrapper scripts to make this a simple curses menu that handles everything should be an interesting endeavor.

Next Post

Previous Post

Leave a Reply

© 2021 Phanes' Canon

The Personal Blog of Chris Punches