Пример #1
0
    def set_setting(self, session_user, params):
        """
        Sets or removes a setting from the config store.  If the value is None
        then the item will be removed from the store.  If there is an error in
        saving the value then a jsonrpc.json_error object is returned.

        :param session_user: Unused
        :param params: Dictionary that must contain 'key' and 'value' keys.
        :return: A 'SUCCESS' string or a jsonrpc.json_error object.
        """
        if 'key' not in params or not params['key']:
            return jsonrpc.json_error(params['message_id'], INVALID_PARAMS,
                                      'Invalid parameter key not set')
        if 'value' not in params:
            return jsonrpc.json_error(params['message_id'], INVALID_PARAMS,
                                      'Invalid parameter key not set')

        config_key = "settings/{}".format(params['key'])
        value = params['value']

        if value is None:
            try:
                self.vip.config.delete(config_key)
            except KeyError:
                pass
        else:
            # We handle empt string here because the config store doesn't allow
            # empty strings to be set as a config store.  I wasn't able to
            # trap the ValueError that is raised on the server side.
            if value == "":
                return jsonrpc.json_error(params['message_id'], INVALID_PARAMS,
                                          'Invalid value set (empty string?)')
            self.vip.config.set(config_key, value)

        return 'SUCCESS'
Пример #2
0
 def processMessage(self, message):
     _log.debug('processResponse()')
     result = 'FAILED'
     try:
         rpcdata = jsonrpc.JsonRpcData.parse(message)
         _log.info('rpc method: {}'.format(rpcdata.method))
         
         if rpcdata.method == "rpc_setPlugThPP":
             args = {'plugID': rpcdata.params['plugID'], 
                     'newThreshold': rpcdata.params['newThreshold']
                     }
             result = self.setThresholdPP(**args)
         elif rpcdata.method == "rpc_ping":
             result = True
         else:
             return jsonrpc.json_error('NA', METHOD_NOT_FOUND,
                 'Invalid method {}'.format(rpcdata.method))
                 
         return jsonrpc.json_result(rpcdata.id, result)
         
     except KeyError as ke:
         print(ke)
         return jsonrpc.json_error('NA', INVALID_PARAMS,
                 'Invalid params {}'.format(rpcdata.params))
     except AssertionError:
         print('AssertionError')
         return jsonrpc.json_error('NA', INVALID_REQUEST,
                 'Invalid rpc data {}'.format(data))
     except Exception as e:
         print(e)
         return jsonrpc.json_error('NA', UNHANDLED_EXCEPTION, e)
Пример #3
0
        def rpc_from_net(self, header, message):
            _log.debug('rpc_from_net()')
            result = False
            try:
                rpcdata = jsonrpc.JsonRpcData.parse(message)
                _log.info('rpc method: {}'.format(rpcdata.method) + \
                            '; rpc params: {}'.format(rpcdata.params))

                if rpcdata.method == "rpc_registerDsBridge":
                    args = {
                        'discovery_address':
                        rpcdata.params['discovery_address'],
                        'deviceId': rpcdata.params['deviceId']
                    }
                    result = self._registerDsBridge(**args)
                elif rpcdata.method == "rpc_unregisterDsBridge":
                    args = {
                        'discovery_address':
                        rpcdata.params['discovery_address'],
                        'deviceId': rpcdata.params['deviceId']
                    }
                    result = self._unregisterDsBridge(**args)
                elif rpcdata.method == "rpc_postEnergyDemand":
                    args = {
                        'discovery_address':
                        rpcdata.params['discovery_address'],
                        'deviceId': rpcdata.params['deviceId'],
                        'newEnergyDemand': rpcdata.params['newEnergyDemand']
                    }
                    #post the new energy demand from ds to the local bus
                    result = self._postEnergyDemand(**args)
                elif rpcdata.method == "rpc_postPricePoint":
                    args = {
                        'discovery_address':
                        rpcdata.params['discovery_address'],
                        'deviceId': rpcdata.params['deviceId'],
                        'newPricePoint': rpcdata.params['newPricePoint']
                    }
                    #post the new new price point from us to the local-us-bus
                    result = self._postPricePoint(**args)
                else:
                    return jsonrpc.json_error(rpcdata.id, METHOD_NOT_FOUND, \
                                                'Invalid method {}'.format(rpcdata.method))
                return jsonrpc.json_result(rpcdata.id, result)

            except KeyError as ke:
                print(ke)
                return jsonrpc.json_error(
                    'NA', INVALID_PARAMS,
                    'Invalid params {}'.format(rpcdata.params))
            except Exception as e:
                print(e)
                return jsonrpc.json_error('NA', UNHANDLED_EXCEPTION, e)
Пример #4
0
    def _handle_bacnet_scan(self, session_user, params):
        platform_uuid = params.pop('platform_uuid')
        id = params.pop('message_id')
        _log.debug('Handling bacnet_scan platform: {}'.format(platform_uuid))

        if not self._platforms.is_registered(platform_uuid):
            return jsonrpc.json_error(id, UNAVAILABLE_PLATFORM,
                                      "Couldn't connect to platform {}".format(
                                          platform_uuid
                                      ))

        scan_length = params.pop('scan_length', 5)

        try:
            scan_length = float(scan_length)
            params['scan_length'] = scan_length
            platform = self._platforms.get_platform(platform_uuid)
            iam_topic = "{}/iam".format(session_user['token'])
            ws_socket_topic = "/vc/ws/{}".format(iam_topic)
            self.vip.web.register_websocket(ws_socket_topic,
                                            self.open_authenticate_ws_endpoint,
                                            self._ws_closed, self._ws_received)

            def start_scan():
                # We want the datatype (iam) to be second in the response so
                # we need to reposition the iam and the session id to the topic
                # that is passed to the rpc function on vcp
                iam_session_topic = "iam/{}".format(session_user['token'])
                platform.call("start_bacnet_scan", iam_session_topic, **params)

                def close_socket():
                    _log.debug('Closing bacnet scan for {}'.format(
                        platform_uuid))
                    gevent.spawn_later(2,
                                       self.vip.web.unregister_websocket,
                                       iam_session_topic)

                gevent.spawn_later(scan_length, close_socket)

            # By starting the scan a second later we allow the websocket
            # client to subscribe to the newly available endpoint.
            gevent.spawn_later(2, start_scan)
        except ValueError:
            return jsonrpc.json_error(id, UNAVAILABLE_PLATFORM,
                                      "Couldn't connect to platform {}".format(
                                          platform_uuid
                                      ))
        except KeyError:
            return jsonrpc.json_error(id, UNAUTHORIZED,
                                      "Invalid user session token")
Пример #5
0
    def _handle_bacnet_scan(self, session_user, params):
        platform_uuid = params.pop('platform_uuid')
        id = params.pop('message_id')
        _log.debug('Handling bacnet_scan platform: {}'.format(platform_uuid))

        if not self._platforms.is_registered(platform_uuid):
            return jsonrpc.json_error(id, UNAVAILABLE_PLATFORM,
                                      "Couldn't connect to platform {}".format(
                                          platform_uuid
                                      ))

        scan_length = params.pop('scan_length', 5)

        try:
            scan_length = float(scan_length)
            params['scan_length'] = scan_length
            platform = self._platforms.get_platform(platform_uuid)
            iam_topic = "{}/iam".format(session_user['token'])
            ws_socket_topic = "/vc/ws/{}".format(iam_topic)
            self.vip.web.register_websocket(ws_socket_topic,
                                            self.open_authenticate_ws_endpoint,
                                            self._ws_closed, self._ws_received)

            def start_scan():
                # We want the datatype (iam) to be second in the response so
                # we need to reposition the iam and the session id to the topic
                # that is passed to the rpc function on vcp
                iam_session_topic = "iam/{}".format(session_user['token'])
                platform.call("start_bacnet_scan", iam_session_topic, **params)

                def close_socket():
                    _log.debug('Closing bacnet scan for {}'.format(
                        platform_uuid))
                    gevent.spawn_later(2,
                                       self.vip.web.unregister_websocket,
                                       iam_session_topic)

                gevent.spawn_later(scan_length, close_socket)

            # By starting the scan a second later we allow the websocket
            # client to subscribe to the newly available endpoint.
            gevent.spawn_later(2, start_scan)
        except ValueError:
            return jsonrpc.json_error(id, UNAVAILABLE_PLATFORM,
                                      "Couldn't connect to platform {}".format(
                                          platform_uuid
                                      ))
        except KeyError:
            return jsonrpc.json_error(id, UNAUTHORIZED,
                                      "Invalid user session token")
Пример #6
0
 def rpc_from_net(self, header, message):
     result = False
     try:
         rpcdata = jsonrpc.JsonRpcData.parse(message)
         '''
         _log.debug('rpc_from_net()...' + \
                     ', rpc method: {}'.format(rpcdata.method) +\
                     ', rpc params: {}'.format(rpcdata.params))
         '''
         if rpcdata.method == "rpc_registerDsBridge":
             args = {'discovery_address': rpcdata.params['discovery_address'],
                     'deviceId':rpcdata.params['deviceId']
                     }
             result = self._registerDsBridge(**args)
         elif rpcdata.method == "rpc_unregisterDsBridge":
             args = {'discovery_address': rpcdata.params['discovery_address'],
                     'deviceId':rpcdata.params['deviceId']
                     }
             result = self._unregisterDsBridge(**args)
         elif rpcdata.method == "rpc_postEnergyDemand":
             args = {'discovery_address': rpcdata.params['discovery_address'],
                     'deviceId':rpcdata.params['deviceId'],
                     'newEnergyDemand': rpcdata.params['newEnergyDemand']
                     }
             #post the new energy demand from ds to the local bus
             result = self._postEnergyDemand(**args)    
         elif rpcdata.method == "rpc_postPricePoint":
             args = {'discovery_address': rpcdata.params['discovery_address'],
                     'deviceId':rpcdata.params['deviceId'],
                     'newPricePoint': rpcdata.params['newPricePoint']
                     }
             #post the new new price point from us to the local-us-bus
             result = self._postPricePoint(**args)
         elif rpcdata.method == "rpc_ping":
             result = True
         else:
             return jsonrpc.json_error(rpcdata.id, METHOD_NOT_FOUND, \
                                         'Invalid method {}'.format(rpcdata.method))
         return jsonrpc.json_result(rpcdata.id, result)
         
     except KeyError as ke:
         print(ke)
         return jsonrpc.json_error('NA', INVALID_PARAMS,
                 'Invalid params {}'.format(rpcdata.params))
     except Exception as e:
         print(e)
         return jsonrpc.json_error('NA', UNHANDLED_EXCEPTION, e)
Пример #7
0
 def _processMessage(self, message):
     #_log.debug('processResponse()')
     result = False
     try:
         rpcdata = jsonrpc.JsonRpcData.parse(message)
         _log.info('rpc method: {}'.format(rpcdata.method))
         _log.info('rpc params: {}'.format(rpcdata.params))
         
         if rpcdata.method == "rpc_setShDeviceState":
             args = {'deviceId': rpcdata.params['deviceId'], 
                     'state': rpcdata.params['newState'],
                     'schdExist': SCHEDULE_NOT_AVLB
                     }
             result = self.setShDeviceState(**args)
             
         elif rpcdata.method == "rpc_setShDeviceLevel":
             args = {'deviceId': rpcdata.params['deviceId'], 
                     'level': rpcdata.params['newLevel'],
                     'schdExist': SCHEDULE_NOT_AVLB
                     }
             result = self.setShDeviceLevel(**args)
             
         elif rpcdata.method == "rpc_setShDeviceThPP":
             args = {'deviceId': rpcdata.params['deviceId'], 
                     'thPP': rpcdata.params['newThPP']
                     }
             result = self.setShDeviceThPP(**args)                
         elif rpcdata.method == "rpc_ping":
             result = True
         else:
             return jsonrpc.json_error('NA', METHOD_NOT_FOUND,
                 'Invalid method {}'.format(rpcdata.method))
         result = True        
         return jsonrpc.json_result(rpcdata.id, result)
         
     except KeyError as ke:
         print(ke)
         return jsonrpc.json_error('NA', INVALID_PARAMS,
                 'Invalid params {}'.format(rpcdata.params))
     except AssertionError:
         print('AssertionError')
         return jsonrpc.json_error('NA', INVALID_REQUEST,
                 'Invalid rpc data {}'.format(data))
     except Exception as e:
         print(e)
         return jsonrpc.json_error('NA', UNHANDLED_EXCEPTION, e)
Пример #8
0
 def _disable_setup_mode(self, session_user, params):
     id = params.pop('message_id')
     if 'admin' not in session_user['groups']:
         _log.debug('Returning json_error disable_setup_mode')
         return jsonrpc.json_error(
             id, UNAUTHORIZED,
             "Admin access is required to disable setup mode")
     self.vip.rpc.call(AUTH, "auth_file.remove_by_credentials", "/.*/")
     return "SUCCESS"
Пример #9
0
 def _disable_setup_mode(self, session_user, params):
     id = params.pop('message_id')
     if 'admin' not in session_user['groups']:
         _log.debug('Returning json_error disable_setup_mode')
         return jsonrpc.json_error(
             id, UNAUTHORIZED,
             "Admin access is required to disable setup mode")
     auth_file = AuthFile()
     auth_file.remove_by_credentials("/.*/")
     return "SUCCESS"
Пример #10
0
 def post(self):
     _log.debug('handling request')
     request_body = self.request.body
     # result will be an RpcParser object  when completed
     self.rpcrequest = RpcRequest(request_body)
     if self.rpcrequest.has_error():
         self._response_complete(
             jsonrpc.json_error(
                 self.rpcrequest.id, self.rpcrequest.error,
                 get_standard_error_message(self.rpcrequest.error)))
     else:
         self._route(self.rpcrequest)
Пример #11
0
    def _get_jsonrpc_response(self, id, result_or_error):
        """ Wrap the response in either a json-rpc error or result.

        :param id:
        :param result_or_error:
        :return:
        """
        if 'error' in result_or_error:
            error = result_or_error['error']
            _log.debug("RPC RESPONSE ERROR: {}".format(error))
            return jsonrpc.json_error(id, error['code'], error['message'])
        return jsonrpc.json_result(id, result_or_error)
Пример #12
0
    def _get_jsonrpc_response(self, id, result_or_error):
        """ Wrap the response in either a json-rpc error or result.

        :param id:
        :param result_or_error:
        :return:
        """
        if 'error' in result_or_error:
            error = result_or_error['error']
            _log.debug("RPC RESPONSE ERROR: {}".format(error))
            return jsonrpc.json_error(id, error['code'], error['message'])
        return jsonrpc.json_result(id, result_or_error)
Пример #13
0
    def set_setting(self, session_user, params):
        """
        Sets or removes a setting from the config store.  If the value is None
        then the item will be removed from the store.  If there is an error in
        saving the value then a jsonrpc.json_error object is returned.

        :param session_user: Unused
        :param params: Dictionary that must contain 'key' and 'value' keys.
        :return: A 'SUCCESS' string or a jsonrpc.json_error object.
        """
        if 'key' not in params or not params['key']:
            return jsonrpc.json_error(params['message_id'],
                                      INVALID_PARAMS,
                                      'Invalid parameter key not set')
        if 'value' not in params:
            return jsonrpc.json_error(params['message_id'],
                                      INVALID_PARAMS,
                                      'Invalid parameter key not set')

        config_key = "settings/{}".format(params['key'])
        value = params['value']

        if value is None:
            try:
                self.vip.config.delete(config_key)
            except KeyError:
                pass
        else:
            # We handle empt string here because the config store doesn't allow
            # empty strings to be set as a config store.  I wasn't able to
            # trap the ValueError that is raised on the server side.
            if value == "":
                return jsonrpc.json_error(params['message_id'],
                                          INVALID_PARAMS,
                                          'Invalid value set (empty string?)')
            self.vip.config.set(config_key, value)

        return 'SUCCESS'
Пример #14
0
 def route_to_agent_method(self, id, agent_method, params):
     try:
         self._log.debug('route_to_agent_method {} {}'.format(
             id, agent_method))
         resp = self.call('route_to_agent_method', id, agent_method, params)
         if isinstance(resp, dict):
             if 'result' not in resp and 'error' not in resp:
                 resp = jsonrpc.json_result(id, resp)
         else:
             resp = jsonrpc.json_result(id, resp)
         return resp
     except RemoteError as e:
         return jsonrpc.json_error(id, INTERNAL_ERROR,
                                   "Internal Error: {}".format(str(e)))
Пример #15
0
 def route_to_agent_method(self, id, agent_method, params):
     try:
         self._log.debug('route_to_agent_method {} {}'.format(id,
                                                              agent_method))
         resp = self.call('route_to_agent_method', id, agent_method,
                                      params)
         if isinstance(resp, dict):
             if 'result' not in resp and 'error' not in resp:
                 resp = jsonrpc.json_result(id, resp)
         else:
             resp = jsonrpc.json_result(id, resp)
         return resp
     except RemoteError as e:
         return jsonrpc.json_error(id, INTERNAL_ERROR,
                                   "Internal Error: {}".format(str(e)))
Пример #16
0
 def post(self):
     _log.debug("handling request")
     self.tmp.seek(0)
     self.rpcrequest = RpcRequest(self.tmp.read())
     self.tmp.close()
     # request_body = self.request.body
     # result will be an RpcParser object  when completed
     # self.rpcrequest = RpcRequest(request_body)
     if self.rpcrequest.has_error():
         self._response_complete(
             jsonrpc.json_error(
                 self.rpcrequest.id, self.rpcrequest.error, get_standard_error_message(self.rpcrequest.error)
             )
         )
     else:
         self._route(self.rpcrequest)
Пример #17
0
    def get_setting(self, session_user, params):
        """
        Retrieve a value from the passed setting key.  The params object must
        contain a "key" to return from the settings store.

        :param session_user: Unused
        :param params: Dictionary that must contain a 'key' key.
        :return: The value or a jsonrpc error object.
        """
        config_key = "settings/{}".format(params['key'])
        try:
            value = self.vip.config.get(config_key)
        except KeyError:
            return jsonrpc.json_error(params['message_id'], INVALID_PARAMS,
                                      'Invalid key specified')
        else:
            return value
Пример #18
0
    def _enable_setup_mode(self, session_user, params):
        id = params.pop('message_id')
        if 'admin' not in session_user['groups']:
            _log.debug('Returning json_error enable_setup_mode')
            return jsonrpc.json_error(
                id, UNAUTHORIZED,
                "Admin access is required to enable setup mode")
        auth_file = AuthFile()
        entries = auth_file.find_by_credentials(".*")
        if len(entries) > 0:
            return "SUCCESS"

        entry = AuthEntry(credentials="/.*/",
                          comments="Un-Authenticated connections allowed here",
                          user_id="unknown")
        auth_file.add(entry)
        return "SUCCESS"
Пример #19
0
    def _enable_setup_mode(self, session_user, params):
        id = params.pop('message_id')
        if 'admin' not in session_user['groups']:
            _log.debug('Returning json_error enable_setup_mode')
            return jsonrpc.json_error(
                id, UNAUTHORIZED,
                "Admin access is required to enable setup mode")
        auth_file = AuthFile()
        entries = auth_file.find_by_credentials(".*")
        if len(entries) > 0:
            return "SUCCESS"

        entry = AuthEntry(credentials="/.*/",
                          comments="Un-Authenticated connections allowed here",
                          user_id="unknown")
        auth_file.add(entry)
        return "SUCCESS"
Пример #20
0
    def get_setting(self, session_user, params):
        """
        Retrieve a value from the passed setting key.  The params object must
        contain a "key" to return from the settings store.

        :param session_user: Unused
        :param params: Dictionary that must contain a 'key' key.
        :return: The value or a jsonrpc error object.
        """
        config_key = "settings/{}".format(params['key'])
        try:
            value = self.vip.config.get(config_key)
        except KeyError:
            return jsonrpc.json_error(params['message_id'],
                                      INVALID_PARAMS,
                                      'Invalid key specified')
        else:
            return value
Пример #21
0
    def _enable_setup_mode(self, session_user, params):
        id = params.pop('message_id')
        if 'admin' not in session_user['groups']:
            _log.debug('Returning json_error enable_setup_mode')
            return jsonrpc.json_error(
                id, UNAUTHORIZED,
                "Admin access is required to enable setup mode")
        entries = self.vip.rpc.call(AUTH, "auth_file.find_by_credentials",
                                    ".*")
        if len(entries) > 0:
            return "SUCCESS"

        entry = {
            "credentials": "/.*/",
            "comments": "Un-Authenticated connections allowed here",
            "user_id": "unknown"
        }
        self.vip.rpc.call(AUTH, "auth_file.add", entry)
        return "SUCCESS"
Пример #22
0
    def store_agent_config(self, session_user, params):
        required = ('agent_identity', 'config_name', 'raw_contents')
        message_id = params.pop('message_id')
        errors = []
        for r in required:
            if r not in params:
                errors.append('Missing {}'.format(r))
        config_type = params.get('config_type', None)
        if config_type:
            if config_type not in ('raw', 'json', 'csv'):
                errors.append('Invalid config_type parameter')

        if errors:
            return jsonrpc.json_error(message_id, INVALID_PARAMS,
                                      "\n".join(errors))
        try:
            self._log.debug("Calling store_agent_config on external platform.")
            self.call("store_agent_config", **params)
        except Exception as e:
            self._log.error(str(e))
            return jsonrpc.json_error(message_id, INTERNAL_ERROR,
                                      str(e))
        config_name = params.get("config_name")
        agent_identity = params.get("agent_identity")
        if config_name.startswith("devices"):
            # Since we start with devices, we assume that we are attempting
            # to save a master driver config file.
            rawdict = jsonapi.loads(params['raw_contents'])

            # if this is not a bacnet device_type then we cannot do anything
            # more than save and retrieve it from the store.
            driver_type = rawdict.get('driver_type', None)
            if driver_type is None or driver_type not in ('bacnet', 'modbus'):
                return jsonrpc.json_result(message_id, "SUCCESS")

            # Registry config starts with config://
            registry_config = rawdict['registry_config'][len('config://'):]

            try:
                self._log.debug("Retrieving registry_config for new device.")
                point_config = self.call("get_agent_config",
                                                     agent_identity,
                                                     registry_config, raw=False)
            except Exception as e:
                self._log.error(str(e))
                return jsonrpc.json_error(message_id, INTERNAL_ERROR,
                                          "Couldn't retrieve registry_config "
                                          "from connection.")
            else:
                new_device = dict(
                    device_address=rawdict['driver_config']['device_address'],
                    device_id=rawdict['driver_config']['device_id'],
                    points=[],
                    path=config_name,
                    health=Status.build(UNKNOWN_STATUS,
                                        context="Unpublished").as_dict()
                )
                points = [p['Volttron Point Name'] for p in point_config]
                new_device['points'] = points
                self._vc.send_management_message("NEW_DEVICE", new_device)

            status = Status.build(UNKNOWN_STATUS,
                                  context="Not published since update")
            device_config_name = params.get('config_name')
            device_no_prefix = device_config_name[len('devices/'):]
            the_device = self._current_devices.get(device_no_prefix, {})

            if not the_device:
                self._current_devices[device_no_prefix] = dict(
                    last_publish_utc=None,
                    health=status.as_dict(),
                    points=points
                )
            else:
                self._current_devices[device_no_prefix]['points'] = points

            return jsonrpc.json_result(message_id, "SUCCESS")
Пример #23
0
    def _route_request(self, session_user, id, method, params):
        """ Handle the methods volttron central can or pass off to platforms.

        :param session_user:
            The authenticated user's session info.
        :param id:
            JSON-RPC id field.
        :param method:
        :param params:
        :return:
        """
        _log.debug(
            'inside _route_request {}, {}, {}'.format(id, method, params))

        def err(message, code=METHOD_NOT_FOUND):
            return {'error': {'code': code, 'message': message}}

        self.send_management_message(method)

        method_split = method.split('.')
        # The last part of the jsonrpc method is the actual method to be called.
        method_check = method_split[-1]

        # These functions will be sent to a platform.agent on either this
        # instance or another.  All of these functions have the same interface
        # and can be collected into a dictionary rather than an if tree.
        platform_methods = dict(
            # bacnet related
            start_bacnet_scan=self._handle_bacnet_scan,
            publish_bacnet_props=self._handle_bacnet_props,
            # config store related
            store_agent_config="store_agent_config",
            get_agent_config="get_agent_config",
            list_agent_configs="get_agent_config_list",
            # management related

            list_agents="get_agent_list",
            get_devices="get_devices",
            status_agents="status_agents"
        )

        # These methods are specifically to be handled by the platform not any
        # agents on the platform that is why we have the length requirement.
        #
        # The jsonrpc method looks like the following
        #
        #   platform.uuid.<dynamic entry>.method_on_vcp
        if method_check in platform_methods:

            platform_uuid = None
            if isinstance(params, dict):
                platform_uuid = params.pop('platform_uuid', None)

            if platform_uuid is None:
                if method_split[0] == 'platforms' and method_split[1] == 'uuid':
                    platform_uuid = method_split[2]

            if not platform_uuid:
                return err("Invalid platform_uuid specified as parameter"
                           .format(platform_uuid),
                           INVALID_PARAMS)

            if not self._platforms.is_registered(platform_uuid):
                return err("Unknown or unavailable platform {} specified as "
                           "parameter".format(platform_uuid),
                           UNAVAILABLE_PLATFORM)

            try:
                _log.debug('Calling {} on platform {}'.format(
                    method_check, platform_uuid
                ))
                class_method = platform_methods[method_check]
                platform = self._platforms.get_platform(platform_uuid)
                # Determine whether the method to call is on the current class
                # or on the platform object.
                if isinstance(class_method, basestring):
                    method_ref = getattr(platform, class_method)
                else:
                    method_ref = class_method
                    # Put the platform_uuid in the params so it can be used
                    # inside the method
                    params['platform_uuid'] = platform_uuid

            except AttributeError or KeyError:
                return jsonrpc.json_error(id, INTERNAL_ERROR,
                                          "Attempted calling function "
                                          "{} was unavailable".format(
                                              class_method
                                          ))

            except ValueError:
                return jsonrpc.json_error(id, UNAVAILABLE_PLATFORM,
                                          "Couldn't connect to platform "
                                          "{}".format(platform_uuid))
            else:
                # pass the id through the message_id parameter.
                if not params:
                    params = dict(message_id=id)
                else:
                    params['message_id'] = id

                # Methods will all have the signature
                #   method(session, params)
                #
                return method_ref(session_user, params)

        vc_methods = dict(
            register_management_endpoint=self._handle_management_endpoint,
            list_platforms=self._platforms.get_platform_list,
            list_performance=self._platforms.get_performance_list,

            # Settings
            set_setting=self.set_setting,
            get_setting=self.get_setting,
            get_setting_keys=self.get_setting_keys,

            # Setup mode
            enable_setup_mode=self._enable_setup_mode,
            disable_setup_mode=self._disable_setup_mode
        )

        if method in vc_methods:
            if not params:
                params = dict(message_id=id)
            else:
                params['message_id'] = id
            response = vc_methods[method](session_user, params)
            _log.debug("Response is {}".format(response))
            return response  # vc_methods[method](session_user, params)

        if method == 'register_instance':
            if isinstance(params, list):
                return self._register_instance(*params)
            else:
                return self._register_instance(**params)
        elif method == 'unregister_platform':
            return self.unregister_platform(params['instance_uuid'])

        elif 'historian' in method:
            has_platform_historian = PLATFORM_HISTORIAN in \
                                     self.vip.peerlist().get(timeout=30)
            if not has_platform_historian:
                return err(
                    'The VOLTTRON Central platform historian is unavailable.',
                    UNAVAILABLE_AGENT)
            _log.debug('Trapping platform.historian to vc.')
            _log.debug('has_platform_historian: {}'.format(
                has_platform_historian))
            if 'historian.query' in method:
                return self.vip.rpc.call(
                    PLATFORM_HISTORIAN, 'query', **params).get(timeout=30)
            elif 'historian.get_topic_list' in method:
                return self.vip.rpc.call(
                    PLATFORM_HISTORIAN, 'get_topic_list').get(timeout=30)

        # This isn't known as a proper method on vc or a platform.
        if len(method_split) < 3:
            return err('Unknown method {}'.format(method))
        if method_split[0] != 'platforms' or method_split[1] != 'uuid':
            return err('Invalid format for instance must start with '
                       'platforms.uuid')
        instance_uuid = method_split[2]
        _log.debug('Instance uuid is: {}'.format(instance_uuid))
        if not self._platforms.is_registered(instance_uuid):
            return err('Unknown platform {}'.format(instance_uuid))
        platform_method = '.'.join(method_split[3:])
        _log.debug("Platform method is: {}".format(platform_method))
        platform = self._platforms.get_platform(instance_uuid)
        if not platform:
            return jsonrpc.json_error(id,
                                      UNAVAILABLE_PLATFORM,
                                      "cannot connect to platform."
                                      )

        if platform_method.startswith('install'):
            if 'admin' not in session_user['groups']:
                return jsonrpc.json_error(
                    id, UNAUTHORIZED,
                    "Admin access is required to install agents")

        return platform.route_to_agent_method(id, platform_method, params)
Пример #24
0
 def list_agent_methods(self, method, params, id, agent_uuid):
     return jsonrpc.json_error(ident=id, code=INTERNAL_ERROR,
                               message='Not implemented')
Пример #25
0
    def jsonrpc(self, env, data):
        """ The main entry point for ^jsonrpc data

        This method will only accept rpcdata.  The first time this method
        is called, per session, it must be using get_authorization.  That
        will return a session token that must be included in every
        subsequent request.  The session is tied to the ip address
        of the caller.

        :param object env: Environment dictionary for the request.
        :param object data: The JSON-RPC 2.0 method to call.
        :return object: An JSON-RPC 2.0 response.
        """
        if env['REQUEST_METHOD'].upper() != 'POST':
            return jsonrpc.json_error('NA', INVALID_REQUEST,
                                      'Invalid request method, only POST allowed'
                                      )

        try:
            rpcdata = self._to_jsonrpc_obj(data)
            _log.info('rpc method: {}'.format(rpcdata.method))
            if rpcdata.method == 'get_authorization':
                args = {'username': rpcdata.params['username'],
                        'password': rpcdata.params['password'],
                        'ip': env['REMOTE_ADDR']}
                sess = self._authenticated_sessions.authenticate(**args)
                if not sess:
                    _log.info('Invalid username/password for {}'.format(
                        rpcdata.params['username']))
                    return jsonrpc.json_error(
                        rpcdata.id, UNAUTHORIZED,
                        "Invalid username/password specified.")
                _log.info('Session created for {}'.format(
                    rpcdata.params['username']))
                self.vip.web.register_websocket(
                    "/vc/ws/{}/management".format(sess),
                    self.open_authenticate_ws_endpoint,
                    self._ws_closed,
                    self._received_data)
                _log.info('Session created for {}'.format(
                    rpcdata.params['username']))

                gevent.sleep(1)
                return jsonrpc.json_result(rpcdata.id, sess)

            token = rpcdata.authorization
            ip = env['REMOTE_ADDR']
            _log.debug('REMOTE_ADDR: {}'.format(ip))
            session_user = self._authenticated_sessions.check_session(token, ip)
            _log.debug('SESSION_USER IS: {}'.format(session_user))
            if not session_user:
                _log.debug("Session Check Failed for Token: {}".format(token))
                return jsonrpc.json_error(rpcdata.id, UNAUTHORIZED,
                                          "Invalid authentication token")
            _log.debug('RPC METHOD IS: {}'.format(rpcdata.method))

            # Route any other method that isn't
            result_or_error = self._route_request(session_user,
                                                  rpcdata.id, rpcdata.method,
                                                  rpcdata.params)

        except AssertionError:
            return jsonrpc.json_error(
                'NA', INVALID_REQUEST, 'Invalid rpc data {}'.format(data))
        except Unreachable:
            return jsonrpc.json_error(
                rpcdata.id, UNAVAILABLE_PLATFORM,
                "Couldn't reach platform with method {} params: {}".format(
                    rpcdata.method,
                    rpcdata.params))
        except Exception as e:

            return jsonrpc.json_error(
                'NA', UNHANDLED_EXCEPTION, e
            )

        return self._get_jsonrpc_response(rpcdata.id, result_or_error)
Пример #26
0
 def list_agent_methods(self, method, params, id, agent_uuid):
     return jsonrpc.json_error(ident=id,
                               code=INTERNAL_ERROR,
                               message='Not implemented')
Пример #27
0
    def _route_request(self, session_user, id, method, params):
        '''Route request to either a registered platform or handle here.'''
        _log.debug('inside _route_request {}, {}, {}'.format(
            id, method, params))

        def err(message, code=METHOD_NOT_FOUND):
            return {'error': {'code': code, 'message': message}}

        if method == 'register_instance':
            if isinstance(params, list):
                return self._register_instance(*params)
            else:
                return self._register_instance(**params)
        elif method == 'list_deivces':
            return self._handle_list_devices()
        elif method == 'list_performance':
            return self._handle_list_performance()
        elif method == 'list_platforms':
            return self._handle_list_platforms()
        elif method == 'unregister_platform':
            return self.unregister_platform(params['platform_uuid'])
        elif method == 'get_setting':
            if 'key' not in params or not params['key']:
                return err('Invalid parameter key not set', INVALID_PARAMS)
            value = self._setting_store.get(params['key'], None)
            if value is None:
                return err('Invalid key specified', INVALID_PARAMS)
            return value
        elif method == 'get_setting_keys':
            return self._setting_store.keys()
        elif method == 'set_setting':
            if 'key' not in params or not params['key']:
                return err('Invalid parameter key not set', INVALID_PARAMS)
            _log.debug('VALUE: {}'.format(params))
            if 'value' not in params:
                return err('Invalid parameter value not set', INVALID_PARAMS)
            # if passing None value then remove the value from the keystore
            # don't raise an error if the key isn't present in the store.
            if params['value'] is None:
                if params['key'] in self._setting_store:
                    del self._setting_store[params['key']]
            else:
                self._setting_store[params['key']] = params['value']
                self._setting_store.sync()
            return 'SUCCESS'
        elif 'historian' in method:
            has_platform_historian = PLATFORM_HISTORIAN in \
                                     self.vip.peerlist().get(timeout=30)
            if not has_platform_historian:
                return err(
                    'The VOLTTRON Central platform historian is unavailable.',
                    UNAVAILABLE_AGENT)
            _log.debug('Trapping platform.historian to vc.')
            _log.debug(
                'has_platform_historian: {}'.format(has_platform_historian))
            if 'historian.query' in method:
                return self.vip.rpc.call(PLATFORM_HISTORIAN, 'query',
                                         **params).get(timeout=30)
            elif 'historian.get_topic_list' in method:
                return self.vip.rpc.call(PLATFORM_HISTORIAN,
                                         'get_topic_list').get(timeout=30)

        fields = method.split('.')
        if len(fields) < 3:
            return err('Unknown method {}'.format(method))
        platform_uuid = fields[2]
        platform = self._registry.get_platform(platform_uuid)
        if not platform:
            return err('Unknown platform {}'.format(platform_uuid))
        platform_method = '.'.join(fields[3:])
        _log.debug(platform_uuid)
        # Get a connection object associated with the platform uuid.
        cn = self._pa_agents.get(platform_uuid)
        if not cn:
            return jsonrpc.json_error(id, UNAVAILABLE_PLATFORM,
                                      "Cannot connect to platform.")
        _log.debug('Routing to {}'.format(VOLTTRON_CENTRAL_PLATFORM))

        if platform_method == 'install':
            if 'admin' not in session_user['groups']:
                return jsonrpc.json_error(
                    id, UNAUTHORIZED,
                    "Admin access is required to install agents")

        if platform_method == 'list_agents':
            _log.debug('Callling list_agents')
            agents = self._registry.get_agent_list(platform_uuid)

            if agents is None:
                _log.warn('No agents found for platform_uuid {}'.format(
                    platform_uuid))
                agents = []

            for a in agents:
                if 'admin' not in session_user['groups']:
                    a['permissions'] = {
                        'can_stop': False,
                        'can_start': False,
                        'can_restart': False,
                        'can_remove': False
                    }
                else:
                    _log.debug('Permissionse for {} are {}'.format(
                        a['name'], a['permissions']))
            return agents
        else:
            try:
                return cn.agent.vip.rpc.call(VOLTTRON_CENTRAL_PLATFORM,
                                             'route_request', id,
                                             platform_method,
                                             params).get(timeout=30)
            except (Unreachable, gevent.Timeout) as e:
                del self._pa_agents[platform_uuid]
                return err("Can't route to platform", UNAVAILABLE_PLATFORM)
Пример #28
0
    def route_request(self, id, method, params):
        _log.debug(
            'platform agent routing request: {}, {}'.format(id, method))

        # First handle the elements that are going to this platform
        if method == 'list_agents':
            result = self.list_agents()
        elif method == 'set_setting':
            result = self.set_setting(**params)
        elif method == 'get_setting':
            result = self.get_setting(**params)
        elif method == 'get_devices':
            result = self.get_devices()
        elif method == 'status_agents':
            _log.debug('Doing status agents')
            result = {'result': [{'name': a[1], 'uuid': a[0],
                                  'process_id': a[2][0],
                                  'return_code': a[2][1]}
                                 for a in
                                 self.vip.rpc.call('control', method).get()]}

        elif method in ('agent_status', 'start_agent', 'stop_agent',
                        'remove_agent'):
            _log.debug('We are trying to exectute method {}'.format(method))
            if isinstance(params, list) and len(params) != 1 or \
                            isinstance(params,
                                       dict) and 'uuid' not in params.keys():
                result = jsonrpc.json_error(ident=id, code=INVALID_PARAMS)
            else:
                if isinstance(params, list):
                    uuid = params[0]
                elif isinstance(params, str):
                    uuid = params
                else:
                    uuid = params['uuid']

                status = self.vip.rpc.call('control', method, uuid).get()
                if method == 'stop_agent' or status == None:
                    # Note we recurse here to get the agent status.
                    result = self.route_request(id, 'agent_status', uuid)
                else:
                    result = {'process_id': status[0],
                              'return_code': status[1]}
        elif method in ('install'):

            if not 'files' in params:
                result = jsonrpc.json_error(ident=id, code=INVALID_PARAMS)
            else:
                result = self._install_agents(params['files'])

        else:

            fields = method.split('.')

            if fields[0] == 'historian':
                if 'platform.historian' in self.vip.peerlist().get(timeout=30):
                    agent_method = fields[1]
                    result = self.vip.rpc.call('platform.historian',
                                               agent_method,
                                               **params).get(timeout=45)
                else:
                    result = jsonrpc.json_error(
                        id, INVALID_PARAMS, 'historian unavailable')
            else:
                agent_uuid = fields[2]
                agent_method = '.'.join(fields[3:])
                _log.debug("Calling method {} on agent {}"
                           .format(agent_method, agent_uuid))
                _log.debug("Params is: {}".format(params))

                result = self.vip.rpc.call(agent_uuid, agent_method,
                                           **params).get()

        if isinstance(result, dict):
            if 'result' in result:
                return result['result']
            elif 'code' in result:
                return result['code']

        return result
Пример #29
0
    def _route_request(self, session_user, id, method, params):
        """ Handle the methods volttron central can or pass off to platforms.

        :param session_user:
            The authenticated user's session info.
        :param id:
            JSON-RPC id field.
        :param method:
        :param params:
        :return:
        """
        _log.debug(
            'inside _route_request {}, {}, {}'.format(id, method, params))

        def err(message, code=METHOD_NOT_FOUND):
            return {'error': {'code': code, 'message': message}}

        self.send_management_message(method)

        method_split = method.split('.')
        # The last part of the jsonrpc method is the actual method to be called.
        method_check = method_split[-1]

        # These functions will be sent to a platform.agent on either this
        # instance or another.  All of these functions have the same interface
        # and can be collected into a dictionary rather than an if tree.
        platform_methods = dict(
            # bacnet related
            start_bacnet_scan=self._handle_bacnet_scan,
            publish_bacnet_props=self._handle_bacnet_props,
            # config store related
            store_agent_config="store_agent_config",
            get_agent_config="get_agent_config",
            list_agent_configs="get_agent_config_list",
            # management related

            list_agents="get_agent_list",
            get_devices="get_devices",
            status_agents="status_agents"
        )

        # These methods are specifically to be handled by the platform not any
        # agents on the platform that is why we have the length requirement.
        #
        # The jsonrpc method looks like the following
        #
        #   platform.uuid.<dynamic entry>.method_on_vcp
        if method_check in platform_methods:

            platform_uuid = None
            if isinstance(params, dict):
                platform_uuid = params.pop('platform_uuid', None)

            if platform_uuid is None:
                if method_split[0] == 'platforms' and method_split[1] == 'uuid':
                    platform_uuid = method_split[2]

            if not platform_uuid:
                return err("Invalid platform_uuid specified as parameter"
                           .format(platform_uuid),
                           INVALID_PARAMS)

            if not self._platforms.is_registered(platform_uuid):
                return err("Unknown or unavailable platform {} specified as "
                           "parameter".format(platform_uuid),
                           UNAVAILABLE_PLATFORM)

            try:
                _log.debug('Calling {} on platform {}'.format(
                    method_check, platform_uuid
                ))
                class_method = platform_methods[method_check]
                platform = self._platforms.get_platform(platform_uuid)
                # Determine whether the method to call is on the current class
                # or on the platform object.
                if isinstance(class_method, basestring):
                    method_ref = getattr(platform, class_method)
                else:
                    method_ref = class_method
                    # Put the platform_uuid in the params so it can be used
                    # inside the method
                    params['platform_uuid'] = platform_uuid

            except AttributeError or KeyError:
                return jsonrpc.json_error(id, INTERNAL_ERROR,
                                          "Attempted calling function "
                                          "{} was unavailable".format(
                                              class_method
                                          ))

            except ValueError:
                return jsonrpc.json_error(id, UNAVAILABLE_PLATFORM,
                                          "Couldn't connect to platform "
                                          "{}".format(platform_uuid))
            else:
                # pass the id through the message_id parameter.
                if not params:
                    params = dict(message_id=id)
                else:
                    params['message_id'] = id

                # Methods will all have the signature
                #   method(session, params)
                #
                return method_ref(session_user, params)

        vc_methods = dict(
            register_management_endpoint=self._handle_management_endpoint,
            list_platforms=self._platforms.get_platform_list,
            list_performance=self._platforms.get_performance_list,

            # Settings
            set_setting=self.set_setting,
            get_setting=self.get_setting,
            get_setting_keys=self.get_setting_keys,

            # Setup mode
            enable_setup_mode=self._enable_setup_mode,
            disable_setup_mode=self._disable_setup_mode
        )

        if method in vc_methods:
            if not params:
                params = dict(message_id=id)
            else:
                params['message_id'] = id
            response = vc_methods[method](session_user, params)
            _log.debug("Response is {}".format(response))
            return response  # vc_methods[method](session_user, params)

        if method == 'register_instance':
            if isinstance(params, list):
                return self._register_instance(*params)
            else:
                return self._register_instance(**params)
        elif method == 'unregister_platform':
            return self.unregister_platform(params['instance_uuid'])

        elif 'historian' in method:
            has_platform_historian = PLATFORM_HISTORIAN in \
                                     self.vip.peerlist().get(timeout=30)
            if not has_platform_historian:
                return err(
                    'The VOLTTRON Central platform historian is unavailable.',
                    UNAVAILABLE_AGENT)
            _log.debug('Trapping platform.historian to vc.')
            _log.debug('has_platform_historian: {}'.format(
                has_platform_historian))
            if 'historian.query' in method:
                return self.vip.rpc.call(
                    PLATFORM_HISTORIAN, 'query', **params).get(timeout=30)
            elif 'historian.get_topic_list' in method:
                return self.vip.rpc.call(
                    PLATFORM_HISTORIAN, 'get_topic_list').get(timeout=30)

        # This isn't known as a proper method on vc or a platform.
        if len(method_split) < 3:
            return err('Unknown method {}'.format(method))
        if method_split[0] != 'platforms' or method_split[1] != 'uuid':
            return err('Invalid format for instance must start with '
                       'platforms.uuid')
        instance_uuid = method_split[2]
        _log.debug('Instance uuid is: {}'.format(instance_uuid))
        if not self._platforms.is_registered(instance_uuid):
            return err('Unknown platform {}'.format(instance_uuid))
        platform_method = '.'.join(method_split[3:])
        _log.debug("Platform method is: {}".format(platform_method))
        platform = self._platforms.get_platform(instance_uuid)
        if not platform:
            return jsonrpc.json_error(id,
                                      UNAVAILABLE_PLATFORM,
                                      "cannot connect to platform."
                                      )

        if platform_method.startswith('install'):
            if 'admin' not in session_user['groups']:
                return jsonrpc.json_error(
                    id, UNAUTHORIZED,
                    "Admin access is required to install agents")

        return platform.route_to_agent_method(id, platform_method, params)
Пример #30
0
    def jsonrpc(self, env, data):
        """ The main entry point for ^jsonrpc data

        This method will only accept rpcdata.  The first time this method
        is called, per session, it must be using get_authorization.  That
        will return a session token that must be included in every
        subsequent request.  The session is tied to the ip address
        of the caller.

        :param object env: Environment dictionary for the request.
        :param object data: The JSON-RPC 2.0 method to call.
        :return object: An JSON-RPC 2.0 response.
        """
        if env['REQUEST_METHOD'].upper() != 'POST':
            return jsonrpc.json_error('NA', INVALID_REQUEST,
                                      'Invalid request method')

        try:
            rpcdata = self._to_jsonrpc_obj(data)
            _log.info('rpc method: {}'.format(rpcdata.method))
            if rpcdata.method == 'get_authorization':
                args = {'username': rpcdata.params['username'],
                        'password': rpcdata.params['password'],
                        'ip': env['REMOTE_ADDR']}
                sess = self._sessions.authenticate(**args)
                if not sess:
                    _log.info('Invalid username/password for {}'.format(
                        rpcdata.params['username']))
                    return jsonrpc.json_error(
                        rpcdata.id, UNAUTHORIZED,
                        "Invalid username/password specified.")
                _log.info('Session created for {}'.format(
                    rpcdata.params['username']))
                return jsonrpc.json_result(rpcdata.id, sess)

            token = rpcdata.authorization
            ip = env['REMOTE_ADDR']
            _log.debug('REMOTE_ADDR: {}'.format(ip))
            session_user = self._sessions.check_session(token, ip)
            _log.debug('SESSION_USER IS: {}'.format(session_user))
            if not session_user:
                _log.debug("Session Check Failed for Token: {}".format(token))
                return jsonrpc.json_error(rpcdata.id, UNAUTHORIZED,
                                          "Invalid authentication token")
            _log.debug('RPC METHOD IS: {}'.format(rpcdata.method))

            # Route any other method that isn't
            result_or_error = self._route_request(session_user,
                                                  rpcdata.id, rpcdata.method,
                                                  rpcdata.params)

        except AssertionError:
            return jsonrpc.json_error(
                'NA', INVALID_REQUEST, 'Invalid rpc data {}'.format(data))
        except Exception as e:

            return jsonrpc.json_error(
                'NA', UNHANDLED_EXCEPTION, e
            )

        _log.debug("RETURNING: {}".format(self._get_jsonrpc_response(
            rpcdata.id, result_or_error)))
        return self._get_jsonrpc_response(rpcdata.id, result_or_error)
Пример #31
0
    def _route_request(self, session_user, id, method, params):
        '''Route request to either a registered platform or handle here.'''
        _log.debug(
            'inside _route_request {}, {}, {}'.format(id, method, params))

        def err(message, code=METHOD_NOT_FOUND):
            return {'error': {'code': code, 'message': message}}

        if method == 'register_instance':
            if isinstance(params, list):
                return self._register_instance(*params)
            else:
                return self._register_instance(**params)
        elif method == 'list_deivces':
            return self._handle_list_devices()
        elif method == 'list_performance':
            return self._handle_list_performance()
        elif method == 'list_platforms':
            return self._handle_list_platforms()
        elif method == 'unregister_platform':
            return self.unregister_platform(params['platform_uuid'])
        elif method == 'get_setting':
            if 'key' not in params or not params['key']:
                return err('Invalid parameter key not set',
                           INVALID_PARAMS)
            value = self._setting_store.get(params['key'], None)
            if value is None:
                return err('Invalid key specified', INVALID_PARAMS)
            return value
        elif method == 'get_setting_keys':
            return self._setting_store.keys()
        elif method == 'set_setting':
            if 'key' not in params or not params['key']:
                return err('Invalid parameter key not set',
                           INVALID_PARAMS)
            _log.debug('VALUE: {}'.format(params))
            if 'value' not in params:
                return err('Invalid parameter value not set',
                           INVALID_PARAMS)
            # if passing None value then remove the value from the keystore
            # don't raise an error if the key isn't present in the store.
            if params['value'] is None:
                if params['key'] in self._setting_store:
                    del self._setting_store[params['key']]
            else:
                self._setting_store[params['key']] = params['value']
                self._setting_store.sync()
            return 'SUCCESS'
        elif 'historian' in method:
            has_platform_historian = PLATFORM_HISTORIAN in \
                                     self.vip.peerlist().get(timeout=30)
            if not has_platform_historian:
                return err('Platform historian not found on volttorn central',
                           UNAVAILABLE_AGENT)
            _log.debug('Trapping platform.historian to vc.')
            _log.debug('has_platform_historian: {}'.format(
                has_platform_historian))
            if 'historian.query' in method:
                return self.vip.rpc.call(
                    PLATFORM_HISTORIAN, 'query', **params).get(timeout=30)
            elif 'historian.get_topic_list' in method:
                return self.vip.rpc.call(
                    PLATFORM_HISTORIAN, 'get_topic_list').get(timeout=30)

        fields = method.split('.')
        if len(fields) < 3:
            return err('Unknown method {}'.format(method))
        platform_uuid = fields[2]
        platform = self._registry.get_platform(platform_uuid)
        if not platform:
            return err('Unknown platform {}'.format(platform_uuid))
        platform_method = '.'.join(fields[3:])
        _log.debug(platform_uuid)
        # Get a connection object associated with the platform uuid.
        cn = self._pa_agents.get(platform_uuid)
        if not cn:
            return jsonrpc.json_error(id,
                                      UNAVAILABLE_PLATFORM,
                                      "Cannot connect to platform."
                                      )
        _log.debug('Routing to {}'.format(VOLTTRON_CENTRAL_PLATFORM))

        if platform_method == 'install':
            if 'admin' not in session_user['groups']:
                return jsonrpc.json_error(
                    id, UNAUTHORIZED,
                    "Admin access is required to install agents")

        if platform_method == 'list_agents':
            _log.debug('Callling list_agents')
            agents = self._registry.get_agent_list(platform_uuid)

            if agents is None:
                _log.warn('No agents found for platform_uuid {}'.format(
                    platform_uuid
                ))
                agents = []

            for a in agents:
                if 'admin' not in session_user['groups']:
                    a['permissions'] = {
                        'can_stop': False,
                        'can_start': False,
                        'can_restart': False,
                        'can_remove': False
                    }
                else:
                    _log.debug('Permissionse for {} are {}'
                               .format(a['name'], a['permissions']))
            return agents
        else:
            try:
                return cn.agent.vip.rpc.call(
                    VOLTTRON_CENTRAL_PLATFORM, 'route_request', id,
                    platform_method,
                    params).get(timeout=30)
            except (Unreachable, gevent.Timeout) as e:
                del self._pa_agents[platform_uuid]
                return err("Can't route to platform",
                           UNAVAILABLE_PLATFORM)
Пример #32
0
    def store_agent_config(self, session_user, params):
        required = ('agent_identity', 'config_name', 'raw_contents')
        message_id = params.pop('message_id')
        errors = []
        for r in required:
            if r not in params:
                errors.append('Missing {}'.format(r))
        config_type = params.get('config_type', None)
        if config_type:
            if config_type not in ('raw', 'json', 'csv'):
                errors.append('Invalid config_type parameter')

        if errors:
            return jsonrpc.json_error(message_id, INVALID_PARAMS,
                                      "\n".join(errors))
        try:
            self._log.debug("Calling store_agent_config on external platform.")
            self.call("store_agent_config", **params)
        except Exception as e:
            self._log.error(str(e))
            return jsonrpc.json_error(message_id, INTERNAL_ERROR, str(e))
        config_name = params.get("config_name")
        agent_identity = params.get("agent_identity")
        if config_name.startswith("devices"):
            # Since we start with devices, we assume that we are attempting
            # to save a master driver config file.
            rawdict = jsonapi.loads(params['raw_contents'])

            # if this is not a bacnet device_type then we cannot do anything
            # more than save and retrieve it from the store.
            driver_type = rawdict.get('driver_type', None)
            if driver_type is None or driver_type not in ('bacnet', 'modbus'):
                return jsonrpc.json_result(message_id, "SUCCESS")

            # Registry config starts with config://
            registry_config = rawdict['registry_config'][len('config://'):]

            try:
                self._log.debug("Retrieving registry_config for new device.")
                point_config = self.call("get_agent_config",
                                         agent_identity,
                                         registry_config,
                                         raw=False)
            except Exception as e:
                self._log.error(str(e))
                return jsonrpc.json_error(
                    message_id, INTERNAL_ERROR,
                    "Couldn't retrieve registry_config "
                    "from connection.")
            else:
                new_device = dict(
                    device_address=rawdict['driver_config']['device_address'],
                    device_id=rawdict['driver_config']['device_id'],
                    points=[],
                    path=config_name,
                    health=Status.build(UNKNOWN_STATUS,
                                        context="Unpublished").as_dict())
                points = [p['Volttron Point Name'] for p in point_config]
                new_device['points'] = points
                self._vc.send_management_message("NEW_DEVICE", new_device)

            status = Status.build(UNKNOWN_STATUS,
                                  context="Not published since update")
            device_config_name = params.get('config_name')
            device_no_prefix = device_config_name[len('devices/'):]
            the_device = self._current_devices.get(device_no_prefix, {})

            if not the_device:
                self._current_devices[device_no_prefix] = dict(
                    last_publish_utc=None,
                    health=status.as_dict(),
                    points=points)
            else:
                self._current_devices[device_no_prefix]['points'] = points

            return jsonrpc.json_result(message_id, "SUCCESS")
Пример #33
0
    def route_request(self, id, method, params):
        _log.debug('platform agent routing request: {}, {}'.format(id, method))

        # First handle the elements that are going to this platform
        if method == 'list_agents':
            result = self.list_agents()
        elif method == 'set_setting':
            result = self.set_setting(**params)
        elif method == 'get_setting':
            result = self.get_setting(**params)
        elif method == 'get_devices':
            result = self.get_devices()
        elif method == 'status_agents':
            _log.debug('Doing status agents')
            result = {
                'result': [{
                    'name': a[1],
                    'uuid': a[0],
                    'process_id': a[2][0],
                    'return_code': a[2][1]
                } for a in self.vip.rpc.call('control', method).get()]
            }

        elif method in ('agent_status', 'start_agent', 'stop_agent',
                        'remove_agent'):
            _log.debug('We are trying to exectute method {}'.format(method))
            if isinstance(params, list) and len(params) != 1 or \
                            isinstance(params,
                                       dict) and 'uuid' not in params.keys():
                result = jsonrpc.json_error(ident=id, code=INVALID_PARAMS)
            else:
                if isinstance(params, list):
                    uuid = params[0]
                elif isinstance(params, str):
                    uuid = params
                else:
                    uuid = params['uuid']

                status = self.vip.rpc.call('control', method, uuid).get()
                if method == 'stop_agent' or status == None:
                    # Note we recurse here to get the agent status.
                    result = self.route_request(id, 'agent_status', uuid)
                else:
                    result = {
                        'process_id': status[0],
                        'return_code': status[1]
                    }
        elif method in ('install'):

            if not 'files' in params:
                result = jsonrpc.json_error(ident=id, code=INVALID_PARAMS)
            else:
                result = self._install_agents(params['files'])

        else:

            fields = method.split('.')

            if fields[0] == 'historian':
                if 'platform.historian' in self.vip.peerlist().get(timeout=30):
                    agent_method = fields[1]
                    result = self.vip.rpc.call('platform.historian',
                                               agent_method,
                                               **params).get(timeout=45)
                else:
                    result = jsonrpc.json_error(id, INVALID_PARAMS,
                                                'historian unavailable')
            else:
                agent_uuid = fields[2]
                agent_method = '.'.join(fields[3:])
                _log.debug("Calling method {} on agent {}".format(
                    agent_method, agent_uuid))
                _log.debug("Params is: {}".format(params))

                result = self.vip.rpc.call(agent_uuid, agent_method,
                                           **params).get()

        if isinstance(result, dict):
            if 'result' in result:
                return result['result']
            elif 'code' in result:
                return result['code']

        return result
Пример #34
0
    def route_request(self, id, method, params):
        _log.debug('platform agent routing request: {}, {}'.format(id, method))

        _log.debug(params)

        method_map = {
            'list_agents': self.list_agents,
            'get_devices': self.get_devices,
        }

        # First handle the elements that are going to this platform
        if method in method_map:
            result = method_map[method]()
        elif method == 'set_setting':
            result = self.set_setting(**params)
        elif method == 'get_setting':
            result = self.get_setting(**params)
        elif method == 'get_devices':
            result = self.get_devices()
        elif method == 'status_agents':
            _log.debug('Doing status agents')
            result = {
                'result': [{
                    'name': a[1],
                    'uuid': a[0],
                    'process_id': a[2][0],
                    'return_code': a[2][1]
                } for a in self.vip.rpc.call(CONTROL, method).get(timeout=5)]
            }

        elif method in ('agent_status', 'start_agent', 'stop_agent',
                        'remove_agent', 'restart_agent'):
            _log.debug('We are trying to exectute method {}'.format(method))
            if isinstance(params, list) and len(params) != 1 or \
                            isinstance(params,
                                       dict) and 'uuid' not in params.keys():
                result = jsonrpc.json_error(ident=id, code=INVALID_PARAMS)
            else:
                if isinstance(params, list):
                    uuid = params[0]
                elif isinstance(params, str):
                    uuid = params
                else:
                    uuid = params['uuid']
                _log.debug('calling control with method: {} uuid: {}'.format(
                    method, uuid))
                status = self.vip.rpc.call(CONTROL, method,
                                           uuid).get(timeout=5)
                if method == 'stop_agent' or status is None:
                    # Note we recurse here to get the agent status.
                    result = self.route_request(id, 'agent_status', uuid)
                else:
                    result = {
                        'process_id': status[0],
                        'return_code': status[1]
                    }
        elif method in ('install', ):
            _log.debug("Attempting install!")
            if 'files' not in params:
                result = jsonrpc.json_error(
                    ident=id,
                    code=INVALID_PARAMS,
                    message="Invalid parameter missing 'files'")
            else:
                # TODD: This should be only a single file at a time for installs
                fileargs = params.get('files')[0]
                result = self._install_agent(fileargs)

        else:

            fields = method.split('.')

            if fields[0] == 'historian':
                if 'platform.historian' in self.vip.peerlist().get(timeout=30):
                    agent_method = fields[1]
                    result = self.vip.rpc.call('platform.historian',
                                               agent_method,
                                               **params).get(timeout=45)
                else:
                    result = jsonrpc.json_error(id, INVALID_PARAMS,
                                                'historian unavailable')
            else:
                agent_uuid = fields[2]
                agent_method = '.'.join(fields[3:])
                _log.debug("Calling method {} on agent {}".format(
                    agent_method, agent_uuid))
                _log.debug("Params is: {}".format(params))
                if agent_method in ('start_bacnet_scan',
                                    'publish_bacnet_props'):
                    identity = params.pop("proxy_identity")
                    if agent_method == 'start_bacnet_scan':
                        result = self.start_bacnet_scan(identity, **params)
                    elif agent_method == 'publish_bacnet_props':
                        result = self.publish_bacnet_props(identity, **params)
                else:
                    # find the identity of the agent so we can call it by name.
                    identity = self.vip.rpc.call(CONTROL, 'agent_vip_identity',
                                                 agent_uuid).get(timeout=5)
                    if params:
                        if isinstance(params, list):
                            result = self.vip.rpc.call(identity, agent_method,
                                                       *params).get(timeout=30)
                        else:
                            result = self.vip.rpc.call(
                                identity, agent_method,
                                **params).get(timeout=30)
                    else:
                        result = self.vip.rpc.call(
                            identity, agent_method).get(timeout=30)
                # find the identity of the agent so we can call it by name.
                identity = self.vip.rpc.call(CONTROL, 'agent_vip_identity',
                                             agent_uuid).get(timeout=5)
                if params:
                    if isinstance(params, list):
                        result = self.vip.rpc.call(identity, agent_method,
                                                   *params).get(timeout=30)
                    else:
                        result = self.vip.rpc.call(identity, agent_method,
                                                   **params).get(timeout=30)
                else:
                    result = self.vip.rpc.call(identity,
                                               agent_method).get(timeout=30)

        if isinstance(result, dict):
            if 'result' in result:
                return result['result']
            elif 'code' in result:
                return result['code']
        elif result is None:
            return
        return result
Пример #35
0
    def jsonrpc(self, env, data):
        """ The main entry point for ^jsonrpc data

        This method will only accept rpcdata.  The first time this method
        is called, per session, it must be using get_authorization.  That
        will return a session token that must be included in every
        subsequent request.  The session is tied to the ip address
        of the caller.

        :param object env: Environment dictionary for the request.
        :param object data: The JSON-RPC 2.0 method to call.
        :return object: An JSON-RPC 2.0 response.
        """
        if env['REQUEST_METHOD'].upper() != 'POST':
            return jsonrpc.json_error(
                'NA', INVALID_REQUEST,
                'Invalid request method, only POST allowed')

        try:
            rpcdata = self._to_jsonrpc_obj(data)
            _log.info('rpc method: {}'.format(rpcdata.method))

            if rpcdata.method == 'get_authorization':

                # Authentication url
                # This does not need to be local, however for now we are going to
                # make it so assuming only one level of authentication.
                auth_url = "{url_scheme}://{HTTP_HOST}/authenticate".format(
                    url_scheme=env['wsgi.url_scheme'],
                    HTTP_HOST=env['HTTP_HOST'])
                user = rpcdata.params['username']
                args = {
                    'username': rpcdata.params['username'],
                    'password': rpcdata.params['password'],
                    'ip': env['REMOTE_ADDR']
                }
                resp = requests.post(auth_url, json=args, verify=False)

                if resp.ok and resp.text:
                    claims = self.vip.web.get_user_claims(resp.text)
                    # Because the web-user.json has the groups under a key and the
                    # groups is just passed into the session we need to make sure
                    # we pass in the proper thing to the _add_sesion function.
                    assert 'groups' in claims
                    authentication_token = resp.text
                    sess = authentication_token
                    self._authenticated_sessions._add_session(
                        user=user,
                        groups=claims['groups'],
                        token=authentication_token,
                        ip=env['REMOTE_ADDR'])
                else:
                    sess = self._authenticated_sessions.authenticate(**args)

                if not sess:
                    _log.info('Invalid username/password for {}'.format(
                        rpcdata.params['username']))
                    return jsonrpc.json_error(
                        rpcdata.id, UNAUTHORIZED,
                        "Invalid username/password specified.")
                _log.info('Session created for {}'.format(
                    rpcdata.params['username']))
                self.vip.web.register_websocket(
                    "/vc/ws/{}/management".format(sess),
                    self.open_authenticate_ws_endpoint, self._ws_closed,
                    self._received_data)
                _log.info('Session created for {}'.format(
                    rpcdata.params['username']))

                gevent.sleep(1)
                return jsonrpc.json_result(rpcdata.id, sess)

            token = rpcdata.authorization
            ip = env['REMOTE_ADDR']
            _log.debug('REMOTE_ADDR: {}'.format(ip))
            session_user = self._authenticated_sessions.check_session(
                token, ip)
            _log.debug('SESSION_USER IS: {}'.format(session_user))
            if not session_user:
                _log.debug("Session Check Failed for Token: {}".format(token))
                return jsonrpc.json_error(rpcdata.id, UNAUTHORIZED,
                                          "Invalid authentication token")
            _log.debug('RPC METHOD IS: {}'.format(rpcdata.method))

            # Route any other method that isn't
            result_or_error = self._route_request(session_user, rpcdata.id,
                                                  rpcdata.method,
                                                  rpcdata.params)

        except AssertionError:
            return jsonrpc.json_error('NA', INVALID_REQUEST,
                                      'Invalid rpc data {}'.format(data))
        except Unreachable:
            return jsonrpc.json_error(
                rpcdata.id, UNAVAILABLE_PLATFORM,
                "Couldn't reach platform with method {} params: {}".format(
                    rpcdata.method, rpcdata.params))
        except Exception as e:

            return jsonrpc.json_error('NA', UNHANDLED_EXCEPTION, e)

        return self._get_jsonrpc_response(rpcdata.id, result_or_error)