Fix dependency loop in mirror_health when a service is set to absent: the file need...
[mirror/dsa-puppet.git] / modules / bacula / files / volumes-delete-old
index e7e9ce2..979e469 100755 (executable)
@@ -2,7 +2,7 @@
 
 # queries a bacula database for volumes to delete and deletes them using bconsole
 
-# Copyright 2010, 2011, 2013, 2017 Peter Palfrader
+# Copyright 2010, 2011, 2013, 2017, 2018 Peter Palfrader
 #
 # Permission is hereby granted, free of charge, to any person obtaining
 # a copy of this software and associated documentation files (the
 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 import argparse
+import os.path
 import psycopg2
 import psycopg2.extras
 import re
 import sys
 import subprocess
 
+DSA_BACULA_DB_CONNECT = '/etc/dsa/bacula-reader-database'
+DSA_CLIENT_LIST_FILE = '/etc/bacula/dsa-clients'
+
 parser = argparse.ArgumentParser()
 parser.add_argument("-d", "--db-connect-string", metavar="connect-string", dest="db",
   help="Database connect string")
 parser.add_argument("-D", "--db-connect-string-file", metavar="FILE", dest="dbfile",
-  default='/etc/dsa/bacula-reader-database',
-  help="File to read database connect string from (/etc/dsa/bacula-reader-database)")
+  default=DSA_BACULA_DB_CONNECT,
+  help="File to read database connect string from (%s)"%(DSA_BACULA_DB_CONNECT,))
+parser.add_argument("-c", "--client-list", metavar="FILE", dest="clientlist",
+  default=DSA_CLIENT_LIST_FILE,
+  help="File with a list of all clients (%s)"%(DSA_CLIENT_LIST_FILE,))
 parser.add_argument("-v", "--verbose", dest="verbose",
   default=False, action="store_true",
   help="Be more verbose.")
 parser.add_argument("-n", "--nodo", dest="nodo",
   default=False, action="store_true",
   help="Print to cat rather than bconsole.")
+parser.add_argument("-t", "--token", metavar='TOKEN', dest="pool_name_token",
+  default='bacula',
+  help="A string token used in pool names.")
 args = parser.parse_args()
 
 if args.db is not None:
@@ -56,6 +66,7 @@ else:
 conn = psycopg2.connect(args.db)
 cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
 
+cmd = []
 # Error volumes
 cursor.execute("""
   SELECT volumename
@@ -67,7 +78,8 @@ cursor.execute("""
     (lastwritten IS NULL OR lastwritten < current_date - interval '6 weeks')
 """, {})
 for r in cursor.fetchall():
-  print("delete volume=%s yes"%(r['volumename'],))
+  c = "delete volume=%s yes"%(r['volumename'],)
+  cmd.append(c)
 
 # Append volumes - we should not have any of these
 cursor.execute("""
@@ -85,7 +97,8 @@ cursor.execute("""
     volwrites = 0
 """, {})
 for r in cursor.fetchall():
-  print("delete volume=%s yes"%(r['volumename'],))
+  c = "delete volume=%s yes"%(r['volumename'],)
+  cmd.append(c)
 
 cursor.execute("""
   SELECT volumename
@@ -100,11 +113,38 @@ cursor.execute("""
     recycle=1
 """, {})
 
-cmd = []
 for r in cursor.fetchall():
   c = "delete volume=%s yes"%(r['volumename'],)
   cmd.append(c)
 
+# find obsolete pools, but only if we have a list of clients
+##
+if os.path.exists(args.clientlist):
+  clients = set(open(args.clientlist).read().split())
+
+  cursor.execute("""
+    SELECT name
+    FROM pool
+    WHERE
+      name != 'Scratch' AND
+      numvols = 0 AND
+      poolid NOT IN (SELECT recyclepoolid FROM media)
+  """, {})
+
+  for r in cursor.fetchall():
+    poolname = r['name']
+    match = re.match('pool[a-z]*-%s-(.*)'%(args.pool_name_token, ), poolname)
+    if match is not None:
+      hostname = match.group(1)
+      if hostname not in clients:
+        c = "delete pool=%s"%(poolname,)
+        cmd.append(c)
+        cmd.append("yes")
+      elif args.verbose:
+        print("Not expiring empty pool %s because client still exists"%(poolname,))
+    elif args.verbose:
+        print("Could not extract client name from poolname %s"%(poolname,))
+
 if args.nodo:
   print("\n".join(cmd))
   sys.exit(0)
@@ -113,14 +153,18 @@ if args.verbose:
     for c in cmd:
       print("Will run: %s"%(c,))
 
-p = subprocess.Popen(['bconsole'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+p = subprocess.Popen(['/usr/sbin/bconsole'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 (out, err) = p.communicate("\n".join(cmd).encode())
 if p.returncode != 0:
     raise Exception("bconsole failed.  stdout:\n%s\nstderr:%s\n"%(out, err))
 
 if args.verbose:
-    print("stdout:\n%s"%(out,))
-
-if err != "":
-  print("bconsole said on stderr:\n%s\n"%(err,), file=sys.stderr)
+    print("stdout:\n")
+    sys.stdout.buffer.write(out)
+    print("\n")
+
+if err != b"":
+  print("bconsole said on stderr:\n", file=sys.stderr)
+  sys.stderr.buffer.write(out)
+  print("", file=sys.stderr)
   sys.exit(1)