#!/usr/bin/env python
"""
ch10_logins_feed.py
Provide reports of login activity.
"""
import sys, os, difflib, gzip
from xml.sax.saxutils import escape
from popen2 import popen4
from scraperlib import FeedEntryDict
from monitorfeedlib import LogBufferFeed
SITE_NAME = "0xDECAFBAD"
COMMAND = "/usr/bin/last -a"
FEED_NAME_FN = "www/www.decafbad.com/docs/private-feeds/logins.%s"
FEED_DIR = "logins_feed"
TITLE_TMPL = "Command output update (%(changes)s changes)"
SUMMARY_TMPL = """
Changes:
%(changes_lines)s
All lines:
%(diff_lines)s
"""
def main():
"""
Detect login activity changes and report in feed.
"""
# Construct the feed generator
f = LogBufferFeed(FEED_DIR)
f.MAX_AGE = 24 * 60 * 60 # 1 day
f.FEED_META['feed.title'] = '%s Login Activity' % SITE_NAME
f.FEED_META['feed.tagline'] = \
'Summary of login activity on the %s server' % SITE_NAME
# Call the command and capture output
(sout, sin) = popen4(COMMAND)
new_lines = [ x for x in sout.readlines()
if x.find('reboot') == -1 ]
# Attempt load up output from the previous run.
old_lines = None
old_output_fn = os.path.join(FEED_DIR, 'old_output.gz')
if os.path.exists(old_output_fn):
old_lines = gzip.open(old_output_fn, "r").readlines()
# If there is previous output, check for changes...
if old_lines:
# Run a diff on the previous and current program output.
diff_lines = [ x for x in difflib.ndiff(old_lines, new_lines) ]
# Extract only the lines that have changed.
changes_lines = [ x for x in diff_lines
if x.startswith('-') or x.startswith('+') ]
# Construct and append a new entry if there were changes
if len(changes_lines) > 0:
esc_changes_lines = [escape(x) for x in changes_lines]
esc_diff_lines = [escape(x) for x in diff_lines]
entry = FeedEntryDict({
'link' : '',
'title' : TITLE_TMPL % {
'changes' : len(changes_lines)
},
'summary' : SUMMARY_TMPL % {
'changes_lines' : "
".join(esc_changes_lines),
'diff_lines' : "
".join(esc_diff_lines)
}
})
f.append_entry(entry)
# Save output from the current run for use next time.
gzip.open(old_output_fn, "w").write("".join(new_lines))
# Output the current feed entries as both RSS and Atom
open(FEED_NAME_FN % 'rss', 'w').write(f.scrape_rss())
open(FEED_NAME_FN % 'atom', 'w').write(f.scrape_atom())
if __name__ == '__main__': main()