grass-remote-cli
Remote command execution library for SSH-based cluster operations.
Features
- ClusterCmd: Execute commands on multiple servers concurrently
- SshCmd: Single-server SSH execution with retry logic
- StderrClassifier: Intelligent error classification (real errors vs innocent warnings)
- Notifications: Slack integration for alerts (optional)
- AnsibleInventory: Parse Ansible inventory files (optional)
Installation
# Core (SSH execution)
pip install grass-remote-cli
# With Ansible inventory support
pip install grass-remote-cli[inventory]
# With Slack notifications
pip install grass-remote-cli[notifications]
# Everything
pip install grass-remote-cli[all]
Quick Start
from grass_remote_cli import ClusterCmd
# Execute command on multiple servers
cluster = ClusterCmd(
servers_ips=["<ip1>", "<ip2>", "<ip3>"],
username="<ssh_user>",
password="<ssh_password>",
timeout_in_sec=300,
)
results, timed_out = cluster.execute("docker ps")
for ip, (_, stdout, stderr) in results:
print(f"{ip}: {stdout}")
Single Server Execution
from grass_remote_cli import SshCmd
ssh = SshCmd()
ip, stdout, stderr = ssh.execute(
host_ip="<server_ip>",
username="<ssh_user>",
password="<ssh_password>",
commands="hostname && uptime"
)
print(stdout)
With Ansible Inventory
from grass_remote_cli import ClusterCmd
from grass_remote_cli.inventory import AnsibleInventory
# Load servers from Ansible inventory
inventory = AnsibleInventory("/path/to/ansible/inventories")
hosts = inventory.get_hosts_by_cluster("<cluster_name>")
# Deploy to cluster
ips = [host[1] for host in hosts] # Extract IPs
cluster = ClusterCmd(ips, username="<ssh_user>", password="<ssh_password>")
results, _ = cluster.execute("docker pull <image>")
Error Classification
The library intelligently classifies stderr output:
from grass_remote_cli.stderr_classifier import StderrClassifier
classifier = StderrClassifier()
result = classifier.classify(stderr_output)
if result['is_error']:
print(f"Real error: {result['summary']}")
else:
print("Innocent warning, safe to ignore")
Slack Notifications
import os
from grass_remote_cli.notifications import post_to_slack
# Set webhook via environment variable
os.environ["SLACK_WEBHOOK_URL"] = "https://hooks.slack.com/services/..."
post_to_slack("Deployment complete!", channel="#deployments")
# Or pass webhook directly
post_to_slack(
"Deployment complete!",
channel="#deployments",
webhook_url="https://hooks.slack.com/services/..."
)
Environment Variables
| Variable | Description |
|---|---|
SLACK_WEBHOOK_URL |
Slack webhook URL for notifications |
SSH_AUTH_TIMEOUT |
SSH authentication timeout (default: 120s) |
SSH_EXEC_TIMEOUT |
Command execution timeout (default: 900s) |
SSH_MAX_RETRIES |
Connection retry attempts (default: 3) |
SSH_MAX_WORKERS |
Concurrent SSH connections (default: 50) |
License
MIT
Metadata
Release files for grass-remote-cli 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| grass_remote_cli-0.2.0.tar.gz | 16.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| grass_remote_cli-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 30.2 kB
Release files / grass_remote_cli-0.2.0.tar.gz
| Download URL | grass_remote_cli-0.2.0.tar.gz |
|---|---|
| Size | 16.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3c14d0a3d38dd8d516a0792b046565dfa3069b91c00d90c97e985e0888179936
|
|
BLAKE2b-256 checksum How to use checksums |
b716938a012c5b89d81ab670b486a7135344270a6500f2b76c5c4b0e24d85473
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / grass_remote_cli-0.2.0-py3-none-any.whl
| Download URL | grass_remote_cli-0.2.0-py3-none-any.whl |
|---|---|
| Size | 13.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8cb35b087478319ddaf00055dfd604bf8f054eb2331a75d2d2733e0d2ecbf981
|
|
BLAKE2b-256 checksum How to use checksums |
9bc359d7b9eefd4fe436f15c4b9c6c1c98180d50542a70ce1c125e9f0aea8bea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|