def start_app(self, appdef=None, config=None): """ @brief Start an app from an app definition. Note: apps can come in one of 2 variants: 1 processapp: In-line defined process to be started 2 regular app: Full app definition """ log.debug("AppManager.start_app(appdef=%s) ..." % appdef) appdef = DotDict(appdef) app_config = DictModifier(CFG) if 'config' in appdef: # Apply config from app file app_file_cfg = DotDict(appdef.config) app_config.update(app_file_cfg) if config: # Nest dict modifier and apply config from rel file app_config = DictModifier(app_config, config) if 'processapp' in appdef: # Case 1: Appdef contains definition of process to start name, module, cls = appdef.processapp try: pid = self.container.spawn_process(name, module, cls, app_config) appdef._pid = pid self.apps.append(appdef) except Exception, ex: log.exception("Appl %s start from processapp failed" % appdef.name)
def spawn_process(self, name=None, module=None, cls=None, config=None): """ Spawn a process within the container. Processes can be of different type. """ # Generate a new process id # TODO: Ensure it is system-wide unique process_id = "%s.%s" % (self.container.id, self.proc_id_pool.get_id()) log.debug("ProcManager.spawn_process(name=%s, module.cls=%s.%s) as pid=%s", name, module, cls, process_id) if config is None: config = DictModifier(CFG) log.debug("spawn_process() pid=%s config=%s", process_id, config) # PROCESS TYPE. Determines basic process context (messaging, service interface) # One of: service, stream_process, agent, simple, immediate service_cls = named_any("%s.%s" % (module, cls)) process_type = config.get("process", {}).get("type", None) or getattr(service_cls, "process_type", "service") service_instance = None try: # spawn service by type if process_type == "service": service_instance = self._spawn_service_process(process_id, name, module, cls, config) elif process_type == "stream_process": service_instance = self._spawn_stream_process(process_id, name, module, cls, config) elif process_type == "agent": service_instance = self._spawn_agent_process(process_id, name, module, cls, config) elif process_type == "standalone": service_instance = self._spawn_standalone_process(process_id, name, module, cls, config) elif process_type == "immediate": service_instance = self._spawn_immediate_process(process_id, name, module, cls, config) elif process_type == "simple": service_instance = self._spawn_simple_process(process_id, name, module, cls, config) else: raise Exception("Unknown process type: %s" % process_type) service_instance._proc_type = process_type self._register_process(service_instance, name) service_instance.errcause = "OK" log.info("AppManager.spawn_process: %s.%s -> pid=%s OK" % (module, cls, process_id)) return service_instance.id except Exception: errcause = service_instance.errcause if service_instance else "instantiating service" log.exception("Error spawning %s %s process (process_id: %s): %s" % (name, process_type, process_id, errcause)) raise
def start_rel(self, rel=None, config=None): """ @brief Recurse over the rel and start apps defined there. Note: apps in a rel file can come in one of 2 forms: 1 processapp: In-line defined process to be started as app 2 app file: Reference to an app definition in an app file """ log.debug("AppManager.start_rel(rel=%s) ..." % str(rel)) if rel is None: rel = {} for rel_app_cfg in rel.apps: name = rel_app_cfg.name log.debug("app definition in rel: %s" % str(rel_app_cfg)) if 'processapp' in rel_app_cfg: # Case 1: Rel contains definition of process to start as app name, module, cls = rel_app_cfg.processapp if 'config' in rel_app_cfg: # Nest dict modifier and apply config from rel file config = DictModifier(config, rel_app_cfg.config) self.container.spawn_process(name, module, cls, config) self.apps.append( DotDict(type="application", name=name, processapp=rel_app_cfg.processapp)) else: # Case 2: Rel contains reference to app file to start app_file_path = 'res/apps/%s.yml' % (name) self.start_app_from_url(app_file_path, config=rel_app_cfg.get('config', None))
def test_dict_modifier(self): base = DotDict({"foo": "bar", "bah": "fah"}) dict_modifier = DictModifier(base) self.assertEqual(dict_modifier["foo"], "bar") top = DotDict({"bah": "lah", "doh": "ray"}) dict_modifier.update(top) saved_dict_modifier = dict_modifier self.assertEqual(dict_modifier["foo"], "bar") self.assertEqual(dict_modifier["bah"], "lah") self.assertEqual(dict_modifier["doh"], "ray") dict_modifier = DictModifier(dict_modifier) self.assertEqual(dict_modifier["foo"], "bar") self.assertEqual(dict_modifier["bah"], "lah") self.assertEqual(dict_modifier["doh"], "ray") self.assertEqual(dict_modifier.base, saved_dict_modifier) top = DotDict({"bah": "trah"}) dict_modifier.update(top) saved_dict_modifier = dict_modifier self.assertEqual(dict_modifier["foo"], "bar") self.assertEqual(dict_modifier["bah"], "trah") self.assertEqual(dict_modifier["doh"], "ray")
def spawn_process(self, name=None, module=None, cls=None, config=None, process_id=None): """ Spawn a process within the container. Processes can be of different type. """ if process_id and not is_valid_identifier(process_id, ws_sub='_'): raise BadRequest("Given process_id %s is not a valid identifier" % process_id) # Generate a new process id if not provided # TODO: Ensure it is system-wide unique process_id = process_id or "%s.%s" % (self.container.id, self.proc_id_pool.get_id()) log.debug( "ProcManager.spawn_process(name=%s, module.cls=%s.%s) as pid=%s", name, module, cls, process_id) if not config: # Use system CFG. It has the command line args in it config = DictModifier(CFG) else: # Use provided config. Must be dict or DotDict if not isinstance(config, DotDict): config = DotDict(config) config = DictModifier(CFG, config) if self.container.spawn_args: # Override config with spawn args dict_merge(config, self.container.spawn_args, inplace=True) #log.debug("spawn_process() pid=%s config=%s", process_id, config) # PROCESS TYPE. Determines basic process context (messaging, service interface) # One of: service, stream_process, agent, simple, immediate service_cls = named_any("%s.%s" % (module, cls)) process_type = get_safe(config, "process.type") or getattr( service_cls, "process_type", "service") service_instance = None try: # spawn service by type if process_type == "service": service_instance = self._spawn_service_process( process_id, name, module, cls, config) elif process_type == "stream_process": service_instance = self._spawn_stream_process( process_id, name, module, cls, config) elif process_type == "agent": service_instance = self._spawn_agent_process( process_id, name, module, cls, config) elif process_type == "standalone": service_instance = self._spawn_standalone_process( process_id, name, module, cls, config) elif process_type == "immediate": service_instance = self._spawn_immediate_process( process_id, name, module, cls, config) elif process_type == "simple": service_instance = self._spawn_simple_process( process_id, name, module, cls, config) else: raise BadRequest("Unknown process type: %s" % process_type) service_instance._proc_type = process_type self._register_process(service_instance, name) service_instance.errcause = "OK" log.info("AppManager.spawn_process: %s.%s -> pid=%s OK", module, cls, process_id) if process_type == 'immediate': log.info('Terminating immediate process: %s', service_instance.id) self.terminate_process(service_instance.id) return service_instance.id except Exception: errcause = service_instance.errcause if service_instance else "instantiating service" log.exception("Error spawning %s %s process (process_id: %s): %s", name, process_type, process_id, errcause) raise