async def forward( node_name: Tuple ) -> [wresults.AbstractWazuhResult, exception.WazuhException]: """Forward a request to a node. Parameters ---------- node_name : tuple Node to forward a request to. Returns ------- wresults.AbstractWazuhResult or exception.WazuhException """ node_name, agent_list = node_name if agent_list: self.f_kwargs['agent_id' if 'agent_id' in self.f_kwargs else 'agent_list'] = agent_list if node_name == 'unknown' or node_name == '' or node_name == self.node_info[ 'node']: # The request will be executed locally if the the node to forward to is unknown, empty or the master # itself result = await self.distribute_function() else: if 'tmp_file' in self.f_kwargs: await self.send_tmp_file(node_name) client = self.get_client() try: result = json.loads(await client.execute( b'dapi_forward', "{} {}".format( node_name, json.dumps( self.to_dict(), cls=c_common.WazuhJSONEncoder)).encode(), self.wait_for_complete), object_hook=c_common.as_wazuh_object) except WazuhClusterError as e: if e.code == 3022: result = e else: raise e # Convert a non existing node into a WazuhError exception if isinstance(result, WazuhClusterError) and result.code == 3022: common.rbac.set(self.rbac_permissions) try: await get_nodes_info(client, filter_node=[node_name]) except WazuhError as e: if e.code == 4000: result = e dikt = result.to_dict() # Add node ID to error message dikt['ids'] = {node_name} result = WazuhError.from_dict(dikt) return result if isinstance(result, (wresults.AbstractWazuhResult, exception.WazuhException)) \ else wresults.WazuhResult(result)
async def distribute_function(self) -> [Dict, exception.WazuhException]: """ Distribute an API call. Returns ------- dict or WazuhException Dictionary with API response or WazuhException in case of error. """ try: if 'password' in self.f_kwargs: self.debug_log( f"Receiving parameters { {**self.f_kwargs, 'password': '******'} }" ) elif 'token_nbf_time' in self.f_kwargs: self.logger.debug(f"Decoded token {self.f_kwargs}") else: self.debug_log(f"Receiving parameters {self.f_kwargs}") is_dapi_enabled = self.cluster_items['distributed_api']['enabled'] is_cluster_disabled = self.node == local_client and not check_cluster_status( ) # First case: execute the request locally. # If the distributed api is not enabled # If the cluster is disabled or the request type is local_any # if the request was made in the master node and the request type is local_master # if the request came forwarded from the master node and its type is distributed_master if not is_dapi_enabled or is_cluster_disabled or self.request_type == 'local_any' or \ (self.request_type == 'local_master' and self.node_info['type'] == 'master') or \ (self.request_type == 'distributed_master' and self.from_cluster): response = await self.execute_local_request() # Second case: forward the request # Only the master node will forward a request, and it will only be forwarded if its type is distributed_ # master elif self.request_type == 'distributed_master' and self.node_info[ 'type'] == 'master': response = await self.forward_request() # Last case: execute the request remotely. # A request will only be executed remotely if it was made in a worker node and its type isn't local_any else: response = await self.execute_remote_request() try: response = json.loads(response, object_hook=c_common.as_wazuh_object) \ if isinstance(response, str) else response except json.decoder.JSONDecodeError: response = {'message': response} return response if isinstance(response, (wresults.AbstractWazuhResult, exception.WazuhException)) \ else wresults.WazuhResult(response) except json.decoder.JSONDecodeError: e = exception.WazuhInternalError(3036) e.dapi_errors = self.get_error_info(e) if self.debug: raise self.logger.error(f"{e.message}") return e except exception.WazuhError as e: e.dapi_errors = self.get_error_info(e) return e except exception.WazuhInternalError as e: e.dapi_errors = self.get_error_info(e) if self.debug: raise self.logger.error(f"{e.message}", exc_info=True) return e except Exception as e: if self.debug: raise self.logger.error(f'Unhandled exception: {str(e)}', exc_info=True) return exception.WazuhInternalError( 1000, dapi_errors=self.get_error_info(e))