84a7d752233e164925e5b8c097df3cc33e9c8a08
[mirror/dsa-puppet.git] / modules / bacula / files / volumes-delete-old
1 #!/usr/bin/python3
2
3 # queries a bacula database for volumes to delete and deletes them using bconsole
4
5 # Copyright 2010, 2011, 2013, 2017 Peter Palfrader
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining
8 # a copy of this software and associated documentation files (the
9 # "Software"), to deal in the Software without restriction, including
10 # without limitation the rights to use, copy, modify, merge, publish,
11 # distribute, sublicense, and/or sell copies of the Software, and to
12 # permit persons to whom the Software is furnished to do so, subject to
13 # the following conditions:
14 #
15 # The above copyright notice and this permission notice shall be
16 # included in all copies or substantial portions of the Software.
17 #
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 import argparse
27 import psycopg2
28 import psycopg2.extras
29 import re
30 import sys
31 import subprocess
32
33 parser = argparse.ArgumentParser()
34 parser.add_argument("-d", "--db-connect-string", metavar="connect-string", dest="db",
35   help="Database connect string")
36 parser.add_argument("-D", "--db-connect-string-file", metavar="FILE", dest="dbfile",
37   default='/etc/dsa/bacula-reader-database',
38   help="File to read database connect string from (/etc/dsa/bacula-reader-database)")
39 parser.add_argument("-v", "--verbose", dest="verbose",
40   default=False, action="store_true",
41   help="Be more verbose.")
42 parser.add_argument("-n", "--nodo", dest="nodo",
43   default=False, action="store_true",
44   help="Print to cat rather than bconsole.")
45 args = parser.parse_args()
46
47 if args.db is not None:
48     pass
49 elif args.dbfile is not None:
50     args.db = open(args.dbfile).read().rstrip()
51 else:
52     print >>sys.stderr, "Need one of -d or -D."
53     sys.exit(1)
54
55
56 conn = psycopg2.connect(args.db)
57 cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
58
59 cmd = []
60 # Error volumes
61 cursor.execute("""
62   SELECT volumename
63   FROM media
64   WHERE
65     volstatus='Error' AND
66     firstwritten < current_date - interval '2 weeks' AND
67     labeldate < current_date - interval '2 weeks' AND
68     (lastwritten IS NULL OR lastwritten < current_date - interval '6 weeks')
69 """, {})
70 for r in cursor.fetchall():
71   c = "delete volume=%s yes"%(r['volumename'],)
72   cmd.append(c)
73
74 # Append volumes - we should not have any of these
75 cursor.execute("""
76   SELECT volumename
77   FROM media
78   WHERE
79     volstatus='Append' AND
80     firstwritten IS NULL AND
81     labeldate IS NULL AND
82     lastwritten IS NULL AND
83     voljobs = 0 AND
84     volfiles = 0 AND
85     volblocks = 0 AND
86     volbytes = 0 AND
87     volwrites = 0
88 """, {})
89 for r in cursor.fetchall():
90   c = "delete volume=%s yes"%(r['volumename'],)
91   cmd.append(c)
92
93 cursor.execute("""
94   SELECT volumename
95   FROM media
96   WHERE
97     volstatus='Purged' AND
98     firstwritten < current_date - interval '18 weeks' AND
99     labeldate < current_date - interval '18 weeks' AND
100     lastwritten < current_date - interval '16 weeks' AND
101     volfiles = 0 AND
102     volbytes < 1000 AND
103     recycle=1
104 """, {})
105
106 for r in cursor.fetchall():
107   c = "delete volume=%s yes"%(r['volumename'],)
108   cmd.append(c)
109
110 if args.nodo:
111   print("\n".join(cmd))
112   sys.exit(0)
113
114 if args.verbose:
115     for c in cmd:
116       print("Will run: %s"%(c,))
117
118 p = subprocess.Popen(['bconsole'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
119 (out, err) = p.communicate("\n".join(cmd).encode())
120 if p.returncode != 0:
121     raise Exception("bconsole failed.  stdout:\n%s\nstderr:%s\n"%(out, err))
122
123 if args.verbose:
124     print("stdout:\n")
125     sys.stdout.buffer.write(out)
126     print("\n")
127
128 if err != b"":
129   print("bconsole said on stderr:\n", file=sys.stderr)
130   sys.stderr.buffer.write(out)
131   print("", file=sys.stderr)
132   sys.exit(1)