def update_status(self, status, context=None): """ Updates the internal state of the `Status` object. This method will throw errors if the context is not serializable or if the status parameter is not within the ACCEPTABLE_STATUS tuple. :param status: :param context: :return: """ if status not in ACCEPTABLE_STATUS: raise ValueError('Invalid status value {}'.format(status)) try: jsonapi.dumps(context) except TypeError: raise ValueError('Context must be JSON serializable.') status_changed = status != self._status self._status = status self._context = context self._last_updated = format_timestamp(get_aware_utc_now()) if status_changed and self._status_changed_callback: print(self._status_changed_callback())
def insert_aggregate(self, agg_topic_id, agg_type, period, ts, data, topic_ids): """ Insert aggregate data collected for a specific time period into database. Data is inserted into <agg_type>_<period> table :param agg_topic_id: topic id :param agg_type: type of aggregation :param period: time period of aggregation :param ts: end time of aggregation period (not inclusive) :param data: computed aggregate :param topic_ids: topic ids or topic ids for which aggregate was computed :return: True if execution was successful, raises exception in case of connection failures """ self.__connect() table_name = agg_type + '_' + period _log.debug("Inserting aggregate: {} {} {} {} into table {}".format( ts, agg_topic_id, jsonapi.dumps(data), str(topic_ids), table_name)) self.execute_stmt( self.insert_aggregate_stmt(table_name), (ts, agg_topic_id, jsonapi.dumps(data), str(topic_ids)), commit=True) return True
def list(self, peer, prefix='', bus='', subscribed=True, reverse=False, all_platforms=False): """Gets list of subscriptions matching the prefix and bus for the specified peer. param peer: peer type peer: str param prefix: prefix of a topic type prefix: str param bus: bus type bus: bus param subscribed: subscribed or not type subscribed: boolean param reverse: reverse type reverse: :returns: List of subscriptions, i.e, list of tuples of bus, topic and flag to indicate if peer is a subscriber or not :rtype: list of tuples :Return Values: List of tuples [(topic, bus, flag to indicate if peer is a subscriber or not)] """ # For backward compatibility with old pubsub if self._send_via_rpc: return self.rpc().call(peer, 'pubsub.list', prefix, bus, subscribed, reverse) else: result = next(self._results) # Parameters are stored initially, in case remote agent/platform is using old pubsub if self._parameters_needed: kwargs = dict(op='list', prefix=prefix, subscribed=subscribed, reverse=reverse, bus=bus) self._save_parameters(result.ident, **kwargs) list_msg = jsonapi.dumps(dict(prefix=prefix, all_platforms=all_platforms, subscribed=subscribed, reverse=reverse, bus=bus)) frames = [b'list', list_msg] self.vip_socket.send_vip(b'', 'pubsub', frames, result.ident, copy=False) return result
def call(self, peer, method, *args, **kwargs): platform = kwargs.pop('external_platform', '') request, result = self._dispatcher.call(method, args, kwargs) ident = '%s.%s' % (next(self._counter), hash(result)) self._outstanding[ident] = result if platform == '': if self._isconnected: try: self.core().socket.send_vip(peer, 'RPC', [request], msg_id=ident) except ZMQError as exc: if exc.errno == ENOTSOCK: _log.debug("Socket send on non socket {}".format(self.core().identity)) else: frames = [] op = b'send_platform' frames.append(op) msg = jsonapi.dumps(dict(to_platform=platform, to_peer=peer, from_platform='', from_peer='', args=[request])) frames.append(msg) #_log.debug("RPC subsystem: External platform RPC msg: {}".format(frames)) if self._isconnected: try: self.core().socket.send_vip('', 'external_rpc', frames, msg_id=ident) except ZMQError as exc: if exc.errno == ENOTSOCK: _log.debug("Socket send on non socket {}".format(self.core().identity)) return result
def notify(self, peer, method, *args, **kwargs): platform = kwargs.pop('external_platform', '') request = self._dispatcher.notify(method, args, kwargs) if platform == '': if self._isconnected: try: self.core().socket.send_vip(peer, 'RPC', [request]) except ZMQError as exc: if exc.errno == ENOTSOCK: _log.debug("Socket send on non socket {}".format(self.core().identity)) else: frames = [] op = b'send_platform' frames.append(op) msg = jsonapi.dumps(dict(to_platform=platform, to_peer=peer, from_platform='', from_peer='', args=[request])) frames.append(msg) # _log.debug("RPC subsystem: External platform RPC msg: {}".format(frames)) if self._isconnected: try: self.core().socket.send_vip('', 'extrenal_rpc', frames) except ZMQError as exc: if exc.errno == ENOTSOCK: _log.debug("Socket send on non socket {}".format(self.core().identity))
def _set_override_off(self, pattern): """Turn off override condition on all devices matching the pattern. It removes the pattern from the override patterns set, clears the list of overriden devices and reevaluates the state of devices. It then cancels the pending override event and removes pattern from the config store. :param pattern: Override pattern to be removed. :type pattern: str """ pattern = pattern.lower() # If pattern exactly matches if pattern in self._override_patterns: self._override_patterns.discard(pattern) # Cancel any pending override events self._cancel_override_events(pattern) self._override_devices.clear() patterns = dict() # Build override devices list again for pat in self._override_patterns: for device in self.instances: device = device.lower() if fnmatch.fnmatch(device, pat): self._override_devices.add(device) if self._override_interval_events[pat] is None: patterns[pat] = str(0.0) else: evt, end_time = self._override_interval_events[pat] patterns[pat] = utils.format_timestamp(end_time) self.vip.config.set("override_patterns", jsonapi.dumps(patterns)) else: _log.error("Override Pattern did not match!") raise OverrideError( "Pattern {} does not exist in list of override patterns".format(pattern))
def _get_discovery(self, environ, start_response, data=None): q = query.Query(self.core) self.instance_name = q.query('instance-name').get(timeout=60) print("Discovery instance: {}".format(self.instance_name)) addreses = q.query('addresses').get(timeout=60) external_vip = None for x in addreses: if not is_ip_private(x): external_vip = x break peers = self.vip.peerlist().get(timeout=60) return_dict = {} if self.serverkey: return_dict['serverkey'] = encode_key(self.serverkey) else: sk = None if self.instance_name: return_dict['instance-name'] = self.instance_name return_dict['vip-address'] = external_vip start_response('200 OK', [('Content-Type', 'application/json')]) return jsonapi.dumps(return_dict)
def _allow(self, environ, start_response, data=None): _log.info('Allowing new vc instance to connect to server.') jsondata = jsonapi.loads(data) json_validate_request(jsondata) assert jsondata.get('method') == 'allowvc' assert jsondata.get('params') params = jsondata.get('params') if isinstance(params, list): vcpublickey = params[0] else: vcpublickey = params.get('vcpublickey') assert vcpublickey assert len(vcpublickey) == 43 authfile = AuthFile() authentry = AuthEntry(credentials=vcpublickey) try: authfile.add(authentry) except AuthFileEntryAlreadyExists: pass start_response('200 OK', [('Content-Type', 'application/json')]) return jsonapi.dumps( json_result(jsondata['id'], "Added") )
def _on_platform_message(self,peer, sender, bus, topic, headers, message): """ Callback function for vcp agent to publish to. Platforms that are being managed should publish to this topic with the agent_list and other interesting things that the volttron central shsould want to know. """ self._log.debug('ON PLATFORM MESSAGE! {}'.format(message)) expected_prefix = "platforms/{}/".format(self.vip_identity) if not topic.startswith(expected_prefix): self._log.warn( "Unexpected topic published to stats function: {}".format( topic )) return self._log.debug("TOPIC WAS: {}".format(topic)) self._log.debug("MESSAGE WAS: {}".format(message)) self._log.debug("Expected topic: {}".format(expected_prefix)) self._log.debug( "Are Equal: {}".format(topic.startswith(expected_prefix))) self._log.debug("topic type: {} prefix_type: {}".format(type(topic), type( expected_prefix))) # Pull off the "real" topic from the prefix # topic = topic[len(expected_prefix):] topicsplit = topic.split('/') if len(topicsplit) < 2: self._log.error('Invalid topic length published to volttron central') return # Topic is platforms/<platform_uuid>/otherdata topicsplit = topic.split('/') if len(topicsplit) < 3: self._log.warn("Invalid topic length no operation or datatype.") self._log.warn("Topic was {}".format(topic)) return _, platform_uuid, op_or_datatype, other = topicsplit[0], \ topicsplit[1], \ topicsplit[2], \ topicsplit[3:] if op_or_datatype in ('iam', 'configure'): if not other: self._log.error("Invalid response to iam or configure endpoint") self._log.error( "the sesson token was not included in response from vcp.") return ws_endpoint = "/vc/ws/{}/{}".format(other[0], op_or_datatype) self._log.debug('SENDING MESSAGE TO {}'.format(ws_endpoint)) self._vc.vip.web.send(ws_endpoint, jsonapi.dumps(message)) else: self._log.debug("OP WAS: {}".format(op_or_datatype))
def handle_subsystem(self, frames, user_id): subsystem = bytes(frames[5]) if subsystem == b'quit': sender = bytes(frames[0]) if sender == b'control' or b'platform.auth' and user_id == self.default_user_id: if self._ext_routing: self._ext_routing.close_external_connections() self.stop() raise KeyboardInterrupt() elif subsystem == b'agentstop': try: drop = frames[6].bytes self._drop_peer(drop) self._drop_pubsub_peers(drop) _log.debug("ROUTER received agent stop message. dropping peer: {}".format(drop)) except IndexError: pass return False elif subsystem == b'query': try: name = bytes(frames[6]) except IndexError: value = None else: if name == b'addresses': if self.addresses: value = [addr.base for addr in self.addresses] else: value = [self.local_address.base] elif name == b'local_address': value = self.local_address.base # Allow the agents to know the serverkey. elif name == b'serverkey': keystore = KeyStore() value = keystore.public elif name == b'volttron-central-address': value = self._volttron_central_address elif name == b'volttron-central-serverkey': value = self._volttron_central_serverkey elif name == b'instance-name': value = self._instance_name elif name == b'bind-web-address': value = self._bind_web_address elif name == b'platform-version': value = __version__ else: value = None frames[6:] = [b'', jsonapi.dumps(value)] frames[3] = b'' return frames elif subsystem == b'pubsub': result = self._pubsub.handle_subsystem(frames, user_id) return result elif subsystem == b'routing_table': result = self._ext_routing.handle_subsystem(frames) return result elif subsystem == b'external_rpc': result = self._ext_rpc.handle_subsystem(frames) return result
def format(self, record): dct = record.__dict__.copy() dct["msg"] = record.getMessage() dct.pop('args') exc_info = dct.pop('exc_info', None) if exc_info: dct['exc_text'] = ''.join(traceback.format_exception(*exc_info)) return jsonapi.dumps(dct)
def forward(self, peer, sender, bus, topic, headers, message): headers = Headers(headers) headers['VIP.peer'] = encode_peer(peer) headers['VIP.sender'] = encode_peer(sender) headers['VIP.bus'] = bus parts = [topic] if message is not None: if 'Content-Type' in headers: if isinstance(message, list): parts.extend(message) else: parts.append(message) else: parts.append(jsonapi.dumps(message)) headers['Content-Type'] = 'application/json' parts.insert(1, jsonapi.dumps(headers.dict)) self.out_sock.send_multipart(parts)
def __str__(self): dk = { 'discovery_address': self.discovery_address, 'vip_address': self.vip_address, 'serverkey': self.serverkey, 'instance_name': self.instance_name } return jsonapi.dumps(dk)
def _send_auth_update_to_pubsub(self): user_to_caps = self.get_user_to_capabilities() #Send auth update message to router json_msg = jsonapi.dumps( dict(capabilities=user_to_caps) ) frames = [zmq.Frame(b'auth_update'), zmq.Frame(str(json_msg))] # <recipient, subsystem, args, msg_id, flags> self.core.socket.send_vip(b'', 'pubsub', frames, copy=False)
def create_response(self, res, start_response): # Dictionaries are going to be treated as if they are meant to be json # serialized with Content-Type of application/json if isinstance(res, dict): # Note this is specific to volttron central agent and should # probably not be at this level of abstraction. _log.debug('res is a dictionary.') if 'error' in res.keys(): if res['error']['code'] == UNAUTHORIZED: start_response('401 Unauthorized', [ ('Content-Type', 'text/html')]) message = res['error']['message'] code = res['error']['code'] return [b'<h1>{}</h1>\n<h2>CODE:{}</h2>' .format(message, code)] start_response('200 OK', [('Content-Type', 'application/json')]) return jsonapi.dumps(res) # If this is a tuple then we know we are going to have a response # and a headers portion of the data. if isinstance(res, tuple) or isinstance(res, list): if len(res) != 2: start_response("500 Programming Error", [('Content-Type', 'text/html')]) _log.error("Invalid length of response tuple (must be 2)") return [b'Invalid response tuple (must contain 2 elements)'] response, headers = res header_dict = dict(headers) if header_dict.get('Content-Encoding', None) == 'gzip': gzip_compress = zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS | 16) data = gzip_compress.compress(response) + gzip_compress.flush() start_response('200 OK', headers) return data else: return response else: start_response('200 OK', [('Content-Type', 'application/json')]) return jsonapi.dumps(res)
def as_json(self): """ Serializes the object to a json string. Note: Does not serialize the change callback function. :return: """ return jsonapi.dumps(self.as_dict())
def _send_protected_update_to_pubsub(self, contents): protected_topics_msg = jsonapi.dumps(contents) frames = [zmq.Frame(b'protected_update'), zmq.Frame(protected_topics_msg)] if self._is_connected: try: # <recipient, subsystem, args, msg_id, flags> self.core.socket.send_vip(b'', 'pubsub', frames, copy=False) except VIPError as ex: _log.error("Error in sending protected topics update to clear PubSub: " + str(ex))
def _handle_external_rpc_subsystem(self, message): ret_msg = dict() #_log.debug("EXT_RPC subsystem handler IN message {0}".format(message)) op = message.args[0].bytes rpc_msg = jsonapi.loads(message.args[1].bytes) try: #_log.debug("EXT_RPC subsystem handler IN message {0}, {1}".format(message.peer, rpc_msg)) method_args = rpc_msg['args'] #message.args = [method_args] message.args = method_args dispatch = self._dispatcher.dispatch #_log.debug("External RPC IN message args {}".format(message)) responses = [response for response in ( dispatch(bytes(msg), message) for msg in message.args) if response] #_log.debug("External RPC Resonses {}".format(responses)) if responses: message.user = '' try: message.peer = '' message.subsystem = 'external_rpc' frames = [] op = b'send_platform' frames.append(op) msg = jsonapi.dumps(dict(to_platform=rpc_msg['from_platform'], to_peer=rpc_msg['from_peer'], from_platform=rpc_msg['to_platform'], from_peer=rpc_msg['to_peer'], args=responses)) frames.append(msg) except KeyError: _log.error("External RPC message did not contain proper message format") message.args = jsonapi.dumps(ret_msg) ret_msg = jsonapi.dumps(ret_msg) #_log.debug("EXT_RPC subsystem handler OUT message {}".format(message)) try: self.core().socket.send_vip(b'', 'external_rpc', frames, user=message.user, msg_id=message.id, copy=False) except ZMQError as ex: _log.error("ZMQ error: {}".format(ex)) pass except KeyError: pass
def _install_agent(agent_dir, config, tag): if not isinstance(config, dict): config_file = config else: cfg = tempfile.NamedTemporaryFile() with open(cfg.name, 'w') as fout: fout.write(jsonapi.dumps(config)) config_file = cfg.name _cmd(['volttron-ctl', 'remove', '--tag', tag, '--force']) _cmd(['scripts/core/pack_install.sh', agent_dir, config_file, tag])
def insert_agg_meta(self, topic_id, metadata): """ Inserts metadata for aggregate topic :param topic_id: aggregate topic id for which metadata is inserted :param metadata: metadata :return: True if execution completes. Raises exception if connection to database fails """ self.execute_stmt(self.replace_agg_meta_stmt(), (topic_id, jsonapi.dumps(metadata)), commit=False) return True
def insert_meta(self, topic_id, metadata): """ Inserts metadata for topic :param topic_id: topic id for which metadata is inserted :param metadata: metadata :return: True if execution completes. Raises exception if unable to connect to database """ self.execute_stmt(self.insert_meta_query(), (topic_id, jsonapi.dumps(metadata)), commit=False) return True
def insert_data(self, ts, topic_id, data): """ Inserts data for topic :param ts: timestamp :param topic_id: topic id for which data is inserted :param metadata: data values :return: True if execution completes. raises Exception if unable to connect to database """ self.execute_stmt(self.insert_data_query(), (ts, topic_id, jsonapi.dumps(data)), commit=False) return True
def _set_override_on(self, pattern, duration=0.0, failsafe_revert=True, staggered_revert=False, from_config_store=False): """Turn on override condition on all devices matching the pattern. It schedules an event to keep track of the duration over which override has to be applied. New override patterns and corresponnding end times are stored in config store. :param pattern: Override pattern to be applied. For example, :type pattern: str :param duration: Time duration for the override in seconds. If duration <= 0.0, it implies as indefinite duration. :type duration: float :param failsafe_revert: Flag to indicate if revert is required :type failsafe_revert: boolean :param staggered_revert: Flag to indicate if staggering of reverts is needed. :type staggered_revert: boolean :param from_config_store: Flag to indicate if this function is called from config store callback :type from_config_store: boolean """ stagger_interval = 0.05 #sec pattern = pattern.lower() #Add to override patterns set self._override_patterns.add(pattern) device_topic_actual = self.instances.keys() i = 0 for name in device_topic_actual: name = name.lower() i += 1 if fnmatch.fnmatch(name, pattern): #If revert to default state is needed if failsafe_revert: if staggered_revert: self.core.spawn_later(i*stagger_interval, self.instances[name].revert_all()) else: self.core.spawn(self.instances[name].revert_all()) # Set override self._override_devices.add(name) config_update = False # Set timer for interval of override condition config_update = self._update_override_interval(duration, pattern) if config_update and not from_config_store: #Update config store patterns = dict() for pat in self._override_patterns: if self._override_interval_events[pat] is None: patterns[pat] = str(0.0) else: evt, end_time = self._override_interval_events[pat] patterns[pat] = utils.format_timestamp(end_time) self.vip.config.set("override_patterns", jsonapi.dumps(patterns))
def publish(self, peer, topic, headers=None, message=None, bus=''): """Publish a message to a given topic via a peer. Publish headers and message to all subscribers of topic on bus. If peer is None, use self. Adds volttron platform version compatibility information to header as variables min_compatible_version and max_compatible version param peer: peer type peer: str param topic: topic for the publish message type topic: str param headers: header info for the message type headers: None or dict param message: actual message type message: None or any param bus: bus type bus: str return: Number of subscribers the message was sent to. :rtype: int :Return Values: Number of subscribers """ if headers is None: headers = {} headers['min_compatible_version'] = min_compatible_version headers['max_compatible_version'] = max_compatible_version if peer is None: peer = 'pubsub' # For backward compatibility with old pubsub if self._send_via_rpc: return self.rpc().call( peer, 'pubsub.publish', topic=topic, headers=headers, message=message, bus=bus) else: result = next(self._results) # Parameters are stored initially, in case remote agent/platform is using old pubsub if self._parameters_needed: kwargs = dict(op='publish', peer=peer, topic=topic, bus=bus, headers=headers, message=message) self._save_parameters(result.ident, **kwargs) json_msg = jsonapi.dumps(dict(bus=bus, headers=headers, message=message)) frames = [zmq.Frame(b'publish'), zmq.Frame(str(topic)), zmq.Frame(str(json_msg))] #<recipient, subsystem, args, msg_id, flags> self.vip_socket.send_vip(b'', 'pubsub', frames, result.ident, copy=False) return result
def _send_protected_update_to_pubsub(self, contents): protected_topics_msg = jsonapi.dumps(contents) frames = [ zmq.Frame(b'protected_update'), zmq.Frame(protected_topics_msg) ] if self._is_connected: try: # <recipient, subsystem, args, msg_id, flags> self.core.socket.send_vip(b'', 'pubsub', frames, copy=False) except VIPError as ex: _log.error( "Error in sending protected topics update to clear PubSub: " + str(ex))
def do_rpc(jsonrpc_address, method, params=None, authentication=None ): json_package = { 'jsonrpc': '2.0', 'id': '2503402', 'method': method, } if authentication: json_package['authorization'] = authentication if params: json_package['params'] = params return requests.post(jsonrpc_address, data=jsonapi.dumps(json_package))
def _peer_list(self, frames): """Returns a list of subscriptions for a specific bus. If bus is None, then it returns list of subscriptions for all the buses. :param frames list of frames :type frames list :returns: list of tuples of bus, topic and flag to indicate if peer is a subscriber or not :rtype: list :Return Values: List of tuples [(bus, topic, flag to indicate if peer is a subscriber or not)]. """ results = [] if len(frames) > 7: data = frames[7].bytes msg = jsonapi.loads(data) peer = frames[0].bytes try: prefix = msg['prefix'] bus = msg['bus'] subscribed = msg['subscribed'] reverse = msg['reverse'] except KeyError as exc: self._logger.error( "Missing key in _peer_list message {}".format(exc)) return results is_all = msg.get('all_platforms', False) if not is_all: platform = 'internal' else: platform = 'all' if bus is None: buses = self._peer_subscriptions[platform].iteritems() else: buses = [(bus, self._peer_subscriptions[platform][bus])] if reverse: test = prefix.startswith else: test = lambda t: t.startswith(prefix) for bus, subscriptions in buses: for topic, subscribers in subscriptions.iteritems(): if test(topic): member = peer in subscribers if not subscribed or member: results.append((bus, topic, member)) results = jsonapi.dumps(results) return results
def _send_external_subscriptions(self, external_platforms): """ Send external subscriptions to remote platforms :param external_platforms: list of remote platforms :return: """ prefixes = self._get_external_prefix_list() instance_name = self._ext_router.my_instance_name() prefix_msg = dict() prefix_msg[instance_name] = prefixes msg = jsonapi.dumps(prefix_msg) frames = [b'', 'VIP1', b'', b'', b'pubsub', b'external_list', msg] if self._ext_router is not None: for name in external_platforms: self._ext_router.send_external(name, frames)
def insert_data(ts, topic_id, data): """ Inserts data records to the list :param ts: time stamp :type string :param topic_id: topic ID :type string :param data: data value :type any valid JSON serializable value :return: Returns True after insert :rtype: bool """ value = jsonapi.dumps(data) records.append(SQL('({}, {}, {})').format(Literal(ts), Literal(topic_id), Literal(value))) return True
def insert_data(ts, topic_id, data): """ Inserts data records to the list :param ts: time stamp :type string :param topic_id: topic ID :type string :param data: data value :type any valid JSON serializable value :return: Returns True after insert :rtype: bool """ value = jsonapi.dumps(data) records.append(SQL('({}, {}, {})').format(Literal(ts), Literal(topic_id), Literal(value))) return True
def subscribe(self, peer, prefix, callback, bus='', all_platforms=False): """Subscribe to topic and register callback. Subscribes to topics beginning with prefix. If callback is supplied, it should be a function taking four arguments, callback(peer, sender, bus, topic, headers, message), where peer is the ZMQ identity of the bus owner sender is identity of the publishing peer, topic is the full message topic, headers is a case-insensitive dictionary (mapping) of message headers, and message is a possibly empty list of message parts. :param peer :type peer :param prefix prefix to the topic :type prefix str :param callback callback method :type callback method :param bus bus :type bus str :param platforms :type platforms :returns: Subscribe is successful or not :rtype: boolean :Return Values: Success or Failure """ # For backward compatibility with old pubsub if self._send_via_rpc == True: self._add_subscription(prefix, callback, bus) return self.rpc().call(peer, 'pubsub.subscribe', prefix, bus=bus) else: result = self._results.next() # Parameters are stored initially, in case remote agent/platform is using old pubsub if self._parameters_needed: kwargs = dict(op='subscribe', prefix=prefix, bus=bus) self._save_parameters(result.ident, **kwargs) self._add_subscription(prefix, callback, bus, all_platforms) sub_msg = jsonapi.dumps( dict(prefix=prefix, bus=bus, all_platforms=all_platforms)) frames = [b'subscribe', sub_msg] self.vip_socket.send_vip(b'', 'pubsub', frames, result.ident, copy=False) return result
def store_config(self, identity, config_name, contents, trigger_callback=False, send_update=True): config_type = None raw_data = None if isinstance(contents, (dict, list)): config_type = 'json' raw_data = jsonapi.dumps(contents) elif isinstance(contents, str): config_type = 'raw' raw_data = contents else: raise ValueError("Unsupported configuration content type: {}".format(str(type(contents)))) self._add_config_to_store(identity, config_name, raw_data,contents, config_type, trigger_callback=trigger_callback, send_update=send_update)
def unsubscribe(self, peer, prefix, callback, bus='', all_platforms=False): """Unsubscribe and remove callback(s). Remove all handlers matching the given info - peer, callback and bus, which was used earlier to subscribe as well. If all handlers for a topic prefix are removed, the topic is also unsubscribed. param peer: peer type peer: str param prefix: prefix that needs to be unsubscribed type prefix: str param callback: callback method type callback: method param bus: bus type bus: bus return: success or not :rtype: boolean :Return Values: success or not """ # For backward compatibility with old pubsub if self._send_via_rpc == True: topics = self._drop_subscription(prefix, callback, bus) return self.rpc().call(peer, 'pubsub.unsubscribe', topics, bus=bus) else: subscriptions = dict() result = next(self._results) if not all_platforms: platform = 'internal' topics = self._drop_subscription(prefix, callback, bus, platform) subscriptions[platform] = dict(prefix=topics, bus=bus) else: platform = 'all' topics = self._drop_subscription(prefix, callback, bus, platform) subscriptions[platform] = dict(prefix=topics, bus=bus) # Parameters are stored initially, in case remote agent/platform is using old pubsub if self._parameters_needed: kwargs = dict(op='unsubscribe', prefix=topics, bus=bus) self._save_parameters(result.ident, **kwargs) unsub_msg = jsonapi.dumps(subscriptions) topics = self._drop_subscription(prefix, callback, bus) frames = [b'unsubscribe', unsub_msg] self.vip_socket.send_vip(b'', 'pubsub', frames, result.ident, copy=False) return result
def publish_callback(self, peer, sender, bus, topic, headers, message): """ Callback method registered with local message bus to receive PubSub messages subscribed by external platform agents. PubSub component of router will route the message to appropriate external platform subscribers. :return: """ json_msg = jsonapi.dumps( dict(bus=bus, headers=headers, message=message)) # Reformat the message into ZMQ VIP message frames frames = [ sender, b'', b'VIP', '', '', 'pubsub', zmq.Frame(b'publish'), zmq.Frame(str(topic)), zmq.Frame(str(json_msg)) ] self.zmq_router.pubsub.handle_subsystem(frames, '')
def subscribe(self, peer, prefix, callback, bus='', all_platforms=False): """Subscribe to topic and register callback. Subscribes to topics beginning with prefix. If callback is supplied, it should be a function taking four arguments, callback(peer, sender, bus, topic, headers, message), where peer is the ZMQ identity of the bus owner sender is identity of the publishing peer, topic is the full message topic, headers is a case-insensitive dictionary (mapping) of message headers, and message is a possibly empty list of message parts. :param peer :type peer :param prefix prefix to the topic :type prefix str :param callback callback method :type callback method :param bus bus :type bus str :param platforms :type platforms :returns: Subscribe is successful or not :rtype: boolean :Return Values: Success or Failure """ # For backward compatibility with old pubsub if self._send_via_rpc == True: self._add_subscription(prefix, callback, bus) return self.rpc().call(peer, 'pubsub.subscribe', prefix, bus=bus) else: result = self._results.next() # Parameters are stored initially, in case remote agent/platform is using old pubsub if self._parameters_needed: kwargs = dict(op='subscribe', prefix=prefix, bus=bus) self._save_parameters(result.ident, **kwargs) self._add_subscription(prefix, callback, bus, all_platforms) sub_msg = jsonapi.dumps( dict(prefix=prefix, bus=bus, all_platforms=all_platforms) ) frames = [b'subscribe', sub_msg] self.vip_socket.send_vip(b'', 'pubsub', frames, result.ident, copy=False) return result
def unsubscribe(self, peer, prefix, callback, bus='', all_platforms=False): """Unsubscribe and remove callback(s). Remove all handlers matching the given info - peer, callback and bus, which was used earlier to subscribe as well. If all handlers for a topic prefix are removed, the topic is also unsubscribed. param peer: peer type peer: str param prefix: prefix that needs to be unsubscribed type prefix: str param callback: callback method type callback: method param bus: bus type bus: bus return: success or not :rtype: boolean :Return Values: success or not """ routing_key = None result = next(self._results) if prefix is not None: routing_key = self._form_routing_key(prefix, all_platforms=all_platforms) topics = self._drop_subscription(routing_key, callback) self.core().spawn_later(0.01, self.set_result, result.ident, topics) # Send the message to proxy router to send it to external 'zmq' platforms if all_platforms: subscriptions = dict() subscriptions['all'] = dict(prefix=topics, bus=bus) rkey = self.core().instance_name + '.proxy.router.pubsub' frames = [ self.core().identity, b'', b'VIP1', b'', b'', b'pubsub', b'unsubscribe', jsonapi.dumps(subscriptions) ] self.core().connection.channel.basic_publish( exchange=self.core().connection.exchange, routing_key=rkey, body=frames) return result
def platform_call(self, peer, platform_name, method, *args, **kwargs): request, result = self._dispatcher.call(method, args, kwargs) ident = '%s.%s' % (next(self._counter), hash(result)) self._outstanding[ident] = result #self.core().socket.send_vip(peer, 'RPC', [request], msg_id=ident) _log.debug("Args: {0}, Kwargs: {1}".format(args, kwargs)) if platform_name is None: self.core().socket.send_vip(peer, 'RPC', [request], msg_id=ident) else: frames = [] op = b'send_platform' frames.append(op) msg = jsonapi.dumps(dict(to_platform=platform_name, to_peer=peer, from_platform='', from_peer='', args=[request])) frames.append(msg) # _log.debug("RPC subsystem: External platform RPC msg: {}".format(frames)) self.core().socket.send_vip('', 'external_rpc', frames, msg_id=ident) return result
def platform_call(self, peer, platform_name, method, *args, **kwargs): request, result = self._dispatcher.call(method, args, kwargs) ident = '%s.%s' % (next(self._counter), hash(result)) self._outstanding[ident] = result #self.core().socket.send_vip(peer, 'RPC', [request], msg_id=ident) _log.debug("Args: {0}, Kwargs: {1}".format(args, kwargs)) if platform_name is None: self.core().socket.send_vip(peer, 'RPC', [request], msg_id=ident) else: frames = [] op = b'send_platform' frames.append(op) msg = jsonapi.dumps(dict(to_platform=platform_name, to_peer=peer, from_platform='', from_peer='', args=[request])) frames.append(msg) # _log.debug("RPC subsystem: External platform RPC msg: {}".format(frames)) self.core().socket.send_vip('', 'external_rpc', frames, msg_id=ident) return result
def build_agentpackage(self, agent_dir, config_file={}): if isinstance(config_file, dict): cfg_path = os.path.join(agent_dir, "config_temp") with open(cfg_path, "w") as tmp_cfg: tmp_cfg.write(jsonapi.dumps(config_file)) config_file = cfg_path # Handle relative paths from the volttron git directory. if not os.path.isabs(agent_dir): agent_dir = os.path.join(self.volttron_root, agent_dir) assert os.path.exists(config_file) assert os.path.exists(agent_dir) wheel_path = packaging.create_package(agent_dir, self.packaged_dir) packaging.add_files_to_package( wheel_path, {'config_file': os.path.join('./', config_file)}) return wheel_path
def _get_discovery(self, environ, start_response, data=None): q = query.Query(self.core) self.instance_name = q.query('instance-name').get(timeout=60) addreses = q.query('addresses').get(timeout=60) external_vip = None for x in addreses: try: if not is_ip_private(x): external_vip = x break except IndexError: pass return_dict = {} if external_vip and self.serverkey: return_dict['serverkey'] = encode_key(self.serverkey) return_dict['vip-address'] = external_vip if self.instance_name: return_dict['instance-name'] = self.instance_name if self.core.messagebus == 'rmq': config = RMQConfig() rmq_address = None if config.is_ssl: rmq_address = "amqps://{host}:{port}/{vhost}".format( host=config.hostname, port=config.amqp_port_ssl, vhost=config.virtual_host) else: rmq_address = "amqp://{host}:{port}/{vhost}".format( host=config.hostname, port=config.amqp_port, vhost=config.virtual_host) return_dict['rmq-address'] = rmq_address return_dict['rmq-ca-cert'] = self._certs.cert( self._certs.root_ca_name).public_bytes( serialization.Encoding.PEM) return Response(jsonapi.dumps(return_dict), content_type="application/json")
def synchronize(self): """Synchronize local subscriptions with the PubSubService. """ result = next(self._results) items = [{platform: {bus: subscriptions.keys()} for platform, bus_subscriptions in self._my_subscriptions.items() for bus, subscriptions in bus_subscriptions.items()}] for subscriptions in items: sync_msg = jsonapi.dumps( dict(subscriptions=subscriptions) ) frames = [b'synchronize', b'connected', sync_msg] # For backward compatibility with old pubsub if self._send_via_rpc: delay = random.random() self.core().spawn_later(delay, self.rpc().notify, 'pubsub', 'pubsub.sync', subscriptions) else: # Parameters are stored initially, in case remote agent/platform is using old pubsub if self._parameters_needed: kwargs = dict(op='synchronize', subscriptions=subscriptions) self._save_parameters(result.ident, **kwargs) self.vip_socket.send_vip(b'', 'pubsub', frames, result.ident, copy=False)
def _distribute(self, peer, topic, headers, message=None, bus=''): self._check_if_protected_topic(topic) try: subscriptions = self._peer_subscriptions[bus] except KeyError: subscriptions = dict() subscribers = set() for prefix, subscription in subscriptions.iteritems(): if subscription and topic.startswith(prefix): subscribers |= subscription if subscribers: sender = encode_peer(peer) json_msg = jsonapi.dumps(jsonrpc.json_method( None, 'pubsub.push', [sender, bus, topic, headers, message], None)) frames = [zmq.Frame(b''), zmq.Frame(b''), zmq.Frame(b'RPC'), zmq.Frame(json_msg)] socket = self.core().socket for subscriber in subscribers: socket.send(subscriber, flags=SNDMORE) socket.send_multipart(frames, copy=False) return len(subscribers)
def multi_messagebus_vc_vcp(volttron_multi_messagebus): vcp_instance, vc_instance = volttron_multi_messagebus assert vcp_instance.instance_name != vc_instance.instance_name # Handles both connections to zmq as well as connections to rmq bus. vc_instance.allow_all_connections() if vc_instance.messagebus == 'rmq': if vcp_instance.messagebus == 'rmq': os.environ[ 'REQUESTS_CA_BUNDLE'] = vcp_instance.certsobj.remote_cert_bundle_file( ) else: os.environ[ 'REQUESTS_CA_BUNDLE'] = vc_instance.certsobj.remote_cert_bundle_file( ) vcp_uuid = add_volttron_central_platform(vcp_instance) vc_uuid = add_volttron_central(vc_instance) assert vcp_uuid assert vc_uuid print("VC LIST AGENTS: {}".format(vc_instance.list_agents())) print("VCP LIST AGENTS: {}".format(vcp_instance.list_agents())) # Update vcp_config store to add the volttron-central-address from vc to the # config store config = jsonapi.dumps( {'volttron-central-address': vc_instance.bind_web_address}) vcp_instance.dynamic_agent.vip.rpc.call(CONFIGURATION_STORE, "manage_store", VOLTTRON_CENTRAL_PLATFORM, "config", config, "json").get() # "manage_store", opts.identity, opts.name, file_contents, config_type = opts.config_type yield vcp_instance, vc_instance, vcp_uuid vcp_instance.remove_agent(vcp_uuid) vc_instance.remove_agent(vc_uuid)
def publish_callback(self, peer, sender, bus, topic, headers, message): """ Callback method to receive PubSub messages from internal RabbitMQ message bus and send it to external platform subscribers over ZMQ message bus. :param peer: pubsub :param sender: publisher :param bus: bus :param topic: publisher topic :param headers: message header :param message: message body :return: """ # self._logger.debug("PubSubService message: {}".format(message)) json_msg = jsonapi.dumps( dict(sender=peer, bus=bus, headers=headers, message=message)) frames = [ sender, b'', b'VIP1', '', '', b'pubsub', b'publish', topic, json_msg ] # Send it through ZMQ bus self._distribute(frames, '') self._logger.debug("Publish callback {}".format(topic))
def send_management_message(self, type, data={}): """ Send a message to any socket that has connected to the management socket. The payload sent to the client is like the following:: { "type": "UPDATE_DEVICE_STATUS", "data": "this is data that was passed" } :param type: A string defining a unique type for sending to the websockets. :param data: An object that str can be called on. :type type: str :type data: serializable """ management_sockets = [s for s in self._websocket_endpoints if s.endswith("management")] # Nothing to send if we don't have any management sockets open. if len(management_sockets) <= 0: return if data is None: data = {} payload = dict( type=type, data=str(data) ) payload = jsonapi.dumps(payload) for s in management_sockets: self.vip.web.send(s, payload)
def _set_override_off(self, pattern): """Turn off override condition on all devices matching the pattern. It removes the pattern from the override patterns set, clears the list of overriden devices and reevaluates the state of devices. It then cancels the pending override event and removes pattern from the config store. :param pattern: Override pattern to be removed. :type pattern: str """ pattern = pattern.lower() # If pattern exactly matches if pattern in self._override_patterns: self._override_patterns.discard(pattern) # Cancel any pending override events self._cancel_override_events(pattern) self._override_devices.clear() patterns = dict() # Build override devices list again for pat in self._override_patterns: for device in self.instances: device = device.lower() if fnmatch.fnmatch(device, pat): self._override_devices.add(device) if self._override_interval_events[pat] is None: patterns[pat] = str(0.0) else: evt, end_time = self._override_interval_events[pat] patterns[pat] = utils.format_timestamp(end_time) self.vip.config.set("override_patterns", jsonapi.dumps(patterns)) else: _log.error("Override Pattern did not match!") raise OverrideError( "Pattern {} does not exist in list of override patterns". format(pattern))
def _peer_publish(self, frames, user_id): """Publish the incoming message to all the subscribers subscribed to the specified topic. :param frames list of frames :type frames list :param user_id user id of the publishing agent. This is required for protected topics check. :type user_id UTF-8 encoded User-Id property :returns: Count of subscribers. :rtype: int :Return Values: Number of subscribers to whom the message was sent """ if len(frames) > 8: data = frames[8].bytes try: msg = jsonapi.loads(data) headers = msg['headers'] message = msg['message'] peer = frames[0].bytes bus = msg['bus'] pub_msg = jsonapi.dumps( dict(sender=peer, bus=bus, headers=headers, message=message)) frames[8] = zmq.Frame(str(pub_msg)) except KeyError as exc: self._logger.error( "Missing key in _peer_publish message {}".format(exc)) return 0 except ValueError: self._logger.error("JSON decode error. Invalid character") return 0 if self._rabbitmq_agent: self._publish_on_rmq_bus(frames) return self._distribute(frames, user_id)
def handle_subsystem(self, frames, user_id): subsystem = bytes(frames[5]) if subsystem == b'quit': sender = bytes(frames[0]) if sender == b'control' and user_id == self.default_user_id: if self._ext_routing: self._ext_routing.close_external_connections() self.stop() raise KeyboardInterrupt() elif subsystem == b'agentstop': try: drop = frames[6].bytes self._drop_peer(drop) self._drop_pubsub_peers(drop) _log.debug( "ROUTER received agent stop message. dropping peer: {}". format(drop)) except IndexError: pass return False elif subsystem == b'query': try: name = bytes(frames[6]) except IndexError: value = None else: if name == b'addresses': if self.addresses: value = [addr.base for addr in self.addresses] else: value = [self.local_address.base] elif name == b'local_address': value = self.local_address.base # Allow the agents to know the serverkey. elif name == b'serverkey': keystore = KeyStore() value = keystore.public elif name == b'volttron-central-address': value = self._volttron_central_address elif name == b'volttron-central-serverkey': value = self._volttron_central_serverkey elif name == b'instance-name': value = self._instance_name elif name == b'bind-web-address': value = self._bind_web_address elif name == b'platform-version': value = __version__ else: value = None frames[6:] = [b'', jsonapi.dumps(value)] frames[3] = b'' return frames elif subsystem == b'pubsub': result = self._pubsub.handle_subsystem(frames, user_id) return result elif subsystem == b'routing_table': result = self._ext_routing.handle_subsystem(frames) return result elif subsystem == b'external_rpc': result = self._ext_rpc.handle_subsystem(frames) return result
def _csr_request_new(self, env, data): _log.debug("New csr request") if not isinstance(data, dict): try: request_data = json.loads(data) except: _log.error( "Invalid data for csr request. Must be json serializable") return Response() else: request_data = data.copy() csr = request_data.get('csr') identity = self._certs.get_csr_common_name(str(csr)) # The identity must start with the current instances name or it is a failure. if not identity.startswith(get_platform_instance_name() + "."): json_response = dict( status="ERROR", message="CSR must start with instance name: {}".format( get_platform_instance_name())) Response(json.dumps(json_response), content_type='application/json', headers={'Content-type': 'application/json'}) csr_file = self._certs.save_pending_csr_request( env.get('REMOTE_ADDR'), identity, csr) if self._auto_allow_csr: _log.debug( "Creating cert and permissions for user: {}".format(identity)) status = self._certs.get_csr_status(identity) json_response = dict(status=status) if status == 'APPROVED': json_response['cert'] = self._certs.get_cert_from_csr(identity) else: cert = self._certs.approve_csr(identity) permissions = self._core().rmq_mgmt.get_default_permissions( identity) self._core().rmq_mgmt.create_user_with_permissions( identity, permissions, True) json_response = dict(status="SUCCESSFUL", cert=cert) else: status = self._certs.get_csr_status(identity) cert = self._certs.get_cert_from_csr(identity) json_response = dict(status=status) if status == "APPROVED": json_response['cert'] = self._certs.get_cert_from_csr(identity) elif status == "PENDING": json_response[ 'message'] = "The request is pending admininstrator approval." elif status == "DENIED": json_response[ 'message'] = "The request has been denied by the administrator." elif status == "UNKNOWN": json.response[ 'message'] = "An unknown common name was specified to the server {}".format( identity) else: json_response[ 'message'] = "An unkonwn error has occured during the respons phase" _ return Response(json.dumps(json_response), content_type='application/json', headers={'Content-type': 'application/json'})
def publish(self, peer, topic, headers=None, message=None, bus=''): """Publish a message to a given topic via a peer. Publish headers and message to all subscribers of topic on bus. If peer is None, use self. Adds volttron platform version compatibility information to header as variables min_compatible_version and max_compatible version param peer: peer type peer: str param topic: topic for the publish message type topic: str param headers: header info for the message type headers: None or dict param message: actual message type message: None or any param bus: bus type bus: str return: Number of subscribers the message was sent to. :rtype: int :Return Values: Number of subscribers """ result = next(self._results) self._pubcount[self._message_number] = result.ident self._message_number += 1 routing_key = self._form_routing_key(topic) connection = self.core().connection self.core().spawn_later(0.01, self.set_result, result.ident, 1) if headers is None: headers = {} headers['min_compatible_version'] = min_compatible_version headers['max_compatible_version'] = max_compatible_version # self._logger.debug("RMQ PUBSUB publish message To. {0}, {1}, {2}, {3} ".format(routing_key, # self.core().identity, # message, # topic)) # VIP format - [SENDER, RECIPIENT, PROTO, USER_ID, MSG_ID, SUBSYS, ARGS...] dct = { # 'user_id': self.core().identity, 'app_id': connection.routing_key, # SENDER 'headers': dict( recipient=b'', # RECEIVER proto=b'VIP', # PROTO user=self.core().identity, # USER_ID ), 'message_id': result.ident, # MSG_ID 'type': 'pubsub', # SUBSYS 'content_type': 'application/json' } properties = pika.BasicProperties(**dct) json_msg = dict(sender=self.core().identity, bus=bus, headers=headers, message=message) try: connection.channel.basic_publish(exchange=connection.exchange, routing_key=routing_key, properties=properties, body=jsonapi.dumps( json_msg, ensure_ascii=False)) except (pika.exceptions.AMQPConnectionError, pika.exceptions.AMQPChannelError) as exc: self._isconnected = False raise Unreachable(errno.EHOSTUNREACH, "Connection to RabbitMQ is lost", 'rabbitmq broker', 'pubsub') return result
def handle_system(self, message): """ Handles messages intended for router. Standard hello, ping, peerlist subsystems are handled. :param props: properties associated with incoming message :param message: actual message :return: """ # [SENDER, RECIPIENT, PROTOCOL, USER_ID, MSG_ID, SUBSYSTEM, ...] sender = message.peer # source subsystem = message.subsystem self._add_peer(sender) if subsystem == b'hello': self.authenticate(sender) # send welcome message back message.args = [b'welcome', b'1.0', self._identity, sender] elif subsystem == b'ping': message.args = [b'pong'] elif subsystem == b'peerlist': try: op = message.args[0] except IndexError: op = None except ValueError: op = None if op == b'list': del message.args[:] message.args = [b'listing'] message.args.extend(self._peers) elif op == b'list_with_messagebus': _log.debug("Router peerlist request op: list_with_messagebus, {}, {}".format(sender, self._peers)) del message.args[:] message.args = [b'listing_with_messagebus'] message.args.append(jsonapi.dumps(self._peers_with_messagebus)) _log.debug("Router peerlist request op: list_with_messagebus, {}, {}".format(sender, self._peers)) elif op == b'add': peer = message.args[1] try: message_bus = message.args[2] except IndexError: message_bus = 'rmq' self._add_peer(peer=peer, message_bus=message_bus) elif op == b'drop': peer = message.args[1] try: message_bus = message.args[2] except IndexError: message_bus = 'rmq' self._drop_peer(peer=peer, message_bus=message_bus) else: error = (b'unknown' if op else b'missing') + b' operation' message.args.extend([b'error', error]) elif subsystem == b'quit': if sender == b'control': self.stop() raise KeyboardInterrupt() elif subsystem == b'agentstop': _log.debug("ROUTER received agent stop {}".format(sender)) try: drop = message.args[0] self._drop_peer(drop) except IndexError: pass except ValueError: pass return False elif subsystem == b'query': try: name = bytes(message.args[0]) except IndexError: value = None except ValueError: value = None else: if name == b'addresses': if self.addresses: value = [addr.base for addr in self.addresses] else: value = [self.local_address.base] elif name == b'local_address': value = self.local_address.base # Allow the agents to know the serverkey. elif name == b'serverkey': keystore = KeyStore() value = keystore.public elif name == b'volttron-central-address': value = self._volttron_central_address elif name == b'volttron-central-serverkey': value = self._volttron_central_serverkey elif name == b'instance-name': value = self._instance_name elif name == b'bind-web-address': value = self._bind_web_address elif name == b'platform-version': value = __version__ elif name == b'message-bus': value = os.environ.get('MESSAGEBUS', 'zmq') else: value = None message.args = [b'', jsonapi.dumps(value)] message.args.append(b'') elif subsystem == b'error': try: errnum = message.args[0] if errnum == errno.EHOSTUNREACH: recipient = message.args[2] self._drop_peer(recipient) return except IndexError: _log.error("ROUTER unable to parse error message {}".format(message.args)) else: # Router does not know of the subsystem message.type = b'error' errnum = errno.EPROTONOSUPPORT errmsg = os.strerror(errnum).encode('ascii') # str(errnum).encode('ascii') _log.debug("ROUTER proto unsupported {}, sender {}".format(subsystem, sender)) message.args = [errnum, errmsg, b'', subsystem] # Send the message back to the sender self.connection.send_vip_object(message)
def publish(self, peer, topic, headers=None, message=None, bus=''): """Publish a message to a given topic via a peer. Publish headers and message to all subscribers of topic on bus. If peer is None, use self. Adds volttron platform version compatibility information to header as variables min_compatible_version and max_compatible version param peer: peer type peer: str param topic: topic for the publish message type topic: str param headers: header info for the message type headers: None or dict param message: actual message type message: None or any param bus: bus type bus: str return: Number of subscribers the message was sent to. :rtype: int :Return Values: Number of subscribers """ if headers is None: headers = {} headers['min_compatible_version'] = min_compatible_version headers['max_compatible_version'] = max_compatible_version if peer is None: peer = 'pubsub' # For backward compatibility with old pubsub if self._send_via_rpc: return self.rpc().call(peer, 'pubsub.publish', topic=topic, headers=headers, message=message, bus=bus) else: result = next(self._results) # Parameters are stored initially, in case remote agent/platform is using old pubsub if self._parameters_needed: kwargs = dict(op='publish', peer=peer, topic=topic, bus=bus, headers=headers, message=message) self._save_parameters(result.ident, **kwargs) json_msg = jsonapi.dumps( dict(bus=bus, headers=headers, message=message)) frames = [ zmq.Frame(b'publish'), zmq.Frame(str(topic)), zmq.Frame(str(json_msg)) ] #<recipient, subsystem, args, msg_id, flags> self.vip_socket.send_vip(b'', 'pubsub', frames, result.ident, copy=False) return result
def call(self, peer, method, *args, **kwargs): platform = kwargs.pop('external_platform', b'') request, result = self._dispatcher.call(method, args, kwargs) ident = '%s.%s' % (next(self._counter), hash(result)) self._outstanding[ident] = result subsystem = None frames = [] if not self._isconnected: return if self._message_bus == 'zmq': if platform == '': #local platform subsystem = b'RPC' frames.append(request) else: frames = [] op = b'send_platform' subsystem = b'external_rpc' frames.append(op) msg = jsonapi.dumps( dict(to_platform=platform, to_peer=peer, from_platform='', from_peer='', args=[request])) frames.append(msg) peer = b'' try: # _log.debug("peer: {0}, subsytem: {1}, args:{2}, id: {3}".format(peer, subsystem, # args, id)) self.core().connection.send_vip(peer, subsystem, args=frames, msg_id=ident) except ZMQError as exc: if exc.errno == ENOTSOCK: _log.debug("Socket send on non socket {}".format( self.core().identity)) # _log.debug("RPC subsystem: External platform RPC msg: {}".format(frames)) else: # Agent running on RMQ message bus. # Adding backward compatibility support for ZMQ. Check if peer # is running on ZMQ bus. If yes, send RPC message to proxy router agent to # forward over ZMQ message bus connection try: peer_msg_bus = self.peer_list[peer] except KeyError: peer_msg_bus = self._message_bus if peer_msg_bus == 'zmq': # peer connected to ZMQ bus, send via proxy router agent self.core().connection.send_via_proxy(peer, b'RPC', msg_id=ident, args=[request]) else: self.core().connection.send_vip(peer, b'RPC', args=[request], msg_id=ident, platform=platform) return result
def format(self, record): dct = record.__dict__.copy() exc_info = dct.pop('exc_info', None) if exc_info: dct['exc_text'] = ''.join(traceback.format_exception(*exc_info)) return jsonapi.dumps(dct)
def serialize(self, json_obj): return jsonapi.dumps(json_obj)
def process_main_config(main_file, output_directory, keep=False): main_config = parse_json_config(main_file.read()) driver_list = main_config.pop("driver_config_list") driver_count = len(driver_list) csv_name_map = {} csv_contents = {} driver_configs = {} for config_path in driver_list: new_config_name, device_config = process_driver_config( config_path, csv_name_map, csv_contents) if new_config_name in driver_configs: print "WARNING DUPLICATE DEVICES:", new_config_name, "FOUND IN", config_path driver_configs[new_config_name] = device_config staggered_start = main_config.pop('staggered_start', None) if staggered_start is not None: main_config["driver_scrape_interval"] = staggered_start / float( driver_count) print "New Main config:" pprint(main_config) print if not os.path.exists(output_directory): os.makedirs(output_directory) os.chdir(output_directory) devices_path = "devices" registries_path = "registry_configs" if not keep: if os.path.exists(devices_path): shutil.rmtree(devices_path, ignore_errors=True) if os.path.exists(registries_path): shutil.rmtree(registries_path, ignore_errors=True) if not os.path.exists(devices_path): os.makedirs(devices_path) if not os.path.exists(registries_path): os.makedirs(registries_path) print "Writing 'config'" with open("config", "w") as f: f.write(jsonapi.dumps(main_config, indent=2)) for name, contents in csv_contents.iteritems(): print "Writing", name with open(name, "w") as f: f.write(contents) unique_paths = set() for name, config in driver_configs.iteritems(): print "Writing", name dir_name = os.path.dirname(name) if dir_name not in unique_paths and not os.path.exists(dir_name): os.makedirs(dir_name) unique_paths.add(dir_name) with open(name, "w") as f: f.write(jsonapi.dumps(config, indent=2))
def __pending_csrs_api(self): csrs = [c for c in self._certs.get_pending_csr_requests()] return Response(json.dumps(csrs), content_type="application/json")