YAMC is a shell-based tool for remote machine configuration and management, allowing you to execute installation scripts, configuration tasks, and maintenance operations on remote machines through SSH.
YAMC enables you to:
- Install and configure software packages on remote machines
- Run maintenance tasks on remote machines
- Maintain a library of reusable configuration modules
- Execute local preparation tasks before remote execution
- Share local module files with the remote machine seamlessly
YAMC follows these key principles:
- Initial setup is usually done once per target host with the
initcommand (recommended) - Each configuration task is organized as a module in its own directory
- Modules can contain both local and remote execution scripts
- Local directory contents are shared with the remote system via SSH and SSHFS
- Environment variables pass data between local and remote execution phases
# Initialize a host first (recommended once per host)
yamc init -h remote_hostname [-u username] [-v] [-t timeout]
# Run modules
yamc -h remote_hostname [-u username] [-e var=value] [-v] [-t timeout] module [subfunction] [args...]
init: Initialization command that sets up SSH key authentication and ensures SSHFS exists on the remote host-h remote_hostname: Required. Specifies the target machine to configure-u username: Optional. SSH username (defaults to current user)-e var=value: Optional. Environment variables to pass to scripts (can be used multiple times)-v: Optional. Enable verbose output for debugging-t timeout: Optional. SSH connection timeout in seconds (default: 30)module: Required. The name of the module directory containing the scriptssubfunction: Optional. The script to run (defaults to "setup")args: Optional. Additional arguments passed to the module scripts
# Initialize a new machine for YAMC (required once per host)
# Must use a regular user account with sudo privileges
yamc init -h new_machine_hostname -u regular_user
# Configure DHCP server
yamc -h new_machine_hostname dhcp
# Edit DHCP configuration
yamc -h new_machine_hostname dhcp edit
# Set timezone with argument as root user
yamc -h new_server -u root timezone America/New_YorkWhen you run yamc init -h hostname -u username:
- YAMC checks for a local SSH key, generating one if needed
- The SSH key is installed on the remote machine using ssh-copy-id for the specified user
- SSHFS is installed on the remote machine if not already present
- Host preferences are saved to
~/.yamc/hostname.env
Important: The initialization must be run with the regular, unprivileged user account on the remote machine. This user must have sudo privileges to install packages. This initialization only needs to be run once per host, setting up passwordless SSH authentication and all required dependencies.
When you run yamc -h hostname module:
- YAMC ensures local prerequisites are available (e.g., local
sftp-serverpath cached in~/.yamc/yamc.env) - It optionally loads host preferences from
~/.yamc/hostname.env(if present) - If a
setup.locscript exists, it's executed locally to prepare resources - A temporary directory is created for data exchange
- Variables
MOD_DIRandMOD_TMPare created to reference paths for both machines - The local module directory is shared with the remote machine using an SFTP server and SSHFS in slave mode
- The remote script is executed on the target machine, with access to local files
- After execution, the temporary resources are cleaned up
Note: yamc init is still the recommended onboarding step. However, if the host is already reachable via SSH and has sshfs installed, modules can run even if ~/.yamc/hostname.env does not exist on the current local machine.
YAMC uses a named pipe and SFTP server approach to share local directories with the remote system:
reverse_sshfs_mount() {
local localpath="$1"
local remotehost="$2"
local remotepath="$3"
local fifo="/tmp/revsshfs-$$"
mkfifo -m600 "$fifo"
trap 'ssh "$remotehost" fusermount -u "$remotepath"; rm -f "$fifo"' EXIT INT TERM
< "$fifo" "$SFTP_SERVER" |
ssh "$remotehost" sshfs -o slave ":$localpath" "$remotepath" > "$fifo"
}How this works:
- Creates a named pipe (FIFO) as a communication channel
- Sets up a trap to handle cleanup on exit
- Runs a local SFTP server and connects its input/output to the named pipe
- Connects via SSH to the remote machine and runs SSHFS in slave mode
- SSHFS connects back to the local SFTP server through the SSH connection's standard I/O
Advantages of this approach:
- Uses a single SSH connection for both file sharing and commands
- More efficient than setting up separate tunnels
- Secure (uses SSH encryption)
- Real-time access to local files without separate file transfers
Modules are organized as directories containing:
setup: The main script executed on the remote machine (default)setup.loc: Optional script executed locally before SSH connection- Any other files or subdirectories used by the scripts
- Additional subfunction scripts with corresponding
.locfiles
When a subfunction is specified, YAMC will look for and execute scripts named after that subfunction instead of "setup". For example, if you run yamc -h host module edit, YAMC will execute:
module/edit.loclocally (if it exists)module/editon the remote machine
Environment variables created in the .loc scripts will be available to the remote scripts.
Every module can ship a help.loc script that prints site-aware usage. It runs locally — there is no SSH, no -h flag is required, and it has read-only access to the module's yamc.local/<module>/ resources via RES_DIR.
yamc help # aggregate over yamc.local/<module>/ with installed modules
yamc help dhcp # one module
yamc dhcp help # symmetric form, identical to 'yamc help dhcp'If <module>/help.loc is missing, YAMC prints a generic fallback (paths, README pointer, discovered subcommand names).
help.loc contract:
- Local only. Sourced in a subshell; treat it as read-only. Do not modify the system.
- Inputs:
MOD_DIR,RES_DIR,RES_BASE,YAMC_MODULE,INSTALL_DIR,RESOURCES_ROOT. - Output: human-readable text on stdout. Keep it short and actionable:
- Site facts (e.g., server names from
cluster.conf) - One-line subcommand summaries
- Suggested
yamc -h <host> <module> <subcommand>invocations
- Site facts (e.g., server names from
- Do not dump full configs (no
cat hosts.conf). - Gracefully degrade when
RES_DIRis empty or expected files are missing.
Run yamc help <module> after editing help.loc to verify output.
These environment variables are available to all scripts:
MOD_DIR: Path to the module directory (different on local vs. remote)MOD_TMP: Path to the temporary directory for file exchangessh_user: The username used for SSH connectiontgt_host: The target hostname being configured- Any variables defined in the
.locscript - Any variables passed through the command line with
-e var=value
Current implemented modules:
test: Test module for verifying YAMC functionality (see Testing section below)timezone: Sets the machine's timezonelocale: Sets the machine's localepref: Installs user preferences like .bash_profile and .inputrcmounter: Installs an NFS mount script and desktop shortcut
Planned modules:
upgrade: Upgrade all packagesdhcp: Configure the machine as a DHCP serverbind9: Configure the machine as a DNS servermailserver: Set up a mail server
YAMC can be installed system-wide or run directly from the source directory.
To install YAMC system-wide with default settings:
git clone https://github.com/gotchoices/yamc.git
cd yamc
sudo ./install.shThis will:
- Install core scripts to
/usr/local/lib/yamc/ - Create symlinks in
/usr/local/bin/foryamcandyamcity - Install modules to
/usr/local/lib/yamc/modules/ - Install documentation to
/usr/local/share/doc/yamc/
You can customize the installation location:
# Install to a different prefix
sudo ./install.sh --prefix /opt
# Install to specific directories
sudo ./install.sh --lib-dir ~/lib/yamc --bin-dir ~/binTo uninstall YAMC:
sudo ./install.sh --uninstallYou can also run YAMC directly from the source directory:
git clone https://github.com/gotchoices/yamc.git
cd yamc
./yamc -h hostname init
./yamc -h hostname moduleYAMC searches for modules in multiple locations (in order):
- Absolute path (if module name is a full path)
- Relative to current directory
- User's personal modules (
$HOME/.yamc/modules/) - System-wide custom modules (
/etc/yamc/modules/) - Installed modules directory (e.g.,
/usr/local/lib/yamc/modules/)
To create and use your own modules:
# Create a user module directory
mkdir -p ~/.yamc/modules/mymodule
# Create the required setup script
touch ~/.yamc/modules/mymodule/setup
chmod +x ~/.yamc/modules/mymodule/setup
# Use the module
yamc -h hostname mymodule- Bash shell environment
- SSH client on the local machine
- SSH server on the remote machine
- SSHFS package on the remote machine (will be auto-installed during init)
- SFTP server on the local machine (typically included with OpenSSH)
Currently targeted for Ubuntu systems. Future versions may support additional distributions with different package managers.
- The initialization process is only run once per target host
- Host preferences are cached in
~/.yamc/hostname.env(optional), and local machine cache is in~/.yamc/yamc.env - Error checking has been implemented for SSH connections and command execution
- The script uses temporary directories that are cleaned up after execution
- A timeout mechanism prevents hung connections
- Interactive scripts are supported through SSH's terminal allocation
YAMC includes a test module to verify functionality. To use it:
# Initialize the host if needed
yamc init -h your_remote_host -u <sudo_user>
# Basic functionality test
yamc -h your_remote_host test
# Test argument passing
yamc -h your_remote_host test args arg1 arg2 "argument 3"
# Test environment variable passing
yamc -h your_remote_host -e test_var1=hello -e test_var2="world" test env
# Verbose mode for debugging
yamc -h your_remote_host -v testThe test module verifies:
- SSH connectivity
- SSHFS file sharing
- Environment variable passing
- Command-line argument passing
- Local and remote script execution
YAMC includes a companion script called yamcity that allows you to automate the execution of multiple YAMC modules in sequence. This is useful for setting up complete machine configurations through a single profile file.
- Create a profile file with module commands (one per line)
- Run yamcity with the hostname and profile file
- The script executes each command in sequence, applying the hostname to all of them
- Profiles can include other profiles for modular composition
- Comprehensive logs are saved for each command and a summary is provided
# Basic usage
./yamcity -h hostname profile_file
# With default username (used when line doesn't specify -u)
./yamcity -h hostname -u username profile_file
# With verbose output
./yamcity -h hostname -v profile_file
# Continue execution after errors
./yamcity -h hostname profile_file trueProfile files use a module-first syntax - the module name comes first, followed by arguments and options:
# Comments start with a hash
# Simple module (no arguments or options)
timezone
# Module with argument
packages base
# Module with argument and user option
packages desktop -u root
# Module with multiple options
bind9 -u root -p master -v
# Include another profile (path must exist as a file)
profiles/base
./common-setup
Key points:
- Module name is always the first word
- Options (
-u,-p,-e,-v,-t) can appear anywhere after the module - Options are automatically reordered before passing to yamc
- If a line's first word is a file path, it's included as a nested profile
- Circular includes are detected and prevented
You can build modular profiles by including others:
# profiles/workstation - includes base server + adds desktop
# First, run the base server setup
profiles/server
# Then add desktop-specific modules
packages desktop -u root
xfce -u root
chrome -u root
The yamcity script creates a timestamped log directory for each run:
yamc-logs/YYYYMMDD_HHMMSS/summary.log- Overview of all commands and their statusyamc-logs/YYYYMMDD_HHMMSS/cmd_N.log- Standard output for command Nyamc-logs/YYYYMMDD_HHMMSS/cmd_N.err- Standard error for command N
To automate the setup of a new workstation:
- Create a profile file (
profiles/workstation) with the desired configuration - Run
./yamcity -h new_workstation profiles/workstation - Review the logs to ensure all modules executed successfully
- Support for multiple distribution package managers
- Configuration file for default settings
- Module templates for easier creation of new modules
- Comprehensive logging for troubleshooting
- Module validation checks before execution
- Local caching of installation states for faster execution