def rich_table(results: AggregatedResult) -> None: console = Console() for hostname, host_result in results.items(): table = Table(box=MINIMAL_DOUBLE_HEAD) table.add_column(hostname, justify="right", style="cyan", no_wrap=True) table.add_column("result") table.add_column("changed") for r in host_result: text = Text() if r.failed: text.append(f"{r.exception}", style="red") else: text.append(f"{r.result or ''}", style="green") changed = Text() if r.changed: color = "orange3" else: color = "green" changed.append(f"{r.changed}", style=color) table.add_row(r.name, text, changed) console.print(table)
def task_completed(self, task: Task, result: AggregatedResult) -> None: # remove tasks with device's output if self.remove_tasks: for hostname, results in result.items(): if len(results) >= self.len_tasks: for i in range(0, self.len_tasks): _ = results.pop(0) # remove non failed tasks if requested to do so if self.failed_only: for hostname, results in result.items(): good_tests = [] for index, i in enumerate(results): if hasattr(i, "success") and i.success == True: good_tests.append(index) # pop starting from last index to preserve lower indexes for i in reversed(good_tests): _ = results.pop(i)
def calculate_result(dc_runner: DCAwareRunner, results: AggregatedResult) -> Dict[str, List[str]]: report: Dict[str, List[str]] = { "failed": [], "skipped": [], "completed": [h for h, r in results.items() if not r.failed], } for _, failed, skipped, _ in dc_runner.report(): report["failed"].extend([h.name for h in failed]) report["skipped"].extend([h.name for h in skipped]) return report
def nr_result_serialize(result: AggregatedResult): if not isinstance(result, AggregatedResult): raise ValueError("result must be of type AggregatedResult") hosts = {} for host, multires in result.items(): hosts[host] = [] for res in multires: hosts[host].append({ 'name': res.name, 'result': res.result, 'diff': res.diff, 'failed': res.failed }) return hosts
def _map_host_to_nutsresult( self, general_result: AggregatedResult) -> Dict[str, NutsResult]: """ Maps a host's name to its corresponding result, which in turn is wrapped into a NutsResult. Used when a nornir tasks queries properties of a host. :param general_result: The raw result as provided by nornir's executed task :return: Host mapped to a NutsResult """ return { host: self.nuts_result_wrapper(multiresult) for host, multiresult in general_result.items() }
def nr_result_serialize(result: AggregatedResult): if not isinstance(result, AggregatedResult): raise ValueError("result must be of type AggregatedResult") hosts = {} for host, multires in result.items(): hosts[host] = {'failed': False, 'job_tasks': []} for res in multires: hosts[host]['job_tasks'].append({ 'task_name': res.name, 'result': res.result, 'diff': res.diff, 'failed': res.failed }) if res.failed: hosts[host]['failed'] = True return hosts
def _map_host_to_dest_to_nutsresult( self, general_result: AggregatedResult, ) -> Dict[str, Dict[str, NutsResult]]: """ Maps a host's name to its corresponding destination and calls a helper function to further map that destination to a NutsResult. Used when a host-destination pair is tested. :param general_result: The raw result as provided by nornir's executed task :return: The host mapped to its corresponding destination mapped to its NutsResult """ return { host: self._map_dest_to_nutsresult(task_results) for host, task_results in general_result.items() }
def normalize_result(nornir_job_result: AggregatedResult) -> Tuple[Dict, Dict]: """ get_host_data result parser. Returns LLDP and FACTS data dicts with hostname keys. """ global_lldp_data = {} global_facts = {} for device, output in nornir_job_result.items(): if output[0].failed: # Write default data to dicts if the task is failed. # Use host inventory object name as a key. global_lldp_data[device] = {} global_facts[device] = { 'nr_role': nr.inventory.hosts[device].get('role', 'undefined'), 'nr_ip': nr.inventory.hosts[device].get('hostname', 'n/a'), } continue # Use FQDN as unique ID for devices withing the script. device_fqdn = output[1].result['facts']['fqdn'] if not device_fqdn: # If FQDN is not set use hostname. # LLDP TLV follows the same logic. device_fqdn = output[1].result['facts']['hostname'] if not device_fqdn: # Use host inventory object name as a key if # neither FQDN nor hostname are set device_fqdn = device global_facts[device_fqdn] = output[1].result['facts'] global_facts[device_fqdn]['nr_role'] = nr.inventory.hosts[device].get( 'role', 'undefined') global_facts[device_fqdn]['nr_ip'] = nr.inventory.hosts[device].get( 'hostname', 'n/a') global_lldp_data[device_fqdn] = output[1].result[ 'lldp_neighbors_detail'] return global_lldp_data, global_facts
def transform_result( self, general_result: AggregatedResult) -> Dict[str, NutsResult]: return { host: nuts_result_wrapper(result, self._transform_host_results) for host, result in general_result.items() }