Source code for reemote.operations.builtin.assemble

# 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.
#
from reemote.command import Command


[docs] class Assemble: """ A class to encapsulate the functionality of assembling configuration files from fragments. This mimics the behavior of the ansible.builtin.assemble module, which concatenates files from a source directory to create a destination file. Often a particular program will take a single configuration file and does not support a conf.d style structure where it is easy to build up the configuration from multiple sources. Assemble will take a directory of files that can be local or have already been transferred to the system, and concatenate them together to produce a destination file. Files are assembled in string sorting order. Attributes: src (str): An already existing directory full of source files. dest (str): A file to create using the concatenation of all of the source files. delimiter (str): A delimiter to separate the file contents. remote_src (bool): If False, it will search for src at originating/master machine. If True, it will go to the remote/target machine for the src. regexp (str): Assemble files only if the given regular expression matches the filename. ignore_hidden (bool): A boolean that controls if files that start with a . will be included or not. backup (bool): Create a backup file (if true), including the timestamp information. decrypt (bool): This option controls the auto-decryption of source files using vault. validate (str): The validation command to run before copying into place. owner (str): Name of the user that should own the filesystem object. group (str): Name of the group that should own the filesystem object. mode (str): The permissions the resulting filesystem object should have. attributes (str): The attributes the resulting filesystem object should have. seuser (str): The user part of the SELinux filesystem object context. serole (str): The role part of the SELinux filesystem object context. setype (str): The type part of the SELinux filesystem object context. selevel (str): The level part of the SELinux filesystem object context. unsafe_writes (bool): Influence when to use atomic operation to prevent data corruption. guard (bool): If `False` the commands will not be executed. **Examples:** .. code:: python # Assemble from fragments from a directory r = yield Assemble(src="/etc/someapp/fragments", dest="/etc/someapp/someapp.conf") # Insert the provided delimiter between fragments r = yield Assemble( src="/etc/someapp/fragments", dest="/etc/someapp/someapp.conf", delimiter="### START FRAGMENT ###" ) # Assemble a new "sshd_config" file into place, after passing validation with sshd r = yield Assemble( src="/etc/ssh/conf.d/", dest="/etc/ssh/sshd_config", validate="/usr/sbin/sshd -t -f %s" ) Usage: This class is designed to be used in a generator-based workflow where commands are yielded for execution. Notes: - Files are assembled in string sorting order. - The command construction handles various file operations and validation. """ def __init__(self, src: str, dest: str, delimiter: str = None, remote_src: bool = True, regexp: str = None, ignore_hidden: bool = False, backup: bool = False, decrypt: bool = True, validate: str = None, owner: str = None, group: str = None, mode: str = None, attributes: str = None, seuser: str = None, serole: str = None, setype: str = None, selevel: str = None, unsafe_writes: bool = False, guard: bool = True): self.src = src self.dest = dest self.delimiter = delimiter self.remote_src = remote_src self.regexp = regexp self.ignore_hidden = ignore_hidden self.backup = backup self.decrypt = decrypt self.validate = validate self.owner = owner self.group = group self.mode = mode self.attributes = attributes self.seuser = seuser self.serole = serole self.setype = setype self.selevel = selevel self.unsafe_writes = unsafe_writes self.guard = guard def __repr__(self): return (f"Assemble(src={self.src!r}, " f"dest={self.dest!r}, " f"delimiter={self.delimiter!r}, " f"remote_src={self.remote_src!r}, " f"regexp={self.regexp!r}, " f"ignore_hidden={self.ignore_hidden!r}, " f"backup={self.backup!r}, " f"decrypt={self.decrypt!r}, " f"validate={self.validate!r}, " f"owner={self.owner!r}, " f"group={self.group!r}, " f"mode={self.mode!r}, " f"attributes={self.attributes!r}, " f"seuser={self.seuser!r}, " f"serole={self.serole!r}, " f"setype={self.setype!r}, " f"selevel={self.selevel!r}, " f"unsafe_writes={self.unsafe_writes!r}, " f"guard={self.guard!r})") def execute(self): # Build the assemble command cmd_parts = ["assemble"] # Add required parameters cmd_parts.extend([f"src={self.src}", f"dest={self.dest}"]) # Add optional parameters if self.delimiter is not None: cmd_parts.append(f"delimiter={self.delimiter}") if not self.remote_src: cmd_parts.append("remote_src=false") if self.regexp is not None: cmd_parts.append(f"regexp={self.regexp}") if self.ignore_hidden: cmd_parts.append("ignore_hidden=true") if self.backup: cmd_parts.append("backup=true") if not self.decrypt: cmd_parts.append("decrypt=false") if self.validate is not None: cmd_parts.append(f"validate={self.validate}") if self.owner is not None: cmd_parts.append(f"owner={self.owner}") if self.group is not None: cmd_parts.append(f"group={self.group}") if self.mode is not None: cmd_parts.append(f"mode={self.mode}") if self.attributes is not None: cmd_parts.append(f"attributes={self.attributes}") if self.seuser is not None: cmd_parts.append(f"seuser={self.seuser}") if self.serole is not None: cmd_parts.append(f"serole={self.serole}") if self.setype is not None: cmd_parts.append(f"setype={self.setype}") if self.selevel is not None: cmd_parts.append(f"selevel={self.selevel}") if self.unsafe_writes: cmd_parts.append("unsafe_writes=true") cmd = " ".join(cmd_parts) # Execute the command r = yield Command(cmd, guard=self.guard) r.changed = True