def __init__(self, uniquename=None, *args, **kwargs): """Check for configuration issues and instantiate a component""" def pick_unique_name(): while True: uniquename = "%s%s" % (self.__class__.__name__, randint(0, 32768)) if uniquename not in self.names: self.uniquename = uniquename self.names.append(uniquename) break self.uniquename = "" if uniquename is not None: if uniquename not in self.names: self.uniquename = uniquename self.names.append(uniquename) else: isolog( "Unique component added twice: ", uniquename, lvl=critical, emitter="CORE", ) pick_unique_name() else: pick_unique_name()
def __init__(self, uuid, packet, sendtype="client", raw=False, username=None, fail_quiet=False, *args): """ :param uuid: Unique User ID of known connection :param packet: Data packet to transmit to client :param args: Further Args """ super(send, self).__init__(*args) if uuid is None and username is None: isolog("[SEND-EVENT] No recipient (uuid/name) given!", lvl=warn) self.uuid = uuid self.packet = packet self.username = username self.sendtype = sendtype self.raw = raw self.fail_quiet = fail_quiet isolog( "[CM-EVENT] Send event generated:", uuid, str(packet)[:80], sendtype, lvl=events, )
def std_datetime(date, date_format="%d.%m.%Y", tz="UTC"): """Return something that looks like a date into a timestamp in ISO format""" if isinstance(date, tuple): now = datetime(*date) elif isinstance(date, str): if date_format == 'iso': now = datetime.fromisoformat(date) else: now = datetime.strptime(date, date_format) else: isolog("Could not convert date:", date, date_format, tz, pretty=True, lvl=warn) return date now = now.astimezone(pytz.timezone(tz)) result = now.isoformat() return result
def serial_ports(): """ Lists serial port names :raises EnvironmentError: On unsupported or unknown platforms :returns: A list of the serial ports available on the system Courtesy: Thomas ( http://stackoverflow.com/questions/12090503 /listing-available-com-ports-with-python ) """ if sys.platform.startswith('win'): ports = ['COM%s' % (i + 1) for i in range(256)] elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'): # this excludes your current terminal "/dev/tty" ports = glob.glob('/dev/tty[A-Za-z]*') elif sys.platform.startswith('darwin'): ports = glob.glob('/dev/tty.*') else: raise EnvironmentError('Unsupported platform') result = [] for port in ports: try: s = serial.Serial(port) s.close() result.append(port) except (OSError, serial.SerialException) as e: isolog('Could not open serial port:', port, e, type(e), exc=True, lvl=warn) return result
def addNode(self, uuid, ip): hoststring = 'tcp://' + ip + ':' + str(PORT) isolog("ZMQ Dealer peer:", hoststring, emitter="ZMQThread") p = self.ctx.socket(zmq.DEALER) p.connect(hoststring) p.send_string('HELLO:' + self.uuid) self.sockets[uuid] = p
def log(*args, **kwargs): """Log as previous emitter""" kwargs.update({"frame_ref": 2}) kwargs["lvl"] = critical if "emitter" not in kwargs: kwargs["emitter"] = "MANAGE" isolog(*args, **kwargs)
def test_script_logging(): logger.live = True logger.isolog("FOOBAR") lastlog = logger.LiveLog[-1][-1] assert "FOOBAR" in lastlog
def __init__(self, vessel): """ :param vessel: Vessel object (System Default Vessel) """ super(updateposition, self).__init__() self.vessel = vessel isolog("[NAVDATA-EVENT] Vessel position has changed: ", vessel, lvl=events)
def write_errors(errors): for error in errors: content = error[1] code = content['code'] msg = content['message'] isolog('Creating Error %i: %s' % (code, msg)) filename = os.path.join(ERROR_OUTPUT, "E%i.rst" % code) write_template_file(TEMPLATE_FILE, filename, content)
def __init__(self, data): """ :param data: Parsed NMEA? Data """ super(referenceframe, self).__init__() self.data = data isolog("[NAVDATA-EVENT] Reference frame generated: ", data, lvl=events)
def __init__(self, clientuuid, useruuid, client, user, *args): super(userlogin, self).__init__(*args) self.clientuuid = clientuuid self.useruuid = useruuid self.client = client self.user = user isolog("[CM-EVENT] User login event generated:", clientuuid, useruuid, lvl=events)
def __init__(self, clientuuid, useruuid=None, *args): super(clientdisconnect, self).__init__(*args) self.clientuuid = clientuuid self.useruuid = useruuid isolog( "[CM-EVENT] Client disconnect event generated:", clientuuid, useruuid, lvl=events, )
def __init__(self, schema, data, *args, **kwargs): super(updatesubscriptions, self).__init__(*args, **kwargs) self.schema = schema self.data = data isolog( "Object event created: ", self.__doc__, self.__dict__, lvl=events, emitter="OBJECT-EVENT", )
def __init__(self, *args): """ :param user: Userobject of client :param data: The new profile data """ super(profilerequest, self).__init__(*args) isolog( "Profile update request: ", self.__dict__, lvl=events, emitter="PROFILE-EVENT", )
def __init__(self, uuid, schema, client, *args, **kwargs): super(objectevent, self).__init__(*args, **kwargs) self.uuid = uuid self.schema = schema self.client = client isolog( "Object event created: ", self.__doc__, self.__dict__, lvl=events, emitter="OBJECT-EVENT", )
def __init__(self, callback, sendcallback, peers, uuid): threading.Thread.__init__(self, daemon=True) isolog("Started", emitter="ZMQThread") self.loop = ioloop.IOLoop.instance() self.callback = callback self.peers = peers self.uuid = uuid self.sockets = {} self.routes = {} self.running = True self._stop = threading.Event() self.ctx = zmq.Context() sendcallback(self.send)
def log(self, *args, **kwargs): """Log a statement from this component""" func = inspect.currentframe().f_back.f_code # Dump the message + the name of this function to the log. if "exc" in kwargs and kwargs["exc"] is True: exc_type, exc_obj, exc_tb = exc_info() line_no = exc_tb.tb_lineno # print('EXCEPTION DATA:', line_no, exc_type, exc_obj, exc_tb) args += (traceback.extract_tb(exc_tb), ) else: line_no = func.co_firstlineno sourceloc = "[%.10s@%s:%i]" % (func.co_name, func.co_filename, line_no) isolog(sourceloc=sourceloc, emitter=self.uniquename, *args, **kwargs)
def __init__(self, action, data, client, *args): """ Initializes an Isomer anonymous user interface event. :param action: :param data: :param client: :param args: :return: """ self.name = self.__module__ + "." + self.__class__.__name__ super(anonymous_event, self).__init__(*args) self.action = action self.data = data self.client = client isolog("AnonymousEvent created:", self.name, lvl=events)
def run(self): s = self.ctx.socket(zmq.ROUTER) s.bind("tcp://*:" + str(PORT)) # s.setsockopt(zmq.SUBSCRIBE, b'') stream = zmqstream.ZMQStream(s, self.loop) stream.on_recv(self.cb) # print(s.getsockopt(zmq.LAST_ENDPOINT)) for peer in self.peers: self.addNode(peer['uuid'], peer['ip']) isolog("Entering thread loop", lvl=debug, emitter="ZMQThread") self.loop.start() # from time import sleep # while self.running: # sleep(0.1) isolog("Exiting thread loop", lvl=debug, emitter="ZMQThread")
def __init__(self, broadcasttype, content, group=None, *args): """ :param broadcasttype: One of [users|clients|usergroup|clientgroup|socks] :param content: Data packet to transmit to client :param group: Used for group broadcasting (a list of either client or user uuids) :param args: Further Args """ super(broadcast, self).__init__(*args) self.broadcasttype = broadcasttype self.content = content self.group = group isolog("[CM-EVENT] Broadcast event generated:", broadcasttype, content, group, lvl=events)
def _on_exception(self, error_type, value, traceback, handler=None, fevent=None): # TODO: Generate hashes and thus unique urls with exceptions and fill # them out with this data: # self.log('EXCEPTIONHANDLER:', error_type, value, traceback, lvl=critical) # The idea is to have error pages in the documentation/public Isomer instance # so people can discuss and get help on runtime errors, like with the # exitcodes system in the documentation try: s = [] if handler is None: handler = "" else: handler = reprhandler(handler) msg = "ERROR" msg += "{0:s} ({1:s}) ({2:s}): {3:s}\n".format( handler, repr(fevent), repr(error_type), repr(value) ) s.append(msg) s.append("\n") isolog("\n".join(s), "\n".join(traceback), lvl=critical, frame_ref=3, emitter="DEBUG") alert = { "component": "isomer.alert.manager", "action": "notify", "data": { "type": "danger", "message": "\n".join(s), "title": "Exception Monitor", }, } for user in self.config.notificationusers: self.fireEvent(send(None, alert, username=user, sendtype="user")) except Exception as e: self.log("Exception during exception handling: ", e, type(e), lvl=critical, exc=True)
def __init__(self, username, userdata, clientuuid, useruuid, sock, *args): """ :param username: Account username :param userdata: Tuple containing both useraccount and userprofile :param uuid: Unique User ID of known connection :param sock: Associated Socket :param args: Further Args """ super(authentication, self).__init__(*args) self.username = username self.userdata = userdata self.clientuuid = clientuuid self.useruuid = useruuid self.sock = sock isolog("[AUTH-EVENT] Authentication granted:", self.__dict__, lvl=events)
def __init__(self, user, action, data, client, *args): """ Initializes an Isomer authorized user interface event. :param user: User object from :py:class:isomer.web.clientmanager.User :param action: :param data: :param client: :param args: :return: """ # assert isinstance(user, User) self.name = self.__module__ + "." + self.__class__.__name__ super(authorized_event, self).__init__(*args) self.user = user self.action = action self.data = data self.client = client isolog("AuthorizedEvent created:", self.name, lvl=events)
def drop_privileges(uid_name="isomer", gid_name="isomer"): """Attempt to drop privileges and change user to 'isomer' user/group""" if os.getuid() != 0: isolog("Not root, cannot drop privileges", lvl=warn, emitter="CORE") return try: # Get the uid/gid from the name running_uid = pwd.getpwnam(uid_name).pw_uid running_gid = grp.getgrnam(gid_name).gr_gid # Remove group privileges os.setgroups([]) # Try setting the new uid/gid os.setgid(running_gid) os.setuid(running_uid) # Ensure a very conservative umask # old_umask = os.umask(22) isolog("Privileges dropped", emitter="CORE") except Exception as e: isolog( "Could not drop privileges:", e, type(e), exc=True, lvl=error, emitter="CORE", )
def build_provision_store(): available = {} for provision_entrypoint in iter_entry_points(group="isomer.provisions", name=None): isolog("Provisions found: ", provision_entrypoint.name, lvl=debug, emitter="DB") try: available[provision_entrypoint.name] = provision_entrypoint.load() except ImportError: isolog( "Problematic provision: ", provision_entrypoint.name, exc=True, lvl=warn, emitter="PROVISIONS", frame_ref=2, ) isolog("Found provisions: ", sorted(list(available.keys())), emitter="PROVISIONS") # pprint(available) return available
def launch(ctx, run=True, **args): """Assemble and run an Isomer instance""" isolog("Launching Mini instance") if ctx.params["live_log"] is True: from isomer import logger logger.live = True if args["web_certificate"] is not None: isolog( "Warning! Using SSL on the backend is currently not recommended!", lvl=critical, emitter="CORE", ) server = construct_graph('MINI', {}, args) if run and not args["no_run"]: server.run() return server
def construct_graph(ctx, name, instance, args): """Preliminary Isomer application Launcher""" app = Core(name, instance, **args) # TODO: This should probably be read-only BaseMeta.context = ctx setup_root(app) if args["debug"]: from circuits import Debugger isolog("Starting circuits debugger", lvl=warn, emitter="GRAPH") dbg = Debugger().register(app) # TODO: Make these configurable from modules, navdata is _very_ noisy # but should not be listed _here_ dbg.IgnoreEvents.extend([ "read", "_read", "write", "_write", "stream_success", "stream_complete", "serial_packet", "raw_data", "stream", "navdatapush", "referenceframe", "updateposition", "updatesubscriptions", "generatevesseldata", "generatenavdata", "sensordata", "reset_flood_offenders", "reset_flood_counters", # Flood counters "task_success", "task_done", # Thread completion "keepalive", # IRC Gateway "peek", # AVIO and others "joystickchange", # AVIO ]) isolog("Beginning graph assembly.", emitter="GRAPH") if args["draw_graph"]: from circuits.tools import graph graph(app) if args["open_gui"]: import webbrowser # TODO: Fix up that url: webbrowser.open("http://%s:%i/" % (args["host"], args["port"])) isolog("Graph assembly done.", emitter="GRAPH") return app
def provision_system_config(items, database_name, overwrite=False, clear=False, skip_user_check=False): """Provision a basic system configuration""" from isomer.provisions.base import provisionList from isomer.database import objectmodels default_system_config_count = objectmodels["systemconfig"].count( {"name": "Default System Configuration"}) if default_system_config_count == 0 or (clear or overwrite): provisionList([SystemConfiguration], "systemconfig", overwrite, clear, skip_user_check) isolog("Provisioning: System: Done.", emitter="PROVISIONS") else: isolog( "Default system configuration already present.", lvl=warn, emitter="PROVISIONS", )
def generate_asyncapi(): """Generate async-api definition""" if not populated: populate_user_events() api_events = {**AuthorizedEvents, **AnonymousEvents} api = copy(asyncapi_template) for package, channel_events in api_events.items(): isolog('Inspecting package:', package) for name, meta in channel_events.items(): isolog(meta, lvl=verbose) if meta['args'] == {}: isolog(name.ljust(20), ":", meta, pretty=True, lvl=debug) else: isolog(meta['args'], pretty=True, lvl=debug) channel, event_name = meta['name'].rsplit('.', 1) channel = channel.replace(".", "/") if channel not in api['channels']: api['channels'][channel] = {} api['channels'][channel][event_name] = { "summary": meta["summary"], "tags": meta["tags"], "description": meta["doc"], 'operationId': event_name, "message": { "payload": meta['args'], } } isolog("\n", api, pretty=True, lvl=hilight) return api
def launch(ctx, run=True, **args): """Assemble and run an Isomer instance""" instance_name = ctx.obj["instance"] instance = load_instance(instance_name) environment_name = ctx.obj["environment"] isolog("Launching instance %s - (%s)" % (instance_name, environment_name), emitter="CORE", lvl=debug) database_host = ctx.obj["dbhost"] database_name = ctx.obj["dbname"] if ctx.params["live_log"] is True: from isomer import logger logger.live = True if args["web_certificate"] is not None: isolog( "Warning! Using SSL on the backend is currently not recommended!", lvl=critical, emitter="CORE", ) isolog("Initializing database access", emitter="CORE", lvl=debug) initialize(database_host, database_name, instance_name) isolog("Setting instance paths", emitter="CORE", lvl=debug) set_instance(instance_name, environment_name) server = construct_graph(ctx, instance_name, instance, args) if run and not args["no_run"]: server.run() return server