| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you 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 ConfigParser |
| import cPickle |
| import os |
| import select |
| import signal |
| import struct |
| import sys |
| import threading |
| import time |
| import traceback |
| import types |
| import getpass |
| |
| import rpyc |
| from tashi.rpycservices import rpycservices |
| from tashi.rpycservices.rpyctypes import TashiException, Errors, InstanceState, HostState |
| |
| def broken(oldFunc): |
| """Decorator that is used to mark a function as temporarily broken""" |
| def newFunc(*args, **kw): |
| raise RuntimeError("%s is broken!" % (oldFunc.__name__)) |
| if (oldFunc.__doc__ is None): |
| newFunc.__doc__ = "[Broken]" |
| else: |
| newFunc.__doc__ = "[Broken] " + oldFunc.__doc__ |
| newFunc.__name__ = oldFunc.__name__ |
| newFunc.__module__ = oldFunc.__module__ |
| return newFunc |
| |
| def deprecated(oldFunc): |
| """Decorator that is used to deprecate functions""" |
| def newFunc(*args, **kw): |
| raise RuntimeError("%s has been deprecated!" % (oldFunc.__name__)) |
| newFunc.__doc__ = "[Deprecated] " + str(oldFunc.__doc__) |
| newFunc.__name__ = oldFunc.__name__ |
| newFunc.__module__ = oldFunc.__module__ |
| return newFunc |
| |
| def logged(oldFunc): |
| """Decorator that is used to log a function's calls -- currently uses sys.stderr""" |
| def newFunc(*args, **kw): |
| logMsg = "%s(%s, %s) -> " % (oldFunc.__name__, str(args).strip("[]"), str(kw).strip("{}").replace(": ", "=")) |
| sys.stderr.write(logMsg) |
| sys.stderr.flush() |
| try: |
| res = oldFunc(*args, **kw) |
| except Exception, e: |
| logMsg = "%s\n" % (str(e)) |
| sys.stderr.write(logMsg) |
| sys.stderr.flush() |
| raise |
| logMsg = "%s\n" % (str(res)) |
| sys.stderr.write(logMsg) |
| sys.stderr.flush() |
| newFunc.__doc__ = oldFunc.__doc__ |
| newFunc.__name__ = oldFunc.__name__ |
| newFunc.__module__ = oldFunc.__module__ |
| return newFunc |
| |
| def timed(oldFunc): |
| """Decorator that is used to time a function's execution""" |
| def newFunc(*args, **kw): |
| start = time.time() |
| try: |
| res = oldFunc(*args, **kw) |
| finally: |
| finish = time.time() |
| print "%s: %f" % (oldFunc.__name__, finish-start) |
| return res |
| return newFunc |
| |
| def editAndContinue(file, mod, name): |
| def wrapper(oldFunc): |
| persist = {} |
| persist['lastMod'] = time.time() |
| persist['oldFunc'] = oldFunc |
| persist['func'] = oldFunc |
| def newFunc(*args, **kw): |
| modTime = os.stat(file)[8] |
| if (modTime > persist['lastMod']): |
| persist['lastMod'] = modTime |
| space = {} |
| exec ("import %s\nreload ( %s )" % (mod, mod)) in space |
| persist['func'] = eval(mod + "." + name, space) |
| return persist['func'](*args, **kw) |
| return newFunc |
| return wrapper |
| |
| class failsafe(object): |
| """Class that attempts to make RPCs, but will fall back to a local object that implements the same methods""" |
| def __attempt__(self, cur, fail): |
| def newFunc(*args, **kw): |
| try: |
| return cur(*args, **kw) |
| except Exception, e: |
| self.__dict__['__current_obj__'] = self.__dict__['__failsafe_obj__'] |
| return fail(*args, **kw) |
| return newFunc |
| |
| @deprecated |
| def __init__(self, obj): |
| self.__dict__['__failsafe_obj__'] = obj |
| self.__dict__['__current_obj__'] = obj |
| |
| def __update_current__(self, obj): |
| self.__dict__['__current_obj__'] = obj |
| |
| def __getattr__(self, name): |
| return self.__attempt__(getattr(self.__dict__['__current_obj__'], name), getattr(self.__dict__['__failsafe_obj__'], name)) |
| |
| def __setattr__(self, name, value): |
| return setattr(self.__dict__['__current_obj__'], name, value) |
| |
| def __delattr__(self, name): |
| return delattr(self.__dict__['__current_obj__'], name) |
| |
| class reference(object): |
| """Class used to create a replacable reference to an object""" |
| @deprecated |
| def __init__(self, obj): |
| self.__dict__['__real_obj__'] = obj |
| |
| def __update__(self, obj): |
| self.__dict__['__real_obj__'] = obj |
| |
| def __getattr__(self, name): |
| return getattr(self.__dict__['__real_obj__'], name) |
| |
| def __setattr__(self, name, value): |
| return setattr(self.__dict__['__real_obj__'], name, value) |
| |
| def __delattr__(self, name): |
| return delattr(self.__dict__['__real_obj__'], name) |
| |
| def isolatedRPC(client, method, *args, **kw): |
| """Opens and closes a thrift transport for a single RPC call""" |
| if (not client._iprot.trans.isOpen()): |
| client._iprot.trans.open() |
| res = getattr(client, method)(*args, **kw) |
| client._iprot.trans.close() |
| return res |
| |
| def signalHandler(signalNumber): |
| """Used to denote a particular function as the signal handler for a |
| specific signal""" |
| def __decorator(function): |
| signal.signal(signalNumber, function) |
| return function |
| return __decorator |
| |
| def boolean(value): |
| """Convert a variable to a boolean""" |
| if (type(value) == types.BooleanType): |
| return value |
| if (type(value) == types.IntType): |
| return (value != 0) |
| lowercaseValue = value.lower() |
| if lowercaseValue in ['yes', 'true', '1']: |
| return True |
| elif lowercaseValue in ['no', 'false', '0']: |
| return False |
| else: |
| raise ValueError |
| |
| def instantiateImplementation(className, *args): |
| """Create an instance of an object with the given class name and list |
| of args to __init__""" |
| if (className.rfind(".") != -1): |
| package = className[:className.rfind(".")] |
| cmd = "import %s\n" % (package) |
| else: |
| cmd = "" |
| cmd += "obj = %s(*args)\n" % (className) |
| exec cmd in locals() |
| return obj |
| |
| def convertExceptions(oldFunc): |
| """This converts any exception type into a TashiException so that |
| it can be passed over a Thrift RPC""" |
| def newFunc(*args, **kw): |
| try: |
| return oldFunc(*args, **kw) |
| except TashiException, e: |
| raise |
| except Exception, e: |
| self = args[0] |
| if (self.convertExceptions): |
| raise TashiException(d={'errno':Errors.ConvertedException, 'msg': traceback.format_exc(10)}) |
| raise |
| return newFunc |
| |
| def getConfig(additionalNames=[], additionalFiles=[]): |
| """Creates many permutations of a list of locations to look for config |
| files and then loads them""" |
| config = ConfigParser.ConfigParser() |
| baseLocations = ['./etc/', '/usr/share/tashi/', '/etc/tashi/', os.path.expanduser('~/.tashi/')] |
| names = ['Tashi'] + additionalNames |
| names = reduce(lambda x, y: x + [y+"Defaults", y], names, []) |
| allLocations = reduce(lambda x, y: x + reduce(lambda z, a: z + [y + a + ".cfg"], names, []), baseLocations, []) + additionalFiles |
| configFiles = config.read(allLocations) |
| if (len(configFiles) == 0): |
| raise Exception("No config file could be found: %s" % (str(allLocations))) |
| return (config, configFiles) |
| |
| def debugConsole(globalDict): |
| """A debugging console that optionally uses pysh""" |
| def realDebugConsole(globalDict): |
| try : |
| import atexit |
| from IPython.Shell import IPShellEmbed |
| def resetConsole(): |
| # XXXpipe: make input window sane |
| (stdin, stdout) = os.popen2("reset") |
| stdout.read() |
| dbgshell = IPShellEmbed() |
| atexit.register(resetConsole) |
| dbgshell(local_ns=globalDict, global_ns=globalDict) |
| except Exception: |
| CONSOLE_TEXT=">>> " |
| input = " " |
| while (input != ""): |
| sys.stdout.write(CONSOLE_TEXT) |
| input = sys.stdin.readline() |
| try: |
| exec(input) in globalDict |
| except Exception, e: |
| sys.stdout.write(str(e) + "\n") |
| if (os.getenv("DEBUG", "0") == "1"): |
| threading.Thread(target=lambda: realDebugConsole(globalDict)).start() |
| |
| def stringPartition(s, field): |
| index = s.find(field) |
| if (index == -1): |
| return (s, "", "") |
| l = s[:index] |
| sep = s[index:index+len(field)] |
| r = s[index+len(field):] |
| return (l, sep, r) |
| |
| def scrubString(s, allowed="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_."): |
| ns = "" |
| for c in s: |
| if (c in allowed): |
| ns = ns + c |
| return ns |
| |
| def createClient(config): |
| cfgHost = config.get('Client', 'clusterManagerHost') |
| cfgPort = config.get('Client', 'clusterManagerPort') |
| cfgTimeout = config.get('Client', 'clusterManagerTimeout') |
| host = os.getenv('TASHI_CM_HOST', cfgHost) |
| port = os.getenv('TASHI_CM_PORT', cfgPort) |
| timeout = float(os.getenv('TASHI_CM_TIMEOUT', cfgTimeout)) * 1000.0 |
| |
| authAndEncrypt = boolean(config.get('Security', 'authAndEncrypt')) |
| if authAndEncrypt: |
| username = config.get('AccessClusterManager', 'username') |
| if username == '': |
| username = raw_input('Enter Username:') |
| password = config.get('AccessClusterManager', 'password') |
| if password == '': |
| password = getpass.getpass('Enter Password:') |
| client = rpycservices.client(host, port, username=username, password=password) |
| else: |
| client = rpycservices.client(host, port) |
| return client |
| |
| def enumToStringDict(cls): |
| d = {} |
| for i in cls.__dict__: |
| if (type(cls.__dict__[i]) is int): |
| d[cls.__dict__[i]] = i |
| return d |
| |
| vmStates = enumToStringDict(InstanceState) |
| hostStates = enumToStringDict(HostState) |