Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

fgouteroux/sshot

Repository files navigation

sshot - SSH Orchestrator Tool

Go Report Card License Release

Orchestrate SSH operations with ease

sshot (SSH Orchestrator Tool) is a lightweight, Ansible-inspired tool for sysadmins who need straightforward SSH orchestration without Python dependency headaches. Built with Go for portability and simplicity, it uses familiar YAML playbooks—perfect for daily administrative tasks.

Why sshot?

If you're a sysadmin who loves Ansible's YAML approach but sometimes finds Python dependencies challenging, sshot might be for you.

sshot is NOT a replacement for Ansible - it doesn't try to be. Ansible is a comprehensive automation platform with an extensive ecosystem. sshot is simply a focused helper tool for sysadmins who need straightforward SSH orchestration.

Key Benefits

  • 🪶 No Python headaches - Single Go binary, no dependencies, no virtualenvs, no pip issues
  • 🎯 Sysadmin-focused - Built for daily SSH tasks, not enterprise-wide automation
  • Portable - Copy one binary, run anywhere (Linux, macOS, even on edge devices)
  • 📝 Familiar syntax - If you know Ansible YAML, you already know sshot
  • 🚀 Fast - Go's performance for quick task execution

Installation

From Source

go install github.com/fgouteroux/sshot@latest

From Release

# Download from GitHub releases
wget https://github.com/fgouteroux/sshot/releases/latest/download/sshot_Linux_x86_64.tar.gz
tar xzf sshot_Linux_x86_64.tar.gz
sudo mv sshot /usr/local/bin/

Build Locally

git clone https://github.com/fgouteroux/sshot.git
cd sshot
go build -o sshot

Quick Start

1. Create an inventory file

# inventory.yml
ssh_config:
 user: admin
 key_file: ~/.ssh/id_rsa
 port: 22
hosts:
 - name: web1
 address: 192.168.1.10
 - name: web2
 address: 192.168.1.11

2. Create a playbook

# playbook.yml
name: Deploy Application
tasks:
 - name: Update system
 command: apt-get update
 sudo: true
 
 - name: Install nginx
 command: apt-get install -y nginx
 sudo: true
 
 - name: Start nginx
 command: systemctl start nginx
 sudo: true

3. Run it

sshot -i inventory.yml playbook.yml

Usage

sshot [options] <playbook.yml>

Options

  • -i, --inventory <file> - Inventory file (supports separate files)
  • -n, --dry-run - Run in dry-run mode (simulate without executing)
  • -v, --verbose - Enable verbose logging
  • --progress - Show progress indicators
  • -f, --full-output - Show complete command output without truncation
  • --no-color - Disable colored output

Examples

Basic execution:

sshot playbook.yml

With separate inventory:

sshot -i inventory.yml playbook.yml

Dry-run mode:

sshot -n -v -i inventory.yml playbook.yml

With progress indicators:

sshot --progress -i inventory.yml playbook.yml

With full output:

sshot -f -i inventory.yml playbook.yml

Verbose with full output:

sshot -v -f playbook.yml

Usage Examples

Example 1: Default behavior (truncated output)

$ sshot playbook.yml
┌─ Host: server1 (192.168.1.10)
│
│ [1/1] Check logs
 ✓ Success
 Output (showing first 5 and last 5 lines of 100 total):
 Line 1
 Line 2
 Line 3
 Line 4
 Line 5
 ... (90 lines omitted) ...
 Line 96
 Line 97
 Line 98
 Line 99
 Line 100

Example 2: With --full-output flag

$ sshot --full-output playbook.yml
# or
$ sshot -f playbook.yml
┌─ Host: server1 (192.168.1.10)
│
│ [1/1] Check logs
 ✓ Success
 Output: (100 lines)
 Line 1
 Line 2
 Line 3
 ...
 Line 100

Example 3: Combined with other options

# Dry-run with full output
$ sshot -n -f playbook.yml
# Verbose with full output
$ sshot -v -f playbook.yml
# Full output without color
$ sshot -f --no-color playbook.yml

Features

Ansible-Inspired, Sysadmin-Focused

sshot borrows Ansible's excellent design philosophy but focuses specifically on sysadmin needs:

  • ✅ YAML playbooks for configuration
  • ✅ Inventory files for host management
  • ✅ Task execution with dependencies
  • ✅ Conditional task execution (when)
  • ✅ Variable substitution
  • ✅ Parallel and sequential execution
  • ✅ Group-based orchestration

Core Capabilities

1. Flexible Execution Modes

  • Parallel execution across multiple hosts
  • Sequential execution with ordered groups
  • Group dependencies for complex workflows

2. Task Types

  • Commands - Execute shell commands
  • Scripts - Upload and run local scripts
  • File copy - Copy files with permissions
  • Wait conditions - Wait for ports, services, files, HTTP endpoints

3. Advanced Features

  • Retries - Automatic retry with configurable delays
  • Timeouts - Task-level timeout control
  • Conditionals - Execute tasks based on variables
  • Dependencies - Define task execution order
  • Variable substitution - Use variables in commands and files
  • Register output - Capture and reuse task output

4. Authentication

  • SSH key-based authentication
  • Password authentication
  • SSH agent support
  • Per-host authentication override

Configuration

Inventory Structure

Global SSH Configuration

ssh_config:
 user: admin
 key_file: ~/.ssh/id_rsa
 port: 22
 strict_host_key_check: true # Set to false to disable verification

Hosts

hosts:
 - name: server1
 address: 192.168.1.10
 user: deploy # Override global user
 vars:
 env: production
 app_port: "8080"

Groups with Dependencies

groups:
 - name: databases
 order: 1
 parallel: false
 hosts:
 - name: db1
 address: 192.168.1.20
 vars:
 role: master
 - name: db2
 address: 192.168.1.21
 vars:
 role: slave
 
 - name: webservers
 order: 2
 parallel: true
 depends_on: [databases] # Wait for databases group
 hosts:
 - name: web1
 address: 192.168.1.30
 - name: web2
 address: 192.168.1.31

Playbook Structure

{% raw %}

name: Multi-tier Deployment
parallel: false # Global parallel setting
tasks:
 - name: Check connectivity
 command: echo "Connected to {{ .hostname }}"
 
 - name: Install packages
 command: apt-get install -y nginx mysql-client
 sudo: true
 retries: 3
 retry_delay: 5
 
 - name: Copy configuration
 copy:
 src: ./nginx.conf
 dest: /etc/nginx/nginx.conf
 mode: "0644"
 sudo: true
 
 - name: Start service
 command: systemctl start nginx
 sudo: true
 wait_for: port:80
 
 - name: Health check
 command: curl -f http://localhost/health
 retries: 5
 retry_delay: 2
 until_success: true
 
 - name: Production only task
 command: deploy-prod.sh
 when: "{{ .env }} == production"
 register: deploy_output

{% endraw %}

Task Reference

Basic Task

- name: Execute command
 command: echo "hello world"

Task with Sudo

- name: Install package
 command: apt-get install -y nginx
 sudo: true

Task with Variables

{% raw %}

- name: Deploy application
 command: deploy {{ .app_name }} --port {{ .app_port }}

{% endraw %}

Task with Conditionals

{% raw %}

- name: Ubuntu specific
 command: apt-get update
 when: "{{ .os }} == ubuntu"

{% endraw %}

Task with Retries

- name: Download artifact
 command: wget https://example.com/artifact.tar.gz
 retries: 3
 retry_delay: 5

Task with Dependencies

- name: Build application
 command: make build
 depends_on: [Install Dependencies, Clone Repository]

Task with Allowed Exit Codes

- name: Search for pattern
 command: grep "error" /var/log/app.log
 allowed_exit_codes: [0, 1] # 0 = found, 1 = not found
 register: search_result
- name: Compare files
 command: diff file1.txt file2.txt
 allowed_exit_codes: [0, 1] # 0 = identical, 1 = different
- name: Custom script
 command: ./check_status.sh
 allowed_exit_codes: [0, 2, 3] # Multiple allowed codes

This is useful for commands like grep, diff, or custom scripts where non-zero exit codes have specific meanings that should still be considered successful. If a command exits with a code in the allowed list, it will be treated as successful and won't trigger retries or fail the playbook.

File Copy Task

- name: Copy config
 copy:
 src: local/config.yml
 dest: /etc/app/config.yml
 mode: "0644"
 sudo: true

Script Execution

- name: Run setup script
 script: ./scripts/setup.sh
 sudo: true

Wait for Condition

- name: Wait for database
 wait_for: port:5432
- name: Wait for service
 wait_for: service:postgresql
- name: Wait for file
 wait_for: file:/var/run/app.pid
- name: Wait for HTTP
 wait_for: http://localhost:8080/health

Local Action, Delegation, and Run Once

Local Action

- name: Run locally
 local_action: echo "Running on the local machine"

Local actions run commands on the local machine rather than on the remote hosts.

Delegate To

- name: Run on specific host
 command: echo "Running delegated command"
 delegate_to: db-server
 
- name: Run locally with delegation
 command: echo "Running locally via delegation"
 delegate_to: localhost

The delegate_to option allows running a command on a specific host, rather than all hosts in the inventory or group.

Run Once

- name: Database schema update
 command: ./update-schema.sh
 run_once: true
 
- name: Local notification
 local_action: ./send-notification.sh "Deployment started"
 run_once: true

The run_once flag ensures a task is only executed once, even if multiple hosts are targeted. This is particularly useful for database migrations, notifications, or other actions that should happen only once during a playbook run.

These features can be combined:

- name: Initialize application
 command: ./init-app.sh
 delegate_to: app-primary
 run_once: true

Examples

Simple Deployment

# inventory.yml
ssh_config:
 user: deploy
 key_file: ~/.ssh/deploy_key
hosts:
 - name: prod-server
 address: production.example.com
# playbook.yml
name: Deploy Website
tasks:
 - name: Pull latest code
 command: git pull origin main
 
 - name: Install dependencies
 command: npm install
 
 - name: Build application
 command: npm run build
 
 - name: Restart service
 command: systemctl restart app
 sudo: true

Multi-tier Application

{% raw %}

# inventory.yml
ssh_config:
 user: admin
 key_file: ~/.ssh/id_rsa
groups:
 - name: database
 order: 1
 hosts:
 - name: db-primary
 address: 10.0.1.10
 vars:
 role: primary
 - name: db-replica
 address: 10.0.1.11
 vars:
 role: replica
 
 - name: application
 order: 2
 parallel: true
 depends_on: [database]
 hosts:
 - name: app1
 address: 10.0.2.10
 - name: app2
 address: 10.0.2.11
 
 - name: loadbalancer
 order: 3
 depends_on: [application]
 hosts:
 - name: lb1
 address: 10.0.3.10
# playbook.yml
name: Deploy Multi-tier Application
tasks:
 - name: Stop application
 command: systemctl stop myapp
 ignore_error: true
 
 - name: Backup database
 command: pg_dump mydb > /backup/mydb.sql
 when: "{{ .role }} == primary"
 sudo: true
 
 - name: Update application
 command: deploy.sh --version {{ .version }}
 vars:
 version: "2.0.0"
 retries: 3
 
 - name: Start application
 command: systemctl start myapp
 sudo: true
 
 - name: Wait for service
 wait_for: port:8080
 
 - name: Health check
 command: curl -f http://localhost:8080/health
 retries: 10
 retry_delay: 3

{% endraw %}

Troubleshooting

Host Key Verification Failed

Error:

host key verification failed for hostname: knownhosts: key is unknown
To add this host, run: ssh-keyscan -H hostname >> /home/user/.ssh/known_hosts

Solution 1: Add the host key

ssh-keyscan -H hostname >> ~/.ssh/known_hosts

Solution 2: Disable strict checking (not recommended for production)

ssh_config:
 strict_host_key_check: false

Authentication Failed

Check:

  1. SSH key permissions: chmod 600 ~/.ssh/id_rsa
  2. SSH key path is correct in inventory
  3. User has SSH access to the host
  4. Try manual SSH: ssh user@host

Connection Timeout

Solutions:

  • Check host is reachable: ping hostname
  • Verify port is correct (default: 22)
  • Check firewall rules
  • Verify SSH service is running: systemctl status sshd

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Setup

# Clone repository
git clone https://github.com/fgouteroux/sshot.git
cd sshot
# Install dependencies
go mod download
# Run tests
make test
# Build
make build
# Run linter
make lint

Running Tests

# All tests
go test -v ./...
# With coverage
go test -cover ./...
# Specific package
go test -v ./pkg/config/...

License

Apache License 2.0 - see LICENSE file for details.

Author

François Gouteroux

Acknowledgments


sshot - SSH Orchestrator Tool | GitHub | Documentation

About

Lightweight ansible in GO.

Topics

Resources

License

Stars

Watchers

Forks

Packages

Contributors

AltStyle によって変換されたページ (->オリジナル) /