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

Appearance settings

fgouteroux/sshot

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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

No packages published
Morty Proxy This is a proxified and sanitized view of the page, visit original site.