entropy/entropy/utils.py

235 lines
6.8 KiB
Python

# -*- coding: utf-8 -*-
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (C) 2013 Yahoo! Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import logging
import os
import sys
import time
from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer
import yaml
LOG = logging.getLogger(__name__)
def get_filename_and_path(path):
return os.path.dirname(path), os.path.basename(path)
def get_key_path():
home_dir = os.path.expanduser("~")
ssh_dir = os.path.join(home_dir, ".ssh")
if not os.path.isdir(ssh_dir):
return None
for k in ('id_rsa', 'id_dsa'):
path = os.path.join(ssh_dir, k)
if os.path.isfile(path):
return path
return None
def load_yaml(filename):
with open(filename, "rb") as fh:
return yaml.safe_load(fh.read())
# importer functions.
# From cloudinit http://bazaar.launchpad.net/~cloud-init-dev/cloud-init/
# trunk/view/head:/cloudinit/importer.py
def import_module(module_name):
__import__(module_name)
return sys.modules[module_name]
# TODO(praneshp): return exception isntead
def find_module(base_name, search_paths, required_attrs=None):
found_places = []
if not required_attrs:
required_attrs = []
# NOTE(harlowja): translate the search paths to include the base name.
real_paths = []
for path in search_paths:
real_path = []
if path:
real_path.extend(path.split("."))
real_path.append(base_name)
full_path = '.'.join(real_path)
real_paths.append(full_path)
LOG.info("Looking for modules %s that have attributes %s",
real_paths, required_attrs)
for full_path in real_paths:
mod = None
try:
mod = import_module(full_path)
except ImportError as e:
LOG.debug("Failed at attempted import of '%s' due to: %s",
full_path, e)
if not mod:
continue
found_attrs = 0
for attr in required_attrs:
if hasattr(mod, attr):
found_attrs += 1
if found_attrs == len(required_attrs):
found_places.append(full_path)
LOG.info("Found %s with attributes %s in %s", base_name,
required_attrs, found_places)
return found_places
class WatchdogHandler(FileSystemEventHandler):
def __init__(self, event_fn):
self.event_fn = event_fn
def on_modified(self, event):
if event.src_path in self.event_fn:
self.event_fn[event.src_path]()
else:
LOG.error('no associated function for %s', event.src_path)
def watch_dir_for_change(dir_to_watch, event_fn):
event_handler = WatchdogHandler(event_fn)
observer = Observer()
observer.schedule(event_handler, path=dir_to_watch, recursive=True)
observer.start()
return observer
def check_duplicate(name, cfg_file):
scripts = load_yaml(cfg_file)
return scripts and name in scripts
def reset_logger(log):
if not log:
return
handlers = list(log.handlers)
for h in handlers:
h.flush()
h.close()
log.removeHandler(h)
log.setLevel(logging.NOTSET)
log.addHandler(logging.NullHandler())
def write_yaml(data, filename):
with open(filename, "a") as cfg_file:
cfg_file.write(yaml.safe_dump(data,
default_flow_style=False,
canonical=False))
def wallclock():
# NOTE(harlowja): made into a function so that this can be easily mocked
# out if we want to alter time related functionality (for testing
# purposes).
return time.time()
# From taskflow:
# https://github.com/openstack/taskflow/blob/master/taskflow/utils/misc.py
class StopWatch(object):
"""A simple timer/stopwatch helper class.
Inspired by: apache-commons-lang java stopwatch.
Not thread-safe.
"""
_STARTED = 'STARTED'
_STOPPED = 'STOPPED'
def __init__(self, duration=None):
self._duration = duration
self._started_at = None
self._stopped_at = None
self._state = None
def start(self):
if self._state == self._STARTED:
return self
self._started_at = wallclock()
self._stopped_at = None
self._state = self._STARTED
return self
def elapsed(self):
if self._state == self._STOPPED:
return float(self._stopped_at - self._started_at)
elif self._state == self._STARTED:
return float(wallclock() - self._started_at)
else:
raise RuntimeError("Can not get the elapsed time of an invalid"
" stopwatch")
def __enter__(self):
self.start()
return self
def __exit__(self, type, value, traceback):
try:
self.stop()
except RuntimeError:
pass
# NOTE(harlowja): don't silence the exception.
return False
def leftover(self):
if self._duration is None:
raise RuntimeError("Can not get the leftover time of a watch that"
" has no duration")
if self._state != self._STARTED:
raise RuntimeError("Can not get the leftover time of a stopwatch"
" that has not been started")
end_time = self._started_at + self._duration
return max(0.0, end_time - wallclock())
def expired(self):
if self._duration is None:
return False
if self.elapsed() > self._duration:
return True
return False
def resume(self):
if self._state == self._STOPPED:
self._state = self._STARTED
return self
else:
raise RuntimeError("Can not resume a stopwatch that has not been"
" stopped")
def stop(self):
if self._state == self._STOPPED:
return self
if self._state != self._STARTED:
raise RuntimeError("Can not stop a stopwatch that has not been"
" started")
self._stopped_at = wallclock()
self._state = self._STOPPED
return self
def create_files(list_of_files):
if not list_of_files:
return
for filename in list_of_files:
if not os.path.isfile(filename):
with open(filename, 'w'):
pass