High-performance SSH and SFTP client for network automation
Project description
Jimiko
A high-performance SSH client for network automation and device management, built with libssh2 and openssl. Inspired by Paramiko and Netmiko. Focused on performance and non-blocking operations.
Features
- Non-blocking SSH operations for high performance
- Support for interactive shell sessions
- Configurable timeouts and interrupt handling
- Cross-platform support (macOS, Linux, Rhel)
- Python 3.6+ compatibility
- Optimized for network device automation
- Support legacy unauthenicated network devices
- Built using libssh2 and OpenSSL for maximum performance
Installation
Building from Source (Prerequisites)
Windows
# Using vcpkg
vcpkg install libssh2:x64-windows openssl:x64-windows
macOS
# Using Homebrew
brew install libssh2 openssl@1.1
Linux (Debian/Ubuntu)
sudo apt-get install libssh2-1-dev libssl-dev
Linux (CentOS/RHEL)
sudo yum install libssh2-devel openssl-devel
Note: For Python 3.10+, OpenSSL 1.1.1 or newer is required. For Python 3.12+, OpenSSL 3.0+ is required.
Installing the Package
# No prerequisites required
pip install jimiko
API Documentation
SSH Client (PyJimikoClient)
Constructor Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| ip | string | Required | IP address or hostname of the remote server |
| username | string | "" | Username for authentication |
| password | string | "" | Password for authentication |
| prompt | string | "" | Regex pattern to identify command completion |
| auth | bool | True | Whether to use authentication |
| port | int | 22 | SSH port number |
| command_timeout_ms | uint32 | 30000 | Command execution timeout in milliseconds |
| read_timeout_ms | uint32 | 5000 | Read operation timeout in milliseconds |
| terminal_type | string | "vt100" | Terminal type to use for PTY requests |
| use_pty | bool | True | Whether to request PTY |
Main Methods
| Method | Parameters | Return | Description |
|---|---|---|---|
| connect() | None | bool | Establishes connection to the server |
| disconnect() | None | None | Closes the connection |
| send(command, command_timeout_ms, read_timeout_ms, prompt) | string, uint32, uint32, string | string | Sends a command and returns output |
| get_initial_output(timeout_ms) | uint32 | string | Captures initial banner output |
PTY Options
When using shell connections, the SSH client uses a PTY (Pseudo Terminal). The available terminal types include:
- "vt100" - DEC VT100 terminal (default, recommended for Cisco devices)
- "vt102" - DEC VT102 terminal
- "vt220" - DEC VT220 terminal
- "xterm" - X Window System terminal
- "ansi" - ANSI terminal
- "linux" - Linux console
- "vanilla" - Basic terminal
- "dumb" - Minimal terminal
Different network devices may require different terminal types for optimal compatibility.
Default "vt100"
SFTP Client (PyJimikoSFTPClient)
Constructor Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| ip | string | Required | IP address or hostname of the remote server |
| username | string | Required | Username for authentication |
| password | string | Required | Password for authentication |
| port | int | 22 | SSH port number |
| operation_timeout_ms | uint32 | 30000 | Operation timeout in milliseconds |
Main Methods
| Method | Parameters | Return | Description |
|---|---|---|---|
| connect() | None | bool | Establishes SFTP connection |
| disconnect() | None | None | Closes the connection |
| put(local_path, remote_path, mode) | string, string, int | bool | Uploads file to remote server |
| get(remote_path, local_path) | string, string | bool | Downloads file from remote server |
| list_dir(path) | string | vector | Lists directory contents |
| file_exists(path) | string | bool | Checks if file exists |
| file_info(path) | string | SFTPFileInfo | Gets file information |
| make_dir(path, mode) | string, int | bool | Creates a directory |
| remove_file(path) | string | bool | Deletes a file |
| remove_dir(path) | string | bool | Removes a directory |
| rename(old_path, new_path) | string, string | bool | Renames a file or directory |
Usage Examples
SSH Client (Authenticated)
from jimiko import PyJimikoClient
# Create SSH client with authentication
client = PyJimikoClient(
ip="192.168.1.1",
username="admin",
password="password123",
prompt="[$#>]", # Regex pattern for common prompts
auth=True,
port=22,
command_timeout_ms=5000, # 5 seconds command timeout
read_timeout_ms=10000, # 10 seconds read timeout
terminal_type="vt100" # Use vt100 for Cisco devices
)
# Connect to device
if client.connect():
# Basic command - uses the default prompt
result = client.send("show version")
print(result)
# Configure command with custom prompt
config_result = client.send("configure terminal", prompt="\\(config\\)#")
interface_result = client.send("interface GigabitEthernet0/1", prompt="\\(config-if\\)#")
# Return to enable mode
client.send("end", prompt="#")
# Command with longer timeout
result = client.send("show tech-support", command_timeout_ms=60000)
print(result)
# Disconnect when done
client.disconnect()
SSH Client (Non-Authenticated)
from jimiko import PyJimikoClient
# Create SSH client without authentication (for legacy devices)
client = PyJimikoClient(
ip="192.168.1.2",
auth=False,
port=22,
terminal_type="vt100" # Using vt100 terminal type
)
# Connect to device
if client.connect():
# Get initial banner/login prompt
initial_output = client.get_initial_output(timeout_ms=5000)
print(initial_output)
# Send login credentials
if "login:" in initial_output:
result = client.send("admin")
result = client.send("password123")
# Now send commands as normal
result = client.send("rtrv-hdr:::;")
print(result)
# Disconnect when done
client.disconnect()
SFTP Client
from jimiko import PyJimikoSFTPClient
import os
# Create SFTP client
sftp = PyJimikoSFTPClient(
ip="127.0.0.1",
username="admin",
password="password123",
port=22,
operation_timeout_ms=30000 # 30 second timeout
)
# Connect to server
if sftp.connect():
# Upload a file (with mode 0644)
sftp.put("local_file.txt", "/remote/path/file.txt", 0o644)
# Download a file
sftp.get("/remote/path/file.txt", "downloaded_file.txt")
# List directory contents
files = sftp.list_dir("/remote/path")
for file_info in files:
print(f"Name: {file_info.name}, Size: {file_info.size} bytes")
# Check if file exists
if sftp.file_exists("/remote/path/file.txt"):
# Get file info
info = sftp.file_info("/remote/path/file.txt")
print(f"File size: {info.size}, Modified: {info.mtime}")
# Create directory
sftp.make_dir("/remote/path/new_dir", 0o755)
# Rename file
sftp.rename("/remote/path/file.txt", "/remote/path/new_file.txt")
# Delete file
sftp.remove_file("/remote/path/new_file.txt")
# Remove directory
sftp.remove_dir("/remote/path/new_dir")
# Disconnect when done
sftp.disconnect()
Why Jimiko?
Jimiko similar features of Paramiko and Netmiko with high-performance C++ implementation:
- Performance: Built on libssh2 with C++ for maximum speed
- Non-blocking: All operations are non-blocking by default
- Timeouts: Fine-grained timeout control for all operations
- Device Support: Special support for network devices including non-authenicated ssh sessions
- Error Handling: Robust error handling with specific exceptions
- Cross-Platform: macOS and Linux
Development Setup
- Clone the repository:
git clone https://github.com/jameshill/jimiko.git
cd jimiko
- Install development dependencies:
pip install -r requirements-dev.txt
- Build the extension:
python setup.py build_ext --inplace
Building from Source
Windows
# Set VCPKG_ROOT environment variable
# See github workflow
set VCPKG_ROOT=C:\vcpkg\installed\x64-windows
python setup.py build
macOS
Build locally on Mac.
bash
python setup.py build
License
MIT License
Contributing
- Fork the repository
- Create your feature branch
- Commit your changes
- Push to the branch
- Create a new Pull Request
Docker Build Environment for Jimiko
This directory contains a Docker-based build environment for compiling Jimiko with static linking of libssh2 and OpenSSL using manylinux-2014 compatibility.
Features
- Based on Fedora 35 (producing binaries compatible with CentOS/Rhel)
- Statically links libssh2 and OpenSSL with position independent code (-fPIC)
- Produces portable binary wheels that work on Centos/Rhel systems
- MacOS build locally
- Ubuntu - wip
Prerequisites
- Docker installed and running
- Access to the Fedora Docker registry
Building the Docker Image
From the root of the project:
See ./docker/
Build Python 3.6-3.11
./docker/build_sequential.sh
Customizing the Build
The Docker image includes:
- Modern GCC compiler from Fedora 35
- OpenSSL 1.1.1w built from source with -fPIC
- libssh2 1.11.0 built from source with -fPIC
- Environment variables set for static linking
If you need to customize the build process:
- Modify the
Dockerfileto install additional dependencies - Adjust the
build.shscript to change how the wheel is built - Rebuild the Docker image with your changes
Troubleshooting
- If you encounter issues with the static libraries, check that the paths in
build.shmatch the actual paths in the container. - Make sure your project is properly mounted as a volume in the container.
- For debugging, you can run the container with an interactive shell and execute build steps manually.
- For "dangerous relocation" errors when linking static libraries, ensure they were compiled with -fPIC.
- If you experience linker issues with Python, ensure that the Python shared libraries are in the LD_LIBRARY_PATH.
What Gets Created
The build process creates several artifacts:
- A standard Python wheel in the
dist/directory - A specific wheel with "-manylinux" in the filename (also in
dist/) - A platform-specific binary file in
src/jimiko/named_jimiko_wrapper.cpython-<python-version>-manylinux2024_x86_64.so
The extracted binary file is used when creating a universal wheel that includes binaries for multiple platforms.
Troubleshooting
Cisco Device Connection Issues
When connecting to Cisco IOS XE devices, you might encounter "Channel open failure" or "Error reading from channel: transport read" errors. This is often related to how these devices handle PTY allocation. Try these solutions:
-
Disable PTY allocation:
# Connect to Cisco device without PTY allocation client = PyJimikoClient( ip="192.168.1.1", username="admin", password="password123", prompt="#", use_pty=False # Skip PTY allocation entirely for problematic devices )
-
Adjust timeouts:
client = PyJimikoClient( ip="192.168.1.1", username="admin", password="password123", prompt="#", command_timeout_ms=60000, # 60 seconds read_timeout_ms=30000 # 30 seconds )
-
Disable pagination on Cisco devices:
client.connect() client.send("terminal length 0")
-
Try different terminal types if PTY is required:
client = PyJimikoClient( ip="192.168.1.1", username="admin", password="password123", prompt="#", terminal_type="dumb" # Try alternative terminal types )
If you're still having issues, check the SSH configuration on your Cisco device using:
show running-config | include ssh
show ssh
Command Prompt Handling
By default, the SSH client uses the prompt pattern specified during initialization to detect when a command has completed. However, for specific commands, you can override this behavior:
-
Default prompt handling: The prompt pattern from the constructor is used to detect command completion:
client = PyJimikoClient( ip="192.168.1.1", username="admin", password="password123", prompt="#", # This will be used for all commands by default )
-
Per-command prompt override: For special commands that have different output patterns, you can specify a command-specific prompt:
# Use the default prompt result = client.send("show version") # Use a custom prompt for a specific command result = client.send("configure terminal", prompt="\\(config\\)#") # Use a specific prompt for a yes/no prompt result = client.send("reload", prompt="\\[yes/no\\]")
-
Prompt matching: Both default and override prompts support:
- Regular expressions (preferred for more complex patterns)
- Simple string matching (as fallback if regex parsing fails)
This approach provides flexibility for working with various device types that may have different prompt styles or interactive commands.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jimiko-2.0.8rc1-py3-none-any.whl.
File metadata
- Download URL: jimiko-2.0.8rc1-py3-none-any.whl
- Upload date:
- Size: 38.1 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2780aafaa70347bf45b3f721d280764befa5b5dad53332a060af2bbdd990b13f
|
|
| MD5 |
3d64e2afcf9bdbb53aff587ece1ff65d
|
|
| BLAKE2b-256 |
1105b6da1fc55a6335250686836a9d9a138b553965fc1434ba9c8ad5f7f9c4d5
|