# Copyright (c) 2025 Kim Jarvis TPF Software Services S.A. kim.jarvis@tpfsystems.com # This software is licensed under the MIT License. See the LICENSE file for details.#fromreemote.commandimportCommand
[docs]classGetEnt:""" A class to encapsulate the functionality of the Unix getent utility. It allows users to query system databases such as passwd, group, hosts, etc. Attributes: database (str): The name of a getent database supported by the target system (passwd, group, hosts, etc). key (str, optional): Key from which to return values from the specified database, otherwise the full contents are returned. fail_key (bool): If a supplied key is missing this will make the task fail if true. Default is True. service (str, optional): Override all databases with the specified service. Requires system support. split (str, optional): Character used to split the database values into lists/arrays such as ':' or '\\t'. **Examples:** .. code:: python # Get root user info r = yield GetEnt(database="passwd", key="root") # Access the result print(r.facts.getent_passwd) # Get all groups r = yield GetEnt(database="group", split=":") # Access the result print(r.facts.getent_group) # Get http service info, no error if missing r = yield GetEnt(database="services", key="http", fail_key=False) # Access the result print(r.facts.getent_services) Usage: This class is designed to be used in a generator-based workflow where commands are yielded for execution. The results are available in the facts dictionary under getent_<database> keys. Notes: - Not all databases support enumeration, check system documentation for details - Commands are constructed based on the provided parameters - Results are returned in ansible_facts format for consistency with Ansible behavior """def__init__(self,database:str,key:str=None,fail_key:bool=True,service:str=None,split:str=None):self.database=databaseself.key=keyself.fail_key=fail_keyself.service=serviceself.split=splitdef__repr__(self):return(f"GetEnt(database={self.database!r}, "f"key={self.key!r}, "f"fail_key={self.fail_key!r}, "f"service={self.service!r}, "f"split={self.split!r})")defexecute(self):# Build the getent commandcmd_parts=["getent"]ifself.service:cmd_parts.extend(["-s",self.service])cmd_parts.append(self.database)ifself.key:cmd_parts.append(self.key)# Add split handling if specifiedifself.split:# For demonstration purposes, we'll handle splitting in post-processingpasscmd=" ".join(cmd_parts)# Execute the commandr=yieldCommand(cmd,guard=True)# Process the output based on split parameterifr.cp.returncode==0:output_lines=r.cp.stdout.strip().split('\n')# Parse the getent outputparsed_results=[]forlineinoutput_lines:ifline.strip():ifself.split:parsed_results.append(line.split(self.split))else:# Try to auto-detect delimiter based on database typeifself.databasein['passwd','shadow','group']:parsed_results.append(line.split(':'))elifself.databasein['hosts']:parsed_results.append(line.split())else:parsed_results.append([line])# Handle fail_key logicifself.keyandnotparsed_resultsandself.fail_key:raiseException(f"Key '{self.key}' not found in database '{self.database}'")# Store results in factsfact_key=f"getent_{self.database}"r.facts={fact_key:parsed_resultsiflen(parsed_results)>1elseparsed_results[0]ifparsed_resultselse[]}elifself.keyandself.fail_key:raiseException(f"Failed to retrieve key '{self.key}' from database '{self.database}'")r.changed=False