Taking backup for znc instance in Python

IRC plays an invaluable role in the life of so many people, separated by so many miles. It has been the primary source of communication for the Free and Open Source community for decades, now. In my last post, I shared how to install a znc bouncer to stay connected persistently to IRC. If you want to stay on top of the comings and goings on, in your favourite communities.

The next step, after installation, is to always create a backup. No sys-admin wants to lose their data. Mainly this was user data for me this time.
So, a backup was needed. But the job of :

  • getting into the server
  • taking a backup
  • scp ing the file down to my computer and then,
  • closing the box down,

seemed pretty dull to me.
So why not automate stuff? I choose Python over Bash for this.
(It was the PyLady inside me :))

Create a tarball backup

The 2 directories I need to backup are :

/etc/letsencrypt : The TLS certificates.
/var/lib/znc/.znc : The znc data directory.

I learned how to use the tarfile module to create the tar file.

This is the code in my backup.py

#!/usr/bin/env python3

import os
import tarfile
import os.path
from pathlib import Path
from datetime import date

today = str(date.today())

def make_tarfile(output_filename, source_dirs):
   with tarfile.open(output_filename, "w:gz") as tar:
       for source_dir in source_dirs:
           tar.add(source_dir, arcname=os.path.basename(source_dir))

filename = f"znc-dgplug-{today}.tar.gz"
homedir = Path.home()
fullpath = os.path.join(str(homedir), "backups")
if not os.path.exists(fullpath):
   os.mkdir(fullpath)

finalpath = os.path.join(fullpath, filename)
make_tarfile(finalpath, ["/etc/letsencrypt", "/var/lib/znc/.znc"])
print(f"Backup is saved at {finalpath}")

Running the code, we get the filepath of the tar file and the date of running the file.

To do the next set of jobs, i.e

  • ssh into the server,
  • execute backup.py from the command output,
  • find the backup filename, and
  • scp the filename back into my computer, I wrote a file called runonserver.py.

I am using the paramiko module to ssh into the box and to execute commands. And the scp module is helping me copy the data down into my local machine.

#!/usr/bin/env python3

import paramiko
from scp import SCPClient
import os.path


def create_backup(client):
   chan = client.get_transport().open_session()
   chan.settimeout(60)
   chan.set_combine_stderr(True)
   chan.get_pty()
   chan.exec_command("/root/backup.py")
   stdout = chan.makefile("r", -1)
   stderr = chan.makefile_stderr("r", -1)
   stdout_text = stdout.read().decode("utf-8").strip("\r\n")
   stderr_text = stderr.read()
   status = int(chan.recv_exit_status())
   return stdout_text, status


def main():
   client = paramiko.SSHClient()
   client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
   client.connect(hostname="znc.dgplug.org", port=22, username="root")
   stdout, status = create_backup(client)
   if status != 0:
       client.close()
       print(f"The command failed with output: {stdout}")
       return
   filepath = get_filepath(stdout)
   scp = SCPClient(client.get_transport())
   scp.get(filepath)
   scp.close()
   client.close()
   filename = os.path.basename(filepath)
   print(filename)


def get_filepath(cmdoutput):
   result = cmdoutput.split()[-1]
   return result


if __name__ == "__main__":
   main()

This little handy script has made my life really easy. Hopefully, this will help you readers, too.