CC-5990, CC-5991 - Python cleanup, removed need for /usr/lib/airtime

This commit is contained in:
Duncan Sommerville 2015-01-27 18:43:36 -05:00
parent cd102b984b
commit 875a9dfd8b
115 changed files with 248 additions and 212 deletions

View file

@ -0,0 +1,73 @@
import os
from os.path import join, basename, dirname
from ..monitor.exceptions import NoConfigFile
from ..monitor.pure import LazyProperty
from ..monitor.config import MMConfig
from ..monitor.owners import Owner
from ..monitor.events import EventRegistry
from ..monitor.listeners import FileMediator
from api_clients.api_client import AirtimeApiClient
# poor man's phantom types...
class SignalString(str): pass
class AirtimeInstance(object):
""" AirtimeInstance is a class that abstracts away every airtime
instance by providing all the necessary objects required to interact
with the instance. ApiClient, configs, root_directory """
@classmethod
def root_make(cls, name, root):
cfg = {
'api_client' : join(root, 'etc/airtime/api_client.cfg'),
'media_monitor' : join(root, 'etc/airtime/airtime.conf'),
}
return cls(name, root, cfg)
def __init__(self,name, root_path, config_paths):
""" name is an internal name only """
for cfg in ['api_client','media_monitor']:
if cfg not in config_paths: raise NoConfigFile(config_paths)
elif not os.path.exists(config_paths[cfg]):
raise NoConfigFile(config_paths[cfg])
self.name = name
self.config_paths = config_paths
self.root_path = root_path
def signal(self, sig):
if isinstance(sig, SignalString): return sig
else: return SignalString("%s_%s" % (self.name, sig))
def touch_file_path(self):
""" Get the path of the touch file for every instance """
touch_base_path = self.mm_config['media-monitor']['index_path']
touch_base_name = basename(touch_base_path)
new_base_name = self.name + touch_base_name
return join(dirname(touch_base_path), new_base_name)
def __str__(self):
return "%s,%s(%s)" % (self.name, self.root_path, self.config_paths)
@LazyProperty
def api_client(self):
return AirtimeApiClient(config_path=self.config_paths['api_client'])
@LazyProperty
def mm_config(self):
return MMConfig(self.config_paths['media_monitor'])
# I'm well aware that I'm using the service locator pattern
# instead of normal constructor injection as I should be.
# It's recommended to rewrite this using proper constructor injection
@LazyProperty
def owner(self): return Owner()
@LazyProperty
def event_registry(self): return EventRegistry()
@LazyProperty
def file_mediator(self): return FileMediator()

View file

@ -0,0 +1,133 @@
import os, sys
import logging
import logging.config
from ..monitor import pure as mmp
from ..monitor.exceptions import FailedToObtainLocale, FailedToSetLocale
from ..monitor.log import get_logger, setup_logging
from std_err_override import LogWriter
from ..saas.thread import InstanceThread, user, apc, getsig
from ..monitor.log import Loggable
from ..monitor.exceptions import CouldNotCreateIndexFile
from ..monitor.toucher import ToucherThread
from ..monitor.airtime import AirtimeNotifier, AirtimeMessageReceiver
from ..monitor.watchersyncer import WatchSyncer
from ..monitor.eventdrainer import EventDrainer
from ..monitor.manager import Manager
from ..monitor.syncdb import AirtimeDB
from airtimeinstance import AirtimeInstance
class MM2(InstanceThread, Loggable):
def index_create(self, index_create_attempt=False):
config = user().mm_config
if not index_create_attempt:
if not os.path.exists(config['media-monitor']['index_path']):
self.logger.info("Attempting to create index file:...")
try:
with open(config['media-monitor']['index_path'], 'w') as f: f.write(" ")
except Exception as e:
self.logger.info("Failed to create index file with exception: %s" \
% str(e))
else:
self.logger.info("Created index file, reloading configuration:")
self.index_create(index_create_attempt=True)
else:
self.logger.info("Already tried to create index. Will not try again ")
if not os.path.exists(config['media-monitor']['index_path']):
raise CouldNotCreateIndexFile(config['media-monitor']['index_path'])
def run(self):
self.index_create()
manager = Manager()
apiclient = apc()
config = user().mm_config
WatchSyncer(signal=getsig('watch'),
chunking_number=config['media-monitor']['chunking_number'],
timeout=config['media-monitor']['request_max_wait'])
airtime_receiver = AirtimeMessageReceiver(config,manager)
airtime_notifier = AirtimeNotifier(config, airtime_receiver)
adb = AirtimeDB(apiclient)
store = {
u'stor' : adb.storage_path(),
u'watched_dirs' : adb.list_watched(),
}
self.logger.info("initializing mm with directories: %s" % str(store))
self.logger.info(
"Initing with the following airtime response:%s" % str(store))
airtime_receiver.change_storage({ 'directory':store[u'stor'] })
for watch_dir in store[u'watched_dirs']:
if not os.path.exists(watch_dir):
# Create the watch_directory here
try: os.makedirs(watch_dir)
except Exception:
self.logger.error("Could not create watch directory: '%s' \
(given from the database)." % watch_dir)
if os.path.exists(watch_dir):
airtime_receiver.new_watch({ 'directory':watch_dir }, restart=True)
else: self.logger.info("Failed to add watch on %s" % str(watch_dir))
EventDrainer(airtime_notifier,
interval=float(config['media-monitor']['rmq_event_wait']))
# Launch the toucher that updates the last time when the script was
# ran every n seconds.
# TODO : verify that this does not interfere with bootstrapping because the
# toucher thread might update the last_ran variable too fast
ToucherThread(path=user().touch_file_path(),
interval=int(config['media-monitor']['touch_interval']))
success = False
while not success:
try:
apiclient.register_component('media-monitor')
success = True
except Exception, e:
self.logger.error(str(e))
import time
time.sleep(10)
manager.loop()
def launch_instance(name, root, global_cfg):
cfg = {
'api_client' : global_cfg,
'media_monitor' : global_cfg,
}
ai = AirtimeInstance(name, root, cfg)
MM2(ai).start()
def setup_global(log):
""" setup unicode and other stuff """
log.info("Attempting to set the locale...")
try: mmp.configure_locale(mmp.get_system_locale())
except FailedToSetLocale as e:
log.info("Failed to set the locale...")
sys.exit(1)
except FailedToObtainLocale as e:
log.info("Failed to obtain the locale form the default path: \
'/etc/default/locale'")
sys.exit(1)
except Exception as e:
log.info("Failed to set the locale for unknown reason. \
Logging exception.")
log.info(str(e))
def setup_logger(log_config, logpath):
logging.config.fileConfig(log_config)
#need to wait for Python 2.7 for this..
#logging.captureWarnings(True)
logger = logging.getLogger()
LogWriter.override_std_err(logger)
logfile = unicode(logpath)
setup_logging(logfile)
log = get_logger()
return log

View file

@ -0,0 +1,28 @@
import threading
class UserlessThread(Exception):
def __str__(self):
return "Current thread: %s is not an instance of InstanceThread \
of InstanceInheritingThread" % str(threading.current_thread())
class HasUser(object):
def user(self): return self._user
def assign_user(self): self._user = threading.current_thread().user()
class InstanceThread(threading.Thread, HasUser):
def __init__(self,user, *args, **kwargs):
super(InstanceThread, self).__init__(*args, **kwargs)
self._user = user
class InstanceInheritingThread(threading.Thread, HasUser):
def __init__(self, *args, **kwargs):
self.assign_user()
super(InstanceInheritingThread, self).__init__(*args, **kwargs)
def user():
try: return threading.current_thread().user()
except AttributeError: raise UserlessThread()
def apc(): return user().api_client
def getsig(s): return user().signal(s)