Exemplo n.º 1
0
    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())
Exemplo n.º 2
0
    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
Exemplo n.º 3
0
    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
Exemplo n.º 4
0
    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
Exemplo n.º 5
0
    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))
Exemplo n.º 6
0
    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))
Exemplo n.º 7
0
    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)
Exemplo n.º 8
0
    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")
        )
Exemplo n.º 9
0
    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))
Exemplo n.º 10
0
 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
Exemplo n.º 11
0
 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)
Exemplo n.º 12
0
 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)
Exemplo n.º 13
0
    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)
Exemplo n.º 14
0
 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)
Exemplo n.º 15
0
    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)
Exemplo n.º 16
0
    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())
Exemplo n.º 17
0
    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))
Exemplo n.º 18
0
    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
Exemplo n.º 19
0
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])
Exemplo n.º 20
0
    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
Exemplo n.º 21
0
    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
Exemplo n.º 22
0
    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
Exemplo n.º 23
0
    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))
Exemplo n.º 24
0
    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
Exemplo n.º 25
0
    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))
Exemplo n.º 26
0
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))
Exemplo n.º 27
0
    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
Exemplo n.º 28
0
    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)
Exemplo n.º 29
0
        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
Exemplo n.º 30
0
        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
Exemplo n.º 31
0
    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
Exemplo n.º 32
0
    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)
Exemplo n.º 33
0
    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
Exemplo n.º 34
0
    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, '')
Exemplo n.º 35
0
    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
Exemplo n.º 36
0
    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
Exemplo n.º 37
0
    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
Exemplo n.º 38
0
    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
Exemplo n.º 39
0
    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
Exemplo n.º 40
0
    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")
Exemplo n.º 41
0
 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)
Exemplo n.º 42
0
 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)
Exemplo n.º 43
0
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)
Exemplo n.º 44
0
 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))
Exemplo n.º 45
0
    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)
Exemplo n.º 46
0
    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))
Exemplo n.º 47
0
    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)
Exemplo n.º 48
0
 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
Exemplo n.º 49
0
    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'})
Exemplo n.º 50
0
    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
Exemplo n.º 51
0
    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)
Exemplo n.º 52
0
    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
Exemplo n.º 53
0
    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
Exemplo n.º 54
0
 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)
Exemplo n.º 55
0
 def serialize(self, json_obj):
     return jsonapi.dumps(json_obj)
Exemplo n.º 56
0
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))
Exemplo n.º 57
0
 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")