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)))
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)))
def _allow(self, environ, start_response, data=None): _log.info('Allowing new vc instance to connect to server.') jsondata = jsonapi.loads(data) json_validate_request(jsondata) assert jsondata.get('method') == 'allowvc' assert jsondata.get('params') params = jsondata.get('params') if isinstance(params, list): vcpublickey = params[0] else: vcpublickey = params.get('vcpublickey') assert vcpublickey assert len(vcpublickey) == 43 authfile = AuthFile() authentry = AuthEntry(credentials=vcpublickey) try: authfile.add(authentry) except AuthFileEntryAlreadyExists: pass start_response('200 OK', [('Content-Type', 'application/json')]) return jsonapi.dumps(json_result(jsondata['id'], "Added"))
def 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)
def rpcendpoint(self, env, data): """ The default response is application/json so our endpoint returns appropriately with a json based response. """ # Note we aren't using a valid json request to get the following output # id will need to be grabbed from data etc return jsonrpc.json_result("id", "A large number of responses go here")
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)
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)
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)
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)
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")
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")
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)
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)
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)