3 """Clean-up after people's deleted VMs.
5 The Invirt janitor goes through and finds virtual disk images that
6 users have requested we delete. For their privacy, it writes over the
7 entire disk with /dev/zero, then removes the logical volume, restoring
10 A request is indicated to the janitor by creating a file in
11 /var/lib/invirt-remote/cleanup/ corresponding to the name of the LV to
12 delete. The janitor notices these requests using inotify.
24 _JANITOR_DIR = '/var/lib/invirt-remote/cleanup'
28 """Actually cleanup deleted LVs.
30 When triggered, continue to iterate over cleanup queue files,
31 deleting LVs one at a time, until there are no more pending
35 lvs = os.listdir(_JANITOR_DIR)
40 lv_path = '/dev/xenvg/%s' % lv
43 # If the LV name doesn't start with old_, we probably
44 # don't actually want to be deleting it.
46 # Put it in the try block because we still want to delete
48 if not lv.startswith('old_'):
51 # If the LV doesn't exist, for whatever reason, don't
52 # proceed because the dd will simply fill the devfs
53 # by creating a regular file and filling it with zeros.
54 if not os.path.exists(lv_path):
57 syslog.syslog(syslog.LOG_INFO, "Cleaning up LV '%s'" % lv_path)
59 # In a perfect world, this should be erroring out with
60 # ENOSPC, so we ignore errors
61 subprocess.call(['/usr/bin/ionice',
70 # Ignore any errors here, because there's really just not
72 subprocess.call(['/sbin/lvchange', '-a', 'n', lv_path])
73 subprocess.call(['/sbin/lvchange', '-a', 'ey', lv_path])
74 subprocess.check_call(['/sbin/lvremove', '--force', lv_path])
76 syslog.syslog(syslog.LOG_INFO, "Successfully cleaned up LV '%s'" % lv_path)
78 syslog.syslog(syslog.LOG_ERR, "Error cleaning up LV '%s':" % lv_path)
80 for line in traceback.format_exc().split('\n'):
81 syslog.syslog(syslog.LOG_ERR, line)
83 # Regardless of what happens, we always want to remove the
84 # cleanup queue file, because even if there's an error, we
85 # don't want to waste time wiping the same disk repeatedly
86 os.unlink(os.path.join(_JANITOR_DIR, lv))
89 class Janitor(pyinotify.ProcessEvent):
90 """Process inotify events by wiping and deleting LVs.
92 The Janitor class receives inotify events when a new file is
93 created in the state directory.
95 def process_IN_CREATE(self, event):
96 """Handle a created file or directory.
98 When an IN_CREATE event comes in, trigger a cleanup.
104 """Initialize the inotifications and start the main loop."""
105 syslog.openlog('invirt-janitor', syslog.LOG_PID, syslog.LOG_DAEMON)
107 watch_manager = pyinotify.WatchManager()
109 notifier = pyinotify.Notifier(watch_manager, janitor)
110 watch_manager.add_watch(_JANITOR_DIR,
111 pyinotify.EventsCodes.ALL_FLAGS['IN_CREATE'])
113 # Before inotifying, run any pending cleanups; otherwise we won't
114 # get notified for them.
118 notifier.process_events()
119 if notifier.check_events():
120 notifier.read_events()
123 if __name__ == '__main__':