def send_hello_msg_to_node(self, nodeId): self.log.debug("Controller sends HelloMsg to agent") dest = nodeId cmdDesc = msgs.CmdDesc() cmdDesc.type = msgs.get_msg_type(msgs.HelloMsg) cmdDesc.func_name = msgs.get_msg_type(msgs.HelloMsg) cmdDesc.serialization_type = msgs.CmdDesc.PROTOBUF msg = msgs.HelloMsg() msg.uuid = str(self.controller.uuid) msg.timeout = self.helloTimeout msgContainer = [dest, cmdDesc, msg] self.controller.transport.send_downlink_msg(msgContainer)
def send_upstream(self, msg): dest = "controller" cmdDesc = msgs.CmdDesc() cmdDesc.type = "hierarchical_control" cmdDesc.func_name = "hierarchical_control" cmdDesc.call_id = str(0) cmdDesc.serialization_type = msgs.CmdDesc.PICKLE encapsulatedMsg = { "node_uuid": self.agent.uuid, "control_program_id": self.id, "msg": msg } msgContainer = [dest, cmdDesc, encapsulatedMsg] self.agent.send_upstream(msgContainer)
def process_cmd(self, msgContainer, localControllerId=None): dest = msgContainer[0] cmdDesc = msgContainer[1] msg = msgContainer[2] self.log.debug("Agent serves command: {}:{} from controller".format( cmdDesc.type, cmdDesc.func_name)) if not cmdDesc.exec_time or cmdDesc.exec_time == 0: self.log.debug("Agent sends message: {}:{} to module".format( cmdDesc.type, cmdDesc.func_name)) self.moduleManager.send_cmd_to_module(msgContainer, localControllerId) else: execTime = datetime.datetime.strptime(cmdDesc.exec_time, "%Y-%m-%d %H:%M:%S.%f") if execTime < datetime.datetime.now(): e = Exception( "Node: {} tried to schedule function: {}:{} call in past, consider time synchronization" .format(self.name, upi_type, fname)) dest = "controller" respDesc = msgs.CmdDesc() respDesc.type = cmdDesc.type respDesc.func_name = cmdDesc.func_name respDesc.call_id = cmdDesc.call_id #TODO: define new protobuf message for return values; currently using repeat_number in CmdDesc #0-executed correctly, 1-exception respDesc.repeat_number = 1 #Serialize return value respDesc.serialization_type = msgs.CmdDesc.PICKLE retVal = e response = [dest, respDesc, retVal] self.send_upstream(response) return self.log.debug( "Agent schedule task for message: {}:{} at {}".format( cmdDesc.type, cmdDesc.func_name, execTime)) self.jobScheduler.add_job(self.moduleManager.send_cmd_to_module, 'date', run_date=execTime, kwargs={ 'msgContainer': msgContainer, 'localControllerId': localControllerId })
def start(self): # Work on requests from controller while True: socks = dict(self.poller.poll()) if self.dl_socket in socks and socks[self.dl_socket] == zmq.POLLIN: msgContainer = self.dl_socket.recv_multipart() assert len(msgContainer) == 3, msgContainer dest = msgContainer[0] cmdDesc = msgs.CmdDesc() cmdDesc.ParseFromString(msgContainer[1]) msg = msgContainer[2] if cmdDesc.serialization_type == msgs.CmdDesc.PICKLE: msg = pickle.loads(msg) msgContainer[0] = dest.decode('utf-8') msgContainer[1] = cmdDesc msgContainer[2] = msg self.recv_callback(msgContainer)
def exec_cmd(self, upi_type, fname, *args, **kwargs): self.log.debug( "Controller executes cmd: {}.{} with args:{}, kwargs:{}".format( upi_type, fname, args, kwargs)) #get function call context iface = self._iface exec_time = self._exec_time delay = self._delay timeout = self._timeout blocking = self._blocking callback = self._callback self._clear_call_context() #TODO: support timeout, on controller and agent sides? callId = str(self.generate_call_id()) #build cmd desc message cmdDesc = msgs.CmdDesc() cmdDesc.type = upi_type cmdDesc.func_name = fname cmdDesc.call_id = callId if iface: cmdDesc.interface = iface if delay: exec_time = datetime.datetime.now() + datetime.timedelta( seconds=delay) blocking = False if exec_time: cmdDesc.exec_time = str(exec_time) blocking = False #call check if exec_time and exec_time < datetime.datetime.now(): raise Exception("Scheduling function: {}:{} call in past".format( upi_type, fname)) if not self.agent.is_upi_supported( iface=iface, upi_type=upi_type, fname=fname): raise Exception( "UPI Function: {}:{} not supported for iface: {}, please install proper modules" .format(upi_type, fname, iface)) #set callback for this function call if callback: self.callbacks[callId] = callback blocking = False msgContainer = ["agent", cmdDesc, kwargs] #if blocking call, return response if blocking: #send command to execution engine response = self.agent.moduleManager.send_cmd_to_module_blocking( msgContainer) cmdDesc = response[1] retVal = response[2] return retVal #send command to execution engine (non-blocking) self.agent.process_cmd(msgContainer=msgContainer, localControllerId=self.id) return None
def exec_cmd(self, upi_type, fname, *args, **kwargs): self.log.debug( "Controller builds cmd message: {}.{} with args:{}, kwargs:{}". format(upi_type, fname, args, kwargs)) #get function call context scope = local_func_call_context._scope iface = local_func_call_context._iface exec_time = local_func_call_context._exec_time delay = local_func_call_context._delay timeout = local_func_call_context._timeout blocking = local_func_call_context._blocking callback = local_func_call_context._callback self._clear_call_context() nodeNum = None callId = str(self.generate_call_id()) #build cmd desc message cmdDesc = msgs.CmdDesc() cmdDesc.type = upi_type cmdDesc.func_name = fname cmdDesc.call_id = callId if iface: cmdDesc.interface = iface if delay: exec_time = datetime.datetime.now() + datetime.timedelta( seconds=delay) blocking = False if exec_time: cmdDesc.exec_time = exec_time.strftime("%Y-%m-%d %H:%M:%S.%f") blocking = False #call check if exec_time and exec_time < datetime.datetime.now(): raise Exception("Scheduling function: {}:{} call in past".format( upi_type, fname)) #count nodes if list passed if hasattr(scope, '__iter__') and not isinstance(scope, str): nodeNum = len(scope) else: nodeNum = 1 #set callback for this function call if callback: self.callbacks[callId] = CallIdCallback(callback, nodeNum) blocking = False #if blocking call, wait for response if blocking: asyncResultCollector = AsyncResultCollector(nodeNum) self._asyncResults[callId] = asyncResultCollector #Serialize kwargs (they contrain args) cmdDesc.serialization_type = msgs.CmdDesc.PICKLE msgContainer = [cmdDesc, kwargs] #TODO: currently sending cmd msg to each node separately; #it would be more efficient to exploit PUB/SUB zmq mechanism #create group with uuid and tell nodes to subscribe to this uuid #then send msg to group if hasattr(scope, '__iter__') and not isinstance(scope, str): for node in scope: self.send_cmd_to_node(node, callId, msgContainer) else: node = scope self.send_cmd_to_node(node, callId, msgContainer) #if blocking call, wait for response if blocking: response = asyncResultCollector.get(timeout=timeout) del self._asyncResults[callId] return response return None