Service Deployment Configs ========================== Each EI service has a deployment configuration, and we automate these via ``_EISvc`` class instances that are used by an EI manager. Functions in these classes can be set to run on all nodes in an EI manager, or instead take a specific node instance as an argument. For example, take the ``PubSub`` service configuration: .. code-block:: python class PubSub(_EISvc): SVCID = 3 SVCNAME = "pubsub" def __init__(self, ei): super().__init__(ei) self.cores = [node for node in ei.nodes if node.sn == 3] @splat_node def config(self, *, node): ctl = QuickCtl(node) res = MiniFutureList() res.append(ctl.call('tree.add_child', 'config', './"services"/"pubsub"')) res.append( ctl.call('tree.add_child', 'config', './"services"/"pubsub"/"core_sn_id"') ) res.append( ctl.call( 'tree.write', 'config', './"services"/"pubsub"/"core_sn_id"', value=3 ) ) return res @splat_node def start_proxy(self, *, node): return node.node.run( f'cd {node.node.pox_dir} ; ./pox.py misc.pidfile=/tmp/eilogs/pid_{node.dom}_{node.sn}_pubsub_proxy web --no-cookieguard --port={node.proxy_port(self.SVCID)} ei.pubsub.proxy --hssock={node.hssock} >&/dev/null &', asynchronous=True, ) The ``SVCID`` and ``SVCNAME`` variables must match what is in EI directly. By defining the ``@splat_node`` decorator on the ``config(...)`` and ``start_proxy(...)`` functions, the EI manager can run this function on all nodes: .. code-block:: python ei.pubsub.config() ei.pubsub.start_proxy() node_mgr.wait_all() The futures list in these functions will cause the commands added onto a node to be run in-order on that node; each node has an asynchronous task manager to do this. Running ``wait_all()`` on a node manager will wait for all commands on all nodes to complete before returning. It is possible to write these functions without ``@splat_node``, in which case they must be called with a service node instance: .. code-block:: python ei.qbss.config(node=node_mgr.instance((1, 1)), ...)